summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authorLuca Casonato <hello@lcas.dev>2021-12-09 16:20:14 +0100
committerGitHub <noreply@github.com>2021-12-09 16:20:14 +0100
commitabd25e59827416eebea0fc3730c9c00e8ced8d3a (patch)
tree913b6d7c5e910d8e5686c885adf2340bc3027a67 /ext
parent2347e60934a8701bb5f0ecba6a460447eab868c6 (diff)
refactor(ext/crypto): clean up `importKey` logic (#13028)
This commit de-duplicates and cleans up some logic in `importKey`. There are no functional changes in this commit (just moves code around).
Diffstat (limited to 'ext')
-rw-r--r--ext/crypto/00_crypto.js1035
1 files changed, 467 insertions, 568 deletions
diff --git a/ext/crypto/00_crypto.js b/ext/crypto/00_crypto.js
index 2efe550e0..bef5155e8 100644
--- a/ext/crypto/00_crypto.js
+++ b/ext/crypto/00_crypto.js
@@ -845,608 +845,70 @@
switch (normalizedAlgorithm.name) {
case "HMAC": {
- // 2.
- if (
- ArrayPrototypeFind(
- keyUsages,
- (u) => !ArrayPrototypeIncludes(["sign", "verify"], u),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
-
- // 3.
- let hash;
- let data;
-
- // 4. https://w3c.github.io/webcrypto/#hmac-operations
- switch (format) {
- case "raw": {
- data = keyData;
- hash = normalizedAlgorithm.hash;
- break;
- }
- case "jwk": {
- // TODO(@littledivy): Why does the spec validate JWK twice?
- const jwk = keyData;
- // 2.
- if (jwk.kty !== "oct") {
- throw new DOMException(
- "`kty` member of JsonWebKey must be `oct`",
- "DataError",
- );
- }
-
- // Section 6.4.1 of RFC7518
- if (!jwk.k) {
- throw new DOMException(
- "`k` member of JsonWebKey must be present",
- "DataError",
- );
- }
-
- // 4.
- data = decodeSymmetricKey(jwk.k);
- // 5.
- hash = normalizedAlgorithm.hash;
- // 6.
- switch (hash.name) {
- case "SHA-1": {
- if (jwk.alg !== undefined && jwk.alg !== "HS1") {
- throw new DOMException(
- "`alg` member of JsonWebKey must be `HS1`",
- "DataError",
- );
- }
- break;
- }
- case "SHA-256": {
- if (jwk.alg !== undefined && jwk.alg !== "HS256") {
- throw new DOMException(
- "`alg` member of JsonWebKey must be `HS256`",
- "DataError",
- );
- }
- break;
- }
- case "SHA-384": {
- if (jwk.alg !== undefined && jwk.alg !== "HS384") {
- throw new DOMException(
- "`alg` member of JsonWebKey must be `HS384`",
- "DataError",
- );
- }
- break;
- }
- case "SHA-512": {
- if (jwk.alg !== undefined && jwk.alg !== "HS512") {
- throw new DOMException(
- "`alg` member of JsonWebKey must be `HS512`",
- "DataError",
- );
- }
- break;
- }
- default:
- throw new TypeError("unreachable");
- }
-
- // 7.
- if (keyUsages.length > 0 && jwk.use && jwk.use !== "sign") {
- throw new DOMException(
- "`use` member of JsonWebKey must be `sign`",
- "DataError",
- );
- }
-
- // 8.
- // Section 4.3 of RFC7517
- if (jwk.key_ops) {
- if (
- ArrayPrototypeFind(
- jwk.key_ops,
- (u) => !ArrayPrototypeIncludes(recognisedUsages, u),
- ) !== undefined
- ) {
- throw new DOMException(
- "`key_ops` member of JsonWebKey is invalid",
- "DataError",
- );
- }
-
- if (
- !ArrayPrototypeEvery(
- jwk.key_ops,
- (u) => ArrayPrototypeIncludes(keyUsages, u),
- )
- ) {
- throw new DOMException(
- "`key_ops` member of JsonWebKey is invalid",
- "DataError",
- );
- }
- }
-
- // 9.
- if (jwk.ext === false && extractable == true) {
- throw new DOMException(
- "`ext` member of JsonWebKey is invalid",
- "DataError",
- );
- }
-
- break;
- }
- default:
- throw new DOMException("Not implemented", "NotSupportedError");
- }
-
- // 5.
- let length = data.byteLength * 8;
- // 6.
- if (length === 0) {
- throw new DOMException("Key length is zero", "DataError");
- }
- // 7.
- if (normalizedAlgorithm.length !== undefined) {
- if (
- normalizedAlgorithm.length > length ||
- normalizedAlgorithm.length <= (length - 8)
- ) {
- throw new DOMException(
- "Key length is invalid",
- "DataError",
- );
- }
- length = normalizedAlgorithm.length;
- }
-
- if (keyUsages.length == 0) {
- throw new DOMException("Key usage is empty", "SyntaxError");
- }
-
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, {
- type: "raw",
- data,
- });
-
- const algorithm = {
- name: "HMAC",
- length,
- hash,
- };
-
- const key = constructKey(
- "secret",
+ return importKeyHMAC(
+ format,
+ normalizedAlgorithm,
+ keyData,
extractable,
- usageIntersection(keyUsages, recognisedUsages),
- algorithm,
- handle,
+ keyUsages,
);
-
- return key;
}
- // TODO(@littledivy): RSA-PSS
case "ECDSA": {
- switch (format) {
- case "raw": {
- // 1.
- if (
- !ArrayPrototypeIncludes(
- supportedNamedCurves,
- normalizedAlgorithm.namedCurve,
- )
- ) {
- throw new DOMException(
- "Invalid namedCurve",
- "DataError",
- );
- }
-
- // 2.
- if (
- ArrayPrototypeFind(
- keyUsages,
- (u) => !ArrayPrototypeIncludes(["verify"], u),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
-
- // 3.
- const { data } = await core.opAsync("op_crypto_import_key", {
- algorithm: "ECDSA",
- namedCurve: normalizedAlgorithm.namedCurve,
- }, keyData);
-
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, {
- type: "raw",
- data,
- });
-
- // 4-5.
- const algorithm = {
- name: "ECDSA",
- namedCurve: normalizedAlgorithm.namedCurve,
- };
-
- // 6-8.
- const key = constructKey(
- "public",
- extractable,
- usageIntersection(keyUsages, recognisedUsages),
- algorithm,
- handle,
- );
-
- return key;
- }
- default:
- throw new DOMException("Not implemented", "NotSupportedError");
- }
- }
- case "RSASSA-PKCS1-v1_5": {
- switch (format) {
- case "pkcs8": {
- // 1.
- if (
- ArrayPrototypeFind(
- keyUsages,
- (u) => !ArrayPrototypeIncludes(["sign"], u),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
-
- if (keyUsages.length == 0) {
- throw new DOMException("Key usage is empty", "SyntaxError");
- }
-
- // 2-9.
- const { modulusLength, publicExponent, data } = await core
- .opAsync(
- "op_crypto_import_key",
- {
- algorithm: "RSASSA-PKCS1-v1_5",
- format: "pkcs8",
- // Needed to perform step 7 without normalization.
- hash: normalizedAlgorithm.hash.name,
- },
- keyData,
- );
-
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, {
- // PKCS#1 for RSA
- type: "raw",
- data,
- });
-
- const algorithm = {
- name: "RSASSA-PKCS1-v1_5",
- modulusLength,
- publicExponent,
- hash: normalizedAlgorithm.hash,
- };
-
- const key = constructKey(
- "private",
- extractable,
- usageIntersection(keyUsages, recognisedUsages),
- algorithm,
- handle,
- );
-
- return key;
- }
- default:
- throw new DOMException("Not implemented", "NotSupportedError");
- }
- }
- case "RSA-PSS": {
- switch (format) {
- case "pkcs8": {
- // 1.
- if (
- ArrayPrototypeFind(
- keyUsages,
- (u) => !ArrayPrototypeIncludes(["sign"], u),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
-
- if (keyUsages.length == 0) {
- throw new DOMException("Key usage is empty", "SyntaxError");
- }
-
- // 2-9.
- const { modulusLength, publicExponent, data } = await core
- .opAsync(
- "op_crypto_import_key",
- {
- algorithm: "RSA-PSS",
- format: "pkcs8",
- // Needed to perform step 7 without normalization.
- hash: normalizedAlgorithm.hash.name,
- },
- keyData,
- );
-
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, {
- // PKCS#1 for RSA
- type: "raw",
- data,
- });
-
- const algorithm = {
- name: "RSA-PSS",
- modulusLength,
- publicExponent,
- hash: normalizedAlgorithm.hash,
- };
-
- const key = constructKey(
- "private",
- extractable,
- usageIntersection(keyUsages, recognisedUsages),
- algorithm,
- handle,
- );
-
- return key;
- }
- default:
- throw new DOMException("Not implemented", "NotSupportedError");
- }
- }
- case "RSA-OAEP": {
- switch (format) {
- case "pkcs8": {
- // 1.
- if (
- ArrayPrototypeFind(
- keyUsages,
- (u) => !ArrayPrototypeIncludes(["decrypt", "unwrapKey"], u),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
-
- if (keyUsages.length == 0) {
- throw new DOMException("Key usage is empty", "SyntaxError");
- }
-
- // 2-9.
- const { modulusLength, publicExponent, data } = await core
- .opAsync(
- "op_crypto_import_key",
- {
- algorithm: "RSA-OAEP",
- format: "pkcs8",
- // Needed to perform step 7 without normalization.
- hash: normalizedAlgorithm.hash.name,
- },
- keyData,
- );
-
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, {
- // PKCS#1 for RSA
- type: "raw",
- data,
- });
-
- const algorithm = {
- name: "RSA-OAEP",
- modulusLength,
- publicExponent,
- hash: normalizedAlgorithm.hash,
- };
-
- const key = constructKey(
- "private",
- extractable,
- usageIntersection(keyUsages, recognisedUsages),
- algorithm,
- handle,
- );
-
- return key;
- }
- default:
- throw new DOMException("Not implemented", "NotSupportedError");
- }
- }
- case "HKDF": {
- if (format !== "raw") {
- throw new DOMException("Format not supported", "NotSupportedError");
- }
-
- // 1.
- if (
- ArrayPrototypeFind(
- keyUsages,
- (u) => !ArrayPrototypeIncludes(["deriveKey", "deriveBits"], u),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
-
- // 2.
- if (extractable !== false) {
- throw new DOMException(
- "Key must not be extractable",
- "SyntaxError",
- );
- }
-
- // 3.
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, {
- type: "raw",
- data: keyData,
- });
-
- // 4-8.
- const algorithm = {
- name: "HKDF",
- };
- const key = constructKey(
- "secret",
- false,
- usageIntersection(keyUsages, recognisedUsages),
- algorithm,
- handle,
- );
-
- // 9.
- return key;
- }
- case "PBKDF2": {
- // 1.
- if (format !== "raw") {
- throw new DOMException("Format not supported", "NotSupportedError");
- }
-
- // 2.
- if (
- ArrayPrototypeFind(
- keyUsages,
- (u) => !ArrayPrototypeIncludes(["deriveKey", "deriveBits"], u),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
-
- // 3.
- if (extractable !== false) {
- throw new DOMException(
- "Key must not be extractable",
- "SyntaxError",
- );
- }
-
- // 4.
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, {
- type: "raw",
- data: keyData,
- });
-
- // 5-9.
- const algorithm = {
- name: "PBKDF2",
- };
- const key = constructKey(
- "secret",
- false,
- usageIntersection(keyUsages, recognisedUsages),
- algorithm,
- handle,
+ return await importKeyECDSA(
+ format,
+ normalizedAlgorithm,
+ keyData,
+ extractable,
+ keyUsages,
);
-
- // 10.
- return key;
}
- case "AES-CTR": {
- // 1.
- if (
- ArrayPrototypeFind(
- keyUsages,
- (u) =>
- !ArrayPrototypeIncludes([
- "encrypt",
- "decrypt",
- "wrapKey",
- "unwrapKey",
- ], u),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
-
- return importKeyAES(
+ case "RSASSA-PKCS1-v1_5":
+ case "RSA-PSS": {
+ return await importKeyRSA(
format,
normalizedAlgorithm,
keyData,
extractable,
keyUsages,
+ ["sign"],
);
}
- case "AES-CBC": {
- // 1.
- if (
- ArrayPrototypeFind(
- keyUsages,
- (u) =>
- !ArrayPrototypeIncludes([
- "encrypt",
- "decrypt",
- "wrapKey",
- "unwrapKey",
- ], u),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
- return importKeyAES(
+ case "RSA-OAEP": {
+ return await importKeyRSA(
format,
normalizedAlgorithm,
keyData,
extractable,
keyUsages,
+ ["decrypt", "unwrapKey"],
);
}
+ case "HKDF": {
+ return importKeyHKDF(format, keyData, extractable, keyUsages);
+ }
+ case "PBKDF2": {
+ return importKeyPBKDF2(format, keyData, extractable, keyUsages);
+ }
+ case "AES-CTR":
+ case "AES-CBC":
case "AES-GCM": {
- // 1.
- if (
- ArrayPrototypeFind(
- keyUsages,
- (u) =>
- !ArrayPrototypeIncludes([
- "encrypt",
- "decrypt",
- "wrapKey",
- "unwrapKey",
- ], u),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
-
- return importKeyAES(
+ return await importKeyAES(
format,
normalizedAlgorithm,
keyData,
extractable,
keyUsages,
+ ["encrypt", "decrypt", "wrapKey", "unwrapKey"],
);
}
case "AES-KW": {
- // 1.
- if (
- ArrayPrototypeFind(
- keyUsages,
- (u) =>
- !ArrayPrototypeIncludes([
- "wrapKey",
- "unwrapKey",
- ], u),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
-
- return importKeyAES(
+ return await importKeyAES(
format,
normalizedAlgorithm,
keyData,
extractable,
keyUsages,
+ ["wrapKey", "unwrapKey"],
);
}
default:
@@ -2659,7 +2121,18 @@
keyData,
extractable,
keyUsages,
+ supportedKeyUsages,
) {
+ // 1.
+ if (
+ ArrayPrototypeFind(
+ keyUsages,
+ (u) => !ArrayPrototypeIncludes(supportedKeyUsages, u),
+ ) !== undefined
+ ) {
+ throw new DOMException("Invalid key usages", "SyntaxError");
+ }
+
// 2.
let data = keyData;
switch (format) {
@@ -2798,6 +2271,432 @@
// 8.
return key;
}
+
+ function importKeyHMAC(
+ format,
+ normalizedAlgorithm,
+ keyData,
+ extractable,
+ keyUsages,
+ ) {
+ // 2.
+ if (
+ ArrayPrototypeFind(
+ keyUsages,
+ (u) => !ArrayPrototypeIncludes(["sign", "verify"], u),
+ ) !== undefined
+ ) {
+ throw new DOMException("Invalid key usages", "SyntaxError");
+ }
+
+ // 3.
+ let hash;
+ let data;
+
+ // 4. https://w3c.github.io/webcrypto/#hmac-operations
+ switch (format) {
+ case "raw": {
+ data = keyData;
+ hash = normalizedAlgorithm.hash;
+ break;
+ }
+ case "jwk": {
+ // TODO(@littledivy): Why does the spec validate JWK twice?
+ const jwk = keyData;
+ // 2.
+ if (jwk.kty !== "oct") {
+ throw new DOMException(
+ "`kty` member of JsonWebKey must be `oct`",
+ "DataError",
+ );
+ }
+
+ // Section 6.4.1 of RFC7518
+ if (!jwk.k) {
+ throw new DOMException(
+ "`k` member of JsonWebKey must be present",
+ "DataError",
+ );
+ }
+
+ // 4.
+ data = decodeSymmetricKey(jwk.k);
+ // 5.
+ hash = normalizedAlgorithm.hash;
+ // 6.
+ switch (hash.name) {
+ case "SHA-1": {
+ if (jwk.alg !== undefined && jwk.alg !== "HS1") {
+ throw new DOMException(
+ "`alg` member of JsonWebKey must be `HS1`",
+ "DataError",
+ );
+ }
+ break;
+ }
+ case "SHA-256": {
+ if (jwk.alg !== undefined && jwk.alg !== "HS256") {
+ throw new DOMException(
+ "`alg` member of JsonWebKey must be `HS256`",
+ "DataError",
+ );
+ }
+ break;
+ }
+ case "SHA-384": {
+ if (jwk.alg !== undefined && jwk.alg !== "HS384") {
+ throw new DOMException(
+ "`alg` member of JsonWebKey must be `HS384`",
+ "DataError",
+ );
+ }
+ break;
+ }
+ case "SHA-512": {
+ if (jwk.alg !== undefined && jwk.alg !== "HS512") {
+ throw new DOMException(
+ "`alg` member of JsonWebKey must be `HS512`",
+ "DataError",
+ );
+ }
+ break;
+ }
+ default:
+ throw new TypeError("unreachable");
+ }
+
+ // 7.
+ if (keyUsages.length > 0 && jwk.use && jwk.use !== "sign") {
+ throw new DOMException(
+ "`use` member of JsonWebKey must be `sign`",
+ "DataError",
+ );
+ }
+
+ // 8.
+ // Section 4.3 of RFC7517
+ if (jwk.key_ops) {
+ if (
+ ArrayPrototypeFind(
+ jwk.key_ops,
+ (u) => !ArrayPrototypeIncludes(recognisedUsages, u),
+ ) !== undefined
+ ) {
+ throw new DOMException(
+ "`key_ops` member of JsonWebKey is invalid",
+ "DataError",
+ );
+ }
+
+ if (
+ !ArrayPrototypeEvery(
+ jwk.key_ops,
+ (u) => ArrayPrototypeIncludes(keyUsages, u),
+ )
+ ) {
+ throw new DOMException(
+ "`key_ops` member of JsonWebKey is invalid",
+ "DataError",
+ );
+ }
+ }
+
+ // 9.
+ if (jwk.ext === false && extractable == true) {
+ throw new DOMException(
+ "`ext` member of JsonWebKey is invalid",
+ "DataError",
+ );
+ }
+
+ break;
+ }
+ default:
+ throw new DOMException("Not implemented", "NotSupportedError");
+ }
+
+ // 5.
+ let length = data.byteLength * 8;
+ // 6.
+ if (length === 0) {
+ throw new DOMException("Key length is zero", "DataError");
+ }
+ // 7.
+ if (normalizedAlgorithm.length !== undefined) {
+ if (
+ normalizedAlgorithm.length > length ||
+ normalizedAlgorithm.length <= (length - 8)
+ ) {
+ throw new DOMException(
+ "Key length is invalid",
+ "DataError",
+ );
+ }
+ length = normalizedAlgorithm.length;
+ }
+
+ if (keyUsages.length == 0) {
+ throw new DOMException("Key usage is empty", "SyntaxError");
+ }
+
+ const handle = {};
+ WeakMapPrototypeSet(KEY_STORE, handle, {
+ type: "raw",
+ data,
+ });
+
+ const algorithm = {
+ name: "HMAC",
+ length,
+ hash,
+ };
+
+ const key = constructKey(
+ "secret",
+ extractable,
+ usageIntersection(keyUsages, recognisedUsages),
+ algorithm,
+ handle,
+ );
+
+ return key;
+ }
+
+ async function importKeyECDSA(
+ format,
+ normalizedAlgorithm,
+ keyData,
+ extractable,
+ keyUsages,
+ ) {
+ switch (format) {
+ case "raw": {
+ // 1.
+ if (
+ !ArrayPrototypeIncludes(
+ supportedNamedCurves,
+ normalizedAlgorithm.namedCurve,
+ )
+ ) {
+ throw new DOMException(
+ "Invalid namedCurve",
+ "DataError",
+ );
+ }
+
+ // 2.
+ if (
+ ArrayPrototypeFind(
+ keyUsages,
+ (u) => !ArrayPrototypeIncludes(["verify"], u),
+ ) !== undefined
+ ) {
+ throw new DOMException("Invalid key usages", "SyntaxError");
+ }
+
+ // 3.
+ const { data } = await core.opAsync("op_crypto_import_key", {
+ algorithm: "ECDSA",
+ namedCurve: normalizedAlgorithm.namedCurve,
+ }, keyData);
+
+ const handle = {};
+ WeakMapPrototypeSet(KEY_STORE, handle, {
+ type: "raw",
+ data,
+ });
+
+ // 4-5.
+ const algorithm = {
+ name: "ECDSA",
+ namedCurve: normalizedAlgorithm.namedCurve,
+ };
+
+ // 6-8.
+ const key = constructKey(
+ "public",
+ extractable,
+ usageIntersection(keyUsages, recognisedUsages),
+ algorithm,
+ handle,
+ );
+
+ return key;
+ }
+ default:
+ throw new DOMException("Not implemented", "NotSupportedError");
+ }
+ }
+
+ async function importKeyRSA(
+ format,
+ normalizedAlgorithm,
+ keyData,
+ extractable,
+ keyUsages,
+ supportedKeyUsages,
+ ) {
+ switch (format) {
+ case "pkcs8": {
+ // 1.
+ if (
+ ArrayPrototypeFind(
+ keyUsages,
+ (u) => !ArrayPrototypeIncludes(supportedKeyUsages, u),
+ ) !== undefined
+ ) {
+ throw new DOMException("Invalid key usages", "SyntaxError");
+ }
+
+ if (keyUsages.length == 0) {
+ throw new DOMException("Key usage is empty", "SyntaxError");
+ }
+
+ // 2-9.
+ const { modulusLength, publicExponent, data } = await core
+ .opAsync(
+ "op_crypto_import_key",
+ {
+ algorithm: normalizedAlgorithm.name,
+ format: "pkcs8",
+ // Needed to perform step 7 without normalization.
+ hash: normalizedAlgorithm.hash.name,
+ },
+ keyData,
+ );
+
+ const handle = {};
+ WeakMapPrototypeSet(KEY_STORE, handle, {
+ // PKCS#1 for RSA
+ type: "raw",
+ data,
+ });
+
+ const algorithm = {
+ name: normalizedAlgorithm.name,
+ modulusLength,
+ publicExponent,
+ hash: normalizedAlgorithm.hash,
+ };
+
+ const key = constructKey(
+ "private",
+ extractable,
+ usageIntersection(keyUsages, recognisedUsages),
+ algorithm,
+ handle,
+ );
+
+ return key;
+ }
+ default:
+ throw new DOMException("Not implemented", "NotSupportedError");
+ }
+ }
+
+ function importKeyHKDF(
+ format,
+ keyData,
+ extractable,
+ keyUsages,
+ ) {
+ if (format !== "raw") {
+ throw new DOMException("Format not supported", "NotSupportedError");
+ }
+
+ // 1.
+ if (
+ ArrayPrototypeFind(
+ keyUsages,
+ (u) => !ArrayPrototypeIncludes(["deriveKey", "deriveBits"], u),
+ ) !== undefined
+ ) {
+ throw new DOMException("Invalid key usages", "SyntaxError");
+ }
+
+ // 2.
+ if (extractable !== false) {
+ throw new DOMException(
+ "Key must not be extractable",
+ "SyntaxError",
+ );
+ }
+
+ // 3.
+ const handle = {};
+ WeakMapPrototypeSet(KEY_STORE, handle, {
+ type: "raw",
+ data: keyData,
+ });
+
+ // 4-8.
+ const algorithm = {
+ name: "HKDF",
+ };
+ const key = constructKey(
+ "secret",
+ false,
+ usageIntersection(keyUsages, recognisedUsages),
+ algorithm,
+ handle,
+ );
+
+ // 9.
+ return key;
+ }
+
+ function importKeyPBKDF2(
+ format,
+ keyData,
+ extractable,
+ keyUsages,
+ ) {
+ // 1.
+ if (format !== "raw") {
+ throw new DOMException("Format not supported", "NotSupportedError");
+ }
+
+ // 2.
+ if (
+ ArrayPrototypeFind(
+ keyUsages,
+ (u) => !ArrayPrototypeIncludes(["deriveKey", "deriveBits"], u),
+ ) !== undefined
+ ) {
+ throw new DOMException("Invalid key usages", "SyntaxError");
+ }
+
+ // 3.
+ if (extractable !== false) {
+ throw new DOMException(
+ "Key must not be extractable",
+ "SyntaxError",
+ );
+ }
+
+ // 4.
+ const handle = {};
+ WeakMapPrototypeSet(KEY_STORE, handle, {
+ type: "raw",
+ data: keyData,
+ });
+
+ // 5-9.
+ const algorithm = {
+ name: "PBKDF2",
+ };
+ const key = constructKey(
+ "secret",
+ false,
+ usageIntersection(keyUsages, recognisedUsages),
+ algorithm,
+ handle,
+ );
+
+ // 10.
+ return key;
+ }
+
async function generateKeyAES(normalizedAlgorithm, extractable, usages) {
// 2.
if (!ArrayPrototypeIncludes([128, 192, 256], normalizedAlgorithm.length)) {