1
0
Fork 0
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:
Divy Srivastava 2021-12-05 09:25:11 +05:30 committed by GitHub
parent c59f90d01f
commit d31378726e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 229 additions and 6 deletions

View file

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

View file

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

View file

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

View file

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