mirror of
https://github.com/denoland/deno.git
synced 2024-12-23 15:49:44 -05:00
feat(ext/crypto): implement wrapKey (#12125)
This commit is contained in:
parent
b354eaa247
commit
5065c7bcd9
4 changed files with 145 additions and 3 deletions
|
@ -499,3 +499,40 @@ unitTest(async function testHkdfDeriveBits() {
|
|||
);
|
||||
assertEquals(result.byteLength, 128 / 8);
|
||||
});
|
||||
|
||||
unitTest(async function testWrapKey() {
|
||||
// Test wrapKey
|
||||
const key = await crypto.subtle.generateKey(
|
||||
{
|
||||
name: "RSA-OAEP",
|
||||
modulusLength: 4096,
|
||||
publicExponent: new Uint8Array([1, 0, 1]),
|
||||
hash: "SHA-256",
|
||||
},
|
||||
true,
|
||||
["wrapKey", "unwrapKey"],
|
||||
);
|
||||
|
||||
const hmacKey = await crypto.subtle.generateKey(
|
||||
{
|
||||
name: "HMAC",
|
||||
hash: "SHA-256",
|
||||
length: 128,
|
||||
},
|
||||
true,
|
||||
["sign"],
|
||||
);
|
||||
|
||||
const wrappedKey = await crypto.subtle.wrapKey(
|
||||
"raw",
|
||||
hmacKey,
|
||||
key.publicKey,
|
||||
{
|
||||
name: "RSA-OAEP",
|
||||
label: new Uint8Array(8),
|
||||
},
|
||||
);
|
||||
|
||||
assert(wrappedKey instanceof ArrayBuffer);
|
||||
assertEquals(wrappedKey.byteLength, 512);
|
||||
});
|
||||
|
|
|
@ -120,6 +120,10 @@
|
|||
"decrypt": {
|
||||
"RSA-OAEP": "RsaOaepParams",
|
||||
},
|
||||
"wrapKey": {
|
||||
// TODO(@littledivy): Enable this once implemented.
|
||||
// "AES-KW": "AesKeyWrapParams",
|
||||
},
|
||||
};
|
||||
|
||||
// Decodes the unpadded base64 to the octet sequence containing key value `k` defined in RFC7518 Section 6.4
|
||||
|
@ -1519,6 +1523,104 @@
|
|||
throw new TypeError("unreachable");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} algorithm
|
||||
* @param {boolean} extractable
|
||||
* @param {KeyUsage[]} keyUsages
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
async wrapKey(format, key, wrappingKey, wrapAlgorithm) {
|
||||
webidl.assertBranded(this, SubtleCrypto);
|
||||
const prefix = "Failed to execute 'wrapKey' on 'SubtleCrypto'";
|
||||
webidl.requiredArguments(arguments.length, 4, { prefix });
|
||||
format = webidl.converters.KeyFormat(format, {
|
||||
prefix,
|
||||
context: "Argument 1",
|
||||
});
|
||||
key = webidl.converters.CryptoKey(key, {
|
||||
prefix,
|
||||
context: "Argument 2",
|
||||
});
|
||||
wrappingKey = webidl.converters.CryptoKey(wrappingKey, {
|
||||
prefix,
|
||||
context: "Argument 3",
|
||||
});
|
||||
wrapAlgorithm = webidl.converters.AlgorithmIdentifier(wrapAlgorithm, {
|
||||
prefix,
|
||||
context: "Argument 4",
|
||||
});
|
||||
|
||||
let normalizedAlgorithm;
|
||||
|
||||
try {
|
||||
// 2.
|
||||
normalizedAlgorithm = normalizeAlgorithm(wrapAlgorithm, "wrapKey");
|
||||
} catch (_) {
|
||||
// 3.
|
||||
normalizedAlgorithm = normalizeAlgorithm(wrapAlgorithm, "encrypt");
|
||||
}
|
||||
|
||||
// 8.
|
||||
if (normalizedAlgorithm.name !== wrappingKey[_algorithm].name) {
|
||||
throw new DOMException(
|
||||
"Wrapping algorithm doesn't match key algorithm.",
|
||||
"InvalidAccessError",
|
||||
);
|
||||
}
|
||||
|
||||
// 9.
|
||||
if (!ArrayPrototypeIncludes(wrappingKey[_usages], "wrapKey")) {
|
||||
throw new DOMException(
|
||||
"Key does not support the 'wrapKey' operation.",
|
||||
"InvalidAccessError",
|
||||
);
|
||||
}
|
||||
|
||||
// 10. NotSupportedError will be thrown in step 12.
|
||||
// 11.
|
||||
if (key[_extractable] === false) {
|
||||
throw new DOMException(
|
||||
"Key is not extractable",
|
||||
"InvalidAccessError",
|
||||
);
|
||||
}
|
||||
|
||||
// 12.
|
||||
const exportedKey = await this.exportKey(format, key);
|
||||
|
||||
let bytes;
|
||||
// 13.
|
||||
if (format !== "jwk") {
|
||||
bytes = exportedKey;
|
||||
} else {
|
||||
// TODO(@littledivy): Implement JWK.
|
||||
throw new DOMException(
|
||||
"Not implemented",
|
||||
"NotSupportedError",
|
||||
);
|
||||
}
|
||||
|
||||
// 14-15.
|
||||
if (
|
||||
supportedAlgorithms["wrapKey"][normalizedAlgorithm.name] !== undefined
|
||||
) {
|
||||
// TODO(@littledivy): Implement this for AES-KW.
|
||||
throw new DOMException(
|
||||
"Not implemented",
|
||||
"NotSupportedError",
|
||||
);
|
||||
} else if (
|
||||
supportedAlgorithms["encrypt"][normalizedAlgorithm.name] !== undefined
|
||||
) {
|
||||
return this.encrypt(normalizedAlgorithm, wrappingKey, bytes);
|
||||
} else {
|
||||
throw new DOMException(
|
||||
"Algorithm not supported",
|
||||
"NotSupportedError",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} algorithm
|
||||
* @param {boolean} extractable
|
||||
|
|
6
ext/crypto/lib.deno_crypto.d.ts
vendored
6
ext/crypto/lib.deno_crypto.d.ts
vendored
|
@ -215,6 +215,12 @@ interface SubtleCrypto {
|
|||
baseKey: CryptoKey,
|
||||
length: number,
|
||||
): Promise<ArrayBuffer>;
|
||||
wrapKey(
|
||||
format: KeyFormat,
|
||||
key: CryptoKey,
|
||||
wrappingKey: CryptoKey,
|
||||
wrapAlgorithm: AlgorithmIdentifier | RsaOaepParams,
|
||||
): Promise<ArrayBuffer>;
|
||||
}
|
||||
|
||||
declare interface Crypto {
|
||||
|
|
|
@ -12149,12 +12149,9 @@
|
|||
"historical.any.html": false,
|
||||
"idlharness.https.any.html": [
|
||||
"SubtleCrypto interface: operation deriveKey(AlgorithmIdentifier, CryptoKey, AlgorithmIdentifier, boolean, sequence<KeyUsage>)",
|
||||
"SubtleCrypto interface: operation wrapKey(KeyFormat, CryptoKey, CryptoKey, AlgorithmIdentifier)",
|
||||
"SubtleCrypto interface: operation unwrapKey(KeyFormat, BufferSource, CryptoKey, AlgorithmIdentifier, AlgorithmIdentifier, boolean, sequence<KeyUsage>)",
|
||||
"SubtleCrypto interface: crypto.subtle must inherit property \"deriveKey(AlgorithmIdentifier, CryptoKey, AlgorithmIdentifier, boolean, sequence<KeyUsage>)\" with the proper type",
|
||||
"SubtleCrypto interface: calling deriveKey(AlgorithmIdentifier, CryptoKey, AlgorithmIdentifier, boolean, sequence<KeyUsage>) on crypto.subtle with too few arguments must throw TypeError",
|
||||
"SubtleCrypto interface: crypto.subtle must inherit property \"wrapKey(KeyFormat, CryptoKey, CryptoKey, AlgorithmIdentifier)\" with the proper type",
|
||||
"SubtleCrypto interface: calling wrapKey(KeyFormat, CryptoKey, CryptoKey, AlgorithmIdentifier) on crypto.subtle with too few arguments must throw TypeError",
|
||||
"SubtleCrypto interface: crypto.subtle must inherit property \"unwrapKey(KeyFormat, BufferSource, CryptoKey, AlgorithmIdentifier, AlgorithmIdentifier, boolean, sequence<KeyUsage>)\" with the proper type",
|
||||
"SubtleCrypto interface: calling unwrapKey(KeyFormat, BufferSource, CryptoKey, AlgorithmIdentifier, AlgorithmIdentifier, boolean, sequence<KeyUsage>) on crypto.subtle with too few arguments must throw TypeError",
|
||||
"Window interface: attribute crypto"
|
||||
|
|
Loading…
Reference in a new issue