nstdlib-nightly
Version:
Node.js standard library converted to runtime-agnostic ES modules.
1,266 lines (1,176 loc) • 32.6 kB
JavaScript
// Source: https://github.com/nodejs/node/blob/65eff1eb/lib/internal/crypto/webcrypto.js
import * as __hoisted_internal_crypto_rsa__ from "nstdlib/lib/internal/crypto/rsa";
import * as __hoisted_internal_crypto_cfrg__ from "nstdlib/lib/internal/crypto/cfrg";
import * as __hoisted_internal_crypto_ec__ from "nstdlib/lib/internal/crypto/ec";
import * as __hoisted_internal_crypto_mac__ from "nstdlib/lib/internal/crypto/mac";
import * as __hoisted_internal_crypto_aes__ from "nstdlib/lib/internal/crypto/aes";
import * as __hoisted_internal_crypto_diffiehellman__ from "nstdlib/lib/internal/crypto/diffiehellman";
import * as __hoisted_internal_crypto_hkdf__ from "nstdlib/lib/internal/crypto/hkdf";
import * as __hoisted_internal_crypto_pbkdf2__ from "nstdlib/lib/internal/crypto/pbkdf2";
import {
kWebCryptoKeyFormatRaw,
kWebCryptoKeyFormatPKCS8,
kWebCryptoKeyFormatSPKI,
kWebCryptoCipherEncrypt,
kWebCryptoCipherDecrypt,
} from "nstdlib/stub/binding/crypto";
import { getOptionValue } from "nstdlib/lib/internal/options";
import { TextDecoder, TextEncoder } from "nstdlib/lib/internal/encoding";
import { codes as __codes__ } from "nstdlib/lib/internal/errors";
import {
CryptoKey,
InternalCryptoKey,
createSecretKey,
} from "nstdlib/lib/internal/crypto/keys";
import { asyncDigest } from "nstdlib/lib/internal/crypto/hash";
import {
getBlockSize,
hasAnyNotIn,
normalizeAlgorithm,
normalizeHashName,
validateMaxBufferLength,
kHandle,
kKeyObject,
} from "nstdlib/lib/internal/crypto/util";
import {
kEnumerableProperty,
lazyDOMException,
} from "nstdlib/lib/internal/util";
import {
getRandomValues as _getRandomValues,
randomUUID as _randomUUID,
} from "nstdlib/lib/internal/crypto/random";
import * as __hoisted_internal_crypto_webidl__ from "nstdlib/lib/internal/crypto/webidl";
const { ERR_ILLEGAL_CONSTRUCTOR, ERR_INVALID_THIS } = __codes__;
let webidl;
async function digest(algorithm, data) {
if (this !== subtle) throw new ERR_INVALID_THIS("SubtleCrypto");
webidl ??= __hoisted_internal_crypto_webidl__;
const prefix = "Failed to execute 'digest' on 'SubtleCrypto'";
webidl.requiredArguments(arguments.length, 2, { prefix });
algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
prefix,
context: "1st argument",
});
data = webidl.converters.BufferSource(data, {
prefix,
context: "2nd argument",
});
algorithm = normalizeAlgorithm(algorithm, "digest");
return ReflectApply(asyncDigest, this, [algorithm, data]);
}
function randomUUID() {
if (this !== crypto) throw new ERR_INVALID_THIS("Crypto");
return _randomUUID();
}
async function generateKey(algorithm, extractable, keyUsages) {
if (this !== subtle) throw new ERR_INVALID_THIS("SubtleCrypto");
webidl ??= __hoisted_internal_crypto_webidl__;
const prefix = "Failed to execute 'generateKey' on 'SubtleCrypto'";
webidl.requiredArguments(arguments.length, 3, { prefix });
algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
prefix,
context: "1st argument",
});
extractable = webidl.converters.boolean(extractable, {
prefix,
context: "2nd argument",
});
keyUsages = webidl.converters["sequence<KeyUsage>"](keyUsages, {
prefix,
context: "3rd argument",
});
algorithm = normalizeAlgorithm(algorithm, "generateKey");
let result;
let resultType;
switch (algorithm.name) {
case "RSASSA-PKCS1-v1_5":
// Fall through
case "RSA-PSS":
// Fall through
case "RSA-OAEP":
resultType = "CryptoKeyPair";
result = await __hoisted_internal_crypto_rsa__.rsaKeyGenerate(
algorithm,
extractable,
keyUsages,
);
break;
case "Ed25519":
// Fall through
case "Ed448":
// Fall through
case "X25519":
// Fall through
case "X448":
resultType = "CryptoKeyPair";
result = await __hoisted_internal_crypto_cfrg__.cfrgGenerateKey(
algorithm,
extractable,
keyUsages,
);
break;
case "ECDSA":
// Fall through
case "ECDH":
resultType = "CryptoKeyPair";
result = await __hoisted_internal_crypto_ec__.ecGenerateKey(
algorithm,
extractable,
keyUsages,
);
break;
case "HMAC":
resultType = "CryptoKey";
result = await __hoisted_internal_crypto_mac__.hmacGenerateKey(
algorithm,
extractable,
keyUsages,
);
break;
case "AES-CTR":
// Fall through
case "AES-CBC":
// Fall through
case "AES-GCM":
// Fall through
case "AES-KW":
resultType = "CryptoKey";
result = await __hoisted_internal_crypto_aes__.aesGenerateKey(
algorithm,
extractable,
keyUsages,
);
break;
default:
throw lazyDOMException(
"Unrecognized algorithm name",
"NotSupportedError",
);
}
if (
(resultType === "CryptoKey" &&
(result.type === "secret" || result.type === "private") &&
result.usages.length === 0) ||
(resultType === "CryptoKeyPair" && result.privateKey.usages.length === 0)
) {
throw lazyDOMException(
"Usages cannot be empty when creating a key.",
"SyntaxError",
);
}
return result;
}
async function deriveBits(algorithm, baseKey, length = null) {
if (this !== subtle) throw new ERR_INVALID_THIS("SubtleCrypto");
webidl ??= __hoisted_internal_crypto_webidl__;
const prefix = "Failed to execute 'deriveBits' on 'SubtleCrypto'";
webidl.requiredArguments(arguments.length, 2, { prefix });
algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
prefix,
context: "1st argument",
});
baseKey = webidl.converters.CryptoKey(baseKey, {
prefix,
context: "2nd argument",
});
if (length !== null) {
length = webidl.converters["unsigned long"](length, {
prefix,
context: "3rd argument",
});
}
algorithm = normalizeAlgorithm(algorithm, "deriveBits");
if (!Array.prototype.includes.call(baseKey.usages, "deriveBits")) {
throw lazyDOMException(
"baseKey does not have deriveBits usage",
"InvalidAccessError",
);
}
if (baseKey.algorithm.name !== algorithm.name)
throw lazyDOMException("Key algorithm mismatch", "InvalidAccessError");
switch (algorithm.name) {
case "X25519":
// Fall through
case "X448":
// Fall through
case "ECDH":
return __hoisted_internal_crypto_diffiehellman__.ecdhDeriveBits(
algorithm,
baseKey,
length,
);
case "HKDF":
return __hoisted_internal_crypto_hkdf__.hkdfDeriveBits(
algorithm,
baseKey,
length,
);
case "PBKDF2":
return __hoisted_internal_crypto_pbkdf2__.pbkdf2DeriveBits(
algorithm,
baseKey,
length,
);
}
throw lazyDOMException("Unrecognized algorithm name", "NotSupportedError");
}
function getKeyLength({ name, length, hash }) {
switch (name) {
case "AES-CTR":
case "AES-CBC":
case "AES-GCM":
case "AES-KW":
if (length !== 128 && length !== 192 && length !== 256)
throw lazyDOMException("Invalid key length", "OperationError");
return length;
case "HMAC":
if (length === undefined) {
return getBlockSize(hash?.name);
}
if (typeof length === "number" && length !== 0) {
return length;
}
throw lazyDOMException("Invalid key length", "OperationError");
case "HKDF":
case "PBKDF2":
return null;
}
}
async function deriveKey(
algorithm,
baseKey,
derivedKeyAlgorithm,
extractable,
keyUsages,
) {
if (this !== subtle) throw new ERR_INVALID_THIS("SubtleCrypto");
webidl ??= __hoisted_internal_crypto_webidl__;
const prefix = "Failed to execute 'deriveKey' on 'SubtleCrypto'";
webidl.requiredArguments(arguments.length, 5, { prefix });
algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
prefix,
context: "1st argument",
});
baseKey = webidl.converters.CryptoKey(baseKey, {
prefix,
context: "2nd argument",
});
derivedKeyAlgorithm = webidl.converters.AlgorithmIdentifier(
derivedKeyAlgorithm,
{
prefix,
context: "3rd argument",
},
);
extractable = webidl.converters.boolean(extractable, {
prefix,
context: "4th argument",
});
keyUsages = webidl.converters["sequence<KeyUsage>"](keyUsages, {
prefix,
context: "5th argument",
});
algorithm = normalizeAlgorithm(algorithm, "deriveBits");
derivedKeyAlgorithm = normalizeAlgorithm(derivedKeyAlgorithm, "importKey");
if (!Array.prototype.includes.call(baseKey.usages, "deriveKey")) {
throw lazyDOMException(
"baseKey does not have deriveKey usage",
"InvalidAccessError",
);
}
if (baseKey.algorithm.name !== algorithm.name)
throw lazyDOMException("Key algorithm mismatch", "InvalidAccessError");
const length = getKeyLength(
normalizeAlgorithm(arguments[2], "get key length"),
);
let bits;
switch (algorithm.name) {
case "X25519":
// Fall through
case "X448":
// Fall through
case "ECDH":
bits = await __hoisted_internal_crypto_diffiehellman__.ecdhDeriveBits(
algorithm,
baseKey,
length,
);
break;
case "HKDF":
bits = await __hoisted_internal_crypto_hkdf__.hkdfDeriveBits(
algorithm,
baseKey,
length,
);
break;
case "PBKDF2":
bits = await __hoisted_internal_crypto_pbkdf2__.pbkdf2DeriveBits(
algorithm,
baseKey,
length,
);
break;
default:
throw lazyDOMException(
"Unrecognized algorithm name",
"NotSupportedError",
);
}
return ReflectApply(importKey, this, [
"raw",
bits,
derivedKeyAlgorithm,
extractable,
keyUsages,
]);
}
async function exportKeySpki(key) {
switch (key.algorithm.name) {
case "RSASSA-PKCS1-v1_5":
// Fall through
case "RSA-PSS":
// Fall through
case "RSA-OAEP":
if (key.type === "public") {
return __hoisted_internal_crypto_rsa__.rsaExportKey(
key,
kWebCryptoKeyFormatSPKI,
);
}
break;
case "ECDSA":
// Fall through
case "ECDH":
if (key.type === "public") {
return __hoisted_internal_crypto_ec__.ecExportKey(
key,
kWebCryptoKeyFormatSPKI,
);
}
break;
case "Ed25519":
// Fall through
case "Ed448":
// Fall through
case "X25519":
// Fall through
case "X448":
if (key.type === "public") {
return __hoisted_internal_crypto_cfrg__.cfrgExportKey(
key,
kWebCryptoKeyFormatSPKI,
);
}
break;
}
throw lazyDOMException(
`Unable to export a raw ${key.algorithm.name} ${key.type} key`,
"InvalidAccessError",
);
}
async function exportKeyPkcs8(key) {
switch (key.algorithm.name) {
case "RSASSA-PKCS1-v1_5":
// Fall through
case "RSA-PSS":
// Fall through
case "RSA-OAEP":
if (key.type === "private") {
return __hoisted_internal_crypto_rsa__.rsaExportKey(
key,
kWebCryptoKeyFormatPKCS8,
);
}
break;
case "ECDSA":
// Fall through
case "ECDH":
if (key.type === "private") {
return __hoisted_internal_crypto_ec__.ecExportKey(
key,
kWebCryptoKeyFormatPKCS8,
);
}
break;
case "Ed25519":
// Fall through
case "Ed448":
// Fall through
case "X25519":
// Fall through
case "X448":
if (key.type === "private") {
return __hoisted_internal_crypto_cfrg__.cfrgExportKey(
key,
kWebCryptoKeyFormatPKCS8,
);
}
break;
}
throw lazyDOMException(
`Unable to export a pkcs8 ${key.algorithm.name} ${key.type} key`,
"InvalidAccessError",
);
}
async function exportKeyRaw(key) {
switch (key.algorithm.name) {
case "ECDSA":
// Fall through
case "ECDH":
if (key.type === "public") {
return __hoisted_internal_crypto_ec__.ecExportKey(
key,
kWebCryptoKeyFormatRaw,
);
}
break;
case "Ed25519":
// Fall through
case "Ed448":
// Fall through
case "X25519":
// Fall through
case "X448":
if (key.type === "public") {
return __hoisted_internal_crypto_cfrg__.cfrgExportKey(
key,
kWebCryptoKeyFormatRaw,
);
}
break;
case "AES-CTR":
// Fall through
case "AES-CBC":
// Fall through
case "AES-GCM":
// Fall through
case "AES-KW":
// Fall through
case "HMAC":
return key[kKeyObject].export().buffer;
}
throw lazyDOMException(
`Unable to export a raw ${key.algorithm.name} ${key.type} key`,
"InvalidAccessError",
);
}
async function exportKeyJWK(key) {
const jwk = key[kKeyObject][kHandle].exportJwk(
{
key_ops: key.usages,
ext: key.extractable,
},
true,
);
switch (key.algorithm.name) {
case "RSASSA-PKCS1-v1_5":
jwk.alg = normalizeHashName(
key.algorithm.hash.name,
normalizeHashName.kContextJwkRsa,
);
return jwk;
case "RSA-PSS":
jwk.alg = normalizeHashName(
key.algorithm.hash.name,
normalizeHashName.kContextJwkRsaPss,
);
return jwk;
case "RSA-OAEP":
jwk.alg = normalizeHashName(
key.algorithm.hash.name,
normalizeHashName.kContextJwkRsaOaep,
);
return jwk;
case "ECDSA":
// Fall through
case "ECDH":
jwk.crv ||= key.algorithm.namedCurve;
return jwk;
case "X25519":
// Fall through
case "X448":
jwk.crv ||= key.algorithm.name;
return jwk;
case "Ed25519":
// Fall through
case "Ed448":
jwk.crv ||= key.algorithm.name;
return jwk;
case "AES-CTR":
// Fall through
case "AES-CBC":
// Fall through
case "AES-GCM":
// Fall through
case "AES-KW":
jwk.alg = __hoisted_internal_crypto_aes__.getAlgorithmName(
key.algorithm.name,
key.algorithm.length,
);
return jwk;
case "HMAC":
jwk.alg = normalizeHashName(
key.algorithm.hash.name,
normalizeHashName.kContextJwkHmac,
);
return jwk;
default:
// Fall through
}
throw lazyDOMException("Not yet supported", "NotSupportedError");
}
async function exportKey(format, key) {
if (this !== subtle) throw new ERR_INVALID_THIS("SubtleCrypto");
webidl ??= __hoisted_internal_crypto_webidl__;
const prefix = "Failed to execute 'exportKey' on 'SubtleCrypto'";
webidl.requiredArguments(arguments.length, 2, { prefix });
format = webidl.converters.KeyFormat(format, {
prefix,
context: "1st argument",
});
key = webidl.converters.CryptoKey(key, {
prefix,
context: "2nd argument",
});
if (!key.extractable)
throw lazyDOMException("key is not extractable", "InvalidAccessException");
switch (format) {
case "spki":
return exportKeySpki(key);
case "pkcs8":
return exportKeyPkcs8(key);
case "jwk":
return exportKeyJWK(key);
case "raw":
return exportKeyRaw(key);
}
throw lazyDOMException("Export format is unsupported", "NotSupportedError");
}
async function importGenericSecretKey(
{ name, length },
format,
keyData,
extractable,
keyUsages,
) {
const usagesSet = new Set(keyUsages);
if (extractable)
throw lazyDOMException(`${name} keys are not extractable`, "SyntaxError");
if (hasAnyNotIn(usagesSet, ["deriveKey", "deriveBits"])) {
throw lazyDOMException(
`Unsupported key usage for a ${name} key`,
"SyntaxError",
);
}
switch (format) {
case "raw": {
if (hasAnyNotIn(usagesSet, ["deriveKey", "deriveBits"])) {
throw lazyDOMException(
`Unsupported key usage for a ${name} key`,
"SyntaxError",
);
}
const checkLength = keyData.byteLength * 8;
// The Web Crypto spec allows for key lengths that are not multiples of
// 8. We don't. Our check here is stricter than that defined by the spec
// in that we require that algorithm.length match keyData.length * 8 if
// algorithm.length is specified.
if (length !== undefined && length !== checkLength) {
throw lazyDOMException("Invalid key length", "DataError");
}
const keyObject = createSecretKey(keyData);
return new InternalCryptoKey(keyObject, { name }, keyUsages, false);
}
}
throw lazyDOMException(
`Unable to import ${name} key with format ${format}`,
"NotSupportedError",
);
}
async function importKey(format, keyData, algorithm, extractable, keyUsages) {
if (this !== subtle) throw new ERR_INVALID_THIS("SubtleCrypto");
webidl ??= __hoisted_internal_crypto_webidl__;
const prefix = "Failed to execute 'importKey' on 'SubtleCrypto'";
webidl.requiredArguments(arguments.length, 4, { prefix });
format = webidl.converters.KeyFormat(format, {
prefix,
context: "1st argument",
});
const type = format === "jwk" ? "JsonWebKey" : "BufferSource";
keyData = webidl.converters[type](keyData, {
prefix,
context: "2nd argument",
});
algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
prefix,
context: "3rd argument",
});
extractable = webidl.converters.boolean(extractable, {
prefix,
context: "4th argument",
});
keyUsages = webidl.converters["sequence<KeyUsage>"](keyUsages, {
prefix,
context: "5th argument",
});
algorithm = normalizeAlgorithm(algorithm, "importKey");
let result;
switch (algorithm.name) {
case "RSASSA-PKCS1-v1_5":
// Fall through
case "RSA-PSS":
// Fall through
case "RSA-OAEP":
result = await __hoisted_internal_crypto_rsa__.rsaImportKey(
format,
keyData,
algorithm,
extractable,
keyUsages,
);
break;
case "ECDSA":
// Fall through
case "ECDH":
result = await __hoisted_internal_crypto_ec__.ecImportKey(
format,
keyData,
algorithm,
extractable,
keyUsages,
);
break;
case "Ed25519":
// Fall through
case "Ed448":
// Fall through
case "X25519":
// Fall through
case "X448":
result = await __hoisted_internal_crypto_cfrg__.cfrgImportKey(
format,
keyData,
algorithm,
extractable,
keyUsages,
);
break;
case "HMAC":
result = await __hoisted_internal_crypto_mac__.hmacImportKey(
format,
keyData,
algorithm,
extractable,
keyUsages,
);
break;
case "AES-CTR":
// Fall through
case "AES-CBC":
// Fall through
case "AES-GCM":
// Fall through
case "AES-KW":
result = await __hoisted_internal_crypto_aes__.aesImportKey(
algorithm,
format,
keyData,
extractable,
keyUsages,
);
break;
case "HKDF":
// Fall through
case "PBKDF2":
result = await importGenericSecretKey(
algorithm,
format,
keyData,
extractable,
keyUsages,
);
break;
default:
throw lazyDOMException(
"Unrecognized algorithm name",
"NotSupportedError",
);
}
if (
(result.type === "secret" || result.type === "private") &&
result.usages.length === 0
) {
throw lazyDOMException(
`Usages cannot be empty when importing a ${result.type} key.`,
"SyntaxError",
);
}
return result;
}
// subtle.wrapKey() is essentially a subtle.exportKey() followed
// by a subtle.encrypt().
async function wrapKey(format, key, wrappingKey, algorithm) {
if (this !== subtle) throw new ERR_INVALID_THIS("SubtleCrypto");
webidl ??= __hoisted_internal_crypto_webidl__;
const prefix = "Failed to execute 'wrapKey' on 'SubtleCrypto'";
webidl.requiredArguments(arguments.length, 4, { prefix });
format = webidl.converters.KeyFormat(format, {
prefix,
context: "1st argument",
});
key = webidl.converters.CryptoKey(key, {
prefix,
context: "2nd argument",
});
wrappingKey = webidl.converters.CryptoKey(wrappingKey, {
prefix,
context: "3rd argument",
});
algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
prefix,
context: "4th argument",
});
try {
algorithm = normalizeAlgorithm(algorithm, "wrapKey");
} catch {
algorithm = normalizeAlgorithm(algorithm, "encrypt");
}
let keyData = await ReflectApply(exportKey, this, [format, key]);
if (format === "jwk") {
const ec = new TextEncoder();
const raw = JSONStringify(keyData);
// As per the NOTE in step 13 https://w3c.github.io/webcrypto/#SubtleCrypto-method-wrapKey
// we're padding AES-KW wrapped JWK to make sure it is always a multiple of 8 bytes
// in length
if (algorithm.name === "AES-KW" && raw.length % 8 !== 0) {
keyData = ec.encode(
raw + String.prototype.repeat.call(" ", 8 - (raw.length % 8)),
);
} else {
keyData = ec.encode(raw);
}
}
return cipherOrWrap(
kWebCryptoCipherEncrypt,
algorithm,
wrappingKey,
keyData,
"wrapKey",
);
}
// subtle.unwrapKey() is essentially a subtle.decrypt() followed
// by a subtle.importKey().
async function unwrapKey(
format,
wrappedKey,
unwrappingKey,
unwrapAlgo,
unwrappedKeyAlgo,
extractable,
keyUsages,
) {
if (this !== subtle) throw new ERR_INVALID_THIS("SubtleCrypto");
webidl ??= __hoisted_internal_crypto_webidl__;
const prefix = "Failed to execute 'unwrapKey' on 'SubtleCrypto'";
webidl.requiredArguments(arguments.length, 7, { prefix });
format = webidl.converters.KeyFormat(format, {
prefix,
context: "1st argument",
});
wrappedKey = webidl.converters.BufferSource(wrappedKey, {
prefix,
context: "2nd argument",
});
unwrappingKey = webidl.converters.CryptoKey(unwrappingKey, {
prefix,
context: "3rd argument",
});
unwrapAlgo = webidl.converters.AlgorithmIdentifier(unwrapAlgo, {
prefix,
context: "4th argument",
});
unwrappedKeyAlgo = webidl.converters.AlgorithmIdentifier(unwrappedKeyAlgo, {
prefix,
context: "5th argument",
});
extractable = webidl.converters.boolean(extractable, {
prefix,
context: "6th argument",
});
keyUsages = webidl.converters["sequence<KeyUsage>"](keyUsages, {
prefix,
context: "7th argument",
});
try {
unwrapAlgo = normalizeAlgorithm(unwrapAlgo, "unwrapKey");
} catch {
unwrapAlgo = normalizeAlgorithm(unwrapAlgo, "decrypt");
}
let keyData = await cipherOrWrap(
kWebCryptoCipherDecrypt,
unwrapAlgo,
unwrappingKey,
wrappedKey,
"unwrapKey",
);
if (format === "jwk") {
// The fatal: true option is only supported in builds that have ICU.
const options =
process.versions.icu !== undefined ? { fatal: true } : undefined;
const dec = new TextDecoder("utf-8", options);
try {
keyData = JSONParse(dec.decode(keyData));
} catch {
throw lazyDOMException("Invalid wrapped JWK key", "DataError");
}
}
return ReflectApply(importKey, this, [
format,
keyData,
unwrappedKeyAlgo,
extractable,
keyUsages,
]);
}
function signVerify(algorithm, key, data, signature) {
let usage = "sign";
if (signature !== undefined) {
usage = "verify";
}
algorithm = normalizeAlgorithm(algorithm, usage);
if (
!Array.prototype.includes.call(key.usages, usage) ||
algorithm.name !== key.algorithm.name
) {
throw lazyDOMException(
`Unable to use this key to ${usage}`,
"InvalidAccessError",
);
}
switch (algorithm.name) {
case "RSA-PSS":
// Fall through
case "RSASSA-PKCS1-v1_5":
return __hoisted_internal_crypto_rsa__.rsaSignVerify(
key,
data,
algorithm,
signature,
);
case "ECDSA":
return __hoisted_internal_crypto_ec__.ecdsaSignVerify(
key,
data,
algorithm,
signature,
);
case "Ed25519":
// Fall through
case "Ed448":
// Fall through
return __hoisted_internal_crypto_cfrg__.eddsaSignVerify(
key,
data,
algorithm,
signature,
);
case "HMAC":
return __hoisted_internal_crypto_mac__.hmacSignVerify(
key,
data,
algorithm,
signature,
);
}
throw lazyDOMException("Unrecognized algorithm name", "NotSupportedError");
}
async function sign(algorithm, key, data) {
if (this !== subtle) throw new ERR_INVALID_THIS("SubtleCrypto");
webidl ??= __hoisted_internal_crypto_webidl__;
const prefix = "Failed to execute 'sign' on 'SubtleCrypto'";
webidl.requiredArguments(arguments.length, 3, { prefix });
algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
prefix,
context: "1st argument",
});
key = webidl.converters.CryptoKey(key, {
prefix,
context: "2nd argument",
});
data = webidl.converters.BufferSource(data, {
prefix,
context: "3rd argument",
});
return signVerify(algorithm, key, data);
}
async function verify(algorithm, key, signature, data) {
if (this !== subtle) throw new ERR_INVALID_THIS("SubtleCrypto");
webidl ??= __hoisted_internal_crypto_webidl__;
const prefix = "Failed to execute 'verify' on 'SubtleCrypto'";
webidl.requiredArguments(arguments.length, 4, { prefix });
algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
prefix,
context: "1st argument",
});
key = webidl.converters.CryptoKey(key, {
prefix,
context: "2nd argument",
});
signature = webidl.converters.BufferSource(signature, {
prefix,
context: "3rd argument",
});
data = webidl.converters.BufferSource(data, {
prefix,
context: "4th argument",
});
return signVerify(algorithm, key, data, signature);
}
async function cipherOrWrap(mode, algorithm, key, data, op) {
// We use a Node.js style error here instead of a DOMException because
// the WebCrypto spec is not specific what kind of error is to be thrown
// in this case. Both Firefox and Chrome throw simple TypeErrors here.
// The key algorithm and cipher algorithm must match, and the
// key must have the proper usage.
if (
key.algorithm.name !== algorithm.name ||
!Array.prototype.includes.call(key.usages, op)
) {
throw lazyDOMException(
"The requested operation is not valid for the provided key",
"InvalidAccessError",
);
}
// While WebCrypto allows for larger input buffer sizes, we limit
// those to sizes that can fit within uint32_t because of limitations
// in the OpenSSL API.
validateMaxBufferLength(data, "data");
switch (algorithm.name) {
case "RSA-OAEP":
return __hoisted_internal_crypto_rsa__.rsaCipher(
mode,
key,
data,
algorithm,
);
case "AES-CTR":
// Fall through
case "AES-CBC":
// Fall through
case "AES-GCM":
return __hoisted_internal_crypto_aes__.aesCipher(
mode,
key,
data,
algorithm,
);
case "AES-KW":
if (op === "wrapKey" || op === "unwrapKey") {
return __hoisted_internal_crypto_aes__.aesCipher(
mode,
key,
data,
algorithm,
);
}
}
throw lazyDOMException("Unrecognized algorithm name", "NotSupportedError");
}
async function encrypt(algorithm, key, data) {
if (this !== subtle) throw new ERR_INVALID_THIS("SubtleCrypto");
webidl ??= __hoisted_internal_crypto_webidl__;
const prefix = "Failed to execute 'encrypt' on 'SubtleCrypto'";
webidl.requiredArguments(arguments.length, 3, { prefix });
algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
prefix,
context: "1st argument",
});
key = webidl.converters.CryptoKey(key, {
prefix,
context: "2nd argument",
});
data = webidl.converters.BufferSource(data, {
prefix,
context: "3rd argument",
});
algorithm = normalizeAlgorithm(algorithm, "encrypt");
return cipherOrWrap(kWebCryptoCipherEncrypt, algorithm, key, data, "encrypt");
}
async function decrypt(algorithm, key, data) {
if (this !== subtle) throw new ERR_INVALID_THIS("SubtleCrypto");
webidl ??= __hoisted_internal_crypto_webidl__;
const prefix = "Failed to execute 'decrypt' on 'SubtleCrypto'";
webidl.requiredArguments(arguments.length, 3, { prefix });
algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
prefix,
context: "1st argument",
});
key = webidl.converters.CryptoKey(key, {
prefix,
context: "2nd argument",
});
data = webidl.converters.BufferSource(data, {
prefix,
context: "3rd argument",
});
algorithm = normalizeAlgorithm(algorithm, "decrypt");
return cipherOrWrap(kWebCryptoCipherDecrypt, algorithm, key, data, "decrypt");
}
// The SubtleCrypto and Crypto classes are defined as part of the
// Web Crypto API standard: https://www.w3.org/TR/WebCryptoAPI/
class SubtleCrypto {
constructor() {
throw new ERR_ILLEGAL_CONSTRUCTOR();
}
}
const subtle = Reflect.construct(function () {}, [], SubtleCrypto);
class Crypto {
constructor() {
throw new ERR_ILLEGAL_CONSTRUCTOR();
}
get subtle() {
if (this !== crypto) throw new ERR_INVALID_THIS("Crypto");
return subtle;
}
}
const crypto = Reflect.construct(function () {}, [], Crypto);
function getRandomValues(array) {
if (this !== crypto) throw new ERR_INVALID_THIS("Crypto");
webidl ??= __hoisted_internal_crypto_webidl__;
const prefix = "Failed to execute 'getRandomValues' on 'Crypto'";
webidl.requiredArguments(arguments.length, 1, { prefix });
return ReflectApply(_getRandomValues, this, arguments);
}
Object.defineProperties(Crypto.prototype, {
[Symbol.toStringTag]: {
__proto__: null,
enumerable: false,
configurable: true,
writable: false,
value: "Crypto",
},
subtle: kEnumerableProperty,
getRandomValues: {
__proto__: null,
enumerable: true,
configurable: true,
writable: true,
value: getRandomValues,
},
randomUUID: {
__proto__: null,
enumerable: true,
configurable: true,
writable: true,
value: randomUUID,
},
});
if (getOptionValue("--no-experimental-global-webcrypto")) {
// For backward compatibility, keep exposing CryptoKey in the Crypto prototype
// when using the flag.
Object.defineProperty(Crypto.prototype, "CryptoKey", {
__proto__: null,
enumerable: true,
configurable: true,
writable: true,
value: CryptoKey,
});
}
Object.defineProperties(SubtleCrypto.prototype, {
[Symbol.toStringTag]: {
__proto__: null,
enumerable: false,
configurable: true,
writable: false,
value: "SubtleCrypto",
},
encrypt: {
__proto__: null,
enumerable: true,
configurable: true,
writable: true,
value: encrypt,
},
decrypt: {
__proto__: null,
enumerable: true,
configurable: true,
writable: true,
value: decrypt,
},
sign: {
__proto__: null,
enumerable: true,
configurable: true,
writable: true,
value: sign,
},
verify: {
__proto__: null,
enumerable: true,
configurable: true,
writable: true,
value: verify,
},
digest: {
__proto__: null,
enumerable: true,
configurable: true,
writable: true,
value: digest,
},
generateKey: {
__proto__: null,
enumerable: true,
configurable: true,
writable: true,
value: generateKey,
},
deriveKey: {
__proto__: null,
enumerable: true,
configurable: true,
writable: true,
value: deriveKey,
},
deriveBits: {
__proto__: null,
enumerable: true,
configurable: true,
writable: true,
value: deriveBits,
},
importKey: {
__proto__: null,
enumerable: true,
configurable: true,
writable: true,
value: importKey,
},
exportKey: {
__proto__: null,
enumerable: true,
configurable: true,
writable: true,
value: exportKey,
},
wrapKey: {
__proto__: null,
enumerable: true,
configurable: true,
writable: true,
value: wrapKey,
},
unwrapKey: {
__proto__: null,
enumerable: true,
configurable: true,
writable: true,
value: unwrapKey,
},
});
export { Crypto };
export { CryptoKey };
export { SubtleCrypto };
export { crypto };