1package eu.siacs.conversations.crypto;
2
3import java.io.ByteArrayInputStream;
4import java.io.ByteArrayOutputStream;
5import java.io.InputStream;
6import java.io.OutputStream;
7
8import org.openintents.openpgp.OpenPgpError;
9import org.openintents.openpgp.OpenPgpSignatureResult;
10import org.openintents.openpgp.util.OpenPgpApi;
11import org.openintents.openpgp.util.OpenPgpApi.IOpenPgpCallback;
12
13import eu.siacs.conversations.entities.Account;
14import eu.siacs.conversations.entities.Contact;
15import eu.siacs.conversations.entities.Message;
16
17import android.app.PendingIntent;
18import android.content.Intent;
19import android.util.Log;
20
21public class PgpEngine {
22 private OpenPgpApi api;
23
24 public PgpEngine(OpenPgpApi api) {
25 this.api = api;
26 }
27
28 public void decrypt(final Message message, final OnPgpEngineResult callback) {
29 Intent params = new Intent();
30 params.setAction(OpenPgpApi.ACTION_DECRYPT_VERIFY);
31 params.putExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME, message
32 .getConversation().getAccount().getJid());
33 InputStream is = new ByteArrayInputStream(message.getBody().getBytes());
34 final OutputStream os = new ByteArrayOutputStream();
35 api.executeApiAsync(params, is, os, new IOpenPgpCallback() {
36
37 @Override
38 public void onReturn(Intent result) {
39 switch (result.getIntExtra(OpenPgpApi.RESULT_CODE,
40 OpenPgpApi.RESULT_CODE_ERROR)) {
41 case OpenPgpApi.RESULT_CODE_SUCCESS:
42 message.setBody(os.toString());
43 message.setEncryption(Message.ENCRYPTION_DECRYPTED);
44 callback.success();
45 return;
46 case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
47 callback.userInputRequried((PendingIntent) result
48 .getParcelableExtra(OpenPgpApi.RESULT_INTENT));
49 return;
50 case OpenPgpApi.RESULT_CODE_ERROR:
51 callback.error((OpenPgpError) result
52 .getParcelableExtra(OpenPgpApi.RESULT_ERROR));
53 return;
54 default:
55 return;
56 }
57 }
58 });
59 }
60
61 public void encrypt(Account account, long keyId, Message message,
62 final OnPgpEngineResult callback) {
63 Log.d("xmppService", "called to pgpengine::encrypt");
64 long[] keys = { keyId };
65 Intent params = new Intent();
66 params.setAction(OpenPgpApi.ACTION_ENCRYPT);
67 params.putExtra(OpenPgpApi.EXTRA_KEY_IDS, keys);
68 params.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
69 params.putExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME, account.getJid());
70
71 InputStream is = new ByteArrayInputStream(message.getBody().getBytes());
72 ByteArrayOutputStream os = new ByteArrayOutputStream();
73 Intent result = api.executeApi(params, is, os);
74 switch (result.getIntExtra(OpenPgpApi.RESULT_CODE,
75 OpenPgpApi.RESULT_CODE_ERROR)) {
76 case OpenPgpApi.RESULT_CODE_SUCCESS:
77 StringBuilder encryptedMessageBody = new StringBuilder();
78 String[] lines = os.toString().split("\n");
79 for (int i = 3; i < lines.length - 1; ++i) {
80 encryptedMessageBody.append(lines[i].trim());
81 }
82 message.setEncryptedBody(encryptedMessageBody.toString());
83 callback.success();
84 return;
85 case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
86 callback.userInputRequried((PendingIntent) result
87 .getParcelableExtra(OpenPgpApi.RESULT_INTENT));
88 return;
89 case OpenPgpApi.RESULT_CODE_ERROR:
90 callback.error((OpenPgpError) result
91 .getParcelableExtra(OpenPgpApi.RESULT_ERROR));
92 return;
93 }
94 }
95
96 public long fetchKeyId(Account account, String status, String signature) {
97 if ((signature == null) || (api == null)) {
98 return 0;
99 }
100 if (status == null) {
101 status = "";
102 }
103 StringBuilder pgpSig = new StringBuilder();
104 pgpSig.append("-----BEGIN PGP SIGNED MESSAGE-----");
105 pgpSig.append('\n');
106 pgpSig.append('\n');
107 pgpSig.append(status);
108 pgpSig.append('\n');
109 pgpSig.append("-----BEGIN PGP SIGNATURE-----");
110 pgpSig.append('\n');
111 pgpSig.append('\n');
112 pgpSig.append(signature.replace("\n", "").trim());
113 pgpSig.append('\n');
114 pgpSig.append("-----END PGP SIGNATURE-----");
115 Intent params = new Intent();
116 params.setAction(OpenPgpApi.ACTION_DECRYPT_VERIFY);
117 params.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
118 params.putExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME, account.getJid());
119 InputStream is = new ByteArrayInputStream(pgpSig.toString().getBytes());
120 ByteArrayOutputStream os = new ByteArrayOutputStream();
121 Intent result = api.executeApi(params, is, os);
122 switch (result.getIntExtra(OpenPgpApi.RESULT_CODE,
123 OpenPgpApi.RESULT_CODE_ERROR)) {
124 case OpenPgpApi.RESULT_CODE_SUCCESS:
125 OpenPgpSignatureResult sigResult = result
126 .getParcelableExtra(OpenPgpApi.RESULT_SIGNATURE);
127 if (sigResult != null) {
128 return sigResult.getKeyId();
129 } else {
130 return 0;
131 }
132 case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
133 Log.d("xmppService","user interaction required");
134 return 0;
135 case OpenPgpApi.RESULT_CODE_ERROR:
136 Log.d("xmppService","pgp error");
137 return 0;
138 }
139 return 0;
140 }
141
142 public void generateSignature(final Account account, String status,
143 final OnPgpEngineResult callback) {
144 Intent params = new Intent();
145 params.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
146 params.setAction(OpenPgpApi.ACTION_SIGN);
147 params.putExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME, account.getJid());
148 InputStream is = new ByteArrayInputStream(status.getBytes());
149 final OutputStream os = new ByteArrayOutputStream();
150 api.executeApiAsync(params, is, os, new IOpenPgpCallback() {
151
152 @Override
153 public void onReturn(Intent result) {
154 switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, 0)) {
155 case OpenPgpApi.RESULT_CODE_SUCCESS:
156 StringBuilder signatureBuilder = new StringBuilder();
157 String[] lines = os.toString().split("\n");
158 for (int i = 7; i < lines.length - 1; ++i) {
159 signatureBuilder.append(lines[i].trim());
160 }
161 account.setKey("pgp_signature", signatureBuilder.toString());
162 callback.success();
163 return;
164 case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
165 callback.userInputRequried((PendingIntent) result
166 .getParcelableExtra(OpenPgpApi.RESULT_INTENT));
167 return;
168 case OpenPgpApi.RESULT_CODE_ERROR:
169 callback.error((OpenPgpError) result
170 .getParcelableExtra(OpenPgpApi.RESULT_ERROR));
171 return;
172 }
173 }
174 });
175 }
176
177 public void hasKey(Account account, long keyId, final OnPgpEngineResult callback) {
178 Intent params = new Intent();
179 params.setAction(OpenPgpApi.ACTION_GET_KEY);
180 params.putExtra(OpenPgpApi.EXTRA_KEY_ID, keyId);
181 params.putExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME, account.getJid());
182 InputStream is = new ByteArrayInputStream(new byte[0]);
183 OutputStream os = new ByteArrayOutputStream();
184 api.executeApiAsync(params, is, os, new IOpenPgpCallback() {
185
186 @Override
187 public void onReturn(Intent result) {
188 switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, 0)) {
189 case OpenPgpApi.RESULT_CODE_SUCCESS:
190 callback.success();
191 return;
192 case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
193 callback.userInputRequried((PendingIntent) result
194 .getParcelableExtra(OpenPgpApi.RESULT_INTENT));
195 return;
196 case OpenPgpApi.RESULT_CODE_ERROR:
197 callback.error((OpenPgpError) result
198 .getParcelableExtra(OpenPgpApi.RESULT_ERROR));
199 return;
200 }
201 }
202 });
203 }
204}