mirror of
https://github.com/denoland/deno.git
synced 2025-01-21 21:50:00 -05:00
feat(ext/crypto): implement unwrapKey (#12539)
This commit is contained in:
parent
c59f90d01f
commit
d31378726e
4 changed files with 229 additions and 6 deletions
|
@ -691,6 +691,60 @@ Deno.test(async function testAesKeyGen() {
|
|||
assertEquals(algorithm.length, 256);
|
||||
});
|
||||
|
||||
Deno.test(async function testUnwrapKey() {
|
||||
const subtle = crypto.subtle;
|
||||
|
||||
const AES_KEY: AesKeyAlgorithm & AesCbcParams = {
|
||||
name: "AES-CBC",
|
||||
length: 128,
|
||||
iv: new Uint8Array(16),
|
||||
};
|
||||
|
||||
const RSA_KEY: RsaHashedKeyGenParams & RsaOaepParams = {
|
||||
name: "RSA-OAEP",
|
||||
modulusLength: 2048,
|
||||
publicExponent: new Uint8Array([1, 0, 1]),
|
||||
hash: "SHA-1",
|
||||
};
|
||||
|
||||
const aesKey = await subtle.generateKey(AES_KEY, true, [
|
||||
"encrypt",
|
||||
"decrypt",
|
||||
]);
|
||||
|
||||
const rsaKeyPair = await subtle.generateKey(
|
||||
{
|
||||
name: "RSA-OAEP",
|
||||
hash: "SHA-1",
|
||||
publicExponent: new Uint8Array([1, 0, 1]),
|
||||
modulusLength: 2048,
|
||||
},
|
||||
false,
|
||||
["wrapKey", "encrypt", "unwrapKey", "decrypt"],
|
||||
);
|
||||
|
||||
const enc = await subtle.wrapKey(
|
||||
"raw",
|
||||
aesKey,
|
||||
rsaKeyPair.publicKey,
|
||||
RSA_KEY,
|
||||
);
|
||||
const unwrappedKey = await subtle.unwrapKey(
|
||||
"raw",
|
||||
enc,
|
||||
rsaKeyPair.privateKey,
|
||||
RSA_KEY,
|
||||
AES_KEY,
|
||||
false,
|
||||
["encrypt", "decrypt"],
|
||||
);
|
||||
|
||||
assert(unwrappedKey instanceof CryptoKey);
|
||||
assertEquals(unwrappedKey.type, "secret");
|
||||
assertEquals(unwrappedKey.extractable, false);
|
||||
assertEquals(unwrappedKey.usages, ["encrypt", "decrypt"]);
|
||||
});
|
||||
|
||||
Deno.test(async function testDecryptWithInvalidIntializationVector() {
|
||||
const data = new Uint8Array([42, 42, 42, 42]);
|
||||
const key = await crypto.subtle.generateKey(
|
||||
|
|
|
@ -140,6 +140,10 @@
|
|||
// TODO(@littledivy): Enable this once implemented.
|
||||
// "AES-KW": "AesKeyWrapParams",
|
||||
},
|
||||
"unwrapKey": {
|
||||
// TODO(@littledivy): Enable this once implemented.
|
||||
// "AES-KW": "AesKeyWrapParams",
|
||||
},
|
||||
};
|
||||
|
||||
const aesJwkAlg = {
|
||||
|
@ -2070,6 +2074,161 @@
|
|||
);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param {string} format
|
||||
* @param {BufferSource} wrappedKey
|
||||
* @param {CryptoKey} unwrappingKey
|
||||
* @param {AlgorithmIdentifier} unwrapAlgorithm
|
||||
* @param {AlgorithmIdentifier} unwrappedKeyAlgorithm
|
||||
* @param {boolean} extractable
|
||||
* @param {KeyUsage[]} keyUsages
|
||||
* @returns {Promise<CryptoKey>}
|
||||
*/
|
||||
async unwrapKey(
|
||||
format,
|
||||
wrappedKey,
|
||||
unwrappingKey,
|
||||
unwrapAlgorithm,
|
||||
unwrappedKeyAlgorithm,
|
||||
extractable,
|
||||
keyUsages,
|
||||
) {
|
||||
webidl.assertBranded(this, SubtleCrypto);
|
||||
const prefix = "Failed to execute 'unwrapKey' on 'SubtleCrypto'";
|
||||
webidl.requiredArguments(arguments.length, 7, { prefix });
|
||||
format = webidl.converters.KeyFormat(format, {
|
||||
prefix,
|
||||
context: "Argument 1",
|
||||
});
|
||||
wrappedKey = webidl.converters.BufferSource(wrappedKey, {
|
||||
prefix,
|
||||
context: "Argument 2",
|
||||
});
|
||||
unwrappingKey = webidl.converters.CryptoKey(unwrappingKey, {
|
||||
prefix,
|
||||
context: "Argument 3",
|
||||
});
|
||||
unwrapAlgorithm = webidl.converters.AlgorithmIdentifier(unwrapAlgorithm, {
|
||||
prefix,
|
||||
context: "Argument 4",
|
||||
});
|
||||
unwrappedKeyAlgorithm = webidl.converters.AlgorithmIdentifier(
|
||||
unwrappedKeyAlgorithm,
|
||||
{
|
||||
prefix,
|
||||
context: "Argument 5",
|
||||
},
|
||||
);
|
||||
extractable = webidl.converters.boolean(extractable, {
|
||||
prefix,
|
||||
context: "Argument 6",
|
||||
});
|
||||
keyUsages = webidl.converters["sequence<KeyUsage>"](keyUsages, {
|
||||
prefix,
|
||||
context: "Argument 7",
|
||||
});
|
||||
|
||||
// 2.
|
||||
if (ArrayBufferIsView(wrappedKey)) {
|
||||
wrappedKey = new Uint8Array(
|
||||
wrappedKey.buffer,
|
||||
wrappedKey.byteOffset,
|
||||
wrappedKey.byteLength,
|
||||
);
|
||||
} else {
|
||||
wrappedKey = new Uint8Array(wrappedKey);
|
||||
}
|
||||
wrappedKey = TypedArrayPrototypeSlice(wrappedKey);
|
||||
|
||||
let normalizedAlgorithm;
|
||||
|
||||
try {
|
||||
// 3.
|
||||
normalizedAlgorithm = normalizeAlgorithm(unwrapAlgorithm, "unwrapKey");
|
||||
} catch (_) {
|
||||
// 4.
|
||||
normalizedAlgorithm = normalizeAlgorithm(unwrapAlgorithm, "decrypt");
|
||||
}
|
||||
|
||||
// 6.
|
||||
const normalizedKeyAlgorithm = normalizeAlgorithm(
|
||||
unwrappedKeyAlgorithm,
|
||||
"importKey",
|
||||
);
|
||||
|
||||
// 11.
|
||||
if (normalizedAlgorithm.name !== unwrappingKey[_algorithm].name) {
|
||||
throw new DOMException(
|
||||
"Unwrapping algorithm doesn't match key algorithm.",
|
||||
"InvalidAccessError",
|
||||
);
|
||||
}
|
||||
|
||||
// 12.
|
||||
if (!ArrayPrototypeIncludes(unwrappingKey[_usages], "unwrapKey")) {
|
||||
throw new DOMException(
|
||||
"Key does not support the 'unwrapKey' operation.",
|
||||
"InvalidAccessError",
|
||||
);
|
||||
}
|
||||
|
||||
// 13.
|
||||
let key;
|
||||
if (
|
||||
supportedAlgorithms["unwrapKey"][normalizedAlgorithm.name] !== undefined
|
||||
) {
|
||||
// TODO(@littledivy): Implement this for AES-KW.
|
||||
throw new DOMException(
|
||||
"Not implemented",
|
||||
"NotSupportedError",
|
||||
);
|
||||
} else if (
|
||||
supportedAlgorithms["decrypt"][normalizedAlgorithm.name] !== undefined
|
||||
) {
|
||||
key = await this.decrypt(
|
||||
normalizedAlgorithm,
|
||||
unwrappingKey,
|
||||
wrappedKey,
|
||||
);
|
||||
} else {
|
||||
throw new DOMException(
|
||||
"Algorithm not supported",
|
||||
"NotSupportedError",
|
||||
);
|
||||
}
|
||||
|
||||
// 14.
|
||||
const bytes = key;
|
||||
if (format == "jwk") {
|
||||
// TODO(@littledivy): Implement JWK.
|
||||
throw new DOMException(
|
||||
"Not implemented",
|
||||
"NotSupportedError",
|
||||
);
|
||||
}
|
||||
|
||||
// 15.
|
||||
const result = await this.importKey(
|
||||
format,
|
||||
bytes,
|
||||
normalizedKeyAlgorithm,
|
||||
extractable,
|
||||
keyUsages,
|
||||
);
|
||||
// 16.
|
||||
if (
|
||||
(result[_type] == "secret" || result[_type] == "private") &&
|
||||
keyUsages.length == 0
|
||||
) {
|
||||
throw new SyntaxError("Invalid key type.");
|
||||
}
|
||||
// 17.
|
||||
result[_extractable] = extractable;
|
||||
// 18.
|
||||
result[_usages] = usageIntersection(keyUsages, recognisedUsages);
|
||||
// 19.
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} algorithm
|
||||
|
|
16
ext/crypto/lib.deno_crypto.d.ts
vendored
16
ext/crypto/lib.deno_crypto.d.ts
vendored
|
@ -257,6 +257,22 @@ interface SubtleCrypto {
|
|||
wrappingKey: CryptoKey,
|
||||
wrapAlgorithm: AlgorithmIdentifier | RsaOaepParams,
|
||||
): Promise<ArrayBuffer>;
|
||||
unwrapKey(
|
||||
format: KeyFormat,
|
||||
wrappedKey: BufferSource,
|
||||
unwrappingKey: CryptoKey,
|
||||
unwrapAlgorithm:
|
||||
| AlgorithmIdentifier
|
||||
| RsaOaepParams
|
||||
| AesCbcParams,
|
||||
unwrappedKeyAlgorithm:
|
||||
| AlgorithmIdentifier
|
||||
| RsaHashedImportParams
|
||||
| HmacImportParams
|
||||
| AesKeyAlgorithm,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[],
|
||||
): Promise<CryptoKey>;
|
||||
}
|
||||
|
||||
declare interface Crypto {
|
||||
|
|
|
@ -4151,15 +4151,9 @@
|
|||
"historical.any.html": false,
|
||||
"historical.any.worker.html": false,
|
||||
"idlharness.https.any.html": [
|
||||
"SubtleCrypto interface: operation unwrapKey(KeyFormat, BufferSource, CryptoKey, AlgorithmIdentifier, AlgorithmIdentifier, boolean, sequence<KeyUsage>)",
|
||||
"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"
|
||||
],
|
||||
"idlharness.https.any.worker.html": [
|
||||
"SubtleCrypto interface: operation unwrapKey(KeyFormat, BufferSource, CryptoKey, AlgorithmIdentifier, AlgorithmIdentifier, boolean, sequence<KeyUsage>)",
|
||||
"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",
|
||||
"WorkerGlobalScope interface: attribute crypto"
|
||||
],
|
||||
"import_export": {
|
||||
|
|
Loading…
Add table
Reference in a new issue