test_WebCrypto_HKDF.html (9644B)
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 "Deriving zero bits should produce an empty array", 28 function() { 29 var that = this; 30 var key = util.hex2abv("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"); 31 32 var alg = { 33 name: "HKDF", 34 hash: "SHA-256", 35 salt: new Uint8Array(), 36 info: new Uint8Array(), 37 }; 38 39 crypto.subtle.importKey("raw", key, "HKDF", false, ["deriveBits"]) 40 .then(x => crypto.subtle.deriveBits(alg, x, 0)) 41 .then(memcmp_complete(that, new Uint8Array([]))) 42 .catch(error(that)); 43 } 44 ); 45 46 // ----------------------------------------------------------------------------- 47 TestArray.addTest( 48 "Derive eight bits with HKDF, no salt or info given", 49 function() { 50 var that = this; 51 var key = util.hex2abv("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"); 52 53 var alg = { 54 name: "HKDF", 55 hash: "SHA-256", 56 salt: new Uint8Array(), 57 info: new Uint8Array(), 58 }; 59 60 crypto.subtle.importKey("raw", key, "HKDF", false, ["deriveBits"]) 61 .then(x => crypto.subtle.deriveBits(alg, x, 8)) 62 .then(memcmp_complete(that, new Uint8Array([0x8d]))) 63 .catch(error(that)); 64 } 65 ); 66 67 // ----------------------------------------------------------------------------- 68 TestArray.addTest( 69 "Deriving too many bits should fail", 70 function() { 71 var that = this; 72 var key = util.hex2abv("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"); 73 74 var alg = { 75 name: "HKDF", 76 hash: "SHA-256", 77 salt: new Uint8Array(), 78 info: new Uint8Array(), 79 }; 80 81 function deriveBits(x) { 82 // The maximum length (in bytes) of output material for HKDF is 255 times 83 // the digest length. In this case, the digest length (in bytes) of 84 // SHA-256 is 32; 32*255 = 8160. deriveBits expects the length to be in 85 // bits, so 8160*8=65280 and add 1 to exceed the maximum length. 86 return crypto.subtle.deriveBits(alg, x, 65281); 87 } 88 89 crypto.subtle.importKey("raw", key, "HKDF", false, ["deriveBits"]) 90 .then(deriveBits, error(that)) 91 .then(error(that), complete(that)); 92 } 93 ); 94 95 // ----------------------------------------------------------------------------- 96 TestArray.addTest( 97 "Deriving with an unsupported PRF should fail", 98 function() { 99 var that = this; 100 var key = util.hex2abv("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"); 101 102 var alg = { 103 name: "HKDF", 104 hash: "HMAC", 105 salt: new Uint8Array(), 106 info: new Uint8Array(), 107 }; 108 109 function deriveBits(x) { 110 return crypto.subtle.deriveBits(alg, x, 8); 111 } 112 113 crypto.subtle.importKey("raw", key, "HKDF", false, ["deriveBits"]) 114 .then(deriveBits, error(that)) 115 .then(error(that), complete(that)); 116 } 117 ); 118 119 // ----------------------------------------------------------------------------- 120 TestArray.addTest( 121 "Deriving with a non-HKDF key should fail", 122 function() { 123 var that = this; 124 125 var alg = { 126 name: "HKDF", 127 hash: "HMAC", 128 salt: new Uint8Array(), 129 info: new Uint8Array(), 130 }; 131 132 function deriveBits(x) { 133 return crypto.subtle.deriveBits(alg, x, 8); 134 } 135 136 var ecAlg = {name: "ECDH", namedCurve: "P-256"}; 137 crypto.subtle.generateKey(ecAlg, false, ["deriveBits"]) 138 .then(deriveBits, error(that)) 139 .then(error(that), complete(that)); 140 } 141 ); 142 143 // ----------------------------------------------------------------------------- 144 TestArray.addTest( 145 "Derive known values from test vectors (SHA-1 and SHA-256)", 146 function() { 147 var that = this; 148 var tests = tv.hkdf.slice(); 149 if (!tests.length) { 150 error(that)("No tests found"); 151 return; 152 } 153 154 function next() { 155 if (!tests.length) { 156 return Promise.resolve(); 157 } 158 159 var test = tests.shift(); 160 var {key} = test; 161 162 return crypto.subtle.importKey("raw", key, "HKDF", false, ["deriveBits"]) 163 .then(function(baseKey) { 164 return crypto.subtle.deriveBits({ 165 name: "HKDF", 166 hash: test.prf, 167 salt: test.salt, 168 info: test.info, 169 }, baseKey, test.data.byteLength * 8); 170 }) 171 .then(function(data) { 172 if (!util.memcmp(data, test.data)) { 173 throw new Error("derived bits don't match expected value"); 174 } 175 176 // Next test vector. 177 return next(); 178 }); 179 } 180 181 next().then(complete(that), error(that)); 182 } 183 ); 184 185 // ----------------------------------------------------------------------------- 186 TestArray.addTest( 187 "Derive known values from test vectors (JWK, SHA-256)", 188 function() { 189 var that = this; 190 var test = tv.hkdf[0]; 191 var alg = { 192 name: "HKDF", 193 hash: test.prf, 194 salt: test.salt, 195 info: test.info, 196 }; 197 198 crypto.subtle.importKey("jwk", test.jwk, "HKDF", false, ["deriveBits"]) 199 .then(x => crypto.subtle.deriveBits(alg, x, test.data.byteLength * 8)) 200 .then(memcmp_complete(that, test.data), error(that)); 201 } 202 ); 203 204 // ----------------------------------------------------------------------------- 205 TestArray.addTest( 206 "Test wrapping/unwrapping an HKDF key", 207 function() { 208 var that = this; 209 var hkdfKey = util.hex2abv("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"); 210 var alg = {name: "AES-GCM", length: 256, iv: new Uint8Array(16)}; 211 var wrappingKey; 212 213 function wrap(x) { 214 wrappingKey = x; 215 return crypto.subtle.encrypt(alg, wrappingKey, hkdfKey); 216 } 217 218 function unwrap(wrappedKey) { 219 return crypto.subtle.unwrapKey( 220 "raw", wrappedKey, wrappingKey, alg, "HKDF", false, ["deriveBits"]) 221 .then(rawKey => { 222 return crypto.subtle.deriveBits({ 223 name: "HKDF", 224 hash: "SHA-256", 225 salt: new Uint8Array(), 226 info: new Uint8Array(), 227 }, rawKey, 8); 228 }) 229 .then(derivedBits => { 230 if (!util.memcmp(derivedBits, new Uint8Array([0x8d]))) { 231 throw new Error("deriving bits failed"); 232 } 233 234 // Forward to reuse. 235 return wrappedKey; 236 }); 237 } 238 239 crypto.subtle.generateKey(alg, false, ["encrypt", "unwrapKey"]) 240 .then(wrap) 241 .then(unwrap) 242 .then(complete(that), error(that)); 243 } 244 ); 245 246 // ----------------------------------------------------------------------------- 247 TestArray.addTest( 248 "Unwrapping an HKDF key in PKCS8 format should fail", 249 function() { 250 var that = this; 251 var hkdfKey = util.hex2abv("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"); 252 var alg = {name: "AES-GCM", length: 256, iv: new Uint8Array(16)}; 253 var wrappingKey; 254 255 function wrap(x) { 256 wrappingKey = x; 257 return crypto.subtle.encrypt(alg, wrappingKey, hkdfKey); 258 } 259 260 function unwrap(x) { 261 return crypto.subtle.unwrapKey( 262 "pkcs8", x, wrappingKey, alg, "HKDF", false, ["deriveBits"]); 263 } 264 265 crypto.subtle.generateKey(alg, false, ["encrypt", "unwrapKey"]) 266 .then(wrap, error(that)) 267 .then(unwrap, error(that)) 268 .then(error(that), complete(that)); 269 } 270 ); 271 272 // ----------------------------------------------------------------------------- 273 TestArray.addTest( 274 "Derive an AES key using with HKDF", 275 function() { 276 var that = this; 277 var key = util.hex2abv("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"); 278 279 var alg = { 280 name: "HKDF", 281 hash: "SHA-256", 282 salt: new Uint8Array(), 283 info: new Uint8Array(), 284 }; 285 286 function deriveKey(x) { 287 var targetAlg = {name: "AES-GCM", length: 256}; 288 return crypto.subtle.deriveKey(alg, x, targetAlg, false, ["encrypt"]); 289 } 290 291 crypto.subtle.importKey("raw", key, "HKDF", false, ["deriveKey"]) 292 .then(deriveKey) 293 .then(complete(that), error(that)); 294 } 295 ); 296 297 // ----------------------------------------------------------------------------- 298 TestArray.addTest( 299 "Deriving an HKDF key with HKDF should fail", 300 function() { 301 var that = this; 302 var key = util.hex2abv("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"); 303 304 var alg = { 305 name: "HKDF", 306 hash: "SHA-256", 307 salt: new Uint8Array(), 308 info: new Uint8Array(), 309 }; 310 311 function deriveKey(x) { 312 return crypto.subtle.deriveKey(alg, x, "HKDF", false, ["deriveBits"]); 313 } 314 315 crypto.subtle.importKey("raw", key, "HKDF", false, ["deriveKey"]) 316 .then(deriveKey) 317 .then(error(that), complete(that)); 318 } 319 ); 320 321 /* ]]>*/</script> 322 </head> 323 324 <body> 325 326 <div id="content"> 327 <div id="head"> 328 <b>Web</b>Crypto<br> 329 </div> 330 331 <div id="start" onclick="start();">RUN ALL</div> 332 333 <div id="resultDiv" class="content"> 334 Summary: 335 <span class="pass"><span id="passN">0</span> passed, </span> 336 <span class="fail"><span id="failN">0</span> failed, </span> 337 <span class="pending"><span id="pendingN">0</span> pending.</span> 338 <br/> 339 <br/> 340 341 <table id="results"> 342 <tr> 343 <th>Test</th> 344 <th>Result</th> 345 <th>Time</th> 346 </tr> 347 </table> 348 349 </div> 350 351 <div id="foot"></div> 352 </div> 353 354 </body> 355 </html>