aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/de/pixart/messenger/crypto/PgpEngine.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/de/pixart/messenger/crypto/PgpEngine.java')
-rw-r--r--src/main/java/de/pixart/messenger/crypto/PgpEngine.java304
1 files changed, 304 insertions, 0 deletions
diff --git a/src/main/java/de/pixart/messenger/crypto/PgpEngine.java b/src/main/java/de/pixart/messenger/crypto/PgpEngine.java
new file mode 100644
index 000000000..6c272f941
--- /dev/null
+++ b/src/main/java/de/pixart/messenger/crypto/PgpEngine.java
@@ -0,0 +1,304 @@
+package de.pixart.messenger.crypto;
+
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.util.Log;
+
+import org.openintents.openpgp.OpenPgpSignatureResult;
+import org.openintents.openpgp.util.OpenPgpApi;
+import org.openintents.openpgp.util.OpenPgpApi.IOpenPgpCallback;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import de.pixart.messenger.Config;
+import de.pixart.messenger.R;
+import de.pixart.messenger.entities.Account;
+import de.pixart.messenger.entities.Contact;
+import de.pixart.messenger.entities.Conversation;
+import de.pixart.messenger.entities.DownloadableFile;
+import de.pixart.messenger.entities.Message;
+import de.pixart.messenger.persistance.FileBackend;
+import de.pixart.messenger.services.XmppConnectionService;
+import de.pixart.messenger.ui.UiCallback;
+
+public class PgpEngine {
+ private OpenPgpApi api;
+ private XmppConnectionService mXmppConnectionService;
+
+ public PgpEngine(OpenPgpApi api, XmppConnectionService service) {
+ this.api = api;
+ this.mXmppConnectionService = service;
+ }
+
+ public void encrypt(final Message message, final UiCallback<Message> callback) {
+ Intent params = new Intent();
+ params.setAction(OpenPgpApi.ACTION_ENCRYPT);
+ final Conversation conversation = message.getConversation();
+ if (conversation.getMode() == Conversation.MODE_SINGLE) {
+ long[] keys = {
+ conversation.getContact().getPgpKeyId(),
+ conversation.getAccount().getPgpId()
+ };
+ params.putExtra(OpenPgpApi.EXTRA_KEY_IDS, keys);
+ } else {
+ params.putExtra(OpenPgpApi.EXTRA_KEY_IDS, conversation.getMucOptions().getPgpKeyIds());
+ }
+
+ if (!message.needsUploading()) {
+ params.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
+ String body;
+ if (message.hasFileOnRemoteHost()) {
+ body = message.getFileParams().url.toString();
+ } else {
+ body = message.getBody();
+ }
+ InputStream is = new ByteArrayInputStream(body.getBytes());
+ final OutputStream os = new ByteArrayOutputStream();
+ api.executeApiAsync(params, is, os, new IOpenPgpCallback() {
+
+ @Override
+ public void onReturn(Intent result) {
+ switch (result.getIntExtra(OpenPgpApi.RESULT_CODE,
+ OpenPgpApi.RESULT_CODE_ERROR)) {
+ case OpenPgpApi.RESULT_CODE_SUCCESS:
+ try {
+ os.flush();
+ StringBuilder encryptedMessageBody = new StringBuilder();
+ String[] lines = os.toString().split("\n");
+ for (int i = 2; i < lines.length - 1; ++i) {
+ if (!lines[i].contains("Version")) {
+ encryptedMessageBody.append(lines[i].trim());
+ }
+ }
+ message.setEncryptedBody(encryptedMessageBody
+ .toString());
+ callback.success(message);
+ } catch (IOException e) {
+ callback.error(R.string.openpgp_error, message);
+ }
+
+ break;
+ case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
+ callback.userInputRequried((PendingIntent) result
+ .getParcelableExtra(OpenPgpApi.RESULT_INTENT),
+ message);
+ break;
+ case OpenPgpApi.RESULT_CODE_ERROR:
+ callback.error(R.string.openpgp_error, message);
+ break;
+ }
+ }
+ });
+ } else {
+ try {
+ DownloadableFile inputFile = this.mXmppConnectionService
+ .getFileBackend().getFile(message, true);
+ DownloadableFile outputFile = this.mXmppConnectionService
+ .getFileBackend().getFile(message, false);
+ outputFile.getParentFile().mkdirs();
+ outputFile.createNewFile();
+ final InputStream is = new FileInputStream(inputFile);
+ final OutputStream os = new FileOutputStream(outputFile);
+ api.executeApiAsync(params, is, os, new IOpenPgpCallback() {
+
+ @Override
+ public void onReturn(Intent result) {
+ switch (result.getIntExtra(OpenPgpApi.RESULT_CODE,
+ OpenPgpApi.RESULT_CODE_ERROR)) {
+ case OpenPgpApi.RESULT_CODE_SUCCESS:
+ try {
+ os.flush();
+ } catch (IOException ignored) {
+ //ignored
+ }
+ FileBackend.close(os);
+ callback.success(message);
+ break;
+ case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
+ callback.userInputRequried(
+ (PendingIntent) result
+ .getParcelableExtra(OpenPgpApi.RESULT_INTENT),
+ message);
+ break;
+ case OpenPgpApi.RESULT_CODE_ERROR:
+ callback.error(R.string.openpgp_error, message);
+ break;
+ }
+ }
+ });
+ } catch (final IOException e) {
+ callback.error(R.string.openpgp_error, message);
+ }
+ }
+ }
+
+ public long fetchKeyId(Account account, String status, String signature) {
+ if ((signature == null) || (api == null)) {
+ return 0;
+ }
+ if (status == null) {
+ status = "";
+ }
+ final StringBuilder pgpSig = new StringBuilder();
+ pgpSig.append("-----BEGIN PGP SIGNED MESSAGE-----");
+ pgpSig.append('\n');
+ pgpSig.append('\n');
+ pgpSig.append(status);
+ pgpSig.append('\n');
+ pgpSig.append("-----BEGIN PGP SIGNATURE-----");
+ pgpSig.append('\n');
+ pgpSig.append('\n');
+ pgpSig.append(signature.replace("\n", "").trim());
+ pgpSig.append('\n');
+ pgpSig.append("-----END PGP SIGNATURE-----");
+ Intent params = new Intent();
+ params.setAction(OpenPgpApi.ACTION_DECRYPT_VERIFY);
+ params.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
+ InputStream is = new ByteArrayInputStream(pgpSig.toString().getBytes());
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ Intent result = api.executeApi(params, is, os);
+ switch (result.getIntExtra(OpenPgpApi.RESULT_CODE,
+ OpenPgpApi.RESULT_CODE_ERROR)) {
+ case OpenPgpApi.RESULT_CODE_SUCCESS:
+ OpenPgpSignatureResult sigResult = result
+ .getParcelableExtra(OpenPgpApi.RESULT_SIGNATURE);
+ if (sigResult != null) {
+ return sigResult.getKeyId();
+ } else {
+ return 0;
+ }
+ case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
+ return 0;
+ case OpenPgpApi.RESULT_CODE_ERROR:
+ return 0;
+ }
+ return 0;
+ }
+
+ public void chooseKey(final Account account, final UiCallback<Account> callback) {
+ Intent p = new Intent();
+ p.setAction(OpenPgpApi.ACTION_GET_SIGN_KEY_ID);
+ api.executeApiAsync(p, null, null, new IOpenPgpCallback() {
+
+ @Override
+ public void onReturn(Intent result) {
+ switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, 0)) {
+ case OpenPgpApi.RESULT_CODE_SUCCESS:
+ callback.success(account);
+ return;
+ case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
+ callback.userInputRequried((PendingIntent) result
+ .getParcelableExtra(OpenPgpApi.RESULT_INTENT),
+ account);
+ return;
+ case OpenPgpApi.RESULT_CODE_ERROR:
+ callback.error(R.string.openpgp_error, account);
+ }
+ }
+ });
+ }
+
+ public void generateSignature(final Account account, String status,
+ final UiCallback<Account> callback) {
+ if (account.getPgpId() == 0) {
+ return;
+ }
+ Intent params = new Intent();
+ params.setAction(OpenPgpApi.ACTION_CLEARTEXT_SIGN);
+ params.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
+ params.putExtra(OpenPgpApi.EXTRA_SIGN_KEY_ID, account.getPgpId());
+ InputStream is = new ByteArrayInputStream(status.getBytes());
+ final OutputStream os = new ByteArrayOutputStream();
+ Log.d(Config.LOGTAG,account.getJid().toBareJid()+": signing status message \""+status+"\"");
+ api.executeApiAsync(params, is, os, new IOpenPgpCallback() {
+
+ @Override
+ public void onReturn(Intent result) {
+ switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, 0)) {
+ case OpenPgpApi.RESULT_CODE_SUCCESS:
+ StringBuilder signatureBuilder = new StringBuilder();
+ try {
+ os.flush();
+ String[] lines = os.toString().split("\n");
+ boolean sig = false;
+ for (String line : lines) {
+ if (sig) {
+ if (line.contains("END PGP SIGNATURE")) {
+ sig = false;
+ } else {
+ if (!line.contains("Version")) {
+ signatureBuilder.append(line.trim());
+ }
+ }
+ }
+ if (line.contains("BEGIN PGP SIGNATURE")) {
+ sig = true;
+ }
+ }
+ } catch (IOException e) {
+ callback.error(R.string.openpgp_error, account);
+ return;
+ }
+ account.setPgpSignature(signatureBuilder.toString());
+ callback.success(account);
+ return;
+ case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
+ callback.userInputRequried((PendingIntent) result
+ .getParcelableExtra(OpenPgpApi.RESULT_INTENT),
+ account);
+ return;
+ case OpenPgpApi.RESULT_CODE_ERROR:
+ callback.error(R.string.unable_to_connect_to_keychain, account);
+ }
+ }
+ });
+ }
+
+ public void hasKey(final Contact contact, final UiCallback<Contact> callback) {
+ Intent params = new Intent();
+ params.setAction(OpenPgpApi.ACTION_GET_KEY);
+ params.putExtra(OpenPgpApi.EXTRA_KEY_ID, contact.getPgpKeyId());
+ api.executeApiAsync(params, null, null, new IOpenPgpCallback() {
+
+ @Override
+ public void onReturn(Intent result) {
+ switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, 0)) {
+ case OpenPgpApi.RESULT_CODE_SUCCESS:
+ callback.success(contact);
+ return;
+ case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
+ callback.userInputRequried((PendingIntent) result
+ .getParcelableExtra(OpenPgpApi.RESULT_INTENT),
+ contact);
+ return;
+ case OpenPgpApi.RESULT_CODE_ERROR:
+ callback.error(R.string.openpgp_error, contact);
+ }
+ }
+ });
+ }
+
+ public PendingIntent getIntentForKey(Contact contact) {
+ Intent params = new Intent();
+ params.setAction(OpenPgpApi.ACTION_GET_KEY);
+ params.putExtra(OpenPgpApi.EXTRA_KEY_ID, contact.getPgpKeyId());
+ Intent result = api.executeApi(params, null, null);
+ return (PendingIntent) result
+ .getParcelableExtra(OpenPgpApi.RESULT_INTENT);
+ }
+
+ public PendingIntent getIntentForKey(Account account, long pgpKeyId) {
+ Intent params = new Intent();
+ params.setAction(OpenPgpApi.ACTION_GET_KEY);
+ params.putExtra(OpenPgpApi.EXTRA_KEY_ID, pgpKeyId);
+ Intent result = api.executeApi(params, null, null);
+ return (PendingIntent) result
+ .getParcelableExtra(OpenPgpApi.RESULT_INTENT);
+ }
+}