summaryrefslogtreecommitdiff
path: root/extensions/crypto
diff options
context:
space:
mode:
authorRyan Dahl <ry@tinyclouds.org>2021-08-11 12:27:05 +0200
committerGitHub <noreply@github.com>2021-08-11 12:27:05 +0200
commita0285e2eb88f6254f6494b0ecd1878db3a3b2a58 (patch)
tree90671b004537e20f9493fd3277ffd21d30b39a0e /extensions/crypto
parent3a6994115176781b3a93d70794b1b81bc95e42b4 (diff)
Rename extensions/ directory to ext/ (#11643)
Diffstat (limited to 'extensions/crypto')
-rw-r--r--extensions/crypto/00_crypto.js1013
-rw-r--r--extensions/crypto/01_webidl.js188
-rw-r--r--extensions/crypto/Cargo.toml28
-rw-r--r--extensions/crypto/README.md5
-rw-r--r--extensions/crypto/key.rs117
-rw-r--r--extensions/crypto/lib.deno_crypto.d.ts155
-rw-r--r--extensions/crypto/lib.rs558
7 files changed, 0 insertions, 2064 deletions
diff --git a/extensions/crypto/00_crypto.js b/extensions/crypto/00_crypto.js
deleted file mode 100644
index 449946295..000000000
--- a/extensions/crypto/00_crypto.js
+++ /dev/null
@@ -1,1013 +0,0 @@
-// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
-
-// @ts-check
-/// <reference path="../../core/internal.d.ts" />
-/// <reference path="../../core/lib.deno_core.d.ts" />
-/// <reference path="../webidl/internal.d.ts" />
-/// <reference path="../web/lib.deno_web.d.ts" />
-
-"use strict";
-
-((window) => {
- const core = window.Deno.core;
- const webidl = window.__bootstrap.webidl;
- const { DOMException } = window.__bootstrap.domException;
-
- const {
- ArrayPrototypeFind,
- ArrayBufferIsView,
- ArrayPrototypeIncludes,
- BigInt64Array,
- StringPrototypeToUpperCase,
- Symbol,
- SymbolFor,
- SymbolToStringTag,
- WeakMap,
- WeakMapPrototypeGet,
- WeakMapPrototypeSet,
- Int8Array,
- Uint8Array,
- TypedArrayPrototypeSlice,
- Int16Array,
- Uint16Array,
- Int32Array,
- Uint32Array,
- Uint8ClampedArray,
- TypeError,
- } = window.__bootstrap.primordials;
-
- // P-521 is not yet supported.
- const supportedNamedCurves = ["P-256", "P-384"];
- const recognisedUsages = [
- "encrypt",
- "decrypt",
- "sign",
- "verify",
- "deriveKey",
- "deriveBits",
- "wrapKey",
- "unwrapKey",
- ];
-
- const simpleAlgorithmDictionaries = {
- RsaHashedKeyGenParams: { hash: "HashAlgorithmIdentifier" },
- EcKeyGenParams: {},
- HmacKeyGenParams: { hash: "HashAlgorithmIdentifier" },
- RsaPssParams: {},
- EcdsaParams: { hash: "HashAlgorithmIdentifier" },
- HmacImportParams: { hash: "HashAlgorithmIdentifier" },
- };
-
- const supportedAlgorithms = {
- "digest": {
- "SHA-1": null,
- "SHA-256": null,
- "SHA-384": null,
- "SHA-512": null,
- },
- "generateKey": {
- "RSASSA-PKCS1-v1_5": "RsaHashedKeyGenParams",
- "RSA-PSS": "RsaHashedKeyGenParams",
- "ECDSA": "EcKeyGenParams",
- "HMAC": "HmacKeyGenParams",
- },
- "sign": {
- "RSASSA-PKCS1-v1_5": null,
- "RSA-PSS": "RsaPssParams",
- "ECDSA": "EcdsaParams",
- "HMAC": null,
- },
- "verify": {
- "RSASSA-PKCS1-v1_5": null,
- "RSA-PSS": "RsaPssParams",
- "HMAC": null,
- },
- "importKey": {
- "HMAC": "HmacImportParams",
- },
- };
-
- // See https://www.w3.org/TR/WebCryptoAPI/#dfn-normalize-an-algorithm
- function normalizeAlgorithm(algorithm, op) {
- if (typeof algorithm == "string") {
- return normalizeAlgorithm({ name: algorithm }, op);
- }
-
- // 1.
- const registeredAlgorithms = supportedAlgorithms[op];
- // 2. 3.
- const initialAlg = webidl.converters.Algorithm(algorithm, {
- prefix: "Failed to normalize algorithm",
- context: "passed algorithm",
- });
- // 4.
- let algName = initialAlg.name;
-
- // 5.
- let desiredType = undefined;
- for (const key in registeredAlgorithms) {
- if (
- StringPrototypeToUpperCase(key) === StringPrototypeToUpperCase(algName)
- ) {
- algName = key;
- desiredType = registeredAlgorithms[key];
- }
- }
- if (desiredType === undefined) {
- throw new DOMException(
- "Unrecognized algorithm name",
- "NotSupportedError",
- );
- }
-
- // Fast path everything below if the registered dictionary is "None".
- if (desiredType === null) {
- return { name: algName };
- }
-
- const normalizedAlgorithm = webidl.converters[desiredType](algorithm, {
- prefix: "Failed to normalize algorithm",
- context: "passed algorithm",
- });
- normalizedAlgorithm.name = algName;
-
- const dict = simpleAlgorithmDictionaries[desiredType];
- for (const member in dict) {
- const idlType = dict[member];
- const idlValue = normalizedAlgorithm[member];
-
- if (idlType === "BufferSource") {
- normalizedAlgorithm[member] = new Uint8Array(
- TypedArrayPrototypeSlice(
- (ArrayBufferIsView(idlValue) ? idlValue.buffer : idlValue),
- idlValue.byteOffset ?? 0,
- idlValue.byteLength,
- ),
- );
- } else if (idlType === "HashAlgorithmIdentifier") {
- normalizedAlgorithm[member] = normalizeAlgorithm(idlValue, "digest");
- } else if (idlType === "AlgorithmIdentifier") {
- // TODO(lucacasonato): implement
- throw new TypeError("unimplemented");
- }
- }
-
- return normalizedAlgorithm;
- }
-
- const _handle = Symbol("[[handle]]");
- const _algorithm = Symbol("[[algorithm]]");
- const _extractable = Symbol("[[extractable]]");
- const _usages = Symbol("[[usages]]");
- const _type = Symbol("[[type]]");
-
- class CryptoKey {
- /** @type {string} */
- [_type];
- /** @type {boolean} */
- [_extractable];
- /** @type {object} */
- [_algorithm];
- /** @type {string[]} */
- [_usages];
- /** @type {object} */
- [_handle];
-
- constructor() {
- webidl.illegalConstructor();
- }
-
- /** @returns {string} */
- get type() {
- webidl.assertBranded(this, CryptoKey);
- return this[_type];
- }
-
- /** @returns {boolean} */
- get extractable() {
- webidl.assertBranded(this, CryptoKey);
- return this[_extractable];
- }
-
- /** @returns {string[]} */
- get usages() {
- webidl.assertBranded(this, CryptoKey);
- // TODO(lucacasonato): return a SameObject copy
- return this[_usages];
- }
-
- /** @returns {object} */
- get algorithm() {
- webidl.assertBranded(this, CryptoKey);
- // TODO(lucacasonato): return a SameObject copy
- return this[_algorithm];
- }
-
- get [SymbolToStringTag]() {
- return "CryptoKey";
- }
-
- [SymbolFor("Deno.customInspect")](inspect) {
- return `${this.constructor.name} ${
- inspect({
- type: this.type,
- extractable: this.extractable,
- algorithm: this.algorithm,
- usages: this.usages,
- })
- }`;
- }
- }
-
- webidl.configurePrototype(CryptoKey);
-
- /**
- * @param {string} type
- * @param {boolean} extractable
- * @param {string[]} usages
- * @param {object} algorithm
- * @param {object} handle
- * @returns
- */
- function constructKey(type, extractable, usages, algorithm, handle) {
- const key = webidl.createBranded(CryptoKey);
- key[_type] = type;
- key[_extractable] = extractable;
- key[_usages] = usages;
- key[_algorithm] = algorithm;
- key[_handle] = handle;
- return key;
- }
-
- // https://w3c.github.io/webcrypto/#concept-usage-intersection
- /**
- * @param {string[]} a
- * @param {string[]} b
- * @returns
- */
- function usageIntersection(a, b) {
- return a.filter((i) => b.includes(i));
- }
-
- // TODO(lucacasonato): this should be moved to rust
- /** @type {WeakMap<object, object>} */
- const KEY_STORE = new WeakMap();
-
- class SubtleCrypto {
- constructor() {
- webidl.illegalConstructor();
- }
-
- /**
- * @param {string} algorithm
- * @param {BufferSource} data
- * @returns {Promise<Uint8Array>}
- */
- async digest(algorithm, data) {
- webidl.assertBranded(this, SubtleCrypto);
- const prefix = "Failed to execute 'digest' on 'SubtleCrypto'";
- webidl.requiredArguments(arguments.length, 2, { prefix });
- algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
- prefix,
- context: "Argument 1",
- });
- data = webidl.converters.BufferSource(data, {
- prefix,
- context: "Argument 2",
- });
-
- if (ArrayBufferIsView(data)) {
- data = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
- } else {
- data = new Uint8Array(data);
- }
-
- data = TypedArrayPrototypeSlice(data);
-
- algorithm = normalizeAlgorithm(algorithm, "digest");
-
- const result = await core.opAsync(
- "op_crypto_subtle_digest",
- algorithm.name,
- data,
- );
-
- return result.buffer;
- }
-
- /**
- * @param {string} algorithm
- * @param {CryptoKey} key
- * @param {BufferSource} data
- * @returns {Promise<any>}
- */
- async sign(algorithm, key, data) {
- webidl.assertBranded(this, SubtleCrypto);
- const prefix = "Failed to execute 'sign' on 'SubtleCrypto'";
- webidl.requiredArguments(arguments.length, 3, { prefix });
- algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
- prefix,
- context: "Argument 1",
- });
- key = webidl.converters.CryptoKey(key, {
- prefix,
- context: "Argument 2",
- });
- data = webidl.converters.BufferSource(data, {
- prefix,
- context: "Argument 3",
- });
-
- // 1.
- if (ArrayBufferIsView(data)) {
- data = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
- } else {
- data = new Uint8Array(data);
- }
- data = TypedArrayPrototypeSlice(data);
-
- // 2.
- const normalizedAlgorithm = normalizeAlgorithm(algorithm, "sign");
-
- const handle = key[_handle];
- const keyData = WeakMapPrototypeGet(KEY_STORE, handle);
-
- // 8.
- if (normalizedAlgorithm.name !== key[_algorithm].name) {
- throw new DOMException(
- "Signing algorithm doesn't match key algorithm.",
- "InvalidAccessError",
- );
- }
-
- // 9.
- if (!ArrayPrototypeIncludes(key[_usages], "sign")) {
- throw new DOMException(
- "Key does not support the 'sign' operation.",
- "InvalidAccessError",
- );
- }
-
- switch (normalizedAlgorithm.name) {
- case "RSASSA-PKCS1-v1_5": {
- // 1.
- if (key[_type] !== "private") {
- throw new DOMException(
- "Key type not supported",
- "InvalidAccessError",
- );
- }
-
- // 2.
- const hashAlgorithm = key[_algorithm].hash.name;
- const signature = await core.opAsync("op_crypto_sign_key", {
- key: keyData,
- algorithm: "RSASSA-PKCS1-v1_5",
- hash: hashAlgorithm,
- }, data);
-
- return signature.buffer;
- }
- case "RSA-PSS": {
- // 1.
- if (key[_type] !== "private") {
- throw new DOMException(
- "Key type not supported",
- "InvalidAccessError",
- );
- }
-
- // 2.
- const hashAlgorithm = key[_algorithm].hash.name;
- const signature = await core.opAsync("op_crypto_sign_key", {
- key: keyData,
- algorithm: "RSA-PSS",
- hash: hashAlgorithm,
- saltLength: normalizedAlgorithm.saltLength,
- }, data);
-
- return signature.buffer;
- }
- case "ECDSA": {
- // 1.
- if (key[_type] !== "private") {
- throw new DOMException(
- "Key type not supported",
- "InvalidAccessError",
- );
- }
-
- // 2.
- const hashAlgorithm = normalizedAlgorithm.hash.name;
- const namedCurve = key[_algorithm].namedCurve;
- if (!ArrayPrototypeIncludes(supportedNamedCurves, namedCurve)) {
- throw new DOMException("Curve not supported", "NotSupportedError");
- }
-
- const signature = await core.opAsync("op_crypto_sign_key", {
- key: keyData,
- algorithm: "ECDSA",
- hash: hashAlgorithm,
- namedCurve,
- }, data);
-
- return signature.buffer;
- }
- case "HMAC": {
- const hashAlgorithm = key[_algorithm].hash.name;
-
- const signature = await core.opAsync("op_crypto_sign_key", {
- key: keyData,
- algorithm: "HMAC",
- hash: hashAlgorithm,
- }, data);
-
- return signature.buffer;
- }
- }
-
- throw new TypeError("unreachable");
- }
-
- /**
- * @param {string} format
- * @param {BufferSource} keyData
- * @param {string} algorithm
- * @param {boolean} extractable
- * @param {KeyUsages[]} keyUsages
- * @returns {Promise<any>}
- */
- // deno-lint-ignore require-await
- async importKey(format, keyData, algorithm, extractable, keyUsages) {
- webidl.assertBranded(this, SubtleCrypto);
- const prefix = "Failed to execute 'importKey' on 'SubtleCrypto'";
- webidl.requiredArguments(arguments.length, 4, { prefix });
- format = webidl.converters.KeyFormat(format, {
- prefix,
- context: "Argument 1",
- });
- keyData = webidl.converters.BufferSource(keyData, {
- prefix,
- context: "Argument 2",
- });
- algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
- prefix,
- context: "Argument 3",
- });
- extractable = webidl.converters.boolean(extractable, {
- prefix,
- context: "Argument 4",
- });
- keyUsages = webidl.converters["sequence<KeyUsage>"](keyUsages, {
- prefix,
- context: "Argument 5",
- });
-
- const normalizedAlgorithm = normalizeAlgorithm(algorithm, "importKey");
-
- if (
- ArrayPrototypeFind(
- keyUsages,
- (u) => !ArrayPrototypeIncludes(["sign", "verify"], u),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
-
- switch (normalizedAlgorithm.name) {
- // https://w3c.github.io/webcrypto/#hmac-operations
- case "HMAC": {
- switch (format) {
- case "raw": {
- const hash = normalizedAlgorithm.hash;
- // 5.
- let length = keyData.byteLength * 8;
- // 6.
- if (length === 0) {
- throw new DOMException("Key length is zero", "DataError");
- }
- if (normalizeAlgorithm.length) {
- // 7.
- if (
- normalizedAlgorithm.length > length ||
- normalizedAlgorithm.length <= (length - 8)
- ) {
- throw new DOMException(
- "Key length is invalid",
- "DataError",
- );
- }
- length = normalizeAlgorithm.length;
- }
-
- if (keyUsages.length == 0) {
- throw new DOMException("Key usage is empty", "SyntaxError");
- }
-
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, {
- type: "raw",
- data: keyData,
- });
-
- const algorithm = {
- name: "HMAC",
- length,
- hash,
- };
-
- const key = constructKey(
- "secret",
- true,
- usageIntersection(keyUsages, recognisedUsages),
- algorithm,
- handle,
- );
-
- return key;
- }
- // TODO(@littledivy): jwk
- default:
- throw new DOMException("Not implemented", "NotSupportedError");
- }
- }
- // TODO(@littledivy): RSASSA-PKCS1-v1_5
- // TODO(@littledivy): RSA-PSS
- // TODO(@littledivy): ECDSA
- default:
- throw new DOMException("Not implemented", "NotSupportedError");
- }
- }
-
- /**
- * @param {string} format
- * @param {CryptoKey} key
- * @returns {Promise<any>}
- */
- // deno-lint-ignore require-await
- async exportKey(format, key) {
- webidl.assertBranded(this, SubtleCrypto);
- const prefix = "Failed to execute 'exportKey' on 'SubtleCrypto'";
- webidl.requiredArguments(arguments.length, 2, { prefix });
- format = webidl.converters.KeyFormat(format, {
- prefix,
- context: "Argument 1",
- });
- key = webidl.converters.CryptoKey(key, {
- prefix,
- context: "Argument 2",
- });
-
- const handle = key[_handle];
- // 2.
- const bits = WeakMapPrototypeGet(KEY_STORE, handle);
-
- switch (key[_algorithm].name) {
- case "HMAC": {
- if (bits == null) {
- throw new DOMException("Key is not available", "OperationError");
- }
- switch (format) {
- // 3.
- case "raw": {
- for (let _i = 7 & (8 - bits.length % 8); _i > 0; _i--) {
- bits.push(0);
- }
- // 4-5.
- return bits.buffer;
- }
- // TODO(@littledivy): jwk
- default:
- throw new DOMException("Not implemented", "NotSupportedError");
- }
- }
- // TODO(@littledivy): RSASSA-PKCS1-v1_5
- // TODO(@littledivy): RSA-PSS
- // TODO(@littledivy): ECDSA
- default:
- throw new DOMException("Not implemented", "NotSupportedError");
- }
- }
-
- /**
- * @param {string} algorithm
- * @param {CryptoKey} key
- * @param {BufferSource} signature
- * @param {BufferSource} data
- * @returns {Promise<boolean>}
- */
- async verify(algorithm, key, signature, data) {
- webidl.assertBranded(this, SubtleCrypto);
- const prefix = "Failed to execute 'verify' on 'SubtleCrypto'";
- webidl.requiredArguments(arguments.length, 4, { prefix });
- algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
- prefix,
- context: "Argument 1",
- });
- key = webidl.converters.CryptoKey(key, {
- prefix,
- context: "Argument 2",
- });
- signature = webidl.converters.BufferSource(signature, {
- prefix,
- context: "Argument 3",
- });
- data = webidl.converters.BufferSource(data, {
- prefix,
- context: "Argument 4",
- });
-
- // 2.
- if (ArrayBufferIsView(signature)) {
- signature = new Uint8Array(
- signature.buffer,
- signature.byteOffset,
- signature.byteLength,
- );
- } else {
- signature = new Uint8Array(signature);
- }
- signature = TypedArrayPrototypeSlice(signature);
-
- // 3.
- if (ArrayBufferIsView(data)) {
- data = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
- } else {
- data = new Uint8Array(data);
- }
- data = TypedArrayPrototypeSlice(data);
-
- const normalizedAlgorithm = normalizeAlgorithm(algorithm, "verify");
-
- const handle = key[_handle];
- const keyData = WeakMapPrototypeGet(KEY_STORE, handle);
-
- if (normalizedAlgorithm.name !== key[_algorithm].name) {
- throw new DOMException(
- "Verifying algorithm doesn't match key algorithm.",
- "InvalidAccessError",
- );
- }
-
- if (!ArrayPrototypeIncludes(key[_usages], "verify")) {
- throw new DOMException(
- "Key does not support the 'verify' operation.",
- "InvalidAccessError",
- );
- }
-
- switch (normalizedAlgorithm.name) {
- case "RSASSA-PKCS1-v1_5": {
- if (key[_type] !== "public") {
- throw new DOMException(
- "Key type not supported",
- "InvalidAccessError",
- );
- }
-
- const hashAlgorithm = key[_algorithm].hash.name;
- return await core.opAsync("op_crypto_verify_key", {
- key: keyData,
- algorithm: "RSASSA-PKCS1-v1_5",
- hash: hashAlgorithm,
- signature,
- }, data);
- }
- case "RSA-PSS": {
- if (key[_type] !== "public") {
- throw new DOMException(
- "Key type not supported",
- "InvalidAccessError",
- );
- }
-
- const hashAlgorithm = key[_algorithm].hash.name;
- const saltLength = normalizedAlgorithm.saltLength;
- return await core.opAsync("op_crypto_verify_key", {
- key: keyData,
- algorithm: "RSA-PSS",
- hash: hashAlgorithm,
- saltLength,
- signature,
- }, data);
- }
- case "HMAC": {
- const hash = key[_algorithm].hash.name;
- return await core.opAsync("op_crypto_verify_key", {
- key: keyData,
- algorithm: "HMAC",
- hash,
- signature,
- }, data);
- }
- }
-
- throw new TypeError("unreachable");
- }
-
- /**
- * @param {string} algorithm
- * @param {boolean} extractable
- * @param {KeyUsage[]} keyUsages
- * @returns {Promise<any>}
- */
- async generateKey(algorithm, extractable, keyUsages) {
- webidl.assertBranded(this, SubtleCrypto);
- const prefix = "Failed to execute 'generateKey' on 'SubtleCrypto'";
- webidl.requiredArguments(arguments.length, 3, { prefix });
- algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
- prefix,
- context: "Argument 1",
- });
- extractable = webidl.converters["boolean"](extractable, {
- prefix,
- context: "Argument 2",
- });
- keyUsages = webidl.converters["sequence<KeyUsage>"](keyUsages, {
- prefix,
- context: "Argument 3",
- });
-
- const usages = keyUsages;
-
- const normalizedAlgorithm = normalizeAlgorithm(algorithm, "generateKey");
-
- // https://github.com/denoland/deno/pull/9614#issuecomment-866049433
- if (!extractable) {
- throw new DOMException(
- "Non-extractable keys are not supported",
- "SecurityError",
- );
- }
-
- const result = await generateKey(
- normalizedAlgorithm,
- extractable,
- usages,
- );
-
- if (result instanceof CryptoKey) {
- const type = result[_type];
- if ((type === "secret" || type === "private") && usages.length === 0) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
- } else if (result.privateKey instanceof CryptoKey) {
- if (result.privateKey[_usages].length === 0) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
- }
-
- return result;
- }
-
- get [SymbolToStringTag]() {
- return "SubtleCrypto";
- }
- }
-
- async function generateKey(normalizedAlgorithm, extractable, usages) {
- switch (normalizedAlgorithm.name) {
- case "RSASSA-PKCS1-v1_5":
- case "RSA-PSS": {
- // 1.
- if (
- ArrayPrototypeFind(
- usages,
- (u) => !ArrayPrototypeIncludes(["sign", "verify"], u),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
-
- // 2.
- const keyData = await core.opAsync(
- "op_crypto_generate_key",
- {
- name: normalizedAlgorithm.name,
- modulusLength: normalizedAlgorithm.modulusLength,
- publicExponent: normalizedAlgorithm.publicExponent,
- },
- );
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, {
- type: "pkcs8",
- data: keyData,
- });
-
- // 4-8.
- const algorithm = {
- name: normalizedAlgorithm.name,
- modulusLength: normalizedAlgorithm.modulusLength,
- publicExponent: normalizedAlgorithm.publicExponent,
- hash: normalizedAlgorithm.hash,
- };
-
- // 9-13.
- const publicKey = constructKey(
- "public",
- true,
- usageIntersection(usages, ["verify"]),
- algorithm,
- handle,
- );
-
- // 14-18.
- const privateKey = constructKey(
- "private",
- extractable,
- usageIntersection(usages, ["sign"]),
- algorithm,
- handle,
- );
-
- // 19-22.
- return { publicKey, privateKey };
- }
- // TODO(lucacasonato): RSA-OAEP
- case "ECDSA": {
- // 1.
- if (
- ArrayPrototypeFind(
- usages,
- (u) => !ArrayPrototypeIncludes(["sign", "verify"], u),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
-
- // 2-3.
- const handle = {};
- if (
- ArrayPrototypeIncludes(
- supportedNamedCurves,
- normalizedAlgorithm.namedCurve,
- )
- ) {
- const keyData = await core.opAsync("op_crypto_generate_key", {
- name: "ECDSA",
- namedCurve: normalizedAlgorithm.namedCurve,
- });
- WeakMapPrototypeSet(KEY_STORE, handle, {
- type: "pkcs8",
- data: keyData,
- });
- } else {
- throw new DOMException("Curve not supported", "NotSupportedError");
- }
-
- // 4-6.
- const algorithm = {
- name: "ECDSA",
- namedCurve: normalizedAlgorithm.namedCurve,
- };
-
- // 7-11.
- const publicKey = constructKey(
- "public",
- true,
- usageIntersection(usages, ["verify"]),
- algorithm,
- handle,
- );
-
- // 12-16.
- const privateKey = constructKey(
- "private",
- extractable,
- usageIntersection(usages, ["sign"]),
- algorithm,
- handle,
- );
-
- // 17-20.
- return { publicKey, privateKey };
- }
- // TODO(lucacasonato): ECDH
- // TODO(lucacasonato): AES-CTR
- // TODO(lucacasonato): AES-CBC
- // TODO(lucacasonato): AES-GCM
- // TODO(lucacasonato): AES-KW
- case "HMAC": {
- // 1.
- if (
- ArrayPrototypeFind(
- usages,
- (u) => !ArrayPrototypeIncludes(["sign", "verify"], u),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
-
- // 2.
- let length;
- if (normalizedAlgorithm.length === undefined) {
- length = null;
- } else if (normalizedAlgorithm.length !== 0) {
- length = normalizedAlgorithm.length;
- } else {
- throw new DOMException("Invalid length", "OperationError");
- }
-
- // 3-4.
- const keyData = await core.opAsync("op_crypto_generate_key", {
- name: "HMAC",
- hash: normalizedAlgorithm.hash.name,
- length,
- });
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, { type: "raw", data: keyData });
-
- // 6-10.
- const algorithm = {
- name: "HMAC",
- hash: {
- name: normalizedAlgorithm.hash.name,
- },
- length: keyData.byteLength * 8,
- };
-
- // 5, 11-13.
- const key = constructKey(
- "secret",
- extractable,
- usages,
- algorithm,
- handle,
- );
-
- // 14.
- return key;
- }
- }
- }
-
- const subtle = webidl.createBranded(SubtleCrypto);
-
- class Crypto {
- constructor() {
- webidl.illegalConstructor();
- }
-
- getRandomValues(arrayBufferView) {
- webidl.assertBranded(this, Crypto);
- const prefix = "Failed to execute 'getRandomValues' on 'Crypto'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- arrayBufferView = webidl.converters.ArrayBufferView(arrayBufferView, {
- prefix,
- context: "Argument 1",
- });
- if (
- !(
- arrayBufferView instanceof Int8Array ||
- arrayBufferView instanceof Uint8Array ||
- arrayBufferView instanceof Uint8ClampedArray ||
- arrayBufferView instanceof Int16Array ||
- arrayBufferView instanceof Uint16Array ||
- arrayBufferView instanceof Int32Array ||
- arrayBufferView instanceof Uint32Array ||
- arrayBufferView instanceof BigInt64Array ||
- arrayBufferView instanceof BigUint64Array
- )
- ) {
- throw new DOMException(
- "The provided ArrayBufferView is not an integer array type",
- "TypeMismatchError",
- );
- }
- const ui8 = new Uint8Array(
- arrayBufferView.buffer,
- arrayBufferView.byteOffset,
- arrayBufferView.byteLength,
- );
- core.opSync("op_crypto_get_random_values", ui8);
- return arrayBufferView;
- }
-
- randomUUID() {
- webidl.assertBranded(this, Crypto);
- return core.opSync("op_crypto_random_uuid");
- }
-
- get subtle() {
- webidl.assertBranded(this, Crypto);
- return subtle;
- }
-
- get [SymbolToStringTag]() {
- return "Crypto";
- }
-
- [SymbolFor("Deno.customInspect")](inspect) {
- return `${this.constructor.name} ${inspect({})}`;
- }
- }
-
- webidl.configurePrototype(Crypto);
-
- window.__bootstrap.crypto = {
- SubtleCrypto,
- crypto: webidl.createBranded(Crypto),
- Crypto,
- CryptoKey,
- };
-})(this);
diff --git a/extensions/crypto/01_webidl.js b/extensions/crypto/01_webidl.js
deleted file mode 100644
index 7e78170b4..000000000
--- a/extensions/crypto/01_webidl.js
+++ /dev/null
@@ -1,188 +0,0 @@
-// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
-
-// @ts-check
-/// <reference path="../../core/lib.deno_core.d.ts" />
-/// <reference path="../webidl/internal.d.ts" />
-
-"use strict";
-
-((window) => {
- const webidl = window.__bootstrap.webidl;
- const { CryptoKey } = window.__bootstrap.crypto;
-
- webidl.converters.AlgorithmIdentifier = (V, opts) => {
- // Union for (object or DOMString)
- if (webidl.type(V) == "Object") {
- return webidl.converters.object(V, opts);
- }
- return webidl.converters.DOMString(V, opts);
- };
-
- webidl.converters.KeyType = webidl.createEnumConverter("KeyType", [
- "public",
- "private",
- "secret",
- ]);
-
- webidl.converters.KeyFormat = webidl.createEnumConverter("KeyFormat", [
- "raw",
- "pkcs8",
- "spki",
- "jwk",
- ]);
-
- webidl.converters.KeyUsage = webidl.createEnumConverter("KeyUsage", [
- "encrypt",
- "decrypt",
- "sign",
- "verify",
- "deriveKey",
- "deriveBits",
- "wrapKey",
- "unwrapKey",
- ]);
-
- webidl.converters["sequence<KeyUsage>"] = webidl.createSequenceConverter(
- webidl.converters.KeyUsage,
- );
-
- webidl.converters.HashAlgorithmIdentifier =
- webidl.converters.AlgorithmIdentifier;
-
- /** @type {__bootstrap.webidl.Dictionary} */
- const dictAlgorithm = [{
- key: "name",
- converter: webidl.converters.DOMString,
- required: true,
- }];
-
- webidl.converters.Algorithm = webidl
- .createDictionaryConverter("Algorithm", dictAlgorithm);
-
- webidl.converters.BigInteger = webidl.converters.Uint8Array;
-
- /** @type {__bootstrap.webidl.Dictionary} */
- const dictRsaKeyGenParams = [
- ...dictAlgorithm,
- {
- key: "modulusLength",
- converter: (V, opts) =>
- webidl.converters["unsigned long"](V, { ...opts, enforceRange: true }),
- required: true,
- },
- {
- key: "publicExponent",
- converter: webidl.converters.BigInteger,
- required: true,
- },
- ];
-
- webidl.converters.RsaKeyGenParams = webidl
- .createDictionaryConverter("RsaKeyGenParams", dictRsaKeyGenParams);
-
- const dictRsaHashedKeyGenParams = [
- ...dictRsaKeyGenParams,
- {
- key: "hash",
- converter: webidl.converters.HashAlgorithmIdentifier,
- required: true,
- },
- ];
-
- webidl.converters.RsaHashedKeyGenParams = webidl.createDictionaryConverter(
- "RsaHashedKeyGenParams",
- dictRsaHashedKeyGenParams,
- );
-
- webidl.converters.NamedCurve = webidl.converters.DOMString;
-
- const dictEcKeyGenParams = [
- ...dictAlgorithm,
- {
- key: "namedCurve",
- converter: webidl.converters.NamedCurve,
- required: true,
- },
- ];
-
- webidl.converters.EcKeyGenParams = webidl
- .createDictionaryConverter("EcKeyGenParams", dictEcKeyGenParams);
-
- const dictHmacKeyGenParams = [
- ...dictAlgorithm,
- {
- key: "hash",
- converter: webidl.converters.HashAlgorithmIdentifier,
- required: true,
- },
- {
- key: "length",
- converter: (V, opts) =>
- webidl.converters["unsigned long"](V, { ...opts, enforceRange: true }),
- },
- ];
-
- webidl.converters.HmacKeyGenParams = webidl
- .createDictionaryConverter("HmacKeyGenParams", dictHmacKeyGenParams);
-
- const dictRsaPssParams = [
- ...dictAlgorithm,
- {
- key: "saltLength",
- converter: (V, opts) =>
- webidl.converters["unsigned long"](V, { ...opts, enforceRange: true }),
- required: true,
- },
- ];
-
- webidl.converters.RsaPssParams = webidl
- .createDictionaryConverter("RsaPssParams", dictRsaPssParams);
-
- const dictEcdsaParams = [
- ...dictAlgorithm,
- {
- key: "hash",
- converter: webidl.converters.HashAlgorithmIdentifier,
- required: true,
- },
- ];
-
- webidl.converters["EcdsaParams"] = webidl
- .createDictionaryConverter("EcdsaParams", dictEcdsaParams);
-
- const dictHmacImportParams = [
- ...dictAlgorithm,
- {
- key: "hash",
- converter: webidl.converters.HashAlgorithmIdentifier,
- required: true,
- },
- {
- key: "length",
- converter: (V, opts) =>
- webidl.converters["unsigned long"](V, { ...opts, enforceRange: true }),
- },
- ];
-
- webidl.converters.HmacImportParams = webidl
- .createDictionaryConverter("HmacImportParams", dictHmacImportParams);
-
- webidl.converters.CryptoKey = webidl.createInterfaceConverter(
- "CryptoKey",
- CryptoKey,
- );
-
- const dictCryptoKeyPair = [
- {
- key: "publicKey",
- converter: webidl.converters.CryptoKey,
- },
- {
- key: "privateKey",
- converter: webidl.converters.CryptoKey,
- },
- ];
-
- webidl.converters.CryptoKeyPair = webidl
- .createDictionaryConverter("CryptoKeyPair", dictCryptoKeyPair);
-})(this);
diff --git a/extensions/crypto/Cargo.toml b/extensions/crypto/Cargo.toml
deleted file mode 100644
index 8eb939e86..000000000
--- a/extensions/crypto/Cargo.toml
+++ /dev/null
@@ -1,28 +0,0 @@
-# Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
-
-[package]
-name = "deno_crypto"
-version = "0.28.0"
-authors = ["the Deno authors"]
-edition = "2018"
-license = "MIT"
-readme = "README.md"
-repository = "https://github.com/denoland/deno"
-description = "Web Cryptography API implementation for Deno"
-
-[lib]
-path = "lib.rs"
-
-[dependencies]
-deno_core = { version = "0.96.0", path = "../../core" }
-deno_web = { version = "0.45.0", path = "../web" }
-lazy_static = "1.4.0"
-num-traits = "0.2.14"
-rand = "0.8.4"
-ring = { version = "0.16.20", features = ["std"] }
-rsa = { version = "0.5.0", default-features = false, features = ["std"] }
-serde = { version = "1.0.126", features = ["derive"] }
-sha-1 = "0.9.7"
-sha2 = "0.9.5"
-tokio = { version = "1.8.1", features = ["full"] }
-uuid = { version = "0.8.2", features = ["v4"] }
diff --git a/extensions/crypto/README.md b/extensions/crypto/README.md
deleted file mode 100644
index be0724458..000000000
--- a/extensions/crypto/README.md
+++ /dev/null
@@ -1,5 +0,0 @@
-# deno_crypto
-
-This crate implements the Web Cryptography API.
-
-Spec: https://www.w3.org/TR/WebCryptoAPI/
diff --git a/extensions/crypto/key.rs b/extensions/crypto/key.rs
deleted file mode 100644
index cb44812fd..000000000
--- a/extensions/crypto/key.rs
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
-
-use ring::agreement::Algorithm as RingAlgorithm;
-use ring::digest;
-use ring::hmac::Algorithm as HmacAlgorithm;
-use ring::signature::EcdsaSigningAlgorithm;
-use serde::Deserialize;
-use serde::Serialize;
-
-#[derive(Serialize, Deserialize, Copy, Clone)]
-#[serde(rename_all = "camelCase")]
-pub enum KeyType {
- Public,
- Private,
- Secret,
-}
-
-#[derive(Serialize, Deserialize, Copy, Clone)]
-pub enum CryptoHash {
- #[serde(rename = "SHA-1")]
- Sha1,
- #[serde(rename = "SHA-256")]
- Sha256,
- #[serde(rename = "SHA-384")]
- Sha384,
- #[serde(rename = "SHA-512")]
- Sha512,
-}
-
-#[derive(Serialize, Deserialize, Copy, Clone)]
-pub enum CryptoNamedCurve {
- #[serde(rename = "P-256")]
- P256,
- #[serde(rename = "P-384")]
- P384,
-}
-
-impl From<CryptoNamedCurve> for &RingAlgorithm {
- fn from(curve: CryptoNamedCurve) -> &'static RingAlgorithm {
- match curve {
- CryptoNamedCurve::P256 => &ring::agreement::ECDH_P256,
- CryptoNamedCurve::P384 => &ring::agreement::ECDH_P384,
- }
- }
-}
-
-impl From<CryptoNamedCurve> for &EcdsaSigningAlgorithm {
- fn from(curve: CryptoNamedCurve) -> &'static EcdsaSigningAlgorithm {
- match curve {
- CryptoNamedCurve::P256 => {
- &ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING
- }
- CryptoNamedCurve::P384 => {
- &ring::signature::ECDSA_P384_SHA384_FIXED_SIGNING
- }
- }
- }
-}
-
-impl From<CryptoHash> for HmacAlgorithm {
- fn from(hash: CryptoHash) -> HmacAlgorithm {
- match hash {
- CryptoHash::Sha1 => ring::hmac::HMAC_SHA1_FOR_LEGACY_USE_ONLY,
- CryptoHash::Sha256 => ring::hmac::HMAC_SHA256,
- CryptoHash::Sha384 => ring::hmac::HMAC_SHA384,
- CryptoHash::Sha512 => ring::hmac::HMAC_SHA512,
- }
- }
-}
-
-impl From<CryptoHash> for &'static digest::Algorithm {
- fn from(hash: CryptoHash) -> &'static digest::Algorithm {
- match hash {
- CryptoHash::Sha1 => &digest::SHA1_FOR_LEGACY_USE_ONLY,
- CryptoHash::Sha256 => &digest::SHA256,
- CryptoHash::Sha384 => &digest::SHA384,
- CryptoHash::Sha512 => &digest::SHA512,
- }
- }
-}
-
-#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq)]
-#[serde(rename_all = "camelCase")]
-pub enum KeyUsage {
- Encrypt,
- Decrypt,
- Sign,
- Verify,
- DeriveKey,
- DeriveBits,
- WrapKey,
- UnwrapKey,
-}
-
-#[derive(Serialize, Deserialize, Clone, Copy)]
-pub enum Algorithm {
- #[serde(rename = "RSASSA-PKCS1-v1_5")]
- RsassaPkcs1v15,
- #[serde(rename = "RSA-PSS")]
- RsaPss,
- #[serde(rename = "RSA-OAEP")]
- RsaOaep,
- #[serde(rename = "ECDSA")]
- Ecdsa,
- #[serde(rename = "ECDH")]
- Ecdh,
- #[serde(rename = "AES-CTR")]
- AesCtr,
- #[serde(rename = "AES-CBC")]
- AesCbc,
- #[serde(rename = "AES-GCM")]
- AesGcm,
- #[serde(rename = "AES-KW")]
- AesKw,
- #[serde(rename = "HMAC")]
- Hmac,
-}
diff --git a/extensions/crypto/lib.deno_crypto.d.ts b/extensions/crypto/lib.deno_crypto.d.ts
deleted file mode 100644
index b89b62f2e..000000000
--- a/extensions/crypto/lib.deno_crypto.d.ts
+++ /dev/null
@@ -1,155 +0,0 @@
-// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
-
-/// <reference no-default-lib="true" />
-/// <reference lib="esnext" />
-
-declare var crypto: Crypto;
-
-interface Algorithm {
- name: string;
-}
-
-interface KeyAlgorithm {
- name: string;
-}
-
-type AlgorithmIdentifier = string | Algorithm;
-type HashAlgorithmIdentifier = AlgorithmIdentifier;
-type KeyType = "private" | "public" | "secret";
-type KeyUsage =
- | "decrypt"
- | "deriveBits"
- | "deriveKey"
- | "encrypt"
- | "sign"
- | "unwrapKey"
- | "verify"
- | "wrapKey";
-
-type NamedCurve = string;
-
-interface HmacKeyGenParams extends Algorithm {
- hash: HashAlgorithmIdentifier;
- length?: number;
-}
-
-interface EcKeyGenParams extends Algorithm {
- namedCurve: NamedCurve;
-}
-
-interface EcdsaParams extends Algorithm {
- hash: HashAlgorithmIdentifier;
-}
-
-interface RsaHashedKeyGenParams extends RsaKeyGenParams {
- hash: HashAlgorithmIdentifier;
-}
-
-interface RsaKeyGenParams extends Algorithm {
- modulusLength: number;
- publicExponent: Uint8Array;
-}
-
-interface RsaPssParams extends Algorithm {
- saltLength: number;
-}
-
-interface HmacImportParams extends Algorithm {
- hash: HashAlgorithmIdentifier;
- length?: number;
-}
-
-/** The CryptoKey dictionary of the Web Crypto API represents a cryptographic key. */
-interface CryptoKey {
- readonly algorithm: KeyAlgorithm;
- readonly extractable: boolean;
- readonly type: KeyType;
- readonly usages: KeyUsage[];
-}
-
-declare var CryptoKey: {
- prototype: CryptoKey;
- new (): CryptoKey;
-};
-
-/** The CryptoKeyPair dictionary of the Web Crypto API represents a key pair for an asymmetric cryptography algorithm, also known as a public-key algorithm. */
-interface CryptoKeyPair {
- privateKey: CryptoKey;
- publicKey: CryptoKey;
-}
-
-declare var CryptoKeyPair: {
- prototype: CryptoKeyPair;
- new (): CryptoKeyPair;
-};
-
-/** This Web Crypto API interface provides a number of low-level cryptographic functions. It is accessed via the Crypto.subtle properties available in a window context (via Window.crypto). */
-interface SubtleCrypto {
- generateKey(
- algorithm: RsaHashedKeyGenParams | EcKeyGenParams,
- extractable: boolean,
- keyUsages: KeyUsage[],
- ): Promise<CryptoKeyPair>;
- generateKey(
- algorithm: HmacKeyGenParams,
- extractable: boolean,
- keyUsages: KeyUsage[],
- ): Promise<CryptoKey>;
- generateKey(
- algorithm: AlgorithmIdentifier,
- extractable: boolean,
- keyUsages: KeyUsage[],
- ): Promise<CryptoKeyPair | CryptoKey>;
- importKey(
- format: "raw",
- keyData: BufferSource,
- algorithm: AlgorithmIdentifier | HmacImportParams,
- extractable: boolean,
- keyUsages: KeyUsage[],
- ): Promise<CryptoKey>;
- sign(
- algorithm: AlgorithmIdentifier | RsaPssParams | EcdsaParams,
- key: CryptoKey,
- data: BufferSource,
- ): Promise<ArrayBuffer>;
- verify(
- algorithm: AlgorithmIdentifier | RsaPssParams,
- key: CryptoKey,
- signature: BufferSource,
- data: BufferSource,
- ): Promise<boolean>;
- digest(
- algorithm: AlgorithmIdentifier,
- data: BufferSource,
- ): Promise<ArrayBuffer>;
-}
-
-declare interface Crypto {
- readonly subtle: SubtleCrypto;
- getRandomValues<
- T extends
- | Int8Array
- | Int16Array
- | Int32Array
- | Uint8Array
- | Uint16Array
- | Uint32Array
- | Uint8ClampedArray
- | Float32Array
- | Float64Array
- | DataView
- | null,
- >(
- array: T,
- ): T;
- randomUUID(): string;
-}
-
-interface Algorithm {
- name: string;
-}
-
-declare var SubtleCrypto: {
- prototype: SubtleCrypto;
- new (): SubtleCrypto;
-};
diff --git a/extensions/crypto/lib.rs b/extensions/crypto/lib.rs
deleted file mode 100644
index 5989b121a..000000000
--- a/extensions/crypto/lib.rs
+++ /dev/null
@@ -1,558 +0,0 @@
-// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
-
-use deno_core::error::custom_error;
-use deno_core::error::not_supported;
-use deno_core::error::null_opbuf;
-use deno_core::error::type_error;
-use deno_core::error::AnyError;
-use deno_core::include_js_files;
-use deno_core::op_async;
-use deno_core::op_sync;
-use deno_core::Extension;
-use deno_core::OpState;
-use deno_core::ZeroCopyBuf;
-use serde::Deserialize;
-
-use std::cell::RefCell;
-use std::convert::TryInto;
-use std::rc::Rc;
-
-use lazy_static::lazy_static;
-use num_traits::cast::FromPrimitive;
-use rand::rngs::OsRng;
-use rand::rngs::StdRng;
-use rand::thread_rng;
-use rand::Rng;
-use rand::SeedableRng;
-use ring::digest;
-use ring::hmac::Algorithm as HmacAlgorithm;
-use ring::hmac::Key as HmacKey;
-use ring::rand as RingRand;
-use ring::rand::SecureRandom;
-use ring::signature::EcdsaKeyPair;
-use ring::signature::EcdsaSigningAlgorithm;
-use rsa::padding::PaddingScheme;
-use rsa::pkcs8::FromPrivateKey;
-use rsa::pkcs8::ToPrivateKey;
-use rsa::BigUint;
-use rsa::PublicKey;
-use rsa::RsaPrivateKey;
-use rsa::RsaPublicKey;
-use sha1::Sha1;
-use sha2::Digest;
-use sha2::Sha256;
-use sha2::Sha384;
-use sha2::Sha512;
-use std::path::PathBuf;
-
-pub use rand; // Re-export rand
-
-mod key;
-
-use crate::key::Algorithm;
-use crate::key::CryptoHash;
-use crate::key::CryptoNamedCurve;
-
-// Allowlist for RSA public exponents.
-lazy_static! {
- static ref PUB_EXPONENT_1: BigUint = BigUint::from_u64(3).unwrap();
- static ref PUB_EXPONENT_2: BigUint = BigUint::from_u64(65537).unwrap();
-}
-
-pub fn init(maybe_seed: Option<u64>) -> Extension {
- Extension::builder()
- .js(include_js_files!(
- prefix "deno:extensions/crypto",
- "00_crypto.js",
- "01_webidl.js",
- ))
- .ops(vec![
- (
- "op_crypto_get_random_values",
- op_sync(op_crypto_get_random_values),
- ),
- ("op_crypto_generate_key", op_async(op_crypto_generate_key)),
- ("op_crypto_sign_key", op_async(op_crypto_sign_key)),
- ("op_crypto_verify_key", op_async(op_crypto_verify_key)),
- ("op_crypto_subtle_digest", op_async(op_crypto_subtle_digest)),
- ("op_crypto_random_uuid", op_sync(op_crypto_random_uuid)),
- ])
- .state(move |state| {
- if let Some(seed) = maybe_seed {
- state.put(StdRng::seed_from_u64(seed));
- }
- Ok(())
- })
- .build()
-}
-
-pub fn op_crypto_get_random_values(
- state: &mut OpState,
- mut zero_copy: ZeroCopyBuf,
- _: (),
-) -> Result<(), AnyError> {
- if zero_copy.len() > 65536 {
- return Err(
- deno_web::DomExceptionQuotaExceededError::new(&format!("The ArrayBufferView's byte length ({}) exceeds the number of bytes of entropy available via this API (65536)", zero_copy.len()))
- .into(),
- );
- }
-
- let maybe_seeded_rng = state.try_borrow_mut::<StdRng>();
- if let Some(seeded_rng) = maybe_seeded_rng {
- seeded_rng.fill(&mut *zero_copy);
- } else {
- let mut rng = thread_rng();
- rng.fill(&mut *zero_copy);
- }
-
- Ok(())
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub struct AlgorithmArg {
- name: Algorithm,
- modulus_length: Option<u32>,
- public_exponent: Option<ZeroCopyBuf>,
- named_curve: Option<CryptoNamedCurve>,
- hash: Option<CryptoHash>,
- length: Option<usize>,
-}
-
-pub async fn op_crypto_generate_key(
- _state: Rc<RefCell<OpState>>,
- args: AlgorithmArg,
- _: (),
-) -> Result<ZeroCopyBuf, AnyError> {
- let algorithm = args.name;
-
- let key = match algorithm {
- Algorithm::RsassaPkcs1v15 | Algorithm::RsaPss => {
- let public_exponent = args.public_exponent.ok_or_else(not_supported)?;
- let modulus_length = args.modulus_length.ok_or_else(not_supported)?;
-
- let exponent = BigUint::from_bytes_be(&public_exponent);
- if exponent != *PUB_EXPONENT_1 && exponent != *PUB_EXPONENT_2 {
- return Err(custom_error(
- "DOMExceptionOperationError",
- "Bad public exponent",
- ));
- }
-
- let mut rng = OsRng;
-
- let private_key: RsaPrivateKey = tokio::task::spawn_blocking(
- move || -> Result<RsaPrivateKey, rsa::errors::Error> {
- RsaPrivateKey::new_with_exp(
- &mut rng,
- modulus_length as usize,
- &exponent,
- )
- },
- )
- .await
- .unwrap()
- .map_err(|e| custom_error("DOMExceptionOperationError", e.to_string()))?;
-
- private_key.to_pkcs8_der()?.as_ref().to_vec()
- }
- Algorithm::Ecdsa => {
- let curve: &EcdsaSigningAlgorithm =
- args.named_curve.ok_or_else(not_supported)?.into();
- let rng = RingRand::SystemRandom::new();
- let private_key: Vec<u8> = tokio::task::spawn_blocking(
- move || -> Result<Vec<u8>, ring::error::Unspecified> {
- let pkcs8 = EcdsaKeyPair::generate_pkcs8(curve, &rng)?;
- Ok(pkcs8.as_ref().to_vec())
- },
- )
- .await
- .unwrap()
- .map_err(|_| {
- custom_error("DOMExceptionOperationError", "Key generation failed")
- })?;
-
- private_key
- }
- Algorithm::Hmac => {
- let hash: HmacAlgorithm = args.hash.ok_or_else(not_supported)?.into();
-
- let length = if let Some(length) = args.length {
- if (length % 8) != 0 {
- return Err(custom_error(
- "DOMExceptionOperationError",
- "hmac block length must be byte aligned",
- ));
- }
- let length = length / 8;
- if length > ring::digest::MAX_BLOCK_LEN {
- return Err(custom_error(
- "DOMExceptionOperationError",
- "hmac block length is too large",
- ));
- }
- length
- } else {
- hash.digest_algorithm().block_len
- };
-
- let rng = RingRand::SystemRandom::new();
- let mut key_bytes = [0; ring::digest::MAX_BLOCK_LEN];
- let key_bytes = &mut key_bytes[..length];
- rng.fill(key_bytes).map_err(|_| {
- custom_error("DOMExceptionOperationError", "Key generation failed")
- })?;
-
- key_bytes.to_vec()
- }
- _ => return Err(not_supported()),
- };
-
- Ok(key.into())
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "lowercase")]
-pub enum KeyFormat {
- Raw,
- Pkcs8,
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "lowercase")]
-pub struct KeyData {
- // TODO(littledivy): Kept here to be used to importKey() in future.
- #[allow(dead_code)]
- r#type: KeyFormat,
- data: ZeroCopyBuf,
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub struct SignArg {
- key: KeyData,
- algorithm: Algorithm,
- salt_length: Option<u32>,
- hash: Option<CryptoHash>,
- named_curve: Option<CryptoNamedCurve>,
-}
-
-pub async fn op_crypto_sign_key(
- _state: Rc<RefCell<OpState>>,
- args: SignArg,
- zero_copy: Option<ZeroCopyBuf>,
-) -> Result<ZeroCopyBuf, AnyError> {
- let zero_copy = zero_copy.ok_or_else(null_opbuf)?;
- let data = &*zero_copy;
- let algorithm = args.algorithm;
-
- let signature = match algorithm {
- Algorithm::RsassaPkcs1v15 => {
- let private_key = RsaPrivateKey::from_pkcs8_der(&*args.key.data)?;
- let (padding, hashed) = match args
- .hash
- .ok_or_else(|| type_error("Missing argument hash".to_string()))?
- {
- CryptoHash::Sha1 => {
- let mut hasher = Sha1::new();
- hasher.update(&data);
- (
- PaddingScheme::PKCS1v15Sign {
- hash: Some(rsa::hash::Hash::SHA1),
- },
- hasher.finalize()[..].to_vec(),
- )
- }
- CryptoHash::Sha256 => {
- let mut hasher = Sha256::new();
- hasher.update(&data);
- (
- PaddingScheme::PKCS1v15Sign {
- hash: Some(rsa::hash::Hash::SHA2_256),
- },
- hasher.finalize()[..].to_vec(),
- )
- }
- CryptoHash::Sha384 => {
- let mut hasher = Sha384::new();
- hasher.update(&data);
- (
- PaddingScheme::PKCS1v15Sign {
- hash: Some(rsa::hash::Hash::SHA2_384),
- },
- hasher.finalize()[..].to_vec(),
- )
- }
- CryptoHash::Sha512 => {
- let mut hasher = Sha512::new();
- hasher.update(&data);
- (
- PaddingScheme::PKCS1v15Sign {
- hash: Some(rsa::hash::Hash::SHA2_512),
- },
- hasher.finalize()[..].to_vec(),
- )
- }
- };
-
- private_key.sign(padding, &hashed)?
- }
- Algorithm::RsaPss => {
- let private_key = RsaPrivateKey::from_pkcs8_der(&*args.key.data)?;
-
- let salt_len = args
- .salt_length
- .ok_or_else(|| type_error("Missing argument saltLength".to_string()))?
- as usize;
-
- let rng = OsRng;
- let (padding, digest_in) = match args
- .hash
- .ok_or_else(|| type_error("Missing argument hash".to_string()))?
- {
- CryptoHash::Sha1 => {
- let mut hasher = Sha1::new();
- hasher.update(&data);
- (
- PaddingScheme::new_pss_with_salt::<Sha1, _>(rng, salt_len),
- hasher.finalize()[..].to_vec(),
- )
- }
- CryptoHash::Sha256 => {
- let mut hasher = Sha256::new();
- hasher.update(&data);
- (
- PaddingScheme::new_pss_with_salt::<Sha256, _>(rng, salt_len),
- hasher.finalize()[..].to_vec(),
- )
- }
- CryptoHash::Sha384 => {
- let mut hasher = Sha384::new();
- hasher.update(&data);
- (
- PaddingScheme::new_pss_with_salt::<Sha384, _>(rng, salt_len),
- hasher.finalize()[..].to_vec(),
- )
- }
- CryptoHash::Sha512 => {
- let mut hasher = Sha512::new();
- hasher.update(&data);
- (
- PaddingScheme::new_pss_with_salt::<Sha512, _>(rng, salt_len),
- hasher.finalize()[..].to_vec(),
- )
- }
- };
-
- // Sign data based on computed padding and return buffer
- private_key.sign(padding, &digest_in)?
- }
- Algorithm::Ecdsa => {
- let curve: &EcdsaSigningAlgorithm =
- args.named_curve.ok_or_else(not_supported)?.try_into()?;
-
- let key_pair = EcdsaKeyPair::from_pkcs8(curve, &*args.key.data)?;
- // We only support P256-SHA256 & P384-SHA384. These are recommended signature pairs.
- // https://briansmith.org/rustdoc/ring/signature/index.html#statics
- if let Some(hash) = args.hash {
- match hash {
- CryptoHash::Sha256 | CryptoHash::Sha384 => (),
- _ => return Err(type_error("Unsupported algorithm")),
- }
- };
-
- let rng = RingRand::SystemRandom::new();
- let signature = key_pair.sign(&rng, data)?;
-
- // Signature data as buffer.
- signature.as_ref().to_vec()
- }
- Algorithm::Hmac => {
- let hash: HmacAlgorithm = args.hash.ok_or_else(not_supported)?.into();
-
- let key = HmacKey::new(hash, &*args.key.data);
-
- let signature = ring::hmac::sign(&key, data);
- signature.as_ref().to_vec()
- }
- _ => return Err(type_error("Unsupported algorithm".to_string())),
- };
-
- Ok(signature.into())
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub struct VerifyArg {
- key: KeyData,
- algorithm: Algorithm,
- salt_length: Option<u32>,
- hash: Option<CryptoHash>,
- signature: ZeroCopyBuf,
-}
-
-pub async fn op_crypto_verify_key(
- _state: Rc<RefCell<OpState>>,
- args: VerifyArg,
- zero_copy: Option<ZeroCopyBuf>,
-) -> Result<bool, AnyError> {
- let zero_copy = zero_copy.ok_or_else(null_opbuf)?;
- let data = &*zero_copy;
- let algorithm = args.algorithm;
-
- let verification = match algorithm {
- Algorithm::RsassaPkcs1v15 => {
- let public_key: RsaPublicKey =
- RsaPrivateKey::from_pkcs8_der(&*args.key.data)?.to_public_key();
- let (padding, hashed) = match args
- .hash
- .ok_or_else(|| type_error("Missing argument hash".to_string()))?
- {
- CryptoHash::Sha1 => {
- let mut hasher = Sha1::new();
- hasher.update(&data);
- (
- PaddingScheme::PKCS1v15Sign {
- hash: Some(rsa::hash::Hash::SHA1),
- },
- hasher.finalize()[..].to_vec(),
- )
- }
- CryptoHash::Sha256 => {
- let mut hasher = Sha256::new();
- hasher.update(&data);
- (
- PaddingScheme::PKCS1v15Sign {
- hash: Some(rsa::hash::Hash::SHA2_256),
- },
- hasher.finalize()[..].to_vec(),
- )
- }
- CryptoHash::Sha384 => {
- let mut hasher = Sha384::new();
- hasher.update(&data);
- (
- PaddingScheme::PKCS1v15Sign {
- hash: Some(rsa::hash::Hash::SHA2_384),
- },
- hasher.finalize()[..].to_vec(),
- )
- }
- CryptoHash::Sha512 => {
- let mut hasher = Sha512::new();
- hasher.update(&data);
- (
- PaddingScheme::PKCS1v15Sign {
- hash: Some(rsa::hash::Hash::SHA2_512),
- },
- hasher.finalize()[..].to_vec(),
- )
- }
- };
-
- public_key
- .verify(padding, &hashed, &*args.signature)
- .is_ok()
- }
- Algorithm::RsaPss => {
- let salt_len = args
- .salt_length
- .ok_or_else(|| type_error("Missing argument saltLength".to_string()))?
- as usize;
- let public_key: RsaPublicKey =
- RsaPrivateKey::from_pkcs8_der(&*args.key.data)?.to_public_key();
-
- let rng = OsRng;
- let (padding, hashed) = match args
- .hash
- .ok_or_else(|| type_error("Missing argument hash".to_string()))?
- {
- CryptoHash::Sha1 => {
- let mut hasher = Sha1::new();
- hasher.update(&data);
- (
- PaddingScheme::new_pss_with_salt::<Sha1, _>(rng, salt_len),
- hasher.finalize()[..].to_vec(),
- )
- }
- CryptoHash::Sha256 => {
- let mut hasher = Sha256::new();
- hasher.update(&data);
- (
- PaddingScheme::new_pss_with_salt::<Sha256, _>(rng, salt_len),
- hasher.finalize()[..].to_vec(),
- )
- }
- CryptoHash::Sha384 => {
- let mut hasher = Sha384::new();
- hasher.update(&data);
- (
- PaddingScheme::new_pss_with_salt::<Sha384, _>(rng, salt_len),
- hasher.finalize()[..].to_vec(),
- )
- }
- CryptoHash::Sha512 => {
- let mut hasher = Sha512::new();
- hasher.update(&data);
- (
- PaddingScheme::new_pss_with_salt::<Sha512, _>(rng, salt_len),
- hasher.finalize()[..].to_vec(),
- )
- }
- };
-
- public_key
- .verify(padding, &hashed, &*args.signature)
- .is_ok()
- }
- Algorithm::Hmac => {
- let hash: HmacAlgorithm = args.hash.ok_or_else(not_supported)?.into();
- let key = HmacKey::new(hash, &*args.key.data);
- ring::hmac::verify(&key, data, &*args.signature).is_ok()
- }
- _ => return Err(type_error("Unsupported algorithm".to_string())),
- };
-
- Ok(verification)
-}
-
-pub fn op_crypto_random_uuid(
- state: &mut OpState,
- _: (),
- _: (),
-) -> Result<String, AnyError> {
- let maybe_seeded_rng = state.try_borrow_mut::<StdRng>();
- let uuid = if let Some(seeded_rng) = maybe_seeded_rng {
- let mut bytes = [0u8; 16];
- seeded_rng.fill(&mut bytes);
- uuid::Builder::from_bytes(bytes)
- .set_version(uuid::Version::Random)
- .build()
- } else {
- uuid::Uuid::new_v4()
- };
-
- Ok(uuid.to_string())
-}
-
-pub async fn op_crypto_subtle_digest(
- _state: Rc<RefCell<OpState>>,
- algorithm: CryptoHash,
- data: Option<ZeroCopyBuf>,
-) -> Result<ZeroCopyBuf, AnyError> {
- let input = data.ok_or_else(null_opbuf)?;
- let output = tokio::task::spawn_blocking(move || {
- digest::digest(algorithm.into(), &input)
- .as_ref()
- .to_vec()
- .into()
- })
- .await?;
-
- Ok(output)
-}
-
-pub fn get_declaration() -> PathBuf {
- PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("lib.deno_crypto.d.ts")
-}