tor-browser

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

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>