disarmored = new ArrayList<>();
for (String line : lines)
if (!TextUtils.isEmpty(line) && !line.contains(": "))
disarmored.add(line);
String pgpMessage = TextUtils.join("\n\r", disarmored);
inline = true;
in = new ByteArrayInputStream(pgpMessage.getBytes());
out = new FileOutputStream(plain);
}
}
}
}
if (in == null)
if (auto)
return null;
else
throw new IllegalArgumentException(context.getString(R.string.title_not_encrypted));
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean autocrypt = prefs.getBoolean("autocrypt", true);
if (autocrypt &&
message.from != null && message.from.length > 0 &&
message.autocrypt != null &&
OpenPgpApi.ACTION_DECRYPT_VERIFY.equals(data.getAction()))
try {
String peer = ((InternetAddress) message.from[0]).getAddress();
String addr = null;
boolean mutual = false;
byte[] keydata = null;
// https://autocrypt.org/level1.html#the-autocrypt-header
String[] param = message.autocrypt.split(";");
for (int i = 0; i < param.length; i++) {
int e = param[i].indexOf("=");
if (e > 0) {
String key = param[i].substring(0, e).trim().toLowerCase(Locale.ROOT);
String value = param[i].substring(e + 1);
Log.i("Autocrypt " + key + "=" + value);
switch (key) {
case "addr":
addr = value;
break;
case "prefer-encrypt":
mutual = value.trim().toLowerCase(Locale.ROOT).equals("mutual");
break;
case "keydata":
keydata = Base64.decode(value, Base64.DEFAULT);
break;
}
}
}
if (addr == null)
throw new IllegalArgumentException("Autocrypt: addr not found");
if (!addr.equalsIgnoreCase(peer))
throw new IllegalArgumentException("Autocrypt: addr different from peer");
if (keydata == null)
throw new IllegalArgumentException("Autocrypt: keydata not found");
AutocryptPeerUpdate update = AutocryptPeerUpdate.create(
keydata, new Date(message.received), mutual);
data.putExtra(OpenPgpApi.EXTRA_AUTOCRYPT_PEER_ID, addr);
data.putExtra(OpenPgpApi.EXTRA_AUTOCRYPT_PEER_UPDATE, update);
} catch (Throwable ex) {
Log.w(ex);
}
Intent result;
try {
// Decrypt message
Log.i("Executing " + data.getAction());
Log.logExtras(data);
OpenPgpApi api = new OpenPgpApi(context, pgpService.getService());
result = api.executeApi(data, in, out);
int resultCode = result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
Log.i("Result action=" + data.getAction() + " code=" + resultCode);
Log.logExtras(data);
switch (resultCode) {
case OpenPgpApi.RESULT_CODE_SUCCESS:
if (out != null)
if (inline) {
try {
db.beginTransaction();
// Write decrypted body
String text = Helper.readText(plain);
String html = "" + HtmlHelper.formatPre(text) + "
";
Helper.writeText(message.getFile(context), html);
db.message().setMessageStored(message.id, new Date().getTime());
db.message().setMessageFts(message.id, false);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
WorkerFts.init(context, false);
} else {
// Decode message
MessageHelper.MessageParts parts;
Properties props = MessageHelper.getSessionProperties();
Session isession = Session.getInstance(props, null);
try (InputStream fis = new FileInputStream(plain)) {
MimeMessage imessage = new MimeMessage(isession, fis);
MessageHelper helper = new MessageHelper(imessage, context);
parts = helper.getMessageParts();
}
try {
db.beginTransaction();
// Write decrypted body
String html = parts.getHtml(context);
Helper.writeText(message.getFile(context), html);
// Remove existing attachments
db.attachment().deleteAttachments(message.id);
// Add decrypted attachments
List remotes = parts.getAttachments();
for (int index = 0; index < remotes.size(); index++) {
EntityAttachment remote = remotes.get(index);
remote.message = message.id;
remote.sequence = index + 1;
remote.id = db.attachment().insertAttachment(remote);
try {
parts.downloadAttachment(context, index, remote);
} catch (Throwable ex) {
Log.e(ex);
}
}
db.message().setMessageEncrypt(message.id, parts.getEncryption());
db.message().setMessageStored(message.id, new Date().getTime());
db.message().setMessageFts(message.id, false);
db.setTransactionSuccessful();
} catch (SQLiteConstraintException ex) {
// Message removed
Log.w(ex);
} finally {
db.endTransaction();
}
WorkerFts.init(context, false);
}
// Check signature status
OpenPgpSignatureResult sigResult = result.getParcelableExtra(OpenPgpApi.RESULT_SIGNATURE);
int sresult = (sigResult == null ? RESULT_NO_SIGNATURE : sigResult.getResult());
if (sigResult == null)
Log.w("PGP signature result missing");
else
Log.i("PGP signature result=" + sresult);
if (sresult == RESULT_NO_SIGNATURE)
args.putString("sigresult", context.getString(R.string.title_signature_none));
else if (sresult == RESULT_VALID_KEY_CONFIRMED || sresult == RESULT_VALID_KEY_UNCONFIRMED) {
List users = sigResult.getConfirmedUserIds();
String text;
if (users.size() > 0)
text = context.getString(sresult == RESULT_VALID_KEY_UNCONFIRMED
? R.string.title_signature_unconfirmed_from
: R.string.title_signature_valid_from,
TextUtils.join(", ", users));
else
text = context.getString(sresult == RESULT_VALID_KEY_UNCONFIRMED
? R.string.title_signature_unconfirmed
: R.string.title_signature_valid);
args.putString("sigresult", text);
if (sresult == RESULT_VALID_KEY_CONFIRMED)
db.message().setMessageVerified(message.id, true);
} else if (sresult == RESULT_KEY_MISSING)
args.putString("sigresult", context.getString(R.string.title_signature_key_missing));
else {
String text = context.getString(R.string.title_signature_invalid_reason, Integer.toString(sresult));
args.putString("sigresult", text);
}
break;
case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
if (auto)
return null;
return result.getParcelableExtra(OpenPgpApi.RESULT_INTENT);
case OpenPgpApi.RESULT_CODE_ERROR:
OpenPgpError error = result.getParcelableExtra(OpenPgpApi.RESULT_ERROR);
throw new IllegalArgumentException(
"OpenPgp" +
" error " + (error == null ? "?" : error.getErrorId()) +
": " + (error == null ? "?" : error.getMessage()));
default:
throw new IllegalStateException("OpenPgp unknown result code=" + resultCode);
}
} finally {
plain.delete();
}
return null;
}
@Override
protected void onExecuted(Bundle args, PendingIntent pi) {
if (args.containsKey("sigresult")) {
String text = args.getString("sigresult");
Snackbar.make(view, text, Snackbar.LENGTH_LONG)
.setGestureInsetBottomIgnored(true).show();
}
if (pi != null)
try {
Log.i("Executing pi=" + pi);
startIntentSenderForResult(
pi.getIntentSender(),
REQUEST_OPENPGP,
null, 0, 0, 0, null);
} catch (IntentSender.SendIntentException ex) {
// Likely cancelled
Log.w(ex);
}
}
@Override
protected void onException(Bundle args, Throwable ex) {
if (ex instanceof IllegalArgumentException) {
Log.i(ex);
Snackbar.make(view, ex.getMessage(), Snackbar.LENGTH_LONG)
.setGestureInsetBottomIgnored(true).show();
} else
Log.unexpectedError(getParentFragmentManager(), ex);
}
}.execute(this, args, "decrypt:pgp");
}
private void onSmime(Bundle args) {
new SimpleTask() {
@Override
protected X509Certificate onExecute(Context context, Bundle args) throws Throwable {
long id = args.getLong("id");
int type = args.getInt("type");
DB db = DB.getInstance(context);
EntityMessage message = db.message().getMessage(id);
if (message == null)
return null;
X509Certificate result = null;
if (EntityMessage.SMIME_SIGNONLY.equals(type)) {
// Get content/signature
boolean sdata = false;
File content = null;
File signature = null;
List attachments = db.attachment().getAttachments(message.id);
for (EntityAttachment attachment : attachments)
if (EntityAttachment.SMIME_SIGNATURE.equals(attachment.encryption)) {
if (!attachment.available)
throw new IllegalArgumentException(context.getString(R.string.title_attachments_missing));
signature = attachment.getFile(context);
} else if (EntityAttachment.SMIME_SIGNED_DATA.equals(attachment.encryption)) {
if (!attachment.available)
throw new IllegalArgumentException(context.getString(R.string.title_attachments_missing));
sdata = true;
signature = attachment.getFile(context);
} else if (EntityAttachment.SMIME_CONTENT.equals(attachment.encryption)) {
if (!attachment.available)
throw new IllegalArgumentException(context.getString(R.string.title_attachments_missing));
content = attachment.getFile(context);
}
if (content == null && !sdata)
throw new IllegalArgumentException("Signed content missing");
if (signature == null)
throw new IllegalArgumentException("Signature missing");
// Build signed data
InputStream is = null;
FileInputStream fis = new FileInputStream(signature);
CMSSignedData signedData;
// TODO: CMSSignedDataParser
if (sdata) {
signedData = new CMSSignedData(fis);
CMSTypedData sc = signedData.getSignedContent();
if (sc == null)
throw new IllegalArgumentException("Signed content missing");
is = new ByteArrayInputStream((byte[]) sc.getContent());
} else {
CMSProcessable signedContent = new CMSProcessableFile(content);
signedData = new CMSSignedData(signedContent, fis);
}
// Check signature
boolean matching = false;
Store store = signedData.getCertificates();
SignerInformationStore signerInfos = signedData.getSignerInfos();
Collection signers = signerInfos.getSigners();
Log.i("Signers count=" + signers.size());
for (SignerInformation signer : signers) {
SignerId sid = signer.getSID();
Log.i("Checking signer=" + (sid == null ? null : sid.getIssuer()));
Collection