test_WebCrypto_Wrap_Unwrap.html (13169B)
1 <!DOCTYPE html> 2 <html> 3 4 <head> 5 <title>WebCrypto Test Suite</title> 6 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> 7 <link rel="stylesheet" href="./test_WebCrypto.css"/> 8 <script src="/tests/SimpleTest/SimpleTest.js"></script> 9 10 <!-- Utilities for manipulating ABVs --> 11 <script src="util.js"></script> 12 13 <!-- A simple wrapper around IndexedDB --> 14 <script src="simpledb.js"></script> 15 16 <!-- Test vectors drawn from the literature --> 17 <script src="./test-vectors.js"></script> 18 19 <!-- General testing framework --> 20 <script src="./test-array.js"></script> 21 22 <script>/* <![CDATA[*/ 23 "use strict"; 24 25 // ----------------------------------------------------------------------------- 26 TestArray.addTest( 27 "Key wrap known answer, using AES-GCM", 28 function() { 29 var that = this; 30 var alg = { 31 name: "AES-GCM", 32 iv: tv.key_wrap_known_answer.wrapping_iv, 33 tagLength: 128, 34 }; 35 var key, wrappingKey; 36 37 function doImport(k) { 38 wrappingKey = k; 39 return crypto.subtle.importKey("raw", tv.key_wrap_known_answer.key, 40 alg, true, ["encrypt", "decrypt"]); 41 } 42 function doWrap(k) { 43 key = k; 44 return crypto.subtle.wrapKey("raw", key, wrappingKey, alg); 45 } 46 47 crypto.subtle.importKey("raw", tv.key_wrap_known_answer.wrapping_key, 48 alg, false, ["wrapKey"]) 49 .then(doImport, error(that)) 50 .then(doWrap, error(that)) 51 .then( 52 memcmp_complete(that, tv.key_wrap_known_answer.wrapped_key), 53 error(that) 54 ); 55 } 56 ); 57 58 // ----------------------------------------------------------------------------- 59 TestArray.addTest( 60 "Key wrap failing on non-extractable key", 61 function() { 62 var that = this; 63 var alg = { 64 name: "AES-GCM", 65 iv: tv.key_wrap_known_answer.wrapping_iv, 66 tagLength: 128, 67 }; 68 var key, wrappingKey; 69 70 function doImport(k) { 71 wrappingKey = k; 72 return crypto.subtle.importKey("raw", tv.key_wrap_known_answer.key, 73 alg, false, ["encrypt", "decrypt"]); 74 } 75 function doWrap(k) { 76 key = k; 77 return crypto.subtle.wrapKey("raw", key, wrappingKey, alg); 78 } 79 80 crypto.subtle.importKey("raw", tv.key_wrap_known_answer.wrapping_key, 81 alg, false, ["wrapKey"]) 82 .then(doImport, error(that)) 83 .then(doWrap, error(that)) 84 .then( 85 error(that), 86 complete(that) 87 ); 88 } 89 ); 90 91 // ----------------------------------------------------------------------------- 92 TestArray.addTest( 93 "Key unwrap known answer, using AES-GCM", 94 function() { 95 var that = this; 96 var alg = { 97 name: "AES-GCM", 98 iv: tv.key_wrap_known_answer.wrapping_iv, 99 tagLength: 128, 100 }; 101 var wrappingKey; 102 103 function doUnwrap(k) { 104 wrappingKey = k; 105 return crypto.subtle.unwrapKey( 106 "raw", tv.key_wrap_known_answer.wrapped_key, 107 wrappingKey, alg, 108 "AES-GCM", true, ["encrypt", "decrypt"] 109 ); 110 } 111 function doExport(k) { 112 return crypto.subtle.exportKey("raw", k); 113 } 114 115 crypto.subtle.importKey("raw", tv.key_wrap_known_answer.wrapping_key, 116 alg, false, ["unwrapKey"]) 117 .then(doUnwrap, error(that)) 118 .then(doExport, error(that)) 119 .then( 120 memcmp_complete(that, tv.key_wrap_known_answer.key), 121 error(that) 122 ); 123 } 124 ); 125 126 // ----------------------------------------------------------------------------- 127 TestArray.addTest( 128 "Key wrap/unwrap round-trip, using RSA-OAEP", 129 function() { 130 var that = this; 131 var oaep = { 132 name: "RSA-OAEP", 133 hash: "SHA-256", 134 }; 135 var gcm = { 136 name: "AES-GCM", 137 iv: tv.aes_gcm_enc.iv, 138 additionalData: tv.aes_gcm_enc.adata, 139 tagLength: 128, 140 }; 141 var unwrapKey; 142 143 function doWrap(keys) { 144 var originalKey = keys[0]; 145 var wrapKey = keys[1]; 146 unwrapKey = keys[2]; 147 return crypto.subtle.wrapKey("raw", originalKey, wrapKey, oaep); 148 } 149 function doUnwrap(wrappedKey) { 150 return crypto.subtle.unwrapKey("raw", wrappedKey, unwrapKey, oaep, 151 gcm, false, ["encrypt"]); 152 } 153 function doEncrypt(aesKey) { 154 return crypto.subtle.encrypt(gcm, aesKey, tv.aes_gcm_enc.data); 155 } 156 157 // 1.Import: 158 // -> HMAC key 159 // -> OAEP wrap key (public) 160 // -> OAEP unwrap key (private) 161 // 2. Wrap the HMAC key 162 // 3. Unwrap it 163 // 4. Compute HMAC 164 // 5. Check HMAC value 165 Promise.all([ 166 crypto.subtle.importKey("raw", tv.aes_gcm_enc.key, gcm, true, ["encrypt"]), 167 crypto.subtle.importKey("spki", tv.rsaoaep.spki, oaep, true, ["wrapKey"]), 168 crypto.subtle.importKey("pkcs8", tv.rsaoaep.pkcs8, oaep, false, ["unwrapKey"]), 169 ]) 170 .then(doWrap, error(that)) 171 .then(doUnwrap, error(that)) 172 .then(doEncrypt, error(that)) 173 .then( 174 memcmp_complete(that, tv.aes_gcm_enc.result), 175 error(that) 176 ); 177 } 178 ); 179 180 // ----------------------------------------------------------------------------- 181 TestArray.addTest( 182 "HMAC JWK wrap/unwrap round-trip, with AES-GCM", 183 function() { 184 var that = this; 185 var genAlg = { name: "HMAC", hash: "SHA-384", length: 512 }; 186 var wrapAlg = { name: "AES-GCM", iv: tv.aes_gcm_enc.iv }; 187 var wrapKey, originalKey, originalKeyJwk; 188 189 function doExport(k) { 190 return crypto.subtle.exportKey("jwk", k); 191 } 192 function doWrap() { 193 return crypto.subtle.wrapKey("jwk", originalKey, wrapKey, wrapAlg); 194 } 195 function doUnwrap(wrappedKey) { 196 return crypto.subtle.unwrapKey("jwk", wrappedKey, wrapKey, wrapAlg, 197 { name: "HMAC", hash: "SHA-384"}, 198 true, ["sign", "verify"]); 199 } 200 201 Promise.all([ 202 crypto.subtle.importKey("jwk", tv.aes_gcm_enc.key_jwk, 203 "AES-GCM", false, ["wrapKey", "unwrapKey"]) 204 .then(function(x) { wrapKey = x; }), 205 crypto.subtle.generateKey(genAlg, true, ["sign", "verify"]) 206 .then(function(x) { originalKey = x; return x; }) 207 .then(doExport) 208 .then(function(x) { originalKeyJwk = x; }), 209 ]) 210 .then(doWrap) 211 .then(doUnwrap) 212 .then(doExport) 213 .then( 214 complete(that, function(x) { 215 return exists(x.k) && x.k == originalKeyJwk.k; 216 }), 217 error(that) 218 ); 219 } 220 ); 221 222 // ----------------------------------------------------------------------------- 223 TestArray.addTest( 224 "ECDSA private JWK wrap/unwrap round-trip, with AES-GCM", 225 function() { 226 var that = this; 227 var genAlg = { name: "ECDSA", namedCurve: "P-256" }; 228 var wrapAlg = { name: "AES-GCM", iv: tv.aes_gcm_enc.iv }; 229 var wrapKey, originalKey, originalKeyJwk; 230 231 function doExport(k) { 232 return crypto.subtle.exportKey("jwk", k); 233 } 234 function doWrap() { 235 return crypto.subtle.wrapKey("jwk", originalKey, wrapKey, wrapAlg); 236 } 237 function doUnwrap(wrappedKey) { 238 return crypto.subtle.unwrapKey("jwk", wrappedKey, wrapKey, wrapAlg, 239 genAlg, true, ["sign"]); 240 } 241 242 Promise.all([ 243 crypto.subtle.importKey("jwk", tv.aes_gcm_enc.key_jwk, 244 "AES-GCM", false, ["wrapKey", "unwrapKey"]) 245 .then(function(x) { wrapKey = x; }), 246 crypto.subtle.generateKey(genAlg, true, ["sign", "verify"]) 247 .then(function(x) { originalKey = x.privateKey; return x.privateKey; }) 248 .then(doExport) 249 .then(function(x) { originalKeyJwk = x; }), 250 ]) 251 .then(doWrap) 252 .then(doUnwrap) 253 .then(doExport) 254 .then( 255 complete(that, function(x) { 256 return (x.kty == originalKeyJwk.kty) && 257 (x.crv == originalKeyJwk.crv) && 258 (x.d == originalKeyJwk.d) && 259 (x.x == originalKeyJwk.x) && 260 (x.y == originalKeyJwk.y); 261 }), 262 error(that) 263 ); 264 } 265 ); 266 267 // ----------------------------------------------------------------------------- 268 TestArray.addTest( 269 "AES-KW known answer", 270 function() { 271 var that = this; 272 273 function doWrap(keys) { 274 var wrapKey = keys[0]; 275 var originalKey = keys[1]; 276 return crypto.subtle.wrapKey("raw", originalKey, wrapKey, "AES-KW"); 277 } 278 279 Promise.all([ 280 crypto.subtle.importKey("jwk", tv.aes_kw.wrapping_key, 281 "AES-KW", false, ["wrapKey"]), 282 crypto.subtle.importKey("jwk", tv.aes_kw.key, 283 "AES-GCM", true, ["encrypt"]), 284 ]) 285 .then(doWrap) 286 .then( 287 memcmp_complete(that, tv.aes_kw.wrapped_key), 288 error(that) 289 ); 290 } 291 ); 292 293 // ----------------------------------------------------------------------------- 294 TestArray.addTest( 295 "AES-KW unwrap failure on tampered key data", 296 function() { 297 var that = this; 298 var tamperedWrappedKey = new Uint8Array(tv.aes_kw.wrapped_key); 299 tamperedWrappedKey[5] ^= 0xFF; 300 301 function doUnwrap(wrapKey) { 302 return crypto.subtle.unwrapKey("raw", tamperedWrappedKey, wrapKey, 303 "AES-KW", "AES-GCM", 304 true, ["encrypt", "decrypt"]); 305 } 306 307 crypto.subtle.importKey("jwk", tv.aes_kw.wrapping_key, 308 "AES-KW", false, ["unwrapKey"]) 309 .then(doUnwrap) 310 .then(error(that), complete(that)); 311 } 312 ); 313 314 // ----------------------------------------------------------------------------- 315 TestArray.addTest( 316 "AES-KW unwrap AES-KW key data", 317 function() { 318 var that = this; 319 var wrappedKey = new Uint8Array(tv.aes_kw.wrapped_key); 320 321 function doUnwrap(wrapKey) { 322 return crypto.subtle.unwrapKey("raw", wrappedKey, wrapKey, 323 "AES-KW", "AES-KW", 324 true, ["wrapKey", "unwrapKey"]); 325 } 326 327 crypto.subtle.importKey("jwk", tv.aes_kw.wrapping_key, 328 "AES-KW", false, ["unwrapKey"]) 329 .then(doUnwrap) 330 .then( 331 memcmp_complete(that, tv.aes_kw.key), 332 error(that) 333 ); 334 } 335 ); 336 337 // ----------------------------------------------------------------------------- 338 TestArray.addTest( 339 "AES-KW wrap/unwrap round-trip", 340 function() { 341 var that = this; 342 var genAlg = { name: "HMAC", hash: "SHA-384", length: 512 }; 343 var wrapKey, originalKey, originalKeyJwk; 344 345 function doExport(k) { 346 return crypto.subtle.exportKey("jwk", k); 347 } 348 function doWrap() { 349 return crypto.subtle.wrapKey("raw", originalKey, wrapKey, "AES-KW"); 350 } 351 function doUnwrap(wrappedKey) { 352 return crypto.subtle.unwrapKey("raw", wrappedKey, wrapKey, 353 "AES-KW", { name: "HMAC", hash: "SHA-384"}, 354 true, ["sign", "verify"]); 355 } 356 357 Promise.all([ 358 crypto.subtle.importKey("jwk", tv.aes_kw.wrapping_key, 359 "AES-KW", false, ["wrapKey", "unwrapKey"]) 360 .then(function(x) { wrapKey = x; }), 361 crypto.subtle.generateKey(genAlg, true, ["sign"]) 362 .then(function(x) { originalKey = x; return x; }) 363 .then(doExport) 364 .then(function(x) { originalKeyJwk = x; }), 365 ]) 366 .then(doWrap) 367 .then(doUnwrap) 368 .then(doExport) 369 .then( 370 complete(that, function(x) { 371 return exists(x.k) && x.k == originalKeyJwk.k; 372 }), 373 error(that) 374 ); 375 } 376 ); 377 378 // ----------------------------------------------------------------------------- 379 TestArray.addTest( 380 "JWK unwrap attempt on bogus data should error out", 381 function() { 382 // Largely cribbed from the "JWK wrap/unwrap round-trip, with AES-GCM" test 383 var that = this; 384 var wrapAlg = { name: "AES-GCM", iv: tv.aes_gcm_enc.iv }; 385 var wrapKey; 386 387 function doBogusWrap() { 388 var abv = new TextEncoder().encode("I am so not JSON"); 389 return crypto.subtle.encrypt(wrapAlg, wrapKey, abv); 390 } 391 function doUnwrap(wrappedKey) { 392 return crypto.subtle.unwrapKey("jwk", wrappedKey, wrapKey, wrapAlg, 393 {name: "HMAC", hash: "SHA-384"}, 394 true, ["sign", "verify"]); 395 } 396 397 crypto.subtle.importKey("jwk", tv.aes_gcm_enc.key_jwk, 398 "AES-GCM", false, ["encrypt", "unwrapKey"]) 399 .then(function(x) { wrapKey = x; }) 400 .then(doBogusWrap, error(that)) 401 .then(doUnwrap, error(that)) 402 .then( 403 error(that), 404 complete(that) 405 ); 406 } 407 ); 408 409 /* ]]>*/</script> 410 </head> 411 412 <body> 413 414 <div id="content"> 415 <div id="head"> 416 <b>Web</b>Crypto<br> 417 </div> 418 419 <div id="start" onclick="start();">RUN ALL</div> 420 421 <div id="resultDiv" class="content"> 422 Summary: 423 <span class="pass"><span id="passN">0</span> passed, </span> 424 <span class="fail"><span id="failN">0</span> failed, </span> 425 <span class="pending"><span id="pendingN">0</span> pending.</span> 426 <br/> 427 <br/> 428 429 <table id="results"> 430 <tr> 431 <th>Test</th> 432 <th>Result</th> 433 <th>Time</th> 434 </tr> 435 </table> 436 437 </div> 438 439 <div id="foot"></div> 440 </div> 441 442 </body> 443 </html>