michael@0: Cu.import("resource://services-crypto/WeaveCrypto.js"); michael@0: michael@0: let cryptoSvc = new WeaveCrypto(); michael@0: michael@0: function run_test() { michael@0: michael@0: if ("makeSECItem" in cryptoSvc) // Only for js-ctypes WeaveCrypto. michael@0: test_makeSECItem(); michael@0: michael@0: if (this.gczeal) { michael@0: _("Running crypto tests with gczeal(2)."); michael@0: gczeal(2); michael@0: } michael@0: test_bug_617650(); michael@0: test_encrypt_decrypt(); michael@0: test_SECItem_byteCompressInts(); michael@0: test_key_memoization(); michael@0: if (this.gczeal) michael@0: gczeal(0); michael@0: } michael@0: michael@0: function test_key_memoization() { michael@0: let oldImport = cryptoSvc.nss && cryptoSvc.nss.PK11_ImportSymKey; michael@0: if (!oldImport) { michael@0: _("Couldn't swizzle PK11_ImportSymKey; returning."); michael@0: return; michael@0: } michael@0: michael@0: let iv = cryptoSvc.generateRandomIV(); michael@0: let key = cryptoSvc.generateRandomKey(); michael@0: let c = 0; michael@0: cryptoSvc.nss.PK11_ImportSymKey = function(slot, type, origin, operation, key, wincx) { michael@0: c++; michael@0: return oldImport(slot, type, origin, operation, key, wincx); michael@0: } michael@0: michael@0: // Encryption should cause a single counter increment. michael@0: do_check_eq(c, 0); michael@0: let cipherText = cryptoSvc.encrypt("Hello, world.", key, iv); michael@0: do_check_eq(c, 1); michael@0: let cipherText = cryptoSvc.encrypt("Hello, world.", key, iv); michael@0: do_check_eq(c, 1); michael@0: michael@0: // ... as should decryption. michael@0: cryptoSvc.decrypt(cipherText, key, iv); michael@0: cryptoSvc.decrypt(cipherText, key, iv); michael@0: cryptoSvc.decrypt(cipherText, key, iv); michael@0: do_check_eq(c, 2); michael@0: michael@0: // Un-swizzle. michael@0: cryptoSvc.nss.PK11_ImportSymKey = oldImport; michael@0: } michael@0: michael@0: function multiple_decrypts(iterations) { michael@0: let iv = cryptoSvc.generateRandomIV(); michael@0: let key = cryptoSvc.generateRandomKey(); michael@0: let cipherText = cryptoSvc.encrypt("Hello, world.", key, iv); michael@0: michael@0: for (let i = 0; i < iterations; ++i) { michael@0: let clearText = cryptoSvc.decrypt(cipherText, key, iv); michael@0: do_check_eq(clearText + " " + i, "Hello, world. " + i); michael@0: } michael@0: _("Done with multiple_decrypts."); michael@0: } michael@0: michael@0: function test_bug_617650() { michael@0: if (this.gczeal) { michael@0: gczeal(2); michael@0: // Few iterations, because gczeal(2) is expensive... and makes it fail much faster! michael@0: _("gczeal set to 2; attempting 10 iterations of multiple_decrypts."); michael@0: multiple_decrypts(10); michael@0: gczeal(0); michael@0: } else { michael@0: // We can't use gczeal on non-debug builds, so try lots of reps instead. michael@0: _("No gczeal (non-debug build?); attempting 10,000 iterations of multiple_decrypts."); michael@0: multiple_decrypts(10000); michael@0: } michael@0: } michael@0: michael@0: // Just verify that it gets populated with the correct bytes. michael@0: function test_makeSECItem() { michael@0: Components.utils.import("resource://gre/modules/ctypes.jsm"); michael@0: michael@0: let item1 = cryptoSvc.makeSECItem("abcdefghi", false); michael@0: do_check_true(!item1.isNull()); michael@0: let intData = ctypes.cast(item1.contents.data, ctypes.uint8_t.array(8).ptr).contents; michael@0: for (let i = 0; i < 8; ++i) michael@0: do_check_eq(intData[i], "abcdefghi".charCodeAt(i)); michael@0: } michael@0: michael@0: function test_SECItem_byteCompressInts() { michael@0: Components.utils.import("resource://gre/modules/ctypes.jsm"); michael@0: michael@0: let item1 = cryptoSvc.makeSECItem("abcdefghi", false); michael@0: do_check_true(!item1.isNull()); michael@0: let intData = ctypes.cast(item1.contents.data, ctypes.uint8_t.array(8).ptr).contents; michael@0: michael@0: // Fill it too short. michael@0: cryptoSvc.byteCompressInts("MMM", intData, 8); michael@0: for (let i = 0; i < 3; ++i) michael@0: do_check_eq(intData[i], [77, 77, 77][i]); michael@0: michael@0: // Fill it too much. Doesn't buffer overrun. michael@0: cryptoSvc.byteCompressInts("NNNNNNNNNNNNNNNN", intData, 8); michael@0: for (let i = 0; i < 8; ++i) michael@0: do_check_eq(intData[i], "NNNNNNNNNNNNNNNN".charCodeAt(i)); michael@0: } michael@0: michael@0: function test_encrypt_decrypt() { michael@0: michael@0: // First, do a normal run with expected usage... Generate a random key and michael@0: // iv, encrypt and decrypt a string. michael@0: var iv = cryptoSvc.generateRandomIV(); michael@0: do_check_eq(iv.length, 24); michael@0: michael@0: var key = cryptoSvc.generateRandomKey(); michael@0: do_check_eq(key.length, 44); michael@0: michael@0: var mySecret = "bacon is a vegetable"; michael@0: var cipherText = cryptoSvc.encrypt(mySecret, key, iv); michael@0: do_check_eq(cipherText.length, 44); michael@0: michael@0: var clearText = cryptoSvc.decrypt(cipherText, key, iv); michael@0: do_check_eq(clearText.length, 20); michael@0: michael@0: // Did the text survive the encryption round-trip? michael@0: do_check_eq(clearText, mySecret); michael@0: do_check_neq(cipherText, mySecret); // just to be explicit michael@0: michael@0: michael@0: // Do some more tests with a fixed key/iv, to check for reproducable results. michael@0: key = "St1tFCor7vQEJNug/465dQ=="; michael@0: iv = "oLjkfrLIOnK2bDRvW4kXYA=="; michael@0: michael@0: _("Testing small IV."); michael@0: mySecret = "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo="; michael@0: shortiv = "YWJj"; // "abc": Less than 16. michael@0: let err; michael@0: try { michael@0: cryptoSvc.encrypt(mySecret, key, shortiv); michael@0: } catch (ex) { michael@0: err = ex; michael@0: } michael@0: do_check_true(!!err); michael@0: michael@0: // Test small input sizes michael@0: mySecret = ""; michael@0: cipherText = cryptoSvc.encrypt(mySecret, key, iv); michael@0: clearText = cryptoSvc.decrypt(cipherText, key, iv); michael@0: do_check_eq(cipherText, "OGQjp6mK1a3fs9k9Ml4L3w=="); michael@0: do_check_eq(clearText, mySecret); michael@0: michael@0: mySecret = "x"; michael@0: cipherText = cryptoSvc.encrypt(mySecret, key, iv); michael@0: clearText = cryptoSvc.decrypt(cipherText, key, iv); michael@0: do_check_eq(cipherText, "96iMl4vhOxFUW/lVHHzVqg=="); michael@0: do_check_eq(clearText, mySecret); michael@0: michael@0: mySecret = "xx"; michael@0: cipherText = cryptoSvc.encrypt(mySecret, key, iv); michael@0: clearText = cryptoSvc.decrypt(cipherText, key, iv); michael@0: do_check_eq(cipherText, "olpPbETRYROCSqFWcH2SWg=="); michael@0: do_check_eq(clearText, mySecret); michael@0: michael@0: mySecret = "xxx"; michael@0: cipherText = cryptoSvc.encrypt(mySecret, key, iv); michael@0: clearText = cryptoSvc.decrypt(cipherText, key, iv); michael@0: do_check_eq(cipherText, "rRbpHGyVSZizLX/x43Wm+Q=="); michael@0: do_check_eq(clearText, mySecret); michael@0: michael@0: mySecret = "xxxx"; michael@0: cipherText = cryptoSvc.encrypt(mySecret, key, iv); michael@0: clearText = cryptoSvc.decrypt(cipherText, key, iv); michael@0: do_check_eq(cipherText, "HeC7miVGDcpxae9RmiIKAw=="); michael@0: do_check_eq(clearText, mySecret); michael@0: michael@0: // Test non-ascii input michael@0: // ("testuser1" using similar-looking glyphs) michael@0: mySecret = String.fromCharCode(355, 277, 349, 357, 533, 537, 101, 345, 185); michael@0: cipherText = cryptoSvc.encrypt(mySecret, key, iv); michael@0: clearText = cryptoSvc.decrypt(cipherText, key, iv); michael@0: do_check_eq(cipherText, "Pj4ixByXoH3SU3JkOXaEKPgwRAWplAWFLQZkpJd5Kr4="); michael@0: do_check_eq(clearText, mySecret); michael@0: michael@0: // Tests input spanning a block boundary (AES block size is 16 bytes) michael@0: mySecret = "123456789012345"; michael@0: cipherText = cryptoSvc.encrypt(mySecret, key, iv); michael@0: clearText = cryptoSvc.decrypt(cipherText, key, iv); michael@0: do_check_eq(cipherText, "e6c5hwphe45/3VN/M0bMUA=="); michael@0: do_check_eq(clearText, mySecret); michael@0: michael@0: mySecret = "1234567890123456"; michael@0: cipherText = cryptoSvc.encrypt(mySecret, key, iv); michael@0: clearText = cryptoSvc.decrypt(cipherText, key, iv); michael@0: do_check_eq(cipherText, "V6aaOZw8pWlYkoIHNkhsP1JOIQF87E2vTUvBUQnyV04="); michael@0: do_check_eq(clearText, mySecret); michael@0: michael@0: mySecret = "12345678901234567"; michael@0: cipherText = cryptoSvc.encrypt(mySecret, key, iv); michael@0: clearText = cryptoSvc.decrypt(cipherText, key, iv); michael@0: do_check_eq(cipherText, "V6aaOZw8pWlYkoIHNkhsP5GvxWJ9+GIAS6lXw+5fHTI="); michael@0: do_check_eq(clearText, mySecret); michael@0: michael@0: michael@0: key = "iz35tuIMq4/H+IYw2KTgow=="; michael@0: iv = "TJYrvva2KxvkM8hvOIvWp3xgjTXgq5Ss"; michael@0: mySecret = "i like pie"; michael@0: michael@0: cipherText = cryptoSvc.encrypt(mySecret, key, iv); michael@0: clearText = cryptoSvc.decrypt(cipherText, key, iv); michael@0: do_check_eq(cipherText, "DLGx8BWqSCLGG7i/xwvvxg=="); michael@0: do_check_eq(clearText, mySecret); michael@0: michael@0: key = "c5hG3YG+NC61FFy8NOHQak1ZhMEWO79bwiAfar2euzI="; michael@0: iv = "gsgLRDaxWvIfKt75RjuvFWERt83FFsY2A0TW+0b2iVk="; michael@0: mySecret = "i like pie"; michael@0: michael@0: cipherText = cryptoSvc.encrypt(mySecret, key, iv); michael@0: clearText = cryptoSvc.decrypt(cipherText, key, iv); michael@0: do_check_eq(cipherText, "o+ADtdMd8ubzNWurS6jt0Q=="); michael@0: do_check_eq(clearText, mySecret); michael@0: michael@0: key = "St1tFCor7vQEJNug/465dQ=="; michael@0: iv = "oLjkfrLIOnK2bDRvW4kXYA=="; michael@0: mySecret = "does thunder read testcases?"; michael@0: cipherText = cryptoSvc.encrypt(mySecret, key, iv); michael@0: do_check_eq(cipherText, "T6fik9Ros+DB2ablH9zZ8FWZ0xm/szSwJjIHZu7sjPs="); michael@0: michael@0: var badkey = "badkeybadkeybadkeybadk=="; michael@0: var badiv = "badivbadivbadivbadivbad="; michael@0: var badcipher = "crapinputcrapinputcrapinputcrapinputcrapinp="; michael@0: var failure; michael@0: michael@0: try { michael@0: failure = false; michael@0: clearText = cryptoSvc.decrypt(cipherText, badkey, iv); michael@0: } catch (e) { michael@0: failure = true; michael@0: } michael@0: do_check_true(failure); michael@0: michael@0: try { michael@0: failure = false; michael@0: clearText = cryptoSvc.decrypt(cipherText, key, badiv); michael@0: } catch (e) { michael@0: failure = true; michael@0: } michael@0: do_check_true(failure); michael@0: michael@0: try { michael@0: failure = false; michael@0: clearText = cryptoSvc.decrypt(cipherText, badkey, badiv); michael@0: } catch (e) { michael@0: failure = true; michael@0: } michael@0: do_check_true(failure); michael@0: michael@0: try { michael@0: failure = false; michael@0: clearText = cryptoSvc.decrypt(badcipher, key, iv); michael@0: } catch (e) { michael@0: failure = true; michael@0: } michael@0: do_check_true(failure); michael@0: }