summaryrefslogtreecommitdiff
path: root/ext/crypto/00_crypto.js
diff options
context:
space:
mode:
Diffstat (limited to 'ext/crypto/00_crypto.js')
-rw-r--r--ext/crypto/00_crypto.js174
1 files changed, 172 insertions, 2 deletions
diff --git a/ext/crypto/00_crypto.js b/ext/crypto/00_crypto.js
index 55e1ba9ad..5065df293 100644
--- a/ext/crypto/00_crypto.js
+++ b/ext/crypto/00_crypto.js
@@ -27,6 +27,7 @@
StringFromCharCode,
Symbol,
SymbolFor,
+ SyntaxError,
WeakMap,
WeakMapPrototypeGet,
WeakMapPrototypeSet,
@@ -123,6 +124,14 @@
"RSA-OAEP": "RsaOaepParams",
"AES-CBC": "AesCbcParams",
},
+ "get key length": {
+ "AES-CBC": "AesDerivedKeyParams",
+ "AES-GCM": "AesDerivedKeyParams",
+ "AES-KW": "AesDerivedKeyParams",
+ "HMAC": "HmacImportParams",
+ "HKDF": null,
+ "PBKDF2": null,
+ },
"wrapKey": {
// TODO(@littledivy): Enable this once implemented.
// "AES-KW": "AesKeyWrapParams",
@@ -322,6 +331,67 @@
/** @type {WeakMap<object, object>} */
const KEY_STORE = new WeakMap();
+ function getKeyLength(algorithm) {
+ switch (algorithm.name) {
+ case "AES-CBC":
+ case "AES-GCM":
+ case "AES-KW": {
+ // 1.
+ if (!ArrayPrototypeIncludes([128, 192, 256], algorithm.length)) {
+ throw new DOMException(
+ "length must be 128, 192, or 256",
+ "OperationError",
+ );
+ }
+
+ // 2.
+ return algorithm.length;
+ }
+ case "HMAC": {
+ // 1.
+ let length;
+ if (algorithm.length === undefined) {
+ switch (algorithm.hash.name) {
+ case "SHA-1":
+ length = 160;
+ break;
+ case "SHA-256":
+ length = 256;
+ break;
+ case "SHA-384":
+ length = 384;
+ break;
+ case "SHA-512":
+ length = 512;
+ break;
+ default:
+ throw new DOMException(
+ "Unrecognized hash algorithm",
+ "NotSupportedError",
+ );
+ }
+ } else if (algorithm.length !== 0) {
+ length = algorithm.length;
+ } else {
+ throw new TypeError("Invalid length.");
+ }
+
+ // 2.
+ return length;
+ }
+ case "HKDF": {
+ // 1.
+ return null;
+ }
+ case "PBKDF2": {
+ // 1.
+ return null;
+ }
+ default:
+ throw new TypeError("unreachable");
+ }
+ }
+
class SubtleCrypto {
constructor() {
webidl.illegalConstructor();
@@ -1574,13 +1644,13 @@
const result = await deriveBits(normalizedAlgorithm, baseKey, length);
// 7.
if (normalizedAlgorithm.name !== baseKey[_algorithm].name) {
- throw new DOMException("InvalidAccessError", "Invalid algorithm name");
+ throw new DOMException("Invalid algorithm name", "InvalidAccessError");
}
// 8.
if (!ArrayPrototypeIncludes(baseKey[_usages], "deriveBits")) {
throw new DOMException(
- "InvalidAccessError",
"baseKey usages does not contain `deriveBits`",
+ "InvalidAccessError",
);
}
// 9-10.
@@ -1588,6 +1658,106 @@
}
/**
+ * @param {AlgorithmIdentifier} algorithm
+ * @param {CryptoKey} baseKey
+ * @param {number} length
+ * @returns {Promise<ArrayBuffer>}
+ */
+ async deriveKey(
+ algorithm,
+ baseKey,
+ derivedKeyType,
+ extractable,
+ keyUsages,
+ ) {
+ webidl.assertBranded(this, SubtleCrypto);
+ const prefix = "Failed to execute 'deriveKey' on 'SubtleCrypto'";
+ webidl.requiredArguments(arguments.length, 5, { prefix });
+ algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
+ prefix,
+ context: "Argument 1",
+ });
+ baseKey = webidl.converters.CryptoKey(baseKey, {
+ prefix,
+ context: "Argument 2",
+ });
+ derivedKeyType = webidl.converters.AlgorithmIdentifier(derivedKeyType, {
+ prefix,
+ context: "Argument 3",
+ });
+ extractable = webidl.converters["boolean"](extractable, {
+ prefix,
+ context: "Argument 4",
+ });
+ keyUsages = webidl.converters["sequence<KeyUsage>"](keyUsages, {
+ prefix,
+ context: "Argument 5",
+ });
+
+ // 2-3.
+ const normalizedAlgorithm = normalizeAlgorithm(algorithm, "deriveBits");
+
+ // 4-5.
+ const normalizedDerivedKeyAlgorithmImport = normalizeAlgorithm(
+ derivedKeyType,
+ "importKey",
+ );
+
+ // 6-7.
+ const normalizedDerivedKeyAlgorithmLength = normalizeAlgorithm(
+ derivedKeyType,
+ "get key length",
+ );
+
+ // 8-10.
+
+ // 11.
+ if (normalizedAlgorithm.name !== baseKey[_algorithm].name) {
+ throw new DOMException(
+ "Invalid algorithm name",
+ "InvalidAccessError",
+ );
+ }
+
+ // 12.
+ if (!ArrayPrototypeIncludes(baseKey[_usages], "deriveKey")) {
+ throw new DOMException(
+ "baseKey usages does not contain `deriveKey`",
+ "InvalidAccessError",
+ );
+ }
+
+ // 13.
+ const length = getKeyLength(normalizedDerivedKeyAlgorithmLength);
+
+ // 14.
+ const secret = await this.deriveBits(
+ normalizedAlgorithm,
+ baseKey,
+ length,
+ );
+
+ // 15.
+ const result = await this.importKey(
+ "raw",
+ secret,
+ normalizedDerivedKeyAlgorithmImport,
+ extractable,
+ keyUsages,
+ );
+
+ // 16.
+ if (
+ ArrayPrototypeIncludes(["private", "secret"], result[_type]) &&
+ keyUsages.length == 0
+ ) {
+ throw new SyntaxError("Invalid key usages");
+ }
+ // 17.
+ return result;
+ }
+
+ /**
* @param {string} algorithm
* @param {CryptoKey} key
* @param {BufferSource} signature