1
0
Fork 0
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:
Divy Srivastava 2021-10-01 15:09:49 +05:30 committed by GitHub
parent b354eaa247
commit 5065c7bcd9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 145 additions and 3 deletions

View file

@ -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);
});

View file

@ -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

View file

@ -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 {

View file

@ -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"