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(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 InputStream is = new ByteArrayInputStream(status.getBytes());
127 ByteArrayOutputStream os = new ByteArrayOutputStream();
128 Intent result = api.executeApi(params, is, os);
129 StringBuilder signatureBuilder = new StringBuilder();
130 switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, 0)) {
131 case OpenPgpApi.RESULT_CODE_SUCCESS:
132 String[] lines = os.toString().split("\n");
133 for (int i = 7; i < lines.length - 1; ++i) {
134 signatureBuilder.append(lines[i].trim());
135 }
136 break;
137 case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
138 throw new UserInputRequiredException((PendingIntent) result.getParcelableExtra(OpenPgpApi.RESULT_INTENT));
139 case OpenPgpApi.RESULT_CODE_ERROR:
140 break;
141 }
142 return signatureBuilder.toString();
143 }
144
145 public class UserInputRequiredException extends Exception {
146 private static final long serialVersionUID = -6913480043269132016L;
147 private PendingIntent pi;
148
149 public UserInputRequiredException(PendingIntent pi) {
150 this.pi = pi;
151 }
152
153 public PendingIntent getPendingIntent() {
154 return this.pi;
155 }
156 }
157
158 public class OpenPgpException extends Exception {
159 private static final long serialVersionUID = -7324789703473056077L;
160 private OpenPgpError error;
161
162 public OpenPgpException(OpenPgpError openPgpError) {
163 this.error = openPgpError;
164 }
165
166 public OpenPgpError getOpenPgpError() {
167 return this.error;
168 }
169 }
170}