|
1 Cu.import("resource://services-crypto/WeaveCrypto.js"); |
|
2 |
|
3 let cryptoSvc = new WeaveCrypto(); |
|
4 |
|
5 function run_test() { |
|
6 |
|
7 if ("makeSECItem" in cryptoSvc) // Only for js-ctypes WeaveCrypto. |
|
8 test_makeSECItem(); |
|
9 |
|
10 if (this.gczeal) { |
|
11 _("Running crypto tests with gczeal(2)."); |
|
12 gczeal(2); |
|
13 } |
|
14 test_bug_617650(); |
|
15 test_encrypt_decrypt(); |
|
16 test_SECItem_byteCompressInts(); |
|
17 test_key_memoization(); |
|
18 if (this.gczeal) |
|
19 gczeal(0); |
|
20 } |
|
21 |
|
22 function test_key_memoization() { |
|
23 let oldImport = cryptoSvc.nss && cryptoSvc.nss.PK11_ImportSymKey; |
|
24 if (!oldImport) { |
|
25 _("Couldn't swizzle PK11_ImportSymKey; returning."); |
|
26 return; |
|
27 } |
|
28 |
|
29 let iv = cryptoSvc.generateRandomIV(); |
|
30 let key = cryptoSvc.generateRandomKey(); |
|
31 let c = 0; |
|
32 cryptoSvc.nss.PK11_ImportSymKey = function(slot, type, origin, operation, key, wincx) { |
|
33 c++; |
|
34 return oldImport(slot, type, origin, operation, key, wincx); |
|
35 } |
|
36 |
|
37 // Encryption should cause a single counter increment. |
|
38 do_check_eq(c, 0); |
|
39 let cipherText = cryptoSvc.encrypt("Hello, world.", key, iv); |
|
40 do_check_eq(c, 1); |
|
41 let cipherText = cryptoSvc.encrypt("Hello, world.", key, iv); |
|
42 do_check_eq(c, 1); |
|
43 |
|
44 // ... as should decryption. |
|
45 cryptoSvc.decrypt(cipherText, key, iv); |
|
46 cryptoSvc.decrypt(cipherText, key, iv); |
|
47 cryptoSvc.decrypt(cipherText, key, iv); |
|
48 do_check_eq(c, 2); |
|
49 |
|
50 // Un-swizzle. |
|
51 cryptoSvc.nss.PK11_ImportSymKey = oldImport; |
|
52 } |
|
53 |
|
54 function multiple_decrypts(iterations) { |
|
55 let iv = cryptoSvc.generateRandomIV(); |
|
56 let key = cryptoSvc.generateRandomKey(); |
|
57 let cipherText = cryptoSvc.encrypt("Hello, world.", key, iv); |
|
58 |
|
59 for (let i = 0; i < iterations; ++i) { |
|
60 let clearText = cryptoSvc.decrypt(cipherText, key, iv); |
|
61 do_check_eq(clearText + " " + i, "Hello, world. " + i); |
|
62 } |
|
63 _("Done with multiple_decrypts."); |
|
64 } |
|
65 |
|
66 function test_bug_617650() { |
|
67 if (this.gczeal) { |
|
68 gczeal(2); |
|
69 // Few iterations, because gczeal(2) is expensive... and makes it fail much faster! |
|
70 _("gczeal set to 2; attempting 10 iterations of multiple_decrypts."); |
|
71 multiple_decrypts(10); |
|
72 gczeal(0); |
|
73 } else { |
|
74 // We can't use gczeal on non-debug builds, so try lots of reps instead. |
|
75 _("No gczeal (non-debug build?); attempting 10,000 iterations of multiple_decrypts."); |
|
76 multiple_decrypts(10000); |
|
77 } |
|
78 } |
|
79 |
|
80 // Just verify that it gets populated with the correct bytes. |
|
81 function test_makeSECItem() { |
|
82 Components.utils.import("resource://gre/modules/ctypes.jsm"); |
|
83 |
|
84 let item1 = cryptoSvc.makeSECItem("abcdefghi", false); |
|
85 do_check_true(!item1.isNull()); |
|
86 let intData = ctypes.cast(item1.contents.data, ctypes.uint8_t.array(8).ptr).contents; |
|
87 for (let i = 0; i < 8; ++i) |
|
88 do_check_eq(intData[i], "abcdefghi".charCodeAt(i)); |
|
89 } |
|
90 |
|
91 function test_SECItem_byteCompressInts() { |
|
92 Components.utils.import("resource://gre/modules/ctypes.jsm"); |
|
93 |
|
94 let item1 = cryptoSvc.makeSECItem("abcdefghi", false); |
|
95 do_check_true(!item1.isNull()); |
|
96 let intData = ctypes.cast(item1.contents.data, ctypes.uint8_t.array(8).ptr).contents; |
|
97 |
|
98 // Fill it too short. |
|
99 cryptoSvc.byteCompressInts("MMM", intData, 8); |
|
100 for (let i = 0; i < 3; ++i) |
|
101 do_check_eq(intData[i], [77, 77, 77][i]); |
|
102 |
|
103 // Fill it too much. Doesn't buffer overrun. |
|
104 cryptoSvc.byteCompressInts("NNNNNNNNNNNNNNNN", intData, 8); |
|
105 for (let i = 0; i < 8; ++i) |
|
106 do_check_eq(intData[i], "NNNNNNNNNNNNNNNN".charCodeAt(i)); |
|
107 } |
|
108 |
|
109 function test_encrypt_decrypt() { |
|
110 |
|
111 // First, do a normal run with expected usage... Generate a random key and |
|
112 // iv, encrypt and decrypt a string. |
|
113 var iv = cryptoSvc.generateRandomIV(); |
|
114 do_check_eq(iv.length, 24); |
|
115 |
|
116 var key = cryptoSvc.generateRandomKey(); |
|
117 do_check_eq(key.length, 44); |
|
118 |
|
119 var mySecret = "bacon is a vegetable"; |
|
120 var cipherText = cryptoSvc.encrypt(mySecret, key, iv); |
|
121 do_check_eq(cipherText.length, 44); |
|
122 |
|
123 var clearText = cryptoSvc.decrypt(cipherText, key, iv); |
|
124 do_check_eq(clearText.length, 20); |
|
125 |
|
126 // Did the text survive the encryption round-trip? |
|
127 do_check_eq(clearText, mySecret); |
|
128 do_check_neq(cipherText, mySecret); // just to be explicit |
|
129 |
|
130 |
|
131 // Do some more tests with a fixed key/iv, to check for reproducable results. |
|
132 key = "St1tFCor7vQEJNug/465dQ=="; |
|
133 iv = "oLjkfrLIOnK2bDRvW4kXYA=="; |
|
134 |
|
135 _("Testing small IV."); |
|
136 mySecret = "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo="; |
|
137 shortiv = "YWJj"; // "abc": Less than 16. |
|
138 let err; |
|
139 try { |
|
140 cryptoSvc.encrypt(mySecret, key, shortiv); |
|
141 } catch (ex) { |
|
142 err = ex; |
|
143 } |
|
144 do_check_true(!!err); |
|
145 |
|
146 // Test small input sizes |
|
147 mySecret = ""; |
|
148 cipherText = cryptoSvc.encrypt(mySecret, key, iv); |
|
149 clearText = cryptoSvc.decrypt(cipherText, key, iv); |
|
150 do_check_eq(cipherText, "OGQjp6mK1a3fs9k9Ml4L3w=="); |
|
151 do_check_eq(clearText, mySecret); |
|
152 |
|
153 mySecret = "x"; |
|
154 cipherText = cryptoSvc.encrypt(mySecret, key, iv); |
|
155 clearText = cryptoSvc.decrypt(cipherText, key, iv); |
|
156 do_check_eq(cipherText, "96iMl4vhOxFUW/lVHHzVqg=="); |
|
157 do_check_eq(clearText, mySecret); |
|
158 |
|
159 mySecret = "xx"; |
|
160 cipherText = cryptoSvc.encrypt(mySecret, key, iv); |
|
161 clearText = cryptoSvc.decrypt(cipherText, key, iv); |
|
162 do_check_eq(cipherText, "olpPbETRYROCSqFWcH2SWg=="); |
|
163 do_check_eq(clearText, mySecret); |
|
164 |
|
165 mySecret = "xxx"; |
|
166 cipherText = cryptoSvc.encrypt(mySecret, key, iv); |
|
167 clearText = cryptoSvc.decrypt(cipherText, key, iv); |
|
168 do_check_eq(cipherText, "rRbpHGyVSZizLX/x43Wm+Q=="); |
|
169 do_check_eq(clearText, mySecret); |
|
170 |
|
171 mySecret = "xxxx"; |
|
172 cipherText = cryptoSvc.encrypt(mySecret, key, iv); |
|
173 clearText = cryptoSvc.decrypt(cipherText, key, iv); |
|
174 do_check_eq(cipherText, "HeC7miVGDcpxae9RmiIKAw=="); |
|
175 do_check_eq(clearText, mySecret); |
|
176 |
|
177 // Test non-ascii input |
|
178 // ("testuser1" using similar-looking glyphs) |
|
179 mySecret = String.fromCharCode(355, 277, 349, 357, 533, 537, 101, 345, 185); |
|
180 cipherText = cryptoSvc.encrypt(mySecret, key, iv); |
|
181 clearText = cryptoSvc.decrypt(cipherText, key, iv); |
|
182 do_check_eq(cipherText, "Pj4ixByXoH3SU3JkOXaEKPgwRAWplAWFLQZkpJd5Kr4="); |
|
183 do_check_eq(clearText, mySecret); |
|
184 |
|
185 // Tests input spanning a block boundary (AES block size is 16 bytes) |
|
186 mySecret = "123456789012345"; |
|
187 cipherText = cryptoSvc.encrypt(mySecret, key, iv); |
|
188 clearText = cryptoSvc.decrypt(cipherText, key, iv); |
|
189 do_check_eq(cipherText, "e6c5hwphe45/3VN/M0bMUA=="); |
|
190 do_check_eq(clearText, mySecret); |
|
191 |
|
192 mySecret = "1234567890123456"; |
|
193 cipherText = cryptoSvc.encrypt(mySecret, key, iv); |
|
194 clearText = cryptoSvc.decrypt(cipherText, key, iv); |
|
195 do_check_eq(cipherText, "V6aaOZw8pWlYkoIHNkhsP1JOIQF87E2vTUvBUQnyV04="); |
|
196 do_check_eq(clearText, mySecret); |
|
197 |
|
198 mySecret = "12345678901234567"; |
|
199 cipherText = cryptoSvc.encrypt(mySecret, key, iv); |
|
200 clearText = cryptoSvc.decrypt(cipherText, key, iv); |
|
201 do_check_eq(cipherText, "V6aaOZw8pWlYkoIHNkhsP5GvxWJ9+GIAS6lXw+5fHTI="); |
|
202 do_check_eq(clearText, mySecret); |
|
203 |
|
204 |
|
205 key = "iz35tuIMq4/H+IYw2KTgow=="; |
|
206 iv = "TJYrvva2KxvkM8hvOIvWp3xgjTXgq5Ss"; |
|
207 mySecret = "i like pie"; |
|
208 |
|
209 cipherText = cryptoSvc.encrypt(mySecret, key, iv); |
|
210 clearText = cryptoSvc.decrypt(cipherText, key, iv); |
|
211 do_check_eq(cipherText, "DLGx8BWqSCLGG7i/xwvvxg=="); |
|
212 do_check_eq(clearText, mySecret); |
|
213 |
|
214 key = "c5hG3YG+NC61FFy8NOHQak1ZhMEWO79bwiAfar2euzI="; |
|
215 iv = "gsgLRDaxWvIfKt75RjuvFWERt83FFsY2A0TW+0b2iVk="; |
|
216 mySecret = "i like pie"; |
|
217 |
|
218 cipherText = cryptoSvc.encrypt(mySecret, key, iv); |
|
219 clearText = cryptoSvc.decrypt(cipherText, key, iv); |
|
220 do_check_eq(cipherText, "o+ADtdMd8ubzNWurS6jt0Q=="); |
|
221 do_check_eq(clearText, mySecret); |
|
222 |
|
223 key = "St1tFCor7vQEJNug/465dQ=="; |
|
224 iv = "oLjkfrLIOnK2bDRvW4kXYA=="; |
|
225 mySecret = "does thunder read testcases?"; |
|
226 cipherText = cryptoSvc.encrypt(mySecret, key, iv); |
|
227 do_check_eq(cipherText, "T6fik9Ros+DB2ablH9zZ8FWZ0xm/szSwJjIHZu7sjPs="); |
|
228 |
|
229 var badkey = "badkeybadkeybadkeybadk=="; |
|
230 var badiv = "badivbadivbadivbadivbad="; |
|
231 var badcipher = "crapinputcrapinputcrapinputcrapinputcrapinp="; |
|
232 var failure; |
|
233 |
|
234 try { |
|
235 failure = false; |
|
236 clearText = cryptoSvc.decrypt(cipherText, badkey, iv); |
|
237 } catch (e) { |
|
238 failure = true; |
|
239 } |
|
240 do_check_true(failure); |
|
241 |
|
242 try { |
|
243 failure = false; |
|
244 clearText = cryptoSvc.decrypt(cipherText, key, badiv); |
|
245 } catch (e) { |
|
246 failure = true; |
|
247 } |
|
248 do_check_true(failure); |
|
249 |
|
250 try { |
|
251 failure = false; |
|
252 clearText = cryptoSvc.decrypt(cipherText, badkey, badiv); |
|
253 } catch (e) { |
|
254 failure = true; |
|
255 } |
|
256 do_check_true(failure); |
|
257 |
|
258 try { |
|
259 failure = false; |
|
260 clearText = cryptoSvc.decrypt(badcipher, key, iv); |
|
261 } catch (e) { |
|
262 failure = true; |
|
263 } |
|
264 do_check_true(failure); |
|
265 } |