chacha20_poly1305.tentative.https.any.js (11325B)
1 // META: title=WebCryptoAPI: encrypt()/decrypt() ChaCha20-Poly1305 2 // META: timeout=long 3 4 var subtle = crypto.subtle; // Change to test prefixed implementations 5 6 var sourceData = { 7 empty: new Uint8Array(0), 8 short: new Uint8Array([ 9 21, 110, 234, 124, 193, 76, 86, 203, 148, 219, 3, 10, 74, 157, 149, 255, 10 ]), 11 medium: new Uint8Array([ 12 182, 200, 249, 223, 100, 140, 208, 136, 183, 15, 56, 231, 65, 151, 177, 140, 13 184, 30, 30, 67, 80, 213, 11, 204, 184, 251, 90, 115, 121, 200, 123, 178, 14 227, 214, 237, 84, 97, 237, 30, 159, 54, 243, 64, 163, 150, 42, 68, 107, 15 129, 91, 121, 75, 75, 212, 58, 68, 3, 80, 32, 119, 178, 37, 108, 200, 7, 16 131, 127, 58, 172, 209, 24, 235, 75, 156, 43, 174, 184, 151, 6, 134, 37, 17 171, 172, 161, 147, 18 ]), 19 long: new Uint8Array( 20 Array(65) 21 .fill(0) 22 .map((_, i) => i % 256) 23 ), 24 }; 25 26 var additionalData = { 27 empty: new Uint8Array(0), 28 short: new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]), 29 medium: new Uint8Array([ 30 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 31 ]), 32 }; 33 34 var iv = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); // 96-bit IV (only valid size for ChaCha20-Poly1305) 35 36 var keyBytes = new Uint8Array([ 37 52, 138, 105, 103, 105, 3, 94, 254, 59, 241, 159, 138, 189, 254, 153, 191, 38 228, 172, 165, 239, 117, 172, 19, 206, 219, 9, 205, 138, 45, 87, 166, 89, 39 ]); 40 41 var encryptedData = { 42 empty_ad: { 43 empty: new Uint8Array([ 44 202, 31, 160, 169, 169, 221, 162, 53, 252, 126, 127, 237, 158, 98, 86, 41, 45 ]), 46 short: new Uint8Array([ 47 226, 238, 222, 234, 202, 96, 116, 202, 205, 199, 126, 40, 167, 93, 65, 48 172, 87, 45, 146, 68, 245, 236, 87, 162, 200, 89, 228, 51, 2, 249, 103, 49 255, 50 ]), 51 medium: new Uint8Array([ 52 65, 72, 205, 73, 111, 160, 242, 137, 238, 19, 69, 197, 172, 87, 101, 223, 53 97, 245, 255, 57, 226, 43, 36, 125, 205, 218, 211, 252, 102, 45, 234, 179, 54 23, 71, 87, 156, 145, 16, 106, 98, 75, 140, 67, 249, 230, 124, 37, 127, 55 192, 145, 40, 129, 203, 31, 15, 182, 15, 226, 211, 111, 132, 132, 114, 56 204, 73, 36, 245, 199, 212, 187, 239, 33, 46, 203, 124, 134, 76, 21, 242, 57 233, 119, 179, 216, 193, 210, 145, 43, 48, 105, 153, 28, 62, 49, 175, 154, 58 142, 222, 68, 219, 229, 66, 59 ]), 60 long: new Uint8Array([ 61 247, 129, 54, 149, 15, 41, 36, 6, 81, 21, 119, 41, 225, 205, 218, 92, 201, 62 250, 243, 105, 166, 235, 57, 166, 109, 56, 147, 148, 3, 248, 143, 30, 212, 63 176, 152, 235, 212, 216, 82, 218, 85, 86, 41, 113, 92, 123, 79, 59, 113, 64 251, 99, 249, 180, 254, 3, 197, 52, 139, 201, 35, 10, 156, 32, 59, 14, 65 225, 117, 48, 100, 126, 58, 112, 157, 195, 18, 185, 178, 97, 215, 233, 66 113, 67 ]), 68 }, 69 short_ad: { 70 empty: new Uint8Array([ 71 0, 176, 175, 37, 156, 39, 141, 93, 198, 224, 223, 214, 239, 212, 50, 215, 72 ]), 73 short: new Uint8Array([ 74 226, 238, 222, 234, 202, 96, 116, 202, 205, 199, 126, 40, 167, 93, 65, 75 172, 40, 45, 199, 67, 109, 80, 99, 203, 246, 137, 82, 206, 183, 23, 175, 76 176, 77 ]), 78 medium: new Uint8Array([ 79 65, 72, 205, 73, 111, 160, 242, 137, 238, 19, 69, 197, 172, 87, 101, 223, 80 97, 245, 255, 57, 226, 43, 36, 125, 205, 218, 211, 252, 102, 45, 234, 179, 81 23, 71, 87, 156, 145, 16, 106, 98, 75, 140, 67, 249, 230, 124, 37, 127, 82 192, 145, 40, 129, 203, 31, 15, 182, 15, 226, 211, 111, 132, 132, 114, 83 204, 73, 36, 245, 199, 212, 187, 239, 33, 46, 203, 124, 134, 76, 21, 242, 84 233, 119, 179, 216, 193, 210, 199, 121, 7, 153, 245, 137, 122, 100, 72, 85 102, 113, 169, 244, 218, 111, 105, 86 ]), 87 long: new Uint8Array([ 88 247, 129, 54, 149, 15, 41, 36, 6, 81, 21, 119, 41, 225, 205, 218, 92, 201, 89 250, 243, 105, 166, 235, 57, 166, 109, 56, 147, 148, 3, 248, 143, 30, 212, 90 176, 152, 235, 212, 216, 82, 218, 85, 86, 41, 113, 92, 123, 79, 59, 113, 91 251, 99, 249, 180, 254, 3, 197, 52, 139, 201, 35, 10, 156, 32, 59, 14, 92 137, 0, 55, 193, 166, 74, 124, 251, 91, 36, 191, 112, 236, 204, 35, 102, 93 ]), 94 }, 95 medium_ad: { 96 empty: new Uint8Array([ 97 163, 122, 139, 166, 205, 190, 132, 236, 17, 19, 31, 4, 16, 47, 13, 242, 98 ]), 99 short: new Uint8Array([ 100 226, 238, 222, 234, 202, 96, 116, 202, 205, 199, 126, 40, 167, 93, 65, 101 172, 18, 242, 253, 220, 52, 138, 67, 162, 201, 38, 125, 119, 44, 53, 147, 102 119, 103 ]), 104 medium: new Uint8Array([ 105 65, 72, 205, 73, 111, 160, 242, 137, 238, 19, 69, 197, 172, 87, 101, 223, 106 97, 245, 255, 57, 226, 43, 36, 125, 205, 218, 211, 252, 102, 45, 234, 179, 107 23, 71, 87, 156, 145, 16, 106, 98, 75, 140, 67, 249, 230, 124, 37, 127, 108 192, 145, 40, 129, 203, 31, 15, 182, 15, 226, 211, 111, 132, 132, 114, 109 204, 73, 36, 245, 199, 212, 187, 239, 33, 46, 203, 124, 134, 76, 21, 242, 110 233, 119, 179, 216, 193, 210, 161, 250, 192, 51, 193, 133, 185, 55, 148, 111 21, 194, 168, 212, 203, 252, 184, 112 ]), 113 long: new Uint8Array([ 114 247, 129, 54, 149, 15, 41, 36, 6, 81, 21, 119, 41, 225, 205, 218, 92, 201, 115 250, 243, 105, 166, 235, 57, 166, 109, 56, 147, 148, 3, 248, 143, 30, 212, 116 176, 152, 235, 212, 216, 82, 218, 85, 86, 41, 113, 92, 123, 79, 59, 113, 117 251, 99, 249, 180, 254, 3, 197, 52, 139, 201, 35, 10, 156, 32, 59, 14, 88, 118 20, 159, 185, 145, 230, 1, 242, 106, 255, 55, 7, 60, 85, 179, 184, 119 ]), 120 }, 121 }; 122 123 function equalBuffers(a, b) { 124 if (a.byteLength !== b.byteLength) { 125 return false; 126 } 127 var aBytes = new Uint8Array(a); 128 var bBytes = new Uint8Array(b); 129 for (var i = 0; i < a.byteLength; i++) { 130 if (aBytes[i] !== bBytes[i]) { 131 return false; 132 } 133 } 134 return true; 135 } 136 137 // Test ChaCha20-Poly1305 encryption/decryption 138 var algorithmName = 'ChaCha20-Poly1305'; 139 140 // Test with different additional data combinations 141 Object.keys(additionalData).forEach(function (adName) { 142 var ad = additionalData[adName]; 143 144 Object.keys(sourceData).forEach(function (dataName) { 145 var plaintext = sourceData[dataName]; 146 var ciphertext = encryptedData[adName + '_ad'][dataName]; 147 148 promise_test(function (test) { 149 var operation = subtle 150 .importKey('raw-secret', keyBytes, { name: algorithmName }, false, [ 151 'encrypt', 152 'decrypt', 153 ]) 154 .then( 155 function (key) { 156 return subtle.encrypt( 157 { name: algorithmName, iv: iv, additionalData: ad }, 158 key, 159 plaintext 160 ); 161 }, 162 function (err) { 163 assert_unreached( 164 'importKey failed unexpectedly: ' + err.toString() 165 ); 166 } 167 ) 168 .then( 169 function (result) { 170 assert_true( 171 equalBuffers(result, ciphertext), 172 'Encrypted data should match expected result' 173 ); 174 return result; 175 }, 176 function (err) { 177 assert_unreached('encrypt failed unexpectedly: ' + err.toString()); 178 } 179 ); 180 181 return operation; 182 }, algorithmName + 183 ' encryption with ' + 184 adName + 185 ' additional data, ' + 186 dataName + 187 ' data'); 188 189 promise_test(function (test) { 190 var operation = subtle 191 .importKey('raw-secret', keyBytes, { name: algorithmName }, false, [ 192 'encrypt', 193 'decrypt', 194 ]) 195 .then( 196 function (key) { 197 return subtle.decrypt( 198 { name: algorithmName, iv: iv, additionalData: ad }, 199 key, 200 ciphertext 201 ); 202 }, 203 function (err) { 204 assert_unreached( 205 'importKey failed unexpectedly: ' + err.toString() 206 ); 207 } 208 ) 209 .then( 210 function (result) { 211 assert_true( 212 equalBuffers(result, plaintext), 213 'Decrypted data should match original plaintext' 214 ); 215 }, 216 function (err) { 217 assert_unreached('decrypt failed unexpectedly: ' + err.toString()); 218 } 219 ); 220 221 return operation; 222 }, algorithmName + 223 ' decryption with ' + 224 adName + 225 ' additional data, ' + 226 dataName + 227 ' data'); 228 }); 229 }); 230 231 // Test round-trip encryption/decryption without fixed vectors 232 promise_test(function (test) { 233 var key; 234 var plaintext = sourceData.medium; 235 var ad = additionalData.short; 236 237 return subtle 238 .generateKey({ name: algorithmName }, false, ['encrypt', 'decrypt']) 239 .then(function (result) { 240 key = result; 241 return subtle.encrypt( 242 { name: algorithmName, iv: iv, additionalData: ad }, 243 key, 244 plaintext 245 ); 246 }) 247 .then(function (encrypted) { 248 return subtle.decrypt( 249 { name: algorithmName, iv: iv, additionalData: ad }, 250 key, 251 encrypted 252 ); 253 }) 254 .then(function (decrypted) { 255 assert_true( 256 equalBuffers(decrypted, plaintext), 257 'Round-trip encryption/decryption should return original plaintext' 258 ); 259 }); 260 }, algorithmName + ' round-trip encrypt/decrypt'); 261 262 // Test decryption with wrong additional data should fail 263 promise_test(function (test) { 264 var key; 265 var plaintext = sourceData.short; 266 var correctAd = additionalData.short; 267 var wrongAd = additionalData.medium; 268 269 return subtle 270 .generateKey({ name: algorithmName }, false, ['encrypt', 'decrypt']) 271 .then(function (result) { 272 key = result; 273 return subtle.encrypt( 274 { name: algorithmName, iv: iv, additionalData: correctAd }, 275 key, 276 plaintext 277 ); 278 }) 279 .then(function (encrypted) { 280 return promise_rejects_dom( 281 test, 282 'OperationError', 283 subtle.decrypt( 284 { name: algorithmName, iv: iv, additionalData: wrongAd }, 285 key, 286 encrypted 287 ) 288 ); 289 }); 290 }, algorithmName + ' decryption with wrong additional data should fail'); 291 292 // Test decryption with wrong IV should fail 293 promise_test(function (test) { 294 var key; 295 var correctIv = iv; 296 var wrongIv = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]); // Different 96-bit IV 297 var plaintext = sourceData.short; 298 var ad = additionalData.empty; 299 300 return subtle 301 .generateKey({ name: algorithmName }, false, ['encrypt', 'decrypt']) 302 .then(function (result) { 303 key = result; 304 return subtle.encrypt( 305 { name: algorithmName, iv: correctIv, additionalData: ad }, 306 key, 307 plaintext 308 ); 309 }) 310 .then(function (encrypted) { 311 return promise_rejects_dom( 312 test, 313 'OperationError', 314 subtle.decrypt( 315 { name: algorithmName, iv: wrongIv, additionalData: ad }, 316 key, 317 encrypted 318 ) 319 ); 320 }); 321 }, algorithmName + ' decryption with wrong IV should fail'); 322 323 // Test invalid IV size should fail 324 promise_test(function (test) { 325 var invalidIv = new Uint8Array(16); // 128-bit IV is invalid for ChaCha20-Poly1305 326 327 return subtle 328 .generateKey({ name: algorithmName }, false, ['encrypt']) 329 .then(function (key) { 330 return promise_rejects_dom( 331 test, 332 'OperationError', 333 subtle.encrypt( 334 { name: algorithmName, iv: invalidIv }, 335 key, 336 sourceData.short 337 ) 338 ); 339 }); 340 }, algorithmName + ' encryption with invalid IV size should fail');