PgpEngine.java

  1package eu.siacs.conversations.crypto;
  2
  3import java.io.ByteArrayInputStream;
  4import java.io.ByteArrayOutputStream;
  5import java.io.InputStream;
  6
  7import org.openintents.openpgp.OpenPgpError;
  8import org.openintents.openpgp.OpenPgpSignatureResult;
  9import org.openintents.openpgp.util.OpenPgpApi;
 10
 11import eu.siacs.conversations.entities.Account;
 12
 13import android.app.PendingIntent;
 14import android.content.Intent;
 15import android.util.Log;
 16
 17public class PgpEngine {
 18	private OpenPgpApi api;
 19
 20	public PgpEngine(OpenPgpApi api) {
 21		this.api = api;
 22	}
 23
 24	public String decrypt(Account account, String message) throws UserInputRequiredException,
 25			OpenPgpException {
 26		Intent params = new Intent();
 27		params.setAction(OpenPgpApi.ACTION_DECRYPT_VERIFY);
 28		params.putExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME, account.getJid());
 29		InputStream is = new ByteArrayInputStream(message.getBytes());
 30		ByteArrayOutputStream os = new ByteArrayOutputStream();
 31		Intent result = api.executeApi(params, is, os);
 32		switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) {
 33		case OpenPgpApi.RESULT_CODE_SUCCESS:
 34			return os.toString();
 35		case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
 36			throw new UserInputRequiredException((PendingIntent) result.getParcelableExtra(OpenPgpApi.RESULT_INTENT));
 37		case OpenPgpApi.RESULT_CODE_ERROR:
 38			throw new OpenPgpException(
 39					(OpenPgpError) result.getParcelableExtra(OpenPgpApi.RESULT_ERROR));
 40		default:
 41			return null;
 42		}
 43	}
 44
 45	public String encrypt(Account account, long keyId, String message) throws UserInputRequiredException, OpenPgpException {
 46		Log.d("xmppService","called to pgpengine::encrypt");
 47		long[] keys = {keyId};
 48		Intent params = new Intent();
 49		params.setAction(OpenPgpApi.ACTION_ENCRYPT);
 50		params.putExtra(OpenPgpApi.EXTRA_KEY_IDS,keys);
 51		params.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
 52		params.putExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME, account.getJid());
 53		
 54		InputStream is = new ByteArrayInputStream(message.getBytes());
 55		ByteArrayOutputStream os = new ByteArrayOutputStream();
 56		Intent result = api.executeApi(params, is, os);
 57		switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) {
 58		case OpenPgpApi.RESULT_CODE_SUCCESS:
 59			StringBuilder encryptedMessageBody = new StringBuilder();
 60			String[] lines = os.toString().split("\n");
 61			for (int i = 3; i < lines.length - 1; ++i) {
 62				encryptedMessageBody.append(lines[i].trim());
 63			}
 64			Log.d("xmppService","encrpyted message: "+encryptedMessageBody.toString());
 65			return encryptedMessageBody.toString();
 66		case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
 67			Log.d("xmppService","user input required");
 68			throw new UserInputRequiredException((PendingIntent) result.getParcelableExtra(OpenPgpApi.RESULT_INTENT));
 69		case OpenPgpApi.RESULT_CODE_ERROR:
 70			OpenPgpError error = (OpenPgpError) result.getParcelableExtra(OpenPgpApi.RESULT_ERROR);
 71			throw new OpenPgpException(error);
 72		default:
 73			return null;
 74		}
 75	}
 76
 77	public long fetchKeyId(Account account, String status, String signature)
 78			throws OpenPgpException {
 79		if ((signature==null)||(api==null)) {
 80			return 0;
 81		}
 82		if (status==null) {
 83			status="";
 84		}
 85		StringBuilder pgpSig = new StringBuilder();
 86		pgpSig.append("-----BEGIN PGP SIGNED MESSAGE-----");
 87		pgpSig.append('\n');
 88		pgpSig.append('\n');
 89		pgpSig.append(status);
 90		pgpSig.append('\n');
 91		pgpSig.append("-----BEGIN PGP SIGNATURE-----");
 92		pgpSig.append('\n');
 93		pgpSig.append('\n');
 94		pgpSig.append(signature.replace("\n", "").trim());
 95		pgpSig.append('\n');
 96		pgpSig.append("-----END PGP SIGNATURE-----");
 97		Intent params = new Intent();
 98		params.setAction(OpenPgpApi.ACTION_DECRYPT_VERIFY);
 99		params.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
100		InputStream is = new ByteArrayInputStream(pgpSig.toString().getBytes());
101		ByteArrayOutputStream os = new ByteArrayOutputStream();
102		Intent result = api.executeApi(params, is, os);
103		switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) {
104		case OpenPgpApi.RESULT_CODE_SUCCESS:
105			OpenPgpSignatureResult sigResult
106            = result.getParcelableExtra(OpenPgpApi.RESULT_SIGNATURE);
107			if (sigResult==null) {
108				return 0;
109			} else {
110				return sigResult.getKeyId();
111			}
112		case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
113			break;
114		case OpenPgpApi.RESULT_CODE_ERROR:
115			throw new OpenPgpException(
116					(OpenPgpError) result.getParcelableExtra(OpenPgpApi.RESULT_ERROR));
117		}
118		return 0;
119	}
120
121	public String generateSignature(Account account, String status)
122			throws UserInputRequiredException {
123		Intent params = new Intent();
124		params.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
125		params.setAction(OpenPgpApi.ACTION_SIGN);
126		params.putExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME, account.getJid());
127		InputStream is = new ByteArrayInputStream(status.getBytes());
128		ByteArrayOutputStream os = new ByteArrayOutputStream();
129		Intent result = api.executeApi(params, is, os);
130		StringBuilder signatureBuilder = new StringBuilder();
131		switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, 0)) {
132		case OpenPgpApi.RESULT_CODE_SUCCESS:
133			String[] lines = os.toString().split("\n");
134			for (int i = 7; i < lines.length - 1; ++i) {
135				signatureBuilder.append(lines[i].trim());
136			}
137			break;
138		case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
139			throw new UserInputRequiredException((PendingIntent) result.getParcelableExtra(OpenPgpApi.RESULT_INTENT));
140		case OpenPgpApi.RESULT_CODE_ERROR:
141			break;
142		}
143		return signatureBuilder.toString();
144	}
145
146	public class UserInputRequiredException extends Exception {
147		private static final long serialVersionUID = -6913480043269132016L;
148		private PendingIntent pi;
149
150		public UserInputRequiredException(PendingIntent pi) {
151			this.pi = pi;
152		}
153
154		public PendingIntent getPendingIntent() {
155			return this.pi;
156		}
157	}
158
159	public class OpenPgpException extends Exception {
160		private static final long serialVersionUID = -7324789703473056077L;
161		private OpenPgpError error;
162
163		public OpenPgpException(OpenPgpError openPgpError) {
164			this.error = openPgpError;
165		}
166
167		public OpenPgpError getOpenPgpError() {
168			return this.error;
169		}
170	}
171}