tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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>