OLD | NEW |
1 <!DOCTYPE html> | 1 <!DOCTYPE html> |
2 <html> | 2 <html> |
3 <head> | 3 <head> |
4 <script src="../fast/js/resources/js-test-pre.js"></script> | 4 <script src="../fast/js/resources/js-test-pre.js"></script> |
5 <script src="resources/common.js"></script> | 5 <script src="resources/common.js"></script> |
6 </head> | 6 </head> |
7 <body> | 7 <body> |
8 <p id="description"></p> | 8 <p id="description"></p> |
9 <div id="console"></div> | 9 <div id="console"></div> |
10 | 10 |
11 <script> | 11 <script> |
12 description("Tests cypto.subtle.encrypt and crypto.subtle.decrypt"); | 12 description("Tests cypto.subtle.encrypt and crypto.subtle.decrypt"); |
13 | 13 |
14 jsTestIsAsync = true; | 14 jsTestIsAsync = true; |
15 | 15 |
16 importTestKeys().then(function(importedKeys) { | 16 // A list of Promises for every test to run. |
| 17 var allTests = []; |
| 18 |
| 19 // ------------------------------------------------- |
| 20 // Successful encryption/decryption |
| 21 // ------------------------------------------------- |
| 22 |
| 23 // Test vectors marked with [1] were copied from: |
| 24 // http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf |
| 25 // |
| 26 // The NIST tests do not have a padding block. To match the WebCrypto |
| 27 // expectations, a PKCS#5 padding block has been added. |
| 28 |
| 29 var kSuccessTestVectors = [ |
| 30 // 128-bit key with plaintext that is an exact multiple of block size. |
| 31 // Derived from [1] F.2.1 (CBC-AES128.Encrypt), by adding padding block. |
| 32 { |
| 33 key: "2b7e151628aed2a6abf7158809cf4f3c", |
| 34 iv: "000102030405060708090a0b0c0d0e0f", |
| 35 plainText: "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51
30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710", |
| 36 cipherText: "7649abac8119b246cee98e9b12e9197d5086cb9b507219ee95db113a917678b
273bed6b8e3c1743b7116e69e222295163ff1caa1681fac09120eca307586e1a7" + |
| 37 // Padding block. |
| 38 "8cb82807230e1321d3fae00d18cc2012" |
| 39 }, |
| 40 |
| 41 // 192-bit key, where final block of plaintext has to pad by 15. |
| 42 // Derived from [1] F.2.3 (CBC-AES192.Encrypt), by stripping 15 bytes off |
| 43 // plaintext and adding padding block. |
| 44 { |
| 45 key: "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b", |
| 46 iv: "000102030405060708090a0b0c0d0e0f", |
| 47 plainText: "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51
30c81c46a35ce411e5fbc1191a0a52eff6", |
| 48 cipherText: "4f021db243bc633d7178183a9fa071e8b4d9ada9ad7dedf4e5e738763f69145
a571b242012fb7ae07fa9baac3df102e0" + |
| 49 // Padding block. |
| 50 "288c6f9ec554652e50ab55e121f099ae" |
| 51 }, |
| 52 |
| 53 // 256-bit key, where final block of plaintext has to pad by 3. |
| 54 // Derived from [1] F.2.6 CBC-AES256.Decrypt, by stripping 3 bytes off |
| 55 // plaintext and adding padding block. |
| 56 { |
| 57 key: "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", |
| 58 iv: "000102030405060708090a0b0c0d0e0f", |
| 59 plainText: "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51
30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be6", |
| 60 cipherText: "f58c4c04d6e5f1ba779eabfb5f7bfbd69cfc4e967edb808d679f777bc6702c7
d39f23369a9d9bacfa530e26304231461c9aaf02a6a54e9e242ccbf48c59daca6" |
| 61 }, |
| 62 |
| 63 // 128-bit key, with empty plaintext. |
| 64 // Derived from Chromium's EncryptorTest.EmptyEncrypt() (encryptor_unittest.cc
) |
| 65 { |
| 66 key: "3132383d5369787465656e4279746573", |
| 67 iv: "5377656574205369787465656e204956", |
| 68 plainText: "", |
| 69 cipherText: "8518b8878d34e7185e300d0fcc426396" |
| 70 }, |
| 71 ]; |
| 72 |
| 73 function runSuccessTestCase(testCase) |
| 74 { |
| 75 var algorithm = {name: 'aes-cbc', iv: hexStringToUint8Array(testCase.iv)}; |
| 76 |
| 77 var key = null; |
| 78 var keyData = hexStringToUint8Array(testCase.key); |
| 79 var usages = ['encrypt', 'decrypt']; |
| 80 var extractable = false; |
| 81 |
| 82 // (1) Import the key |
| 83 return crypto.subtle.importKey('raw', keyData, algorithm, extractable, usage
s).then(function(result) { |
| 84 key = result; |
| 85 |
| 86 // shouldBe() can only resolve variables in global context. |
| 87 tmpKey = key; |
| 88 shouldBe("tmpKey.type", "'secret'") |
| 89 shouldBe("tmpKey.extractable", "false") |
| 90 shouldBe("tmpKey.algorithm.name", "'AES-CBC'") |
| 91 shouldBe("tmpKey.usages.join(',')", "'encrypt,decrypt'") |
| 92 |
| 93 // (2) Encrypt. |
| 94 return crypto.subtle.encrypt(algorithm, key, hexStringToUint8Array(testC
ase.plainText)); |
| 95 }).then(function(result) { |
| 96 bytesShouldMatchHexString("Encryption", testCase.cipherText, result); |
| 97 |
| 98 // (3) Decrypt |
| 99 return crypto.subtle.decrypt(algorithm, key, hexStringToUint8Array(testC
ase.cipherText)); |
| 100 }).then(function(result) { |
| 101 bytesShouldMatchHexString("Decryption", testCase.plainText, result); |
| 102 }); |
| 103 } |
| 104 |
| 105 // Add all of the tests defined above. |
| 106 for (var i = 0; i < kSuccessTestVectors.length; ++i) { |
| 107 allTests.push(runSuccessTestCase(kSuccessTestVectors[i])); |
| 108 } |
| 109 |
| 110 // ------------------------------------------------- |
| 111 // Failed key import. |
| 112 // ------------------------------------------------- |
| 113 |
| 114 // Supported key lengths are 16 (128-bit), 32 (256-bit), 24 (192-bit), |
| 115 // Try key lengths that are off by 1 from the supported ones. |
| 116 var kUnsupportedKeyLengths = [ |
| 117 0, 1, 15, 17, 31, 33, 23, 25, 64 |
| 118 ]; |
| 119 |
| 120 function testInvalidKeyImport(keyLengthBytes) |
| 121 { |
| 122 var algorithm = {name: 'aes-cbc'}; |
| 123 var keyData = new Uint8Array(keyLengthBytes); |
| 124 |
| 125 var usages = ['encrypt', 'decrypt']; |
| 126 var extractable = false; |
| 127 |
| 128 return crypto.subtle.importKey('raw', keyData, algorithm, extractable, usage
s).then(function(result) { |
| 129 debug("FAIL: Successfully import key of length " + keyData.byteLength +
" bytes"); |
| 130 }, function(result) { |
| 131 debug("PASS: Failed to import key of length " + keyData.byteLength + " b
ytes"); |
| 132 }); |
| 133 } |
| 134 |
| 135 for (var i = 0; i < kUnsupportedKeyLengths.length; ++i) { |
| 136 allTests.push(testInvalidKeyImport(kUnsupportedKeyLengths[i])); |
| 137 } |
| 138 |
| 139 // ------------------------------------------------- |
| 140 // Invalid cipher texts |
| 141 // ------------------------------------------------- |
| 142 |
| 143 function testInvalidDecryptions() |
| 144 { |
| 145 // 128-bit key with plaintext that is an exact multiple of block size. |
| 146 // Derived from [1] F.2.1 (CBC-AES128.Encrypt), by adding padding block. |
| 147 var iv = hexStringToUint8Array("000102030405060708090a0b0c0d0e0f"); |
| 148 var keyData = hexStringToUint8Array("2b7e151628aed2a6abf7158809cf4f3c"); |
| 149 var cipherText = hexStringToUint8Array("7649abac8119b246cee98e9b12e9197d5086
cb9b507219ee95db113a917678b273bed6b8e3c1743b7116e69e222295163ff1caa1681fac09120e
ca307586e1a78cb82807230e1321d3fae00d18cc2012"); |
| 150 |
| 151 var key = null; |
| 152 var usages = ['encrypt', 'decrypt']; |
| 153 var extractable = false; |
| 154 var algorithm = {name: 'aes-cbc', iv: iv}; |
| 155 |
| 156 function verifyDecryptionFails(newCipherTextLength) |
| 157 { |
| 158 var newCipherText = cipherText.subarray(0, newCipherTextLength); |
| 159 |
| 160 var description = "ciphertext length: " + newCipherText.byteLength; |
| 161 return crypto.subtle.decrypt(algorithm, key, newCipherText).then(functio
n(result) { |
| 162 debug("FAIL: decrypting succeeded. " + description); |
| 163 }, function(result) { |
| 164 debug("PASS: decrypting failed. " + description); |
| 165 }); |
| 166 } |
| 167 |
| 168 return crypto.subtle.importKey('raw', keyData, algorithm, extractable, usage
s).then(function(result) { |
| 169 key = result; |
| 170 |
| 171 // Verify that decryption works with the original ciphertext. |
| 172 return crypto.subtle.decrypt(algorithm, key, cipherText); |
| 173 }).then(function(result) { |
| 174 debug("PASS: Decryption succeeded"); |
| 175 |
| 176 // Try a number of bad ciphertexts. |
| 177 return Promise.all([ |
| 178 verifyDecryptionFails(0), |
| 179 verifyDecryptionFails(cipherText.byteLength - 1), |
| 180 |
| 181 // Stripped a whole block. This new final block will result in a |
| 182 // padding error. |
| 183 verifyDecryptionFails(cipherText.byteLength - 16), |
| 184 verifyDecryptionFails(1), |
| 185 verifyDecryptionFails(15), |
| 186 verifyDecryptionFails(16), |
| 187 verifyDecryptionFails(17), |
| 188 ]); |
| 189 }); |
| 190 } |
| 191 |
| 192 allTests.push(testInvalidDecryptions()); |
| 193 |
| 194 function testNormalizationFailures(importedKeys) |
| 195 { |
17 keys = importedKeys; | 196 keys = importedKeys; |
18 | 197 |
19 data = asciiToUint8Array("hello"); | 198 data = asciiToUint8Array("hello"); |
20 | 199 |
21 // --------------------------------------------------- | 200 // --------------------------------------------------- |
22 // AES-CBC normalization failures (AesCbcParams) | 201 // AES-CBC normalization failures (AesCbcParams) |
23 // --------------------------------------------------- | 202 // --------------------------------------------------- |
24 | 203 |
25 shouldThrow("crypto.subtle.encrypt({name: 'AES-CBC', iv: null}, keys.aesCbc,
data)"); | 204 shouldThrow("crypto.subtle.encrypt({name: 'AES-CBC', iv: null}, keys.aesCbc,
data)"); |
26 shouldThrow("crypto.subtle.encrypt({name: 'AES-CBC'}, keys.aesCbc, data)"); | 205 shouldThrow("crypto.subtle.encrypt({name: 'AES-CBC'}, keys.aesCbc, data)"); |
27 shouldThrow("crypto.subtle.encrypt({name: 'AES-CBC', iv: 3}, keys.aesCbc, da
ta)"); | 206 shouldThrow("crypto.subtle.encrypt({name: 'AES-CBC', iv: 3}, keys.aesCbc, da
ta)"); |
28 shouldThrow("crypto.subtle.encrypt({name: 'AES-CBC', iv: new Uint8Array[0]},
keys.aesCbc, data)"); | 207 shouldThrow("crypto.subtle.encrypt({name: 'AES-CBC', iv: new Uint8Array[0]},
keys.aesCbc, data)"); |
29 | 208 |
30 // Try calling with the wrong key type. | 209 // Try calling with the wrong key type. |
31 aesCbc = {name: 'AES-CBC', iv: new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15])}; | 210 aesCbc = {name: 'AES-CBC', iv: new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15])}; |
32 shouldThrow("crypto.subtle.encrypt(aesCbc, keys.hmacSha1, data)"); | 211 shouldThrow("crypto.subtle.encrypt(aesCbc, keys.hmacSha1, data)"); |
33 | 212 |
34 // Key doesn't support encrypt. | 213 // Key doesn't support encrypt. |
35 shouldThrow("crypto.subtle.encrypt(aesCbc, keys.aesCbcJustDecrypt, data)"); | 214 shouldThrow("crypto.subtle.encrypt(aesCbc, keys.aesCbcJustDecrypt, data)"); |
36 | 215 |
37 // If no key was specified AND the algorithm was bogus, should complain | 216 // If no key was specified AND the algorithm was bogus, should complain |
38 // about the missing key first. | 217 // about the missing key first. |
39 shouldThrow("crypto.subtle.encrypt({name: 'bogus'}, null, data)"); | 218 shouldThrow("crypto.subtle.encrypt({name: 'bogus'}, null, data)"); |
40 }).then(finishJSTest, failAndFinishJSTest); | 219 } |
| 220 |
| 221 allTests.push(importTestKeys().then(testNormalizationFailures)); |
| 222 |
| 223 // ------------------------------------------------- |
| 224 // Wait until all the tests have been run. |
| 225 // ------------------------------------------------- |
| 226 |
| 227 Promise.all(allTests).then(finishJSTest, failAndFinishJSTest); |
41 | 228 |
42 </script> | 229 </script> |
43 | 230 |
44 <script src="../fast/js/resources/js-test-post.js"></script> | 231 <script src="../fast/js/resources/js-test-post.js"></script> |
45 </body> | 232 </body> |
OLD | NEW |