1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/services/crypto/tests/unit/test_crypto_crypt.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,265 @@ 1.4 +Cu.import("resource://services-crypto/WeaveCrypto.js"); 1.5 + 1.6 +let cryptoSvc = new WeaveCrypto(); 1.7 + 1.8 +function run_test() { 1.9 + 1.10 + if ("makeSECItem" in cryptoSvc) // Only for js-ctypes WeaveCrypto. 1.11 + test_makeSECItem(); 1.12 + 1.13 + if (this.gczeal) { 1.14 + _("Running crypto tests with gczeal(2)."); 1.15 + gczeal(2); 1.16 + } 1.17 + test_bug_617650(); 1.18 + test_encrypt_decrypt(); 1.19 + test_SECItem_byteCompressInts(); 1.20 + test_key_memoization(); 1.21 + if (this.gczeal) 1.22 + gczeal(0); 1.23 +} 1.24 + 1.25 +function test_key_memoization() { 1.26 + let oldImport = cryptoSvc.nss && cryptoSvc.nss.PK11_ImportSymKey; 1.27 + if (!oldImport) { 1.28 + _("Couldn't swizzle PK11_ImportSymKey; returning."); 1.29 + return; 1.30 + } 1.31 + 1.32 + let iv = cryptoSvc.generateRandomIV(); 1.33 + let key = cryptoSvc.generateRandomKey(); 1.34 + let c = 0; 1.35 + cryptoSvc.nss.PK11_ImportSymKey = function(slot, type, origin, operation, key, wincx) { 1.36 + c++; 1.37 + return oldImport(slot, type, origin, operation, key, wincx); 1.38 + } 1.39 + 1.40 + // Encryption should cause a single counter increment. 1.41 + do_check_eq(c, 0); 1.42 + let cipherText = cryptoSvc.encrypt("Hello, world.", key, iv); 1.43 + do_check_eq(c, 1); 1.44 + let cipherText = cryptoSvc.encrypt("Hello, world.", key, iv); 1.45 + do_check_eq(c, 1); 1.46 + 1.47 + // ... as should decryption. 1.48 + cryptoSvc.decrypt(cipherText, key, iv); 1.49 + cryptoSvc.decrypt(cipherText, key, iv); 1.50 + cryptoSvc.decrypt(cipherText, key, iv); 1.51 + do_check_eq(c, 2); 1.52 + 1.53 + // Un-swizzle. 1.54 + cryptoSvc.nss.PK11_ImportSymKey = oldImport; 1.55 +} 1.56 + 1.57 +function multiple_decrypts(iterations) { 1.58 + let iv = cryptoSvc.generateRandomIV(); 1.59 + let key = cryptoSvc.generateRandomKey(); 1.60 + let cipherText = cryptoSvc.encrypt("Hello, world.", key, iv); 1.61 + 1.62 + for (let i = 0; i < iterations; ++i) { 1.63 + let clearText = cryptoSvc.decrypt(cipherText, key, iv); 1.64 + do_check_eq(clearText + " " + i, "Hello, world. " + i); 1.65 + } 1.66 + _("Done with multiple_decrypts."); 1.67 +} 1.68 + 1.69 +function test_bug_617650() { 1.70 + if (this.gczeal) { 1.71 + gczeal(2); 1.72 + // Few iterations, because gczeal(2) is expensive... and makes it fail much faster! 1.73 + _("gczeal set to 2; attempting 10 iterations of multiple_decrypts."); 1.74 + multiple_decrypts(10); 1.75 + gczeal(0); 1.76 + } else { 1.77 + // We can't use gczeal on non-debug builds, so try lots of reps instead. 1.78 + _("No gczeal (non-debug build?); attempting 10,000 iterations of multiple_decrypts."); 1.79 + multiple_decrypts(10000); 1.80 + } 1.81 +} 1.82 + 1.83 +// Just verify that it gets populated with the correct bytes. 1.84 +function test_makeSECItem() { 1.85 + Components.utils.import("resource://gre/modules/ctypes.jsm"); 1.86 + 1.87 + let item1 = cryptoSvc.makeSECItem("abcdefghi", false); 1.88 + do_check_true(!item1.isNull()); 1.89 + let intData = ctypes.cast(item1.contents.data, ctypes.uint8_t.array(8).ptr).contents; 1.90 + for (let i = 0; i < 8; ++i) 1.91 + do_check_eq(intData[i], "abcdefghi".charCodeAt(i)); 1.92 +} 1.93 + 1.94 +function test_SECItem_byteCompressInts() { 1.95 + Components.utils.import("resource://gre/modules/ctypes.jsm"); 1.96 + 1.97 + let item1 = cryptoSvc.makeSECItem("abcdefghi", false); 1.98 + do_check_true(!item1.isNull()); 1.99 + let intData = ctypes.cast(item1.contents.data, ctypes.uint8_t.array(8).ptr).contents; 1.100 + 1.101 + // Fill it too short. 1.102 + cryptoSvc.byteCompressInts("MMM", intData, 8); 1.103 + for (let i = 0; i < 3; ++i) 1.104 + do_check_eq(intData[i], [77, 77, 77][i]); 1.105 + 1.106 + // Fill it too much. Doesn't buffer overrun. 1.107 + cryptoSvc.byteCompressInts("NNNNNNNNNNNNNNNN", intData, 8); 1.108 + for (let i = 0; i < 8; ++i) 1.109 + do_check_eq(intData[i], "NNNNNNNNNNNNNNNN".charCodeAt(i)); 1.110 +} 1.111 + 1.112 +function test_encrypt_decrypt() { 1.113 + 1.114 + // First, do a normal run with expected usage... Generate a random key and 1.115 + // iv, encrypt and decrypt a string. 1.116 + var iv = cryptoSvc.generateRandomIV(); 1.117 + do_check_eq(iv.length, 24); 1.118 + 1.119 + var key = cryptoSvc.generateRandomKey(); 1.120 + do_check_eq(key.length, 44); 1.121 + 1.122 + var mySecret = "bacon is a vegetable"; 1.123 + var cipherText = cryptoSvc.encrypt(mySecret, key, iv); 1.124 + do_check_eq(cipherText.length, 44); 1.125 + 1.126 + var clearText = cryptoSvc.decrypt(cipherText, key, iv); 1.127 + do_check_eq(clearText.length, 20); 1.128 + 1.129 + // Did the text survive the encryption round-trip? 1.130 + do_check_eq(clearText, mySecret); 1.131 + do_check_neq(cipherText, mySecret); // just to be explicit 1.132 + 1.133 + 1.134 + // Do some more tests with a fixed key/iv, to check for reproducable results. 1.135 + key = "St1tFCor7vQEJNug/465dQ=="; 1.136 + iv = "oLjkfrLIOnK2bDRvW4kXYA=="; 1.137 + 1.138 + _("Testing small IV."); 1.139 + mySecret = "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo="; 1.140 + shortiv = "YWJj"; // "abc": Less than 16. 1.141 + let err; 1.142 + try { 1.143 + cryptoSvc.encrypt(mySecret, key, shortiv); 1.144 + } catch (ex) { 1.145 + err = ex; 1.146 + } 1.147 + do_check_true(!!err); 1.148 + 1.149 + // Test small input sizes 1.150 + mySecret = ""; 1.151 + cipherText = cryptoSvc.encrypt(mySecret, key, iv); 1.152 + clearText = cryptoSvc.decrypt(cipherText, key, iv); 1.153 + do_check_eq(cipherText, "OGQjp6mK1a3fs9k9Ml4L3w=="); 1.154 + do_check_eq(clearText, mySecret); 1.155 + 1.156 + mySecret = "x"; 1.157 + cipherText = cryptoSvc.encrypt(mySecret, key, iv); 1.158 + clearText = cryptoSvc.decrypt(cipherText, key, iv); 1.159 + do_check_eq(cipherText, "96iMl4vhOxFUW/lVHHzVqg=="); 1.160 + do_check_eq(clearText, mySecret); 1.161 + 1.162 + mySecret = "xx"; 1.163 + cipherText = cryptoSvc.encrypt(mySecret, key, iv); 1.164 + clearText = cryptoSvc.decrypt(cipherText, key, iv); 1.165 + do_check_eq(cipherText, "olpPbETRYROCSqFWcH2SWg=="); 1.166 + do_check_eq(clearText, mySecret); 1.167 + 1.168 + mySecret = "xxx"; 1.169 + cipherText = cryptoSvc.encrypt(mySecret, key, iv); 1.170 + clearText = cryptoSvc.decrypt(cipherText, key, iv); 1.171 + do_check_eq(cipherText, "rRbpHGyVSZizLX/x43Wm+Q=="); 1.172 + do_check_eq(clearText, mySecret); 1.173 + 1.174 + mySecret = "xxxx"; 1.175 + cipherText = cryptoSvc.encrypt(mySecret, key, iv); 1.176 + clearText = cryptoSvc.decrypt(cipherText, key, iv); 1.177 + do_check_eq(cipherText, "HeC7miVGDcpxae9RmiIKAw=="); 1.178 + do_check_eq(clearText, mySecret); 1.179 + 1.180 + // Test non-ascii input 1.181 + // ("testuser1" using similar-looking glyphs) 1.182 + mySecret = String.fromCharCode(355, 277, 349, 357, 533, 537, 101, 345, 185); 1.183 + cipherText = cryptoSvc.encrypt(mySecret, key, iv); 1.184 + clearText = cryptoSvc.decrypt(cipherText, key, iv); 1.185 + do_check_eq(cipherText, "Pj4ixByXoH3SU3JkOXaEKPgwRAWplAWFLQZkpJd5Kr4="); 1.186 + do_check_eq(clearText, mySecret); 1.187 + 1.188 + // Tests input spanning a block boundary (AES block size is 16 bytes) 1.189 + mySecret = "123456789012345"; 1.190 + cipherText = cryptoSvc.encrypt(mySecret, key, iv); 1.191 + clearText = cryptoSvc.decrypt(cipherText, key, iv); 1.192 + do_check_eq(cipherText, "e6c5hwphe45/3VN/M0bMUA=="); 1.193 + do_check_eq(clearText, mySecret); 1.194 + 1.195 + mySecret = "1234567890123456"; 1.196 + cipherText = cryptoSvc.encrypt(mySecret, key, iv); 1.197 + clearText = cryptoSvc.decrypt(cipherText, key, iv); 1.198 + do_check_eq(cipherText, "V6aaOZw8pWlYkoIHNkhsP1JOIQF87E2vTUvBUQnyV04="); 1.199 + do_check_eq(clearText, mySecret); 1.200 + 1.201 + mySecret = "12345678901234567"; 1.202 + cipherText = cryptoSvc.encrypt(mySecret, key, iv); 1.203 + clearText = cryptoSvc.decrypt(cipherText, key, iv); 1.204 + do_check_eq(cipherText, "V6aaOZw8pWlYkoIHNkhsP5GvxWJ9+GIAS6lXw+5fHTI="); 1.205 + do_check_eq(clearText, mySecret); 1.206 + 1.207 + 1.208 + key = "iz35tuIMq4/H+IYw2KTgow=="; 1.209 + iv = "TJYrvva2KxvkM8hvOIvWp3xgjTXgq5Ss"; 1.210 + mySecret = "i like pie"; 1.211 + 1.212 + cipherText = cryptoSvc.encrypt(mySecret, key, iv); 1.213 + clearText = cryptoSvc.decrypt(cipherText, key, iv); 1.214 + do_check_eq(cipherText, "DLGx8BWqSCLGG7i/xwvvxg=="); 1.215 + do_check_eq(clearText, mySecret); 1.216 + 1.217 + key = "c5hG3YG+NC61FFy8NOHQak1ZhMEWO79bwiAfar2euzI="; 1.218 + iv = "gsgLRDaxWvIfKt75RjuvFWERt83FFsY2A0TW+0b2iVk="; 1.219 + mySecret = "i like pie"; 1.220 + 1.221 + cipherText = cryptoSvc.encrypt(mySecret, key, iv); 1.222 + clearText = cryptoSvc.decrypt(cipherText, key, iv); 1.223 + do_check_eq(cipherText, "o+ADtdMd8ubzNWurS6jt0Q=="); 1.224 + do_check_eq(clearText, mySecret); 1.225 + 1.226 + key = "St1tFCor7vQEJNug/465dQ=="; 1.227 + iv = "oLjkfrLIOnK2bDRvW4kXYA=="; 1.228 + mySecret = "does thunder read testcases?"; 1.229 + cipherText = cryptoSvc.encrypt(mySecret, key, iv); 1.230 + do_check_eq(cipherText, "T6fik9Ros+DB2ablH9zZ8FWZ0xm/szSwJjIHZu7sjPs="); 1.231 + 1.232 + var badkey = "badkeybadkeybadkeybadk=="; 1.233 + var badiv = "badivbadivbadivbadivbad="; 1.234 + var badcipher = "crapinputcrapinputcrapinputcrapinputcrapinp="; 1.235 + var failure; 1.236 + 1.237 + try { 1.238 + failure = false; 1.239 + clearText = cryptoSvc.decrypt(cipherText, badkey, iv); 1.240 + } catch (e) { 1.241 + failure = true; 1.242 + } 1.243 + do_check_true(failure); 1.244 + 1.245 + try { 1.246 + failure = false; 1.247 + clearText = cryptoSvc.decrypt(cipherText, key, badiv); 1.248 + } catch (e) { 1.249 + failure = true; 1.250 + } 1.251 + do_check_true(failure); 1.252 + 1.253 + try { 1.254 + failure = false; 1.255 + clearText = cryptoSvc.decrypt(cipherText, badkey, badiv); 1.256 + } catch (e) { 1.257 + failure = true; 1.258 + } 1.259 + do_check_true(failure); 1.260 + 1.261 + try { 1.262 + failure = false; 1.263 + clearText = cryptoSvc.decrypt(badcipher, key, iv); 1.264 + } catch (e) { 1.265 + failure = true; 1.266 + } 1.267 + do_check_true(failure); 1.268 +}