Encrypt/decrypt attachments

This commit is contained in:
M66B 2018-10-29 09:13:29 +00:00
parent 78005ab869
commit 97562a9b38
3 changed files with 76 additions and 48 deletions

View File

@ -920,32 +920,62 @@ public class ActivityView extends ActivityBilling implements FragmentManager.OnB
new SimpleTask<PendingIntent>() { new SimpleTask<PendingIntent>() {
@Override @Override
protected PendingIntent onLoad(Context context, Bundle args) throws Throwable { protected PendingIntent onLoad(Context context, Bundle args) throws Throwable {
// Get arguments
long id = args.getLong("id"); long id = args.getLong("id");
Intent data = args.getParcelable("data"); Intent data = args.getParcelable("data");
DB db = DB.getInstance(context); if (!pgpService.isBound())
for (EntityAttachment attachment : db.attachment().getAttachments(id)) throw new IllegalArgumentException(getString(R.string.title_no_openpgp));
if (attachment.available && "encrypted.asc".equals(attachment.name)) {
if (!pgpService.isBound())
throw new IllegalArgumentException(getString(R.string.title_no_openpgp));
OpenPgpApi api = new OpenPgpApi(context, pgpService.getService()); DB db = DB.getInstance(context);
// Find encrypted data
List<EntityAttachment> attachments = db.attachment().getAttachments(id);
for (EntityAttachment attachment : attachments)
if (attachment.available && "encrypted.asc".equals(attachment.name)) {
// Serialize encrypted data
FileInputStream encrypted = new FileInputStream(EntityAttachment.getFile(context, attachment.id)); FileInputStream encrypted = new FileInputStream(EntityAttachment.getFile(context, attachment.id));
ByteArrayOutputStream decrypted = new ByteArrayOutputStream(); ByteArrayOutputStream decrypted = new ByteArrayOutputStream();
// Decrypt message
OpenPgpApi api = new OpenPgpApi(context, pgpService.getService());
Intent result = api.executeApi(data, encrypted, decrypted); Intent result = api.executeApi(data, encrypted, decrypted);
switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) { switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) {
case OpenPgpApi.RESULT_CODE_SUCCESS: case OpenPgpApi.RESULT_CODE_SUCCESS:
ByteArrayInputStream is = new ByteArrayInputStream(decrypted.toByteArray()); // Decode message
Properties props = MessageHelper.getSessionProperties(Helper.AUTH_TYPE_PASSWORD, false); Properties props = MessageHelper.getSessionProperties(Helper.AUTH_TYPE_PASSWORD, false);
Session isession = Session.getInstance(props, null); Session isession = Session.getInstance(props, null);
ByteArrayInputStream is = new ByteArrayInputStream(decrypted.toByteArray());
MimeMessage imessage = new MimeMessage(isession, is); MimeMessage imessage = new MimeMessage(isession, is);
MessageHelper helper = new MessageHelper(imessage); MessageHelper helper = new MessageHelper(imessage);
EntityMessage m = db.message().getMessage(id); try {
m.write(context, helper.getHtml()); db.beginTransaction();
db.message().setMessageStored(id, new Date().getTime());
// Write decrypted body
EntityMessage m = db.message().getMessage(id);
m.write(context, helper.getHtml());
// Remove previously decrypted attachments
for (EntityAttachment a : attachments)
if (!"encrypted.asc".equals(a.name))
db.attachment().deleteAttachment(a.id);
// Add decrypted attachments
int sequence = db.attachment().getAttachmentSequence(id);
for (EntityAttachment a : helper.getAttachments()) {
a.message = id;
a.sequence = ++sequence;
a.id = db.attachment().insertAttachment(a);
}
db.message().setMessageStored(id, new Date().getTime());
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
break; break;
case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED: case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:

View File

@ -66,7 +66,6 @@ import android.widget.Toast;
import com.google.android.material.bottomnavigation.BottomNavigationView; import com.google.android.material.bottomnavigation.BottomNavigationView;
import com.google.android.material.snackbar.Snackbar; import com.google.android.material.snackbar.Snackbar;
import org.jsoup.Jsoup;
import org.openintents.openpgp.OpenPgpError; import org.openintents.openpgp.OpenPgpError;
import org.openintents.openpgp.util.OpenPgpApi; import org.openintents.openpgp.util.OpenPgpApi;
import org.openintents.openpgp.util.OpenPgpServiceConnection; import org.openintents.openpgp.util.OpenPgpServiceConnection;
@ -79,7 +78,6 @@ import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@ -89,15 +87,11 @@ import java.util.List;
import java.util.Properties; import java.util.Properties;
import javax.mail.Address; import javax.mail.Address;
import javax.mail.BodyPart;
import javax.mail.MessageRemovedException; import javax.mail.MessageRemovedException;
import javax.mail.Multipart;
import javax.mail.Session; import javax.mail.Session;
import javax.mail.internet.AddressException; import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress; import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@ -526,64 +520,62 @@ public class FragmentCompose extends FragmentEx {
new SimpleTask<PendingIntent>() { new SimpleTask<PendingIntent>() {
@Override @Override
protected PendingIntent onLoad(Context context, Bundle args) throws Throwable { protected PendingIntent onLoad(Context context, Bundle args) throws Throwable {
// Get arguments
long id = args.getLong("id"); long id = args.getLong("id");
Intent data = args.getParcelable("data"); Intent data = args.getParcelable("data");
String body = EntityMessage.read(getContext(), id); if (!pgpService.isBound())
throw new IllegalArgumentException(getString(R.string.title_no_openpgp));
BodyPart plain = new MimeBodyPart(); DB db = DB.getInstance(context);
plain.setContent(Jsoup.parse(body).text(), "text/plain; charset=" + Charset.defaultCharset().name());
BodyPart html = new MimeBodyPart(); // Get attachments
html.setContent(body, "text/html; charset=" + Charset.defaultCharset().name()); EntityMessage message = db.message().getMessage(id);
List<EntityAttachment> attachments = db.attachment().getAttachments(id);
Multipart alternative = new MimeMultipart("alternative"); for (EntityAttachment attachment : new ArrayList<>(attachments))
alternative.addBodyPart(plain); if ("encrypted.asc".equals(attachment.name) || "signature.asc".equals(attachment.name))
alternative.addBodyPart(html); attachments.remove(attachment);
// Build message
Properties props = MessageHelper.getSessionProperties(Helper.AUTH_TYPE_PASSWORD, false); Properties props = MessageHelper.getSessionProperties(Helper.AUTH_TYPE_PASSWORD, false);
Session isession = Session.getInstance(props, null); Session isession = Session.getInstance(props, null);
MimeMessage imessage = new MimeMessage(isession); MimeMessage imessage = new MimeMessage(isession);
imessage.setContent(alternative); MessageHelper.build(context, message, attachments, imessage);
// Serialize message
ByteArrayOutputStream os = new ByteArrayOutputStream(); ByteArrayOutputStream os = new ByteArrayOutputStream();
imessage.writeTo(os); imessage.writeTo(os);
ByteArrayInputStream decrypted = new ByteArrayInputStream(os.toByteArray()); ByteArrayInputStream decrypted = new ByteArrayInputStream(os.toByteArray());
ByteArrayOutputStream encrypted = new ByteArrayOutputStream(); ByteArrayOutputStream encrypted = new ByteArrayOutputStream();
if (!pgpService.isBound()) // Encrypt message
throw new IllegalArgumentException(getString(R.string.title_no_openpgp)); OpenPgpApi api = new OpenPgpApi(context, pgpService.getService());
OpenPgpApi api = new OpenPgpApi(getContext(), pgpService.getService());
Intent result = api.executeApi(data, decrypted, encrypted); Intent result = api.executeApi(data, decrypted, encrypted);
switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) { switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) {
case OpenPgpApi.RESULT_CODE_SUCCESS: case OpenPgpApi.RESULT_CODE_SUCCESS:
EntityAttachment attachment1 = new EntityAttachment(); // Get public signature
EntityAttachment attachment2 = new EntityAttachment();
Intent keyRequest = new Intent(); Intent keyRequest = new Intent();
keyRequest.setAction(OpenPgpApi.ACTION_DETACHED_SIGN); keyRequest.setAction(OpenPgpApi.ACTION_DETACHED_SIGN);
keyRequest.putExtra(OpenPgpApi.EXTRA_SIGN_KEY_ID, data.getLongExtra(OpenPgpApi.EXTRA_SIGN_KEY_ID, -1)); keyRequest.putExtra(OpenPgpApi.EXTRA_SIGN_KEY_ID, data.getLongExtra(OpenPgpApi.EXTRA_SIGN_KEY_ID, -1));
Intent keyData = api.executeApi(keyRequest, decrypted, null); Intent key = api.executeApi(keyRequest, decrypted, null);
int r = keyData.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); int r = key.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
if (r != OpenPgpApi.RESULT_CODE_SUCCESS) { if (r != OpenPgpApi.RESULT_CODE_SUCCESS) {
OpenPgpError error = keyData.getParcelableExtra(OpenPgpApi.RESULT_ERROR); OpenPgpError error = key.getParcelableExtra(OpenPgpApi.RESULT_ERROR);
throw new IllegalArgumentException(error.getMessage()); throw new IllegalArgumentException(error.getMessage());
} }
byte[] signature = keyData.getByteArrayExtra(OpenPgpApi.RESULT_DETACHED_SIGNATURE); // Attach encrypted data
DB db = DB.getInstance(context);
try { try {
db.beginTransaction(); db.beginTransaction();
// Delete previously encrypted data
for (EntityAttachment attachment : db.attachment().getAttachments(id)) for (EntityAttachment attachment : db.attachment().getAttachments(id))
if ("encrypted.asc".equals(attachment.name) || "signature.asc".equals(attachment.name)) if ("encrypted.asc".equals(attachment.name) || "signature.asc".equals(attachment.name))
db.attachment().deleteAttachment(attachment.id); db.attachment().deleteAttachment(attachment.id);
int seq = db.attachment().getAttachmentSequence(id); int seq = db.attachment().getAttachmentSequence(id);
EntityAttachment attachment1 = new EntityAttachment();
attachment1.message = id; attachment1.message = id;
attachment1.sequence = seq + 1; attachment1.sequence = seq + 1;
attachment1.name = "encrypted.asc"; attachment1.name = "encrypted.asc";
@ -594,11 +586,11 @@ public class FragmentCompose extends FragmentEx {
OutputStream os1 = null; OutputStream os1 = null;
try { try {
byte[] bytes1 = encrypted.toByteArray();
os1 = new BufferedOutputStream(new FileOutputStream(file1)); os1 = new BufferedOutputStream(new FileOutputStream(file1));
byte[] bytes = encrypted.toByteArray(); os1.write(bytes1);
os1.write(bytes);
attachment1.size = bytes.length; attachment1.size = bytes1.length;
attachment1.progress = null; attachment1.progress = null;
attachment1.available = true; attachment1.available = true;
db.attachment().updateAttachment(attachment1); db.attachment().updateAttachment(attachment1);
@ -607,6 +599,7 @@ public class FragmentCompose extends FragmentEx {
os1.close(); os1.close();
} }
EntityAttachment attachment2 = new EntityAttachment();
attachment2.message = id; attachment2.message = id;
attachment2.sequence = seq + 2; attachment2.sequence = seq + 2;
attachment2.name = "signature.asc"; attachment2.name = "signature.asc";
@ -617,10 +610,11 @@ public class FragmentCompose extends FragmentEx {
OutputStream os2 = null; OutputStream os2 = null;
try { try {
byte[] bytes2 = key.getByteArrayExtra(OpenPgpApi.RESULT_DETACHED_SIGNATURE);
os2 = new BufferedOutputStream(new FileOutputStream(file2)); os2 = new BufferedOutputStream(new FileOutputStream(file2));
os2.write(signature); os2.write(bytes2);
attachment2.size = signature.length; attachment2.size = bytes2.length;
attachment2.progress = null; attachment2.progress = null;
attachment2.available = true; attachment2.available = true;
db.attachment().updateAttachment(attachment2); db.attachment().updateAttachment(attachment2);

View File

@ -254,6 +254,12 @@ public class MessageHelper {
return imessage; return imessage;
} }
build(context, message, attachments, imessage);
return imessage;
}
static void build(Context context, EntityMessage message, List<EntityAttachment> attachments, MimeMessage imessage) throws IOException, MessagingException {
String body = message.read(context); String body = message.read(context);
BodyPart plain = new MimeBodyPart(); BodyPart plain = new MimeBodyPart();
@ -302,8 +308,6 @@ public class MessageHelper {
imessage.setContent(multipart); imessage.setContent(multipart);
} }
return imessage;
} }
MessageHelper(MimeMessage message) { MessageHelper(MimeMessage message) {