tor-browser

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

ecdh_bits.js (18020B)


      1 function define_tests() {
      2    // May want to test prefixed implementations.
      3    var subtle = self.crypto.subtle;
      4 
      5    var pkcs8 = {
      6        "P-521": new Uint8Array([48, 129, 238, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 4, 129, 214, 48, 129, 211, 2, 1, 1, 4, 66, 1, 166, 126, 211, 33, 145, 90, 100, 170, 53, 155, 125, 100, 141, 220, 38, 24, 250, 142, 141, 24, 103, 232, 247, 24, 48, 177, 13, 37, 237, 40, 145, 250, 241, 47, 60, 126, 117, 66, 26, 46, 162, 100, 249, 169, 21, 50, 13, 39, 79, 225, 71, 7, 66, 185, 132, 233, 107, 152, 145, 32, 129, 250, 205, 71, 141, 161, 129, 137, 3, 129, 134, 0, 4, 0, 32, 157, 72, 63, 40, 102, 104, 129, 198, 100, 31, 58, 18, 111, 64, 15, 81, 228, 101, 17, 112, 254, 103, 140, 117, 232, 87, 18, 226, 134, 138, 220, 133, 8, 36, 153, 123, 235, 240, 188, 130, 180, 48, 40, 166, 210, 236, 23, 119, 202, 69, 39, 159, 114, 6, 163, 234, 139, 92, 210, 7, 63, 73, 62, 69, 0, 12, 181, 76, 58, 90, 202, 162, 104, 197, 103, 16, 66, 136, 120, 217, 139, 138, 251, 246, 138, 97, 33, 83, 99, 40, 70, 216, 7, 233, 38, 114, 105, 143, 27, 156, 97, 29, 231, 211, 142, 52, 205, 108, 115, 136, 144, 146, 197, 110, 82, 214, 128, 241, 223, 208, 146, 184, 122, 200, 239, 159, 243, 200, 251, 72]),
      7        "P-256": new Uint8Array([48, 129, 135, 2, 1, 0, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 4, 109, 48, 107, 2, 1, 1, 4, 32, 15, 247, 79, 232, 241, 202, 175, 97, 92, 206, 241, 29, 217, 53, 114, 87, 98, 217, 216, 65, 236, 186, 185, 94, 170, 38, 68, 123, 52, 100, 245, 113, 161, 68, 3, 66, 0, 4, 140, 96, 11, 44, 102, 25, 45, 97, 158, 39, 210, 37, 107, 59, 151, 118, 178, 141, 30, 5, 246, 13, 234, 189, 98, 174, 123, 154, 211, 157, 224, 217, 59, 4, 102, 109, 199, 119, 14, 126, 207, 13, 211, 203, 203, 211, 110, 221, 107, 94, 220, 153, 81, 7, 55, 161, 237, 104, 46, 205, 112, 244, 10, 47]),
      8        "P-384": new Uint8Array([48, 129, 182, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 4, 129, 158, 48, 129, 155, 2, 1, 1, 4, 48, 248, 113, 165, 102, 101, 137, 193, 74, 87, 71, 38, 62, 248, 91, 49, 156, 192, 35, 219, 110, 53, 103, 108, 61, 120, 30, 239, 139, 5, 95, 207, 190, 134, 250, 13, 6, 208, 86, 181, 25, 95, 177, 50, 58, 248, 222, 37, 179, 161, 100, 3, 98, 0, 4, 241, 25, 101, 223, 125, 212, 89, 77, 4, 25, 197, 8, 100, 130, 163, 184, 38, 185, 121, 127, 155, 224, 189, 13, 16, 156, 158, 30, 153, 137, 193, 185, 169, 43, 143, 38, 159, 152, 225, 122, 209, 132, 186, 115, 193, 247, 151, 98, 175, 69, 175, 129, 65, 96, 38, 66, 218, 39, 26, 107, 176, 255, 235, 12, 180, 71, 143, 207, 112, 126, 102, 26, 166, 214, 205, 245, 21, 73, 200, 140, 63, 19, 11, 233, 232, 32, 31, 111, 106, 9, 244, 24, 90, 175, 149, 196])
      9    };
     10 
     11    var spki = {
     12        "P-521": new Uint8Array([48, 129, 155, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 3, 129, 134, 0, 4, 0, 238, 105, 249, 71, 21, 215, 1, 233, 226, 1, 19, 51, 212, 244, 249, 108, 186, 125, 145, 248, 139, 17, 43, 175, 117, 207, 9, 204, 31, 138, 202, 151, 97, 141, 169, 56, 152, 34, 210, 155, 111, 233, 153, 106, 97, 32, 62, 247, 82, 183, 113, 232, 149, 143, 196, 103, 123, 179, 119, 133, 101, 171, 96, 214, 237, 0, 222, 171, 103, 97, 137, 91, 147, 94, 58, 211, 37, 251, 133, 73, 229, 111, 19, 120, 106, 167, 63, 136, 162, 236, 254, 64, 147, 52, 115, 216, 174, 242, 64, 196, 223, 215, 213, 6, 242, 44, 221, 14, 85, 85, 143, 63, 191, 5, 235, 247, 239, 239, 122, 114, 215, 143, 70, 70, 155, 132, 72, 242, 110, 39, 18]),
     13        "P-256": new Uint8Array([48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 154, 116, 32, 120, 126, 95, 77, 105, 211, 232, 34, 114, 115, 1, 109, 56, 224, 71, 129, 133, 223, 127, 238, 156, 142, 103, 60, 202, 211, 79, 126, 128, 254, 49, 141, 182, 221, 107, 119, 218, 99, 32, 165, 246, 151, 89, 9, 68, 23, 177, 52, 239, 138, 139, 116, 193, 101, 4, 57, 198, 115, 0, 90, 61]),
     14        "P-384": new Uint8Array([48, 118, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 3, 98, 0, 4, 145, 130, 45, 194, 175, 89, 193, 143, 91, 103, 248, 13, 246, 26, 38, 3, 194, 168, 240, 179, 192, 175, 130, 45, 99, 194, 121, 112, 26, 130, 69, 96, 64, 68, 1, 221, 233, 165, 110, 229, 39, 87, 234, 139, 199, 72, 212, 200, 43, 83, 55, 180, 141, 123, 101, 88, 58, 61, 87, 36, 56, 136, 0, 54, 186, 198, 115, 15, 66, 202, 82, 120, 150, 107, 213, 242, 30, 134, 226, 29, 48, 197, 166, 208, 70, 62, 197, 19, 221, 80, 159, 252, 220, 175, 31, 245])
     15    };
     16 
     17    var sizes = {
     18        "P-521": 66,
     19        "P-256": 32,
     20        "P-384": 48
     21    };
     22 
     23    var derivations = {
     24        "P-521": new Uint8Array([0, 156, 43, 206, 87, 190, 128, 173, 171, 59, 7, 56, 91, 142, 89, 144, 235, 125, 111, 222, 189, 176, 27, 243, 83, 113, 164, 246, 7, 94, 157, 40, 138, 193, 42, 109, 254, 3, 170, 87, 67, 188, 129, 112, 157, 73, 168, 34, 148, 2, 25, 182, 75, 118, 138, 205, 82, 15, 161, 54, 142, 160, 175, 141, 71, 93]),
     25        "P-256": new Uint8Array([14, 143, 60, 77, 177, 178, 162, 131, 115, 90, 0, 220, 87, 31, 26, 232, 151, 28, 227, 35, 250, 17, 131, 137, 203, 95, 65, 196, 59, 61, 181, 161]),
     26        "P-384": new Uint8Array([224, 189, 107, 206, 10, 239, 140, 164, 136, 56, 166, 226, 252, 197, 126, 103, 185, 197, 232, 134, 12, 95, 11, 233, 218, 190, 197, 62, 69, 78, 24, 160, 161, 116, 196, 136, 136, 162, 100, 136, 17, 91, 45, 201, 241, 223, 165, 45])
     27    };
     28 
     29    return importKeys(pkcs8, spki, sizes)
     30    .then(function(results) {
     31        publicKeys = results.publicKeys;
     32        privateKeys = results.privateKeys;
     33        ecdsaKeyPairs = results.ecdsaKeyPairs;
     34        noDeriveBitsKeys = results.noDeriveBitsKeys;
     35 
     36        Object.keys(sizes).forEach(function(namedCurve) {
     37            // Basic success case
     38            promise_test(function(test) {
     39                return subtle.deriveBits({name: "ECDH", public: publicKeys[namedCurve]}, privateKeys[namedCurve], 8 * sizes[namedCurve])
     40                .then(function(derivation) {
     41                    assert_true(equalBuffers(derivation, derivations[namedCurve]), "Derived correct bits");
     42                }, function(err) {
     43                    assert_unreached("deriveBits failed with error " + err.name + ": " + err.message);
     44                });
     45            }, namedCurve + " good parameters");
     46 
     47            // Case insensitivity check
     48            promise_test(function(test) {
     49                return subtle.deriveBits({name: "EcDh", public: publicKeys[namedCurve]}, privateKeys[namedCurve], 8 * sizes[namedCurve])
     50                .then(function(derivation) {
     51                    assert_true(equalBuffers(derivation, derivations[namedCurve]), "Derived correct bits");
     52                }, function(err) {
     53                    assert_unreached("deriveBits failed with error " + err.name + ": " + err.message);
     54                });
     55            }, namedCurve + " mixed case parameters");
     56 
     57            // Shorter than entire derivation per algorithm
     58            promise_test(function(test) {
     59                return subtle.deriveBits({name: "ECDH", public: publicKeys[namedCurve]}, privateKeys[namedCurve], 8 * sizes[namedCurve] - 32)
     60                .then(function(derivation) {
     61                    assert_true(equalBuffers(derivation, derivations[namedCurve], 8 * sizes[namedCurve] - 32), "Derived correct bits");
     62                }, function(err) {
     63                    assert_unreached("deriveBits failed with error " + err.name + ": " + err.message);
     64                });
     65            }, namedCurve + " short result");
     66 
     67            // Non-multiple of 8
     68            promise_test(function(test) {
     69                return subtle.deriveBits({name: "ECDH", public: publicKeys[namedCurve]}, privateKeys[namedCurve], 8 * sizes[namedCurve] - 11)
     70                .then(function(derivation) {
     71                    assert_true(equalBuffers(derivation, derivations[namedCurve], 8 * sizes[namedCurve] - 11), "Derived correct bits");
     72                }, function(err) {
     73                    assert_unreached("deriveBits failed with error " + err.name + ": " + err.message);
     74                });
     75            }, namedCurve + " non-multiple of 8 bits");
     76 
     77            // Errors to test:
     78 
     79            // - missing public property TypeError
     80            promise_test(function(test) {
     81                return subtle.deriveBits({name: "ECDH"}, privateKeys[namedCurve], 8 * sizes[namedCurve])
     82                .then(function(derivation) {
     83                    assert_unreached("deriveBits succeeded but should have failed with TypeError");
     84                }, function(err) {
     85                    assert_equals(err.name, "TypeError", "Should throw correct error, not " + err.name + ": " + err.message);
     86                });
     87            }, namedCurve + " missing public curve");
     88 
     89            // - Non CryptoKey public property TypeError
     90            promise_test(function(test) {
     91                return subtle.deriveBits({name: "ECDH", public: {message: "Not a CryptoKey"}}, privateKeys[namedCurve], 8 * sizes[namedCurve])
     92                .then(function(derivation) {
     93                    assert_unreached("deriveBits succeeded but should have failed with TypeError");
     94                }, function(err) {
     95                    assert_equals(err.name, "TypeError", "Should throw correct error, not " + err.name + ": " + err.message);
     96                });
     97            }, namedCurve + " public property of algorithm is not a CryptoKey");
     98 
     99            // - wrong named curve
    100            promise_test(function(test) {
    101                publicKey = publicKeys["P-256"];
    102                if (namedCurve === "P-256") {
    103                    publicKey = publicKeys["P-384"];
    104                }
    105                return subtle.deriveBits({name: "ECDH", public: publicKey}, privateKeys[namedCurve], 8 * sizes[namedCurve])
    106                .then(function(derivation) {
    107                    assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError");
    108                }, function(err) {
    109                    assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message);
    110                });
    111            }, namedCurve + " mismatched curves");
    112 
    113            // - not ECDH public property InvalidAccessError
    114            promise_test(function(test) {
    115                return subtle.deriveBits({name: "ECDH", public: ecdsaKeyPairs[namedCurve].publicKey}, privateKeys[namedCurve], 8 * sizes[namedCurve])
    116                .then(function(derivation) {
    117                    assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError");
    118                }, function(err) {
    119                    assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message);
    120                });
    121            }, namedCurve + " public property of algorithm is not an ECDSA public key");
    122 
    123            // - No deriveBits usage in baseKey InvalidAccessError
    124            promise_test(function(test) {
    125                return subtle.deriveBits({name: "ECDH", public: publicKeys[namedCurve]}, noDeriveBitsKeys[namedCurve], 8 * sizes[namedCurve])
    126                .then(function(derivation) {
    127                    assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError");
    128                }, function(err) {
    129                    assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message);
    130                });
    131            }, namedCurve + " no deriveBits usage for base key");
    132 
    133            // - Use public key for baseKey InvalidAccessError
    134            promise_test(function(test) {
    135                return subtle.deriveBits({name: "ECDH", public: publicKeys[namedCurve]}, publicKeys[namedCurve], 8 * sizes[namedCurve])
    136                .then(function(derivation) {
    137                    assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError");
    138                }, function(err) {
    139                    assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message);
    140                });
    141            }, namedCurve + " base key is not a private key");
    142 
    143            // - Use private key for public property InvalidAccessError
    144            promise_test(function(test) {
    145                return subtle.deriveBits({name: "ECDH", public: privateKeys[namedCurve]}, privateKeys[namedCurve], 8 * sizes[namedCurve])
    146                .then(function(derivation) {
    147                    assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError");
    148                }, function(err) {
    149                    assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message);
    150                });
    151            }, namedCurve + " public property value is a private key");
    152 
    153            // - Use secret key for public property InvalidAccessError
    154            promise_test(function(test) {
    155                return subtle.generateKey({name: "AES-CBC", length: 128}, true, ["encrypt", "decrypt"])
    156                .then(function(secretKey) {
    157                    return subtle.deriveBits({name: "ECDH", public: secretKey}, privateKeys[namedCurve], 8 * sizes[namedCurve])
    158                    .then(function(derivation) {
    159                        assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError");
    160                    }, function(err) {
    161                        assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message);
    162                    });
    163                });
    164            }, namedCurve + " public property value is a secret key");
    165 
    166            // - Length greater than 256, 384, 521 for particular curves OperationError
    167            promise_test(function(test) {
    168                return subtle.deriveBits({name: "ECDH", public: publicKeys[namedCurve]}, privateKeys[namedCurve], 8 * sizes[namedCurve] + 8)
    169                .then(function(derivation) {
    170                    assert_unreached("deriveBits succeeded but should have failed with OperationError");
    171                }, function(err) {
    172                    assert_equals(err.name, "OperationError", "Should throw correct error, not " + err.name + ": " + err.message);
    173                });
    174            }, namedCurve + " asking for too many bits");
    175        });
    176    });
    177 
    178    function importKeys(pkcs8, spki, sizes) {
    179        var privateKeys = {};
    180        var publicKeys = {};
    181        var ecdsaKeyPairs = {};
    182        var noDeriveBitsKeys = {};
    183 
    184        var promises = [];
    185        Object.keys(pkcs8).forEach(function(namedCurve) {
    186            var operation = subtle.importKey("pkcs8", pkcs8[namedCurve],
    187                                            {name: "ECDH", namedCurve: namedCurve},
    188                                            false, ["deriveBits", "deriveKey"])
    189                            .then(function(key) {
    190                                privateKeys[namedCurve] = key;
    191                            }, function (err) {
    192                                privateKeys[namedCurve] = null;
    193                            });
    194            promises.push(operation);
    195        });
    196        Object.keys(pkcs8).forEach(function(namedCurve) {
    197            var operation = subtle.importKey("pkcs8", pkcs8[namedCurve],
    198                                            {name: "ECDH", namedCurve: namedCurve},
    199                                            false, ["deriveKey"])
    200                            .then(function(key) {
    201                                noDeriveBitsKeys[namedCurve] = key;
    202                            }, function (err) {
    203                                noDeriveBitsKeys[namedCurve] = null;
    204                            });
    205            promises.push(operation);
    206        });
    207        Object.keys(spki).forEach(function(namedCurve) {
    208            var operation = subtle.importKey("spki", spki[namedCurve],
    209                                            {name: "ECDH", namedCurve: namedCurve},
    210                                            false, [])
    211                            .then(function(key) {
    212                                publicKeys[namedCurve] = key;
    213                            }, function (err) {
    214                                publicKeys[namedCurve] = null;
    215                            });
    216            promises.push(operation);
    217        });
    218        Object.keys(sizes).forEach(function(namedCurve) {
    219            var operation = subtle.generateKey({name: "ECDSA", namedCurve: namedCurve}, false, ["sign", "verify"])
    220                            .then(function(keyPair) {
    221                                ecdsaKeyPairs[namedCurve] = keyPair;
    222                            }, function (err) {
    223                                ecdsaKeyPairs[namedCurve] = null;
    224                            });
    225            promises.push(operation);
    226        });
    227 
    228        return Promise.all(promises)
    229               .then(function(results) {return {privateKeys: privateKeys, publicKeys: publicKeys, ecdsaKeyPairs: ecdsaKeyPairs, noDeriveBitsKeys: noDeriveBitsKeys}});
    230    }
    231 
    232    // Compares two ArrayBuffer or ArrayBufferView objects. If bitCount is
    233    // omitted, the two values must be the same length and have the same contents
    234    // in every byte. If bitCount is included, only that leading number of bits
    235    // have to match.
    236    function equalBuffers(a, b, bitCount) {
    237        var remainder;
    238 
    239        if (typeof bitCount === "undefined" && a.byteLength !== b.byteLength) {
    240            return false;
    241        }
    242 
    243        var aBytes = new Uint8Array(a);
    244        var bBytes = new Uint8Array(b);
    245 
    246        var length = a.byteLength;
    247        if (typeof bitCount !== "undefined") {
    248            length = Math.floor(bitCount / 8);
    249        }
    250 
    251        for (var i=0; i<length; i++) {
    252            if (aBytes[i] !== bBytes[i]) {
    253                return false;
    254            }
    255        }
    256 
    257        if (typeof bitCount !== "undefined") {
    258            remainder = bitCount % 8;
    259            return aBytes[length] >> (8 - remainder) === bBytes[length] >> (8 - remainder);
    260        }
    261 
    262        return true;
    263    }
    264 
    265 }