summaryrefslogtreecommitdiff
path: root/ext/node/polyfills/internal/crypto
diff options
context:
space:
mode:
authorBartek IwaƄczuk <biwanczuk@gmail.com>2023-02-14 17:38:45 +0100
committerGitHub <noreply@github.com>2023-02-14 17:38:45 +0100
commitd47147fb6ad229b1c039aff9d0959b6e281f4df5 (patch)
tree6e9e790f2b9bc71b5f0c9c7e64b95cae31579d58 /ext/node/polyfills/internal/crypto
parent1d00bbe47e2ca14e2d2151518e02b2324461a065 (diff)
feat(ext/node): embed std/node into the snapshot (#17724)
This commit moves "deno_std/node" in "ext/node" crate. The code is transpiled and snapshotted during the build process. During the first pass a minimal amount of work was done to create the snapshot, a lot of code in "ext/node" depends on presence of "Deno" global. This code will be gradually fixed in the follow up PRs to migrate it to import relevant APIs from "internal:" modules. Currently the code from snapshot is not used in any way, and all Node/npm compatibility still uses code from "https://deno.land/std/node" (or from the location specified by "DENO_NODE_COMPAT_URL"). This will also be handled in a follow up PRs. --------- Co-authored-by: crowlkats <crowlkats@toaxl.com> Co-authored-by: Divy Srivastava <dj.srivastava23@gmail.com> Co-authored-by: Yoshiya Hinosawa <stibium121@gmail.com>
Diffstat (limited to 'ext/node/polyfills/internal/crypto')
-rw-r--r--ext/node/polyfills/internal/crypto/_hex.ts19
-rw-r--r--ext/node/polyfills/internal/crypto/_keys.ts16
-rw-r--r--ext/node/polyfills/internal/crypto/_randomBytes.ts70
-rw-r--r--ext/node/polyfills/internal/crypto/_randomFill.ts84
-rw-r--r--ext/node/polyfills/internal/crypto/_randomInt.ts60
-rw-r--r--ext/node/polyfills/internal/crypto/certificate.ts23
-rw-r--r--ext/node/polyfills/internal/crypto/cipher.ts292
-rw-r--r--ext/node/polyfills/internal/crypto/constants.ts5
-rw-r--r--ext/node/polyfills/internal/crypto/diffiehellman.ts306
-rw-r--r--ext/node/polyfills/internal/crypto/hash.ts230
-rw-r--r--ext/node/polyfills/internal/crypto/hkdf.ts130
-rw-r--r--ext/node/polyfills/internal/crypto/keygen.ts682
-rw-r--r--ext/node/polyfills/internal/crypto/keys.ts294
-rw-r--r--ext/node/polyfills/internal/crypto/pbkdf2.ts183
-rw-r--r--ext/node/polyfills/internal/crypto/random.ts140
-rw-r--r--ext/node/polyfills/internal/crypto/scrypt.ts278
-rw-r--r--ext/node/polyfills/internal/crypto/sig.ts148
-rw-r--r--ext/node/polyfills/internal/crypto/types.ts46
-rw-r--r--ext/node/polyfills/internal/crypto/util.ts129
-rw-r--r--ext/node/polyfills/internal/crypto/x509.ts186
20 files changed, 3321 insertions, 0 deletions
diff --git a/ext/node/polyfills/internal/crypto/_hex.ts b/ext/node/polyfills/internal/crypto/_hex.ts
new file mode 100644
index 000000000..5cc44aaa8
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/_hex.ts
@@ -0,0 +1,19 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+
+// deno-fmt-ignore
+const hexTable = new Uint8Array([
+ 48, 49, 50, 51, 52, 53,
+ 54, 55, 56, 57, 97, 98,
+ 99, 100, 101, 102
+]);
+
+/** Encodes `src` into `src.length * 2` bytes. */
+export function encode(src: Uint8Array): Uint8Array {
+ const dst = new Uint8Array(src.length * 2);
+ for (let i = 0; i < dst.length; i++) {
+ const v = src[i];
+ dst[i * 2] = hexTable[v >> 4];
+ dst[i * 2 + 1] = hexTable[v & 0x0f];
+ }
+ return dst;
+}
diff --git a/ext/node/polyfills/internal/crypto/_keys.ts b/ext/node/polyfills/internal/crypto/_keys.ts
new file mode 100644
index 000000000..794582bf1
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/_keys.ts
@@ -0,0 +1,16 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+import { kKeyObject } from "internal:deno_node/polyfills/internal/crypto/constants.ts";
+
+export const kKeyType = Symbol("kKeyType");
+
+export function isKeyObject(obj: unknown): boolean {
+ return (
+ obj != null && (obj as Record<symbol, unknown>)[kKeyType] !== undefined
+ );
+}
+
+export function isCryptoKey(obj: unknown): boolean {
+ return (
+ obj != null && (obj as Record<symbol, unknown>)[kKeyObject] !== undefined
+ );
+}
diff --git a/ext/node/polyfills/internal/crypto/_randomBytes.ts b/ext/node/polyfills/internal/crypto/_randomBytes.ts
new file mode 100644
index 000000000..41678fcf1
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/_randomBytes.ts
@@ -0,0 +1,70 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+
+export const MAX_RANDOM_VALUES = 65536;
+export const MAX_SIZE = 4294967295;
+
+function generateRandomBytes(size: number) {
+ if (size > MAX_SIZE) {
+ throw new RangeError(
+ `The value of "size" is out of range. It must be >= 0 && <= ${MAX_SIZE}. Received ${size}`,
+ );
+ }
+
+ const bytes = Buffer.allocUnsafe(size);
+
+ //Work around for getRandomValues max generation
+ if (size > MAX_RANDOM_VALUES) {
+ for (let generated = 0; generated < size; generated += MAX_RANDOM_VALUES) {
+ globalThis.crypto.getRandomValues(
+ bytes.slice(generated, generated + MAX_RANDOM_VALUES),
+ );
+ }
+ } else {
+ globalThis.crypto.getRandomValues(bytes);
+ }
+
+ return bytes;
+}
+
+/**
+ * @param size Buffer length, must be equal or greater than zero
+ */
+export default function randomBytes(size: number): Buffer;
+export default function randomBytes(
+ size: number,
+ cb?: (err: Error | null, buf?: Buffer) => void,
+): void;
+export default function randomBytes(
+ size: number,
+ cb?: (err: Error | null, buf?: Buffer) => void,
+): Buffer | void {
+ if (typeof cb === "function") {
+ let err: Error | null = null, bytes: Buffer;
+ try {
+ bytes = generateRandomBytes(size);
+ } catch (e) {
+ //NodeJS nonsense
+ //If the size is out of range it will throw sync, otherwise throw async
+ if (
+ e instanceof RangeError &&
+ e.message.includes('The value of "size" is out of range')
+ ) {
+ throw e;
+ } else if (e instanceof Error) {
+ err = e;
+ } else {
+ err = new Error("[non-error thrown]");
+ }
+ }
+ setTimeout(() => {
+ if (err) {
+ cb(err);
+ } else {
+ cb(null, bytes);
+ }
+ }, 0);
+ } else {
+ return generateRandomBytes(size);
+ }
+}
diff --git a/ext/node/polyfills/internal/crypto/_randomFill.ts b/ext/node/polyfills/internal/crypto/_randomFill.ts
new file mode 100644
index 000000000..045072696
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/_randomFill.ts
@@ -0,0 +1,84 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+import randomBytes, {
+ MAX_SIZE as kMaxUint32,
+} from "internal:deno_node/polyfills/internal/crypto/_randomBytes.ts";
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+
+const kBufferMaxLength = 0x7fffffff;
+
+function assertOffset(offset: number, length: number) {
+ if (offset > kMaxUint32 || offset < 0) {
+ throw new TypeError("offset must be a uint32");
+ }
+
+ if (offset > kBufferMaxLength || offset > length) {
+ throw new RangeError("offset out of range");
+ }
+}
+
+function assertSize(size: number, offset: number, length: number) {
+ if (size > kMaxUint32 || size < 0) {
+ throw new TypeError("size must be a uint32");
+ }
+
+ if (size + offset > length || size > kBufferMaxLength) {
+ throw new RangeError("buffer too small");
+ }
+}
+
+export default function randomFill(
+ buf: Buffer,
+ cb: (err: Error | null, buf: Buffer) => void,
+): void;
+
+export default function randomFill(
+ buf: Buffer,
+ offset: number,
+ cb: (err: Error | null, buf: Buffer) => void,
+): void;
+
+export default function randomFill(
+ buf: Buffer,
+ offset: number,
+ size: number,
+ cb: (err: Error | null, buf: Buffer) => void,
+): void;
+
+export default function randomFill(
+ buf: Buffer,
+ offset?: number | ((err: Error | null, buf: Buffer) => void),
+ size?: number | ((err: Error | null, buf: Buffer) => void),
+ cb?: (err: Error | null, buf: Buffer) => void,
+) {
+ if (typeof offset === "function") {
+ cb = offset;
+ offset = 0;
+ size = buf.length;
+ } else if (typeof size === "function") {
+ cb = size;
+ size = buf.length - Number(offset as number);
+ }
+
+ assertOffset(offset as number, buf.length);
+ assertSize(size as number, offset as number, buf.length);
+
+ randomBytes(size as number, (err, bytes) => {
+ if (err) return cb!(err, buf);
+ bytes?.copy(buf, offset as number);
+ cb!(null, buf);
+ });
+}
+
+export function randomFillSync(buf: Buffer, offset = 0, size?: number) {
+ assertOffset(offset, buf.length);
+
+ if (size === undefined) size = buf.length - offset;
+
+ assertSize(size, offset, buf.length);
+
+ const bytes = randomBytes(size);
+
+ bytes.copy(buf, offset);
+
+ return buf;
+}
diff --git a/ext/node/polyfills/internal/crypto/_randomInt.ts b/ext/node/polyfills/internal/crypto/_randomInt.ts
new file mode 100644
index 000000000..637251541
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/_randomInt.ts
@@ -0,0 +1,60 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+export default function randomInt(max: number): number;
+export default function randomInt(min: number, max: number): number;
+export default function randomInt(
+ max: number,
+ cb: (err: Error | null, n?: number) => void,
+): void;
+export default function randomInt(
+ min: number,
+ max: number,
+ cb: (err: Error | null, n?: number) => void,
+): void;
+
+export default function randomInt(
+ max: number,
+ min?: ((err: Error | null, n?: number) => void) | number,
+ cb?: (err: Error | null, n?: number) => void,
+): number | void {
+ if (typeof max === "number" && typeof min === "number") {
+ [max, min] = [min, max];
+ }
+ if (min === undefined) min = 0;
+ else if (typeof min === "function") {
+ cb = min;
+ min = 0;
+ }
+
+ if (
+ !Number.isSafeInteger(min) ||
+ typeof max === "number" && !Number.isSafeInteger(max)
+ ) {
+ throw new Error("max or min is not a Safe Number");
+ }
+
+ if (max - min > Math.pow(2, 48)) {
+ throw new RangeError("max - min should be less than 2^48!");
+ }
+
+ if (min >= max) {
+ throw new Error("Min is bigger than Max!");
+ }
+
+ const randomBuffer = new Uint32Array(1);
+
+ globalThis.crypto.getRandomValues(randomBuffer);
+
+ const randomNumber = randomBuffer[0] / (0xffffffff + 1);
+
+ min = Math.ceil(min);
+ max = Math.floor(max);
+
+ const result = Math.floor(randomNumber * (max - min)) + min;
+
+ if (cb) {
+ cb(null, result);
+ return;
+ }
+
+ return result;
+}
diff --git a/ext/node/polyfills/internal/crypto/certificate.ts b/ext/node/polyfills/internal/crypto/certificate.ts
new file mode 100644
index 000000000..f6fb333a9
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/certificate.ts
@@ -0,0 +1,23 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license.
+
+import { notImplemented } from "internal:deno_node/polyfills/_utils.ts";
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+import { BinaryLike } from "internal:deno_node/polyfills/internal/crypto/types.ts";
+
+export class Certificate {
+ static Certificate = Certificate;
+ static exportChallenge(_spkac: BinaryLike, _encoding?: string): Buffer {
+ notImplemented("crypto.Certificate.exportChallenge");
+ }
+
+ static exportPublicKey(_spkac: BinaryLike, _encoding?: string): Buffer {
+ notImplemented("crypto.Certificate.exportPublicKey");
+ }
+
+ static verifySpkac(_spkac: BinaryLike, _encoding?: string): boolean {
+ notImplemented("crypto.Certificate.verifySpkac");
+ }
+}
+
+export default Certificate;
diff --git a/ext/node/polyfills/internal/crypto/cipher.ts b/ext/node/polyfills/internal/crypto/cipher.ts
new file mode 100644
index 000000000..2778b40fa
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/cipher.ts
@@ -0,0 +1,292 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license.
+
+import { ERR_INVALID_ARG_TYPE } from "internal:deno_node/polyfills/internal/errors.ts";
+import {
+ validateInt32,
+ validateObject,
+} from "internal:deno_node/polyfills/internal/validators.mjs";
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+import { notImplemented } from "internal:deno_node/polyfills/_utils.ts";
+import type { TransformOptions } from "internal:deno_node/polyfills/_stream.d.ts";
+import { Transform } from "internal:deno_node/polyfills/_stream.mjs";
+import { KeyObject } from "internal:deno_node/polyfills/internal/crypto/keys.ts";
+import type { BufferEncoding } from "internal:deno_node/polyfills/_global.d.ts";
+import type {
+ BinaryLike,
+ Encoding,
+} from "internal:deno_node/polyfills/internal/crypto/types.ts";
+import {
+ privateDecrypt,
+ privateEncrypt,
+ publicDecrypt,
+ publicEncrypt,
+} from "internal:deno_node/polyfills/_crypto/crypto_browserify/public_encrypt/mod.js";
+
+export {
+ privateDecrypt,
+ privateEncrypt,
+ publicDecrypt,
+ publicEncrypt,
+} from "internal:deno_node/polyfills/_crypto/crypto_browserify/public_encrypt/mod.js";
+
+export type CipherCCMTypes =
+ | "aes-128-ccm"
+ | "aes-192-ccm"
+ | "aes-256-ccm"
+ | "chacha20-poly1305";
+export type CipherGCMTypes = "aes-128-gcm" | "aes-192-gcm" | "aes-256-gcm";
+export type CipherOCBTypes = "aes-128-ocb" | "aes-192-ocb" | "aes-256-ocb";
+
+export type CipherKey = BinaryLike | KeyObject;
+
+export interface CipherCCMOptions extends TransformOptions {
+ authTagLength: number;
+}
+
+export interface CipherGCMOptions extends TransformOptions {
+ authTagLength?: number | undefined;
+}
+
+export interface CipherOCBOptions extends TransformOptions {
+ authTagLength: number;
+}
+
+export interface Cipher extends ReturnType<typeof Transform> {
+ update(data: BinaryLike): Buffer;
+ update(data: string, inputEncoding: Encoding): Buffer;
+ update(
+ data: ArrayBufferView,
+ inputEncoding: undefined,
+ outputEncoding: Encoding,
+ ): string;
+ update(
+ data: string,
+ inputEncoding: Encoding | undefined,
+ outputEncoding: Encoding,
+ ): string;
+
+ final(): Buffer;
+ final(outputEncoding: BufferEncoding): string;
+
+ setAutoPadding(autoPadding?: boolean): this;
+}
+
+export type Decipher = Cipher;
+
+export interface CipherCCM extends Cipher {
+ setAAD(
+ buffer: ArrayBufferView,
+ options: {
+ plaintextLength: number;
+ },
+ ): this;
+ getAuthTag(): Buffer;
+}
+
+export interface CipherGCM extends Cipher {
+ setAAD(
+ buffer: ArrayBufferView,
+ options?: {
+ plaintextLength: number;
+ },
+ ): this;
+ getAuthTag(): Buffer;
+}
+
+export interface CipherOCB extends Cipher {
+ setAAD(
+ buffer: ArrayBufferView,
+ options?: {
+ plaintextLength: number;
+ },
+ ): this;
+ getAuthTag(): Buffer;
+}
+
+export interface DecipherCCM extends Decipher {
+ setAuthTag(buffer: ArrayBufferView): this;
+ setAAD(
+ buffer: ArrayBufferView,
+ options: {
+ plaintextLength: number;
+ },
+ ): this;
+}
+
+export interface DecipherGCM extends Decipher {
+ setAuthTag(buffer: ArrayBufferView): this;
+ setAAD(
+ buffer: ArrayBufferView,
+ options?: {
+ plaintextLength: number;
+ },
+ ): this;
+}
+
+export interface DecipherOCB extends Decipher {
+ setAuthTag(buffer: ArrayBufferView): this;
+ setAAD(
+ buffer: ArrayBufferView,
+ options?: {
+ plaintextLength: number;
+ },
+ ): this;
+}
+
+export class Cipheriv extends Transform implements Cipher {
+ constructor(
+ _cipher: string,
+ _key: CipherKey,
+ _iv: BinaryLike | null,
+ _options?: TransformOptions,
+ ) {
+ super();
+
+ notImplemented("crypto.Cipheriv");
+ }
+
+ final(): Buffer;
+ final(outputEncoding: BufferEncoding): string;
+ final(_outputEncoding?: string): Buffer | string {
+ notImplemented("crypto.Cipheriv.prototype.final");
+ }
+
+ getAuthTag(): Buffer {
+ notImplemented("crypto.Cipheriv.prototype.getAuthTag");
+ }
+
+ setAAD(
+ _buffer: ArrayBufferView,
+ _options?: {
+ plaintextLength: number;
+ },
+ ): this {
+ notImplemented("crypto.Cipheriv.prototype.setAAD");
+ }
+
+ setAutoPadding(_autoPadding?: boolean): this {
+ notImplemented("crypto.Cipheriv.prototype.setAutoPadding");
+ }
+
+ update(data: BinaryLike): Buffer;
+ update(data: string, inputEncoding: Encoding): Buffer;
+ update(
+ data: ArrayBufferView,
+ inputEncoding: undefined,
+ outputEncoding: Encoding,
+ ): string;
+ update(
+ data: string,
+ inputEncoding: Encoding | undefined,
+ outputEncoding: Encoding,
+ ): string;
+ update(
+ _data: string | BinaryLike | ArrayBufferView,
+ _inputEncoding?: Encoding,
+ _outputEncoding?: Encoding,
+ ): Buffer | string {
+ notImplemented("crypto.Cipheriv.prototype.update");
+ }
+}
+
+export class Decipheriv extends Transform implements Cipher {
+ constructor(
+ _cipher: string,
+ _key: CipherKey,
+ _iv: BinaryLike | null,
+ _options?: TransformOptions,
+ ) {
+ super();
+
+ notImplemented("crypto.Decipheriv");
+ }
+
+ final(): Buffer;
+ final(outputEncoding: BufferEncoding): string;
+ final(_outputEncoding?: string): Buffer | string {
+ notImplemented("crypto.Decipheriv.prototype.final");
+ }
+
+ setAAD(
+ _buffer: ArrayBufferView,
+ _options?: {
+ plaintextLength: number;
+ },
+ ): this {
+ notImplemented("crypto.Decipheriv.prototype.setAAD");
+ }
+
+ setAuthTag(_buffer: BinaryLike, _encoding?: string): this {
+ notImplemented("crypto.Decipheriv.prototype.setAuthTag");
+ }
+
+ setAutoPadding(_autoPadding?: boolean): this {
+ notImplemented("crypto.Decipheriv.prototype.setAutoPadding");
+ }
+
+ update(data: BinaryLike): Buffer;
+ update(data: string, inputEncoding: Encoding): Buffer;
+ update(
+ data: ArrayBufferView,
+ inputEncoding: undefined,
+ outputEncoding: Encoding,
+ ): string;
+ update(
+ data: string,
+ inputEncoding: Encoding | undefined,
+ outputEncoding: Encoding,
+ ): string;
+ update(
+ _data: string | BinaryLike | ArrayBufferView,
+ _inputEncoding?: Encoding,
+ _outputEncoding?: Encoding,
+ ): Buffer | string {
+ notImplemented("crypto.Decipheriv.prototype.update");
+ }
+}
+
+export function getCipherInfo(
+ nameOrNid: string | number,
+ options?: { keyLength?: number; ivLength?: number },
+) {
+ if (typeof nameOrNid !== "string" && typeof nameOrNid !== "number") {
+ throw new ERR_INVALID_ARG_TYPE(
+ "nameOrNid",
+ ["string", "number"],
+ nameOrNid,
+ );
+ }
+
+ if (typeof nameOrNid === "number") {
+ validateInt32(nameOrNid, "nameOrNid");
+ }
+
+ let keyLength, ivLength;
+
+ if (options !== undefined) {
+ validateObject(options, "options");
+
+ ({ keyLength, ivLength } = options);
+
+ if (keyLength !== undefined) {
+ validateInt32(keyLength, "options.keyLength");
+ }
+
+ if (ivLength !== undefined) {
+ validateInt32(ivLength, "options.ivLength");
+ }
+ }
+
+ notImplemented("crypto.getCipherInfo");
+}
+
+export default {
+ privateDecrypt,
+ privateEncrypt,
+ publicDecrypt,
+ publicEncrypt,
+ Cipheriv,
+ Decipheriv,
+ getCipherInfo,
+};
diff --git a/ext/node/polyfills/internal/crypto/constants.ts b/ext/node/polyfills/internal/crypto/constants.ts
new file mode 100644
index 000000000..d62415360
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/constants.ts
@@ -0,0 +1,5 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license.
+
+export const kHandle = Symbol("kHandle");
+export const kKeyObject = Symbol("kKeyObject");
diff --git a/ext/node/polyfills/internal/crypto/diffiehellman.ts b/ext/node/polyfills/internal/crypto/diffiehellman.ts
new file mode 100644
index 000000000..eb903ccb3
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/diffiehellman.ts
@@ -0,0 +1,306 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license.
+
+import { notImplemented } from "internal:deno_node/polyfills/_utils.ts";
+import {
+ isAnyArrayBuffer,
+ isArrayBufferView,
+} from "internal:deno_node/polyfills/internal/util/types.ts";
+import { ERR_INVALID_ARG_TYPE } from "internal:deno_node/polyfills/internal/errors.ts";
+import {
+ validateInt32,
+ validateString,
+} from "internal:deno_node/polyfills/internal/validators.mjs";
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+import {
+ getDefaultEncoding,
+ toBuf,
+} from "internal:deno_node/polyfills/internal/crypto/util.ts";
+import type {
+ BinaryLike,
+ BinaryToTextEncoding,
+ ECDHKeyFormat,
+} from "internal:deno_node/polyfills/internal/crypto/types.ts";
+import { KeyObject } from "internal:deno_node/polyfills/internal/crypto/keys.ts";
+import type { BufferEncoding } from "internal:deno_node/polyfills/_global.d.ts";
+
+const DH_GENERATOR = 2;
+
+export class DiffieHellman {
+ verifyError!: number;
+
+ constructor(
+ sizeOrKey: unknown,
+ keyEncoding?: unknown,
+ generator?: unknown,
+ genEncoding?: unknown,
+ ) {
+ if (
+ typeof sizeOrKey !== "number" &&
+ typeof sizeOrKey !== "string" &&
+ !isArrayBufferView(sizeOrKey) &&
+ !isAnyArrayBuffer(sizeOrKey)
+ ) {
+ throw new ERR_INVALID_ARG_TYPE(
+ "sizeOrKey",
+ ["number", "string", "ArrayBuffer", "Buffer", "TypedArray", "DataView"],
+ sizeOrKey,
+ );
+ }
+
+ if (typeof sizeOrKey === "number") {
+ validateInt32(sizeOrKey, "sizeOrKey");
+ }
+
+ if (
+ keyEncoding &&
+ !Buffer.isEncoding(keyEncoding as BinaryToTextEncoding) &&
+ keyEncoding !== "buffer"
+ ) {
+ genEncoding = generator;
+ generator = keyEncoding;
+ keyEncoding = false;
+ }
+
+ const encoding = getDefaultEncoding();
+ keyEncoding = keyEncoding || encoding;
+ genEncoding = genEncoding || encoding;
+
+ if (typeof sizeOrKey !== "number") {
+ sizeOrKey = toBuf(sizeOrKey as string, keyEncoding as string);
+ }
+
+ if (!generator) {
+ generator = DH_GENERATOR;
+ } else if (typeof generator === "number") {
+ validateInt32(generator, "generator");
+ } else if (typeof generator === "string") {
+ generator = toBuf(generator, genEncoding as string);
+ } else if (!isArrayBufferView(generator) && !isAnyArrayBuffer(generator)) {
+ throw new ERR_INVALID_ARG_TYPE(
+ "generator",
+ ["number", "string", "ArrayBuffer", "Buffer", "TypedArray", "DataView"],
+ generator,
+ );
+ }
+
+ notImplemented("crypto.DiffieHellman");
+ }
+
+ computeSecret(otherPublicKey: ArrayBufferView): Buffer;
+ computeSecret(
+ otherPublicKey: string,
+ inputEncoding: BinaryToTextEncoding,
+ ): Buffer;
+ computeSecret(
+ otherPublicKey: ArrayBufferView,
+ outputEncoding: BinaryToTextEncoding,
+ ): string;
+ computeSecret(
+ otherPublicKey: string,
+ inputEncoding: BinaryToTextEncoding,
+ outputEncoding: BinaryToTextEncoding,
+ ): string;
+ computeSecret(
+ _otherPublicKey: ArrayBufferView | string,
+ _inputEncoding?: BinaryToTextEncoding,
+ _outputEncoding?: BinaryToTextEncoding,
+ ): Buffer | string {
+ notImplemented("crypto.DiffieHellman.prototype.computeSecret");
+ }
+
+ generateKeys(): Buffer;
+ generateKeys(encoding: BinaryToTextEncoding): string;
+ generateKeys(_encoding?: BinaryToTextEncoding): Buffer | string {
+ notImplemented("crypto.DiffieHellman.prototype.generateKeys");
+ }
+
+ getGenerator(): Buffer;
+ getGenerator(encoding: BinaryToTextEncoding): string;
+ getGenerator(_encoding?: BinaryToTextEncoding): Buffer | string {
+ notImplemented("crypto.DiffieHellman.prototype.getGenerator");
+ }
+
+ getPrime(): Buffer;
+ getPrime(encoding: BinaryToTextEncoding): string;
+ getPrime(_encoding?: BinaryToTextEncoding): Buffer | string {
+ notImplemented("crypto.DiffieHellman.prototype.getPrime");
+ }
+
+ getPrivateKey(): Buffer;
+ getPrivateKey(encoding: BinaryToTextEncoding): string;
+ getPrivateKey(_encoding?: BinaryToTextEncoding): Buffer | string {
+ notImplemented("crypto.DiffieHellman.prototype.getPrivateKey");
+ }
+
+ getPublicKey(): Buffer;
+ getPublicKey(encoding: BinaryToTextEncoding): string;
+ getPublicKey(_encoding?: BinaryToTextEncoding): Buffer | string {
+ notImplemented("crypto.DiffieHellman.prototype.getPublicKey");
+ }
+
+ setPrivateKey(privateKey: ArrayBufferView): void;
+ setPrivateKey(privateKey: string, encoding: BufferEncoding): void;
+ setPrivateKey(
+ _privateKey: ArrayBufferView | string,
+ _encoding?: BufferEncoding,
+ ) {
+ notImplemented("crypto.DiffieHellman.prototype.setPrivateKey");
+ }
+
+ setPublicKey(publicKey: ArrayBufferView): void;
+ setPublicKey(publicKey: string, encoding: BufferEncoding): void;
+ setPublicKey(
+ _publicKey: ArrayBufferView | string,
+ _encoding?: BufferEncoding,
+ ) {
+ notImplemented("crypto.DiffieHellman.prototype.setPublicKey");
+ }
+}
+
+export class DiffieHellmanGroup {
+ verifyError!: number;
+
+ constructor(_name: string) {
+ notImplemented("crypto.DiffieHellmanGroup");
+ }
+
+ computeSecret(otherPublicKey: ArrayBufferView): Buffer;
+ computeSecret(
+ otherPublicKey: string,
+ inputEncoding: BinaryToTextEncoding,
+ ): Buffer;
+ computeSecret(
+ otherPublicKey: ArrayBufferView,
+ outputEncoding: BinaryToTextEncoding,
+ ): string;
+ computeSecret(
+ otherPublicKey: string,
+ inputEncoding: BinaryToTextEncoding,
+ outputEncoding: BinaryToTextEncoding,
+ ): string;
+ computeSecret(
+ _otherPublicKey: ArrayBufferView | string,
+ _inputEncoding?: BinaryToTextEncoding,
+ _outputEncoding?: BinaryToTextEncoding,
+ ): Buffer | string {
+ notImplemented("crypto.DiffieHellman.prototype.computeSecret");
+ }
+
+ generateKeys(): Buffer;
+ generateKeys(encoding: BinaryToTextEncoding): string;
+ generateKeys(_encoding?: BinaryToTextEncoding): Buffer | string {
+ notImplemented("crypto.DiffieHellman.prototype.generateKeys");
+ }
+
+ getGenerator(): Buffer;
+ getGenerator(encoding: BinaryToTextEncoding): string;
+ getGenerator(_encoding?: BinaryToTextEncoding): Buffer | string {
+ notImplemented("crypto.DiffieHellman.prototype.getGenerator");
+ }
+
+ getPrime(): Buffer;
+ getPrime(encoding: BinaryToTextEncoding): string;
+ getPrime(_encoding?: BinaryToTextEncoding): Buffer | string {
+ notImplemented("crypto.DiffieHellman.prototype.getPrime");
+ }
+
+ getPrivateKey(): Buffer;
+ getPrivateKey(encoding: BinaryToTextEncoding): string;
+ getPrivateKey(_encoding?: BinaryToTextEncoding): Buffer | string {
+ notImplemented("crypto.DiffieHellman.prototype.getPrivateKey");
+ }
+
+ getPublicKey(): Buffer;
+ getPublicKey(encoding: BinaryToTextEncoding): string;
+ getPublicKey(_encoding?: BinaryToTextEncoding): Buffer | string {
+ notImplemented("crypto.DiffieHellman.prototype.getPublicKey");
+ }
+}
+
+export class ECDH {
+ constructor(curve: string) {
+ validateString(curve, "curve");
+
+ notImplemented("crypto.ECDH");
+ }
+
+ static convertKey(
+ _key: BinaryLike,
+ _curve: string,
+ _inputEncoding?: BinaryToTextEncoding,
+ _outputEncoding?: "latin1" | "hex" | "base64" | "base64url",
+ _format?: "uncompressed" | "compressed" | "hybrid",
+ ): Buffer | string {
+ notImplemented("crypto.ECDH.prototype.convertKey");
+ }
+
+ computeSecret(otherPublicKey: ArrayBufferView): Buffer;
+ computeSecret(
+ otherPublicKey: string,
+ inputEncoding: BinaryToTextEncoding,
+ ): Buffer;
+ computeSecret(
+ otherPublicKey: ArrayBufferView,
+ outputEncoding: BinaryToTextEncoding,
+ ): string;
+ computeSecret(
+ otherPublicKey: string,
+ inputEncoding: BinaryToTextEncoding,
+ outputEncoding: BinaryToTextEncoding,
+ ): string;
+ computeSecret(
+ _otherPublicKey: ArrayBufferView | string,
+ _inputEncoding?: BinaryToTextEncoding,
+ _outputEncoding?: BinaryToTextEncoding,
+ ): Buffer | string {
+ notImplemented("crypto.ECDH.prototype.computeSecret");
+ }
+
+ generateKeys(): Buffer;
+ generateKeys(encoding: BinaryToTextEncoding, format?: ECDHKeyFormat): string;
+ generateKeys(
+ _encoding?: BinaryToTextEncoding,
+ _format?: ECDHKeyFormat,
+ ): Buffer | string {
+ notImplemented("crypto.ECDH.prototype.generateKeys");
+ }
+
+ getPrivateKey(): Buffer;
+ getPrivateKey(encoding: BinaryToTextEncoding): string;
+ getPrivateKey(_encoding?: BinaryToTextEncoding): Buffer | string {
+ notImplemented("crypto.ECDH.prototype.getPrivateKey");
+ }
+
+ getPublicKey(): Buffer;
+ getPublicKey(encoding: BinaryToTextEncoding, format?: ECDHKeyFormat): string;
+ getPublicKey(
+ _encoding?: BinaryToTextEncoding,
+ _format?: ECDHKeyFormat,
+ ): Buffer | string {
+ notImplemented("crypto.ECDH.prototype.getPublicKey");
+ }
+
+ setPrivateKey(privateKey: ArrayBufferView): void;
+ setPrivateKey(privateKey: string, encoding: BinaryToTextEncoding): void;
+ setPrivateKey(
+ _privateKey: ArrayBufferView | string,
+ _encoding?: BinaryToTextEncoding,
+ ): Buffer | string {
+ notImplemented("crypto.ECDH.prototype.setPrivateKey");
+ }
+}
+
+export function diffieHellman(_options: {
+ privateKey: KeyObject;
+ publicKey: KeyObject;
+}): Buffer {
+ notImplemented("crypto.diffieHellman");
+}
+
+export default {
+ DiffieHellman,
+ DiffieHellmanGroup,
+ ECDH,
+ diffieHellman,
+};
diff --git a/ext/node/polyfills/internal/crypto/hash.ts b/ext/node/polyfills/internal/crypto/hash.ts
new file mode 100644
index 000000000..7995e5f8c
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/hash.ts
@@ -0,0 +1,230 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license.
+
+import {
+ TextDecoder,
+ TextEncoder,
+} from "internal:deno_web/08_text_encoding.js";
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+import { Transform } from "internal:deno_node/polyfills/stream.ts";
+import { encode as encodeToHex } from "internal:deno_node/polyfills/internal/crypto/_hex.ts";
+import {
+ forgivingBase64Encode as encodeToBase64,
+ forgivingBase64UrlEncode as encodeToBase64Url,
+} from "internal:deno_web/00_infra.js";
+import type { TransformOptions } from "internal:deno_node/polyfills/_stream.d.ts";
+import { validateString } from "internal:deno_node/polyfills/internal/validators.mjs";
+import type {
+ BinaryToTextEncoding,
+ Encoding,
+} from "internal:deno_node/polyfills/internal/crypto/types.ts";
+import {
+ KeyObject,
+ prepareSecretKey,
+} from "internal:deno_node/polyfills/internal/crypto/keys.ts";
+import { notImplemented } from "internal:deno_node/polyfills/_utils.ts";
+
+const { ops } = globalThis.__bootstrap.core;
+
+const coerceToBytes = (data: string | BufferSource): Uint8Array => {
+ if (data instanceof Uint8Array) {
+ return data;
+ } else if (typeof data === "string") {
+ // This assumes UTF-8, which may not be correct.
+ return new TextEncoder().encode(data);
+ } else if (ArrayBuffer.isView(data)) {
+ return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
+ } else if (data instanceof ArrayBuffer) {
+ return new Uint8Array(data);
+ } else {
+ throw new TypeError("expected data to be string | BufferSource");
+ }
+};
+
+/**
+ * The Hash class is a utility for creating hash digests of data. It can be used in one of two ways:
+ *
+ * - As a stream that is both readable and writable, where data is written to produce a computed hash digest on the readable side, or
+ * - Using the hash.update() and hash.digest() methods to produce the computed hash.
+ *
+ * The crypto.createHash() method is used to create Hash instances. Hash objects are not to be created directly using the new keyword.
+ */
+export class Hash extends Transform {
+ #context: number;
+
+ constructor(
+ algorithm: string | number,
+ _opts?: TransformOptions,
+ ) {
+ super({
+ transform(chunk: string, _encoding: string, callback: () => void) {
+ ops.op_node_hash_update(context, coerceToBytes(chunk));
+ callback();
+ },
+ flush(callback: () => void) {
+ this.push(context.digest(undefined));
+ callback();
+ },
+ });
+
+ if (typeof algorithm === "string") {
+ this.#context = ops.op_node_create_hash(
+ algorithm,
+ );
+ } else {
+ this.#context = algorithm;
+ }
+
+ const context = this.#context;
+ }
+
+ copy(): Hash {
+ return new Hash(ops.op_node_clone_hash(this.#context));
+ }
+
+ /**
+ * Updates the hash content with the given data.
+ */
+ update(data: string | ArrayBuffer, _encoding?: string): this {
+ let bytes;
+ if (typeof data === "string") {
+ data = new TextEncoder().encode(data);
+ bytes = coerceToBytes(data);
+ } else {
+ bytes = coerceToBytes(data);
+ }
+
+ ops.op_node_hash_update(this.#context, bytes);
+
+ return this;
+ }
+
+ /**
+ * Calculates the digest of all of the data.
+ *
+ * If encoding is provided a string will be returned; otherwise a Buffer is returned.
+ *
+ * Supported encodings are currently 'hex', 'binary', 'base64', 'base64url'.
+ */
+ digest(encoding?: string): Buffer | string {
+ const digest = this.#context.digest(undefined);
+ if (encoding === undefined) {
+ return Buffer.from(digest);
+ }
+
+ switch (encoding) {
+ case "hex":
+ return new TextDecoder().decode(encodeToHex(new Uint8Array(digest)));
+ case "binary":
+ return String.fromCharCode(...digest);
+ case "base64":
+ return encodeToBase64(digest);
+ case "base64url":
+ return encodeToBase64Url(digest);
+ case "buffer":
+ return Buffer.from(digest);
+ default:
+ return Buffer.from(digest).toString(encoding);
+ }
+ }
+}
+
+export function Hmac(
+ hmac: string,
+ key: string | ArrayBuffer | KeyObject,
+ options?: TransformOptions,
+): Hmac {
+ return new HmacImpl(hmac, key, options);
+}
+
+type Hmac = HmacImpl;
+
+class HmacImpl extends Transform {
+ #ipad: Uint8Array;
+ #opad: Uint8Array;
+ #ZEROES = Buffer.alloc(128);
+ #algorithm: string;
+ #hash: Hash;
+
+ constructor(
+ hmac: string,
+ key: string | ArrayBuffer | KeyObject,
+ options?: TransformOptions,
+ ) {
+ super({
+ transform(chunk: string, encoding: string, callback: () => void) {
+ // deno-lint-ignore no-explicit-any
+ self.update(coerceToBytes(chunk), encoding as any);
+ callback();
+ },
+ flush(callback: () => void) {
+ this.push(self.digest());
+ callback();
+ },
+ });
+ // deno-lint-ignore no-this-alias
+ const self = this;
+ if (key instanceof KeyObject) {
+ notImplemented("Hmac: KeyObject key is not implemented");
+ }
+
+ validateString(hmac, "hmac");
+ const u8Key = prepareSecretKey(key, options?.encoding) as Buffer;
+
+ const alg = hmac.toLowerCase();
+ this.#hash = new Hash(alg, options);
+ this.#algorithm = alg;
+ const blockSize = (alg === "sha512" || alg === "sha384") ? 128 : 64;
+ const keySize = u8Key.length;
+
+ let bufKey: Buffer;
+
+ if (keySize > blockSize) {
+ bufKey = this.#hash.update(u8Key).digest() as Buffer;
+ } else {
+ bufKey = Buffer.concat([u8Key, this.#ZEROES], blockSize);
+ }
+
+ this.#ipad = Buffer.allocUnsafe(blockSize);
+ this.#opad = Buffer.allocUnsafe(blockSize);
+
+ for (let i = 0; i < blockSize; i++) {
+ this.#ipad[i] = bufKey[i] ^ 0x36;
+ this.#opad[i] = bufKey[i] ^ 0x5C;
+ }
+
+ this.#hash = new Hash(alg);
+ this.#hash.update(this.#ipad);
+ }
+
+ digest(): Buffer;
+ digest(encoding: BinaryToTextEncoding): string;
+ digest(encoding?: BinaryToTextEncoding): Buffer | string {
+ const result = this.#hash.digest();
+
+ return new Hash(this.#algorithm).update(this.#opad).update(result).digest(
+ encoding,
+ );
+ }
+
+ update(data: string | ArrayBuffer, inputEncoding?: Encoding): this {
+ this.#hash.update(data, inputEncoding);
+ return this;
+ }
+}
+
+Hmac.prototype = HmacImpl.prototype;
+
+/**
+ * Creates and returns a Hash object that can be used to generate hash digests
+ * using the given `algorithm`. Optional `options` argument controls stream behavior.
+ */
+export function createHash(algorithm: string, opts?: TransformOptions) {
+ return new Hash(algorithm, opts);
+}
+
+export default {
+ Hash,
+ Hmac,
+ createHash,
+};
diff --git a/ext/node/polyfills/internal/crypto/hkdf.ts b/ext/node/polyfills/internal/crypto/hkdf.ts
new file mode 100644
index 000000000..aebdd9152
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/hkdf.ts
@@ -0,0 +1,130 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license.
+
+import {
+ validateFunction,
+ validateInteger,
+ validateString,
+} from "internal:deno_node/polyfills/internal/validators.mjs";
+import {
+ ERR_INVALID_ARG_TYPE,
+ ERR_OUT_OF_RANGE,
+ hideStackFrames,
+} from "internal:deno_node/polyfills/internal/errors.ts";
+import {
+ toBuf,
+ validateByteSource,
+} from "internal:deno_node/polyfills/internal/crypto/util.ts";
+import {
+ createSecretKey,
+ isKeyObject,
+ KeyObject,
+} from "internal:deno_node/polyfills/internal/crypto/keys.ts";
+import type { BinaryLike } from "internal:deno_node/polyfills/internal/crypto/types.ts";
+import { kMaxLength } from "internal:deno_node/polyfills/internal/buffer.mjs";
+import {
+ isAnyArrayBuffer,
+ isArrayBufferView,
+} from "internal:deno_node/polyfills/internal/util/types.ts";
+import { notImplemented } from "internal:deno_node/polyfills/_utils.ts";
+
+const validateParameters = hideStackFrames((hash, key, salt, info, length) => {
+ key = prepareKey(key);
+ salt = toBuf(salt);
+ info = toBuf(info);
+
+ validateString(hash, "digest");
+ validateByteSource(salt, "salt");
+ validateByteSource(info, "info");
+
+ validateInteger(length, "length", 0, kMaxLength);
+
+ if (info.byteLength > 1024) {
+ throw new ERR_OUT_OF_RANGE(
+ "info",
+ "must not contain more than 1024 bytes",
+ info.byteLength,
+ );
+ }
+
+ return {
+ hash,
+ key,
+ salt,
+ info,
+ length,
+ };
+});
+
+function prepareKey(key: BinaryLike | KeyObject) {
+ if (isKeyObject(key)) {
+ return key;
+ }
+
+ if (isAnyArrayBuffer(key)) {
+ return createSecretKey(new Uint8Array(key as unknown as ArrayBufferLike));
+ }
+
+ key = toBuf(key as string);
+
+ if (!isArrayBufferView(key)) {
+ throw new ERR_INVALID_ARG_TYPE(
+ "ikm",
+ [
+ "string",
+ "SecretKeyObject",
+ "ArrayBuffer",
+ "TypedArray",
+ "DataView",
+ "Buffer",
+ ],
+ key,
+ );
+ }
+
+ return createSecretKey(key);
+}
+
+export function hkdf(
+ hash: string,
+ key: BinaryLike | KeyObject,
+ salt: BinaryLike,
+ info: BinaryLike,
+ length: number,
+ callback: (err: Error | null, derivedKey: ArrayBuffer) => void,
+) {
+ ({ hash, key, salt, info, length } = validateParameters(
+ hash,
+ key,
+ salt,
+ info,
+ length,
+ ));
+
+ validateFunction(callback, "callback");
+
+ notImplemented("crypto.hkdf");
+}
+
+export function hkdfSync(
+ hash: string,
+ key: BinaryLike | KeyObject,
+ salt: BinaryLike,
+ info: BinaryLike,
+ length: number,
+) {
+ ({ hash, key, salt, info, length } = validateParameters(
+ hash,
+ key,
+ salt,
+ info,
+ length,
+ ));
+
+ notImplemented("crypto.hkdfSync");
+}
+
+export default {
+ hkdf,
+ hkdfSync,
+};
diff --git a/ext/node/polyfills/internal/crypto/keygen.ts b/ext/node/polyfills/internal/crypto/keygen.ts
new file mode 100644
index 000000000..1a947b95b
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/keygen.ts
@@ -0,0 +1,682 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license.
+
+import { KeyObject } from "internal:deno_node/polyfills/internal/crypto/keys.ts";
+import { notImplemented } from "internal:deno_node/polyfills/_utils.ts";
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+import {
+ KeyFormat,
+ KeyType,
+} from "internal:deno_node/polyfills/internal/crypto/types.ts";
+
+export function generateKey(
+ _type: "hmac" | "aes",
+ _options: {
+ length: number;
+ },
+ _callback: (err: Error | null, key: KeyObject) => void,
+) {
+ notImplemented("crypto.generateKey");
+}
+
+export interface BasePrivateKeyEncodingOptions<T extends KeyFormat> {
+ format: T;
+ cipher?: string | undefined;
+ passphrase?: string | undefined;
+}
+
+export interface RSAKeyPairOptions<
+ PubF extends KeyFormat,
+ PrivF extends KeyFormat,
+> {
+ /**
+ * Key size in bits
+ */
+ modulusLength: number;
+ /**
+ * Public exponent
+ * @default 0x10001
+ */
+ publicExponent?: number | undefined;
+ publicKeyEncoding: {
+ type: "pkcs1" | "spki";
+ format: PubF;
+ };
+ privateKeyEncoding: BasePrivateKeyEncodingOptions<PrivF> & {
+ type: "pkcs1" | "pkcs8";
+ };
+}
+
+export interface RSAPSSKeyPairOptions<
+ PubF extends KeyFormat,
+ PrivF extends KeyFormat,
+> {
+ /**
+ * Key size in bits
+ */
+ modulusLength: number;
+ /**
+ * Public exponent
+ * @default 0x10001
+ */
+ publicExponent?: number | undefined;
+ /**
+ * Name of the message digest
+ */
+ hashAlgorithm?: string;
+ /**
+ * Name of the message digest used by MGF1
+ */
+ mgf1HashAlgorithm?: string;
+ /**
+ * Minimal salt length in bytes
+ */
+ saltLength?: string;
+ publicKeyEncoding: {
+ type: "spki";
+ format: PubF;
+ };
+ privateKeyEncoding: BasePrivateKeyEncodingOptions<PrivF> & {
+ type: "pkcs8";
+ };
+}
+
+export interface DSAKeyPairOptions<
+ PubF extends KeyFormat,
+ PrivF extends KeyFormat,
+> {
+ /**
+ * Key size in bits
+ */
+ modulusLength: number;
+ /**
+ * Size of q in bits
+ */
+ divisorLength: number;
+ publicKeyEncoding: {
+ type: "spki";
+ format: PubF;
+ };
+ privateKeyEncoding: BasePrivateKeyEncodingOptions<PrivF> & {
+ type: "pkcs8";
+ };
+}
+
+export interface ECKeyPairOptions<
+ PubF extends KeyFormat,
+ PrivF extends KeyFormat,
+> {
+ /**
+ * Name of the curve to use.
+ */
+ namedCurve: string;
+ publicKeyEncoding: {
+ type: "pkcs1" | "spki";
+ format: PubF;
+ };
+ privateKeyEncoding: BasePrivateKeyEncodingOptions<PrivF> & {
+ type: "sec1" | "pkcs8";
+ };
+}
+
+export interface ED25519KeyPairOptions<
+ PubF extends KeyFormat,
+ PrivF extends KeyFormat,
+> {
+ publicKeyEncoding: {
+ type: "spki";
+ format: PubF;
+ };
+ privateKeyEncoding: BasePrivateKeyEncodingOptions<PrivF> & {
+ type: "pkcs8";
+ };
+}
+
+export interface ED448KeyPairOptions<
+ PubF extends KeyFormat,
+ PrivF extends KeyFormat,
+> {
+ publicKeyEncoding: {
+ type: "spki";
+ format: PubF;
+ };
+ privateKeyEncoding: BasePrivateKeyEncodingOptions<PrivF> & {
+ type: "pkcs8";
+ };
+}
+
+export interface X25519KeyPairOptions<
+ PubF extends KeyFormat,
+ PrivF extends KeyFormat,
+> {
+ publicKeyEncoding: {
+ type: "spki";
+ format: PubF;
+ };
+ privateKeyEncoding: BasePrivateKeyEncodingOptions<PrivF> & {
+ type: "pkcs8";
+ };
+}
+
+export interface X448KeyPairOptions<
+ PubF extends KeyFormat,
+ PrivF extends KeyFormat,
+> {
+ publicKeyEncoding: {
+ type: "spki";
+ format: PubF;
+ };
+ privateKeyEncoding: BasePrivateKeyEncodingOptions<PrivF> & {
+ type: "pkcs8";
+ };
+}
+
+export interface RSAKeyPairKeyObjectOptions {
+ /**
+ * Key size in bits
+ */
+ modulusLength: number;
+ /**
+ * Public exponent
+ * @default 0x10001
+ */
+ publicExponent?: number | undefined;
+}
+
+export interface RSAPSSKeyPairKeyObjectOptions {
+ /**
+ * Key size in bits
+ */
+ modulusLength: number;
+ /**
+ * Public exponent
+ * @default 0x10001
+ */
+ publicExponent?: number | undefined;
+ /**
+ * Name of the message digest
+ */
+ hashAlgorithm?: string;
+ /**
+ * Name of the message digest used by MGF1
+ */
+ mgf1HashAlgorithm?: string;
+ /**
+ * Minimal salt length in bytes
+ */
+ saltLength?: string;
+}
+
+export interface DSAKeyPairKeyObjectOptions {
+ /**
+ * Key size in bits
+ */
+ modulusLength: number;
+ /**
+ * Size of q in bits
+ */
+ divisorLength: number;
+}
+
+// deno-lint-ignore no-empty-interface
+export interface ED25519KeyPairKeyObjectOptions {}
+
+// deno-lint-ignore no-empty-interface
+export interface ED448KeyPairKeyObjectOptions {}
+
+// deno-lint-ignore no-empty-interface
+export interface X25519KeyPairKeyObjectOptions {}
+
+// deno-lint-ignore no-empty-interface
+export interface X448KeyPairKeyObjectOptions {}
+
+export interface ECKeyPairKeyObjectOptions {
+ /**
+ * Name of the curve to use
+ */
+ namedCurve: string;
+}
+
+export function generateKeyPair(
+ type: "rsa",
+ options: RSAKeyPairOptions<"pem", "pem">,
+ callback: (err: Error | null, publicKey: string, privateKey: string) => void,
+): void;
+export function generateKeyPair(
+ type: "rsa",
+ options: RSAKeyPairOptions<"pem", "der">,
+ callback: (err: Error | null, publicKey: string, privateKey: Buffer) => void,
+): void;
+export function generateKeyPair(
+ type: "rsa",
+ options: RSAKeyPairOptions<"der", "pem">,
+ callback: (err: Error | null, publicKey: Buffer, privateKey: string) => void,
+): void;
+export function generateKeyPair(
+ type: "rsa",
+ options: RSAKeyPairOptions<"der", "der">,
+ callback: (err: Error | null, publicKey: Buffer, privateKey: Buffer) => void,
+): void;
+export function generateKeyPair(
+ type: "rsa",
+ options: RSAKeyPairKeyObjectOptions,
+ callback: (
+ err: Error | null,
+ publicKey: KeyObject,
+ privateKey: KeyObject,
+ ) => void,
+): void;
+export function generateKeyPair(
+ type: "rsa-pss",
+ options: RSAPSSKeyPairOptions<"pem", "pem">,
+ callback: (err: Error | null, publicKey: string, privateKey: string) => void,
+): void;
+export function generateKeyPair(
+ type: "rsa-pss",
+ options: RSAPSSKeyPairOptions<"pem", "der">,
+ callback: (err: Error | null, publicKey: string, privateKey: Buffer) => void,
+): void;
+export function generateKeyPair(
+ type: "rsa-pss",
+ options: RSAPSSKeyPairOptions<"der", "pem">,
+ callback: (err: Error | null, publicKey: Buffer, privateKey: string) => void,
+): void;
+export function generateKeyPair(
+ type: "rsa-pss",
+ options: RSAPSSKeyPairOptions<"der", "der">,
+ callback: (err: Error | null, publicKey: Buffer, privateKey: Buffer) => void,
+): void;
+export function generateKeyPair(
+ type: "rsa-pss",
+ options: RSAPSSKeyPairKeyObjectOptions,
+ callback: (
+ err: Error | null,
+ publicKey: KeyObject,
+ privateKey: KeyObject,
+ ) => void,
+): void;
+export function generateKeyPair(
+ type: "dsa",
+ options: DSAKeyPairOptions<"pem", "pem">,
+ callback: (err: Error | null, publicKey: string, privateKey: string) => void,
+): void;
+export function generateKeyPair(
+ type: "dsa",
+ options: DSAKeyPairOptions<"pem", "der">,
+ callback: (err: Error | null, publicKey: string, privateKey: Buffer) => void,
+): void;
+export function generateKeyPair(
+ type: "dsa",
+ options: DSAKeyPairOptions<"der", "pem">,
+ callback: (err: Error | null, publicKey: Buffer, privateKey: string) => void,
+): void;
+export function generateKeyPair(
+ type: "dsa",
+ options: DSAKeyPairOptions<"der", "der">,
+ callback: (err: Error | null, publicKey: Buffer, privateKey: Buffer) => void,
+): void;
+export function generateKeyPair(
+ type: "dsa",
+ options: DSAKeyPairKeyObjectOptions,
+ callback: (
+ err: Error | null,
+ publicKey: KeyObject,
+ privateKey: KeyObject,
+ ) => void,
+): void;
+export function generateKeyPair(
+ type: "ec",
+ options: ECKeyPairOptions<"pem", "pem">,
+ callback: (err: Error | null, publicKey: string, privateKey: string) => void,
+): void;
+export function generateKeyPair(
+ type: "ec",
+ options: ECKeyPairOptions<"pem", "der">,
+ callback: (err: Error | null, publicKey: string, privateKey: Buffer) => void,
+): void;
+export function generateKeyPair(
+ type: "ec",
+ options: ECKeyPairOptions<"der", "pem">,
+ callback: (err: Error | null, publicKey: Buffer, privateKey: string) => void,
+): void;
+export function generateKeyPair(
+ type: "ec",
+ options: ECKeyPairOptions<"der", "der">,
+ callback: (err: Error | null, publicKey: Buffer, privateKey: Buffer) => void,
+): void;
+export function generateKeyPair(
+ type: "ec",
+ options: ECKeyPairKeyObjectOptions,
+ callback: (
+ err: Error | null,
+ publicKey: KeyObject,
+ privateKey: KeyObject,
+ ) => void,
+): void;
+export function generateKeyPair(
+ type: "ed25519",
+ options: ED25519KeyPairOptions<"pem", "pem">,
+ callback: (err: Error | null, publicKey: string, privateKey: string) => void,
+): void;
+export function generateKeyPair(
+ type: "ed25519",
+ options: ED25519KeyPairOptions<"pem", "der">,
+ callback: (err: Error | null, publicKey: string, privateKey: Buffer) => void,
+): void;
+export function generateKeyPair(
+ type: "ed25519",
+ options: ED25519KeyPairOptions<"der", "pem">,
+ callback: (err: Error | null, publicKey: Buffer, privateKey: string) => void,
+): void;
+export function generateKeyPair(
+ type: "ed25519",
+ options: ED25519KeyPairOptions<"der", "der">,
+ callback: (err: Error | null, publicKey: Buffer, privateKey: Buffer) => void,
+): void;
+export function generateKeyPair(
+ type: "ed25519",
+ options: ED25519KeyPairKeyObjectOptions | undefined,
+ callback: (
+ err: Error | null,
+ publicKey: KeyObject,
+ privateKey: KeyObject,
+ ) => void,
+): void;
+export function generateKeyPair(
+ type: "ed448",
+ options: ED448KeyPairOptions<"pem", "pem">,
+ callback: (err: Error | null, publicKey: string, privateKey: string) => void,
+): void;
+export function generateKeyPair(
+ type: "ed448",
+ options: ED448KeyPairOptions<"pem", "der">,
+ callback: (err: Error | null, publicKey: string, privateKey: Buffer) => void,
+): void;
+export function generateKeyPair(
+ type: "ed448",
+ options: ED448KeyPairOptions<"der", "pem">,
+ callback: (err: Error | null, publicKey: Buffer, privateKey: string) => void,
+): void;
+export function generateKeyPair(
+ type: "ed448",
+ options: ED448KeyPairOptions<"der", "der">,
+ callback: (err: Error | null, publicKey: Buffer, privateKey: Buffer) => void,
+): void;
+export function generateKeyPair(
+ type: "ed448",
+ options: ED448KeyPairKeyObjectOptions | undefined,
+ callback: (
+ err: Error | null,
+ publicKey: KeyObject,
+ privateKey: KeyObject,
+ ) => void,
+): void;
+export function generateKeyPair(
+ type: "x25519",
+ options: X25519KeyPairOptions<"pem", "pem">,
+ callback: (err: Error | null, publicKey: string, privateKey: string) => void,
+): void;
+export function generateKeyPair(
+ type: "x25519",
+ options: X25519KeyPairOptions<"pem", "der">,
+ callback: (err: Error | null, publicKey: string, privateKey: Buffer) => void,
+): void;
+export function generateKeyPair(
+ type: "x25519",
+ options: X25519KeyPairOptions<"der", "pem">,
+ callback: (err: Error | null, publicKey: Buffer, privateKey: string) => void,
+): void;
+export function generateKeyPair(
+ type: "x25519",
+ options: X25519KeyPairOptions<"der", "der">,
+ callback: (err: Error | null, publicKey: Buffer, privateKey: Buffer) => void,
+): void;
+export function generateKeyPair(
+ type: "x25519",
+ options: X25519KeyPairKeyObjectOptions | undefined,
+ callback: (
+ err: Error | null,
+ publicKey: KeyObject,
+ privateKey: KeyObject,
+ ) => void,
+): void;
+export function generateKeyPair(
+ type: "x448",
+ options: X448KeyPairOptions<"pem", "pem">,
+ callback: (err: Error | null, publicKey: string, privateKey: string) => void,
+): void;
+export function generateKeyPair(
+ type: "x448",
+ options: X448KeyPairOptions<"pem", "der">,
+ callback: (err: Error | null, publicKey: string, privateKey: Buffer) => void,
+): void;
+export function generateKeyPair(
+ type: "x448",
+ options: X448KeyPairOptions<"der", "pem">,
+ callback: (err: Error | null, publicKey: Buffer, privateKey: string) => void,
+): void;
+export function generateKeyPair(
+ type: "x448",
+ options: X448KeyPairOptions<"der", "der">,
+ callback: (err: Error | null, publicKey: Buffer, privateKey: Buffer) => void,
+): void;
+export function generateKeyPair(
+ type: "x448",
+ options: X448KeyPairKeyObjectOptions | undefined,
+ callback: (
+ err: Error | null,
+ publicKey: KeyObject,
+ privateKey: KeyObject,
+ ) => void,
+): void;
+export function generateKeyPair(
+ _type: KeyType,
+ _options: unknown,
+ _callback: (
+ err: Error | null,
+ // deno-lint-ignore no-explicit-any
+ publicKey: any,
+ // deno-lint-ignore no-explicit-any
+ privateKey: any,
+ ) => void,
+) {
+ notImplemented("crypto.generateKeyPair");
+}
+
+export interface KeyPairKeyObjectResult {
+ publicKey: KeyObject;
+ privateKey: KeyObject;
+}
+
+export interface KeyPairSyncResult<
+ T1 extends string | Buffer,
+ T2 extends string | Buffer,
+> {
+ publicKey: T1;
+ privateKey: T2;
+}
+
+export function generateKeyPairSync(
+ type: "rsa",
+ options: RSAKeyPairOptions<"pem", "pem">,
+): KeyPairSyncResult<string, string>;
+export function generateKeyPairSync(
+ type: "rsa",
+ options: RSAKeyPairOptions<"pem", "der">,
+): KeyPairSyncResult<string, Buffer>;
+export function generateKeyPairSync(
+ type: "rsa",
+ options: RSAKeyPairOptions<"der", "pem">,
+): KeyPairSyncResult<Buffer, string>;
+export function generateKeyPairSync(
+ type: "rsa",
+ options: RSAKeyPairOptions<"der", "der">,
+): KeyPairSyncResult<Buffer, Buffer>;
+export function generateKeyPairSync(
+ type: "rsa",
+ options: RSAKeyPairKeyObjectOptions,
+): KeyPairKeyObjectResult;
+export function generateKeyPairSync(
+ type: "rsa-pss",
+ options: RSAPSSKeyPairOptions<"pem", "pem">,
+): KeyPairSyncResult<string, string>;
+export function generateKeyPairSync(
+ type: "rsa-pss",
+ options: RSAPSSKeyPairOptions<"pem", "der">,
+): KeyPairSyncResult<string, Buffer>;
+export function generateKeyPairSync(
+ type: "rsa-pss",
+ options: RSAPSSKeyPairOptions<"der", "pem">,
+): KeyPairSyncResult<Buffer, string>;
+export function generateKeyPairSync(
+ type: "rsa-pss",
+ options: RSAPSSKeyPairOptions<"der", "der">,
+): KeyPairSyncResult<Buffer, Buffer>;
+export function generateKeyPairSync(
+ type: "rsa-pss",
+ options: RSAPSSKeyPairKeyObjectOptions,
+): KeyPairKeyObjectResult;
+export function generateKeyPairSync(
+ type: "dsa",
+ options: DSAKeyPairOptions<"pem", "pem">,
+): KeyPairSyncResult<string, string>;
+export function generateKeyPairSync(
+ type: "dsa",
+ options: DSAKeyPairOptions<"pem", "der">,
+): KeyPairSyncResult<string, Buffer>;
+export function generateKeyPairSync(
+ type: "dsa",
+ options: DSAKeyPairOptions<"der", "pem">,
+): KeyPairSyncResult<Buffer, string>;
+export function generateKeyPairSync(
+ type: "dsa",
+ options: DSAKeyPairOptions<"der", "der">,
+): KeyPairSyncResult<Buffer, Buffer>;
+export function generateKeyPairSync(
+ type: "dsa",
+ options: DSAKeyPairKeyObjectOptions,
+): KeyPairKeyObjectResult;
+export function generateKeyPairSync(
+ type: "ec",
+ options: ECKeyPairOptions<"pem", "pem">,
+): KeyPairSyncResult<string, string>;
+export function generateKeyPairSync(
+ type: "ec",
+ options: ECKeyPairOptions<"pem", "der">,
+): KeyPairSyncResult<string, Buffer>;
+export function generateKeyPairSync(
+ type: "ec",
+ options: ECKeyPairOptions<"der", "pem">,
+): KeyPairSyncResult<Buffer, string>;
+export function generateKeyPairSync(
+ type: "ec",
+ options: ECKeyPairOptions<"der", "der">,
+): KeyPairSyncResult<Buffer, Buffer>;
+export function generateKeyPairSync(
+ type: "ec",
+ options: ECKeyPairKeyObjectOptions,
+): KeyPairKeyObjectResult;
+export function generateKeyPairSync(
+ type: "ed25519",
+ options: ED25519KeyPairOptions<"pem", "pem">,
+): KeyPairSyncResult<string, string>;
+export function generateKeyPairSync(
+ type: "ed25519",
+ options: ED25519KeyPairOptions<"pem", "der">,
+): KeyPairSyncResult<string, Buffer>;
+export function generateKeyPairSync(
+ type: "ed25519",
+ options: ED25519KeyPairOptions<"der", "pem">,
+): KeyPairSyncResult<Buffer, string>;
+export function generateKeyPairSync(
+ type: "ed25519",
+ options: ED25519KeyPairOptions<"der", "der">,
+): KeyPairSyncResult<Buffer, Buffer>;
+export function generateKeyPairSync(
+ type: "ed25519",
+ options?: ED25519KeyPairKeyObjectOptions,
+): KeyPairKeyObjectResult;
+export function generateKeyPairSync(
+ type: "ed448",
+ options: ED448KeyPairOptions<"pem", "pem">,
+): KeyPairSyncResult<string, string>;
+export function generateKeyPairSync(
+ type: "ed448",
+ options: ED448KeyPairOptions<"pem", "der">,
+): KeyPairSyncResult<string, Buffer>;
+export function generateKeyPairSync(
+ type: "ed448",
+ options: ED448KeyPairOptions<"der", "pem">,
+): KeyPairSyncResult<Buffer, string>;
+export function generateKeyPairSync(
+ type: "ed448",
+ options: ED448KeyPairOptions<"der", "der">,
+): KeyPairSyncResult<Buffer, Buffer>;
+export function generateKeyPairSync(
+ type: "ed448",
+ options?: ED448KeyPairKeyObjectOptions,
+): KeyPairKeyObjectResult;
+export function generateKeyPairSync(
+ type: "x25519",
+ options: X25519KeyPairOptions<"pem", "pem">,
+): KeyPairSyncResult<string, string>;
+export function generateKeyPairSync(
+ type: "x25519",
+ options: X25519KeyPairOptions<"pem", "der">,
+): KeyPairSyncResult<string, Buffer>;
+export function generateKeyPairSync(
+ type: "x25519",
+ options: X25519KeyPairOptions<"der", "pem">,
+): KeyPairSyncResult<Buffer, string>;
+export function generateKeyPairSync(
+ type: "x25519",
+ options: X25519KeyPairOptions<"der", "der">,
+): KeyPairSyncResult<Buffer, Buffer>;
+export function generateKeyPairSync(
+ type: "x25519",
+ options?: X25519KeyPairKeyObjectOptions,
+): KeyPairKeyObjectResult;
+export function generateKeyPairSync(
+ type: "x448",
+ options: X448KeyPairOptions<"pem", "pem">,
+): KeyPairSyncResult<string, string>;
+export function generateKeyPairSync(
+ type: "x448",
+ options: X448KeyPairOptions<"pem", "der">,
+): KeyPairSyncResult<string, Buffer>;
+export function generateKeyPairSync(
+ type: "x448",
+ options: X448KeyPairOptions<"der", "pem">,
+): KeyPairSyncResult<Buffer, string>;
+export function generateKeyPairSync(
+ type: "x448",
+ options: X448KeyPairOptions<"der", "der">,
+): KeyPairSyncResult<Buffer, Buffer>;
+export function generateKeyPairSync(
+ type: "x448",
+ options?: X448KeyPairKeyObjectOptions,
+): KeyPairKeyObjectResult;
+export function generateKeyPairSync(
+ _type: KeyType,
+ _options: unknown,
+):
+ | KeyPairKeyObjectResult
+ | KeyPairSyncResult<string | Buffer, string | Buffer> {
+ notImplemented("crypto.generateKeyPairSync");
+}
+
+export function generateKeySync(
+ _type: "hmac" | "aes",
+ _options: {
+ length: number;
+ },
+): KeyObject {
+ notImplemented("crypto.generateKeySync");
+}
+
+export default {
+ generateKey,
+ generateKeySync,
+ generateKeyPair,
+ generateKeyPairSync,
+};
diff --git a/ext/node/polyfills/internal/crypto/keys.ts b/ext/node/polyfills/internal/crypto/keys.ts
new file mode 100644
index 000000000..7c9e7bad9
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/keys.ts
@@ -0,0 +1,294 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license.
+
+import {
+ kHandle,
+ kKeyObject,
+} from "internal:deno_node/polyfills/internal/crypto/constants.ts";
+import {
+ ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE,
+ ERR_INVALID_ARG_TYPE,
+ ERR_INVALID_ARG_VALUE,
+} from "internal:deno_node/polyfills/internal/errors.ts";
+import { notImplemented } from "internal:deno_node/polyfills/_utils.ts";
+import type {
+ KeyFormat,
+ KeyType,
+ PrivateKeyInput,
+ PublicKeyInput,
+} from "internal:deno_node/polyfills/internal/crypto/types.ts";
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+import {
+ isAnyArrayBuffer,
+ isArrayBufferView,
+} from "internal:deno_node/polyfills/internal/util/types.ts";
+import { hideStackFrames } from "internal:deno_node/polyfills/internal/errors.ts";
+import {
+ isCryptoKey as isCryptoKey_,
+ isKeyObject as isKeyObject_,
+ kKeyType,
+} from "internal:deno_node/polyfills/internal/crypto/_keys.ts";
+
+const getArrayBufferOrView = hideStackFrames(
+ (
+ buffer,
+ name,
+ encoding,
+ ):
+ | ArrayBuffer
+ | SharedArrayBuffer
+ | Buffer
+ | DataView
+ | BigInt64Array
+ | BigUint64Array
+ | Float32Array
+ | Float64Array
+ | Int8Array
+ | Int16Array
+ | Int32Array
+ | Uint8Array
+ | Uint8ClampedArray
+ | Uint16Array
+ | Uint32Array => {
+ if (isAnyArrayBuffer(buffer)) {
+ return buffer;
+ }
+ if (typeof buffer === "string") {
+ if (encoding === "buffer") {
+ encoding = "utf8";
+ }
+ return Buffer.from(buffer, encoding);
+ }
+ if (!isArrayBufferView(buffer)) {
+ throw new ERR_INVALID_ARG_TYPE(
+ name,
+ [
+ "string",
+ "ArrayBuffer",
+ "Buffer",
+ "TypedArray",
+ "DataView",
+ ],
+ buffer,
+ );
+ }
+ return buffer;
+ },
+);
+
+export interface AsymmetricKeyDetails {
+ /**
+ * Key size in bits (RSA, DSA).
+ */
+ modulusLength?: number | undefined;
+ /**
+ * Public exponent (RSA).
+ */
+ publicExponent?: bigint | undefined;
+ /**
+ * Name of the message digest (RSA-PSS).
+ */
+ hashAlgorithm?: string | undefined;
+ /**
+ * Name of the message digest used by MGF1 (RSA-PSS).
+ */
+ mgf1HashAlgorithm?: string | undefined;
+ /**
+ * Minimal salt length in bytes (RSA-PSS).
+ */
+ saltLength?: number | undefined;
+ /**
+ * Size of q in bits (DSA).
+ */
+ divisorLength?: number | undefined;
+ /**
+ * Name of the curve (EC).
+ */
+ namedCurve?: string | undefined;
+}
+
+export type KeyObjectType = "secret" | "public" | "private";
+
+export interface KeyExportOptions<T extends KeyFormat> {
+ type: "pkcs1" | "spki" | "pkcs8" | "sec1";
+ format: T;
+ cipher?: string | undefined;
+ passphrase?: string | Buffer | undefined;
+}
+
+export interface JwkKeyExportOptions {
+ format: "jwk";
+}
+
+export function isKeyObject(obj: unknown): obj is KeyObject {
+ return isKeyObject_(obj);
+}
+
+export function isCryptoKey(
+ obj: unknown,
+): obj is { type: string; [kKeyObject]: KeyObject } {
+ return isCryptoKey_(obj);
+}
+
+export class KeyObject {
+ [kKeyType]: KeyObjectType;
+ [kHandle]: unknown;
+
+ constructor(type: KeyObjectType, handle: unknown) {
+ if (type !== "secret" && type !== "public" && type !== "private") {
+ throw new ERR_INVALID_ARG_VALUE("type", type);
+ }
+
+ if (typeof handle !== "object") {
+ throw new ERR_INVALID_ARG_TYPE("handle", "object", handle);
+ }
+
+ this[kKeyType] = type;
+
+ Object.defineProperty(this, kHandle, {
+ value: handle,
+ enumerable: false,
+ configurable: false,
+ writable: false,
+ });
+ }
+
+ get type(): KeyObjectType {
+ return this[kKeyType];
+ }
+
+ get asymmetricKeyDetails(): AsymmetricKeyDetails | undefined {
+ notImplemented("crypto.KeyObject.prototype.asymmetricKeyDetails");
+
+ return undefined;
+ }
+
+ get asymmetricKeyType(): KeyType | undefined {
+ notImplemented("crypto.KeyObject.prototype.asymmetricKeyType");
+
+ return undefined;
+ }
+
+ get symmetricKeySize(): number | undefined {
+ notImplemented("crypto.KeyObject.prototype.symmetricKeySize");
+
+ return undefined;
+ }
+
+ static from(key: CryptoKey): KeyObject {
+ if (!isCryptoKey(key)) {
+ throw new ERR_INVALID_ARG_TYPE("key", "CryptoKey", key);
+ }
+
+ notImplemented("crypto.KeyObject.prototype.from");
+ }
+
+ equals(otherKeyObject: KeyObject): boolean {
+ if (!isKeyObject(otherKeyObject)) {
+ throw new ERR_INVALID_ARG_TYPE(
+ "otherKeyObject",
+ "KeyObject",
+ otherKeyObject,
+ );
+ }
+
+ notImplemented("crypto.KeyObject.prototype.equals");
+ }
+
+ export(options: KeyExportOptions<"pem">): string | Buffer;
+ export(options?: KeyExportOptions<"der">): Buffer;
+ export(options?: JwkKeyExportOptions): JsonWebKey;
+ export(_options?: unknown): string | Buffer | JsonWebKey {
+ notImplemented("crypto.KeyObject.prototype.asymmetricKeyType");
+ }
+}
+
+export interface JsonWebKeyInput {
+ key: JsonWebKey;
+ format: "jwk";
+}
+
+export function createPrivateKey(
+ _key: PrivateKeyInput | string | Buffer | JsonWebKeyInput,
+): KeyObject {
+ notImplemented("crypto.createPrivateKey");
+}
+
+export function createPublicKey(
+ _key: PublicKeyInput | string | Buffer | KeyObject | JsonWebKeyInput,
+): KeyObject {
+ notImplemented("crypto.createPublicKey");
+}
+
+function getKeyTypes(allowKeyObject: boolean, bufferOnly = false) {
+ const types = [
+ "ArrayBuffer",
+ "Buffer",
+ "TypedArray",
+ "DataView",
+ "string", // Only if bufferOnly == false
+ "KeyObject", // Only if allowKeyObject == true && bufferOnly == false
+ "CryptoKey", // Only if allowKeyObject == true && bufferOnly == false
+ ];
+ if (bufferOnly) {
+ return types.slice(0, 4);
+ } else if (!allowKeyObject) {
+ return types.slice(0, 5);
+ }
+ return types;
+}
+
+export function prepareSecretKey(
+ key: string | ArrayBuffer | KeyObject,
+ encoding: string | undefined,
+ bufferOnly = false,
+) {
+ if (!bufferOnly) {
+ if (isKeyObject(key)) {
+ if (key.type !== "secret") {
+ throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE(key.type, "secret");
+ }
+ return key[kHandle];
+ } else if (isCryptoKey(key)) {
+ if (key.type !== "secret") {
+ throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE(key.type, "secret");
+ }
+ return key[kKeyObject][kHandle];
+ }
+ }
+ if (
+ typeof key !== "string" &&
+ !isArrayBufferView(key) &&
+ !isAnyArrayBuffer(key)
+ ) {
+ throw new ERR_INVALID_ARG_TYPE(
+ "key",
+ getKeyTypes(!bufferOnly, bufferOnly),
+ key,
+ );
+ }
+
+ return getArrayBufferOrView(key, "key", encoding);
+}
+
+export function createSecretKey(key: ArrayBufferView): KeyObject;
+export function createSecretKey(
+ key: string,
+ encoding: string,
+): KeyObject;
+export function createSecretKey(
+ _key: string | ArrayBufferView,
+ _encoding?: string,
+): KeyObject {
+ notImplemented("crypto.createSecretKey");
+}
+
+export default {
+ createPrivateKey,
+ createPublicKey,
+ createSecretKey,
+ isKeyObject,
+ isCryptoKey,
+ KeyObject,
+ prepareSecretKey,
+};
diff --git a/ext/node/polyfills/internal/crypto/pbkdf2.ts b/ext/node/polyfills/internal/crypto/pbkdf2.ts
new file mode 100644
index 000000000..a3d821ae7
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/pbkdf2.ts
@@ -0,0 +1,183 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+import { createHash } from "internal:deno_node/polyfills/internal/crypto/hash.ts";
+import { HASH_DATA } from "internal:deno_node/polyfills/internal/crypto/types.ts";
+
+export const MAX_ALLOC = Math.pow(2, 30) - 1;
+
+export type NormalizedAlgorithms =
+ | "md5"
+ | "ripemd160"
+ | "sha1"
+ | "sha224"
+ | "sha256"
+ | "sha384"
+ | "sha512";
+
+export type Algorithms =
+ | "md5"
+ | "ripemd160"
+ | "rmd160"
+ | "sha1"
+ | "sha224"
+ | "sha256"
+ | "sha384"
+ | "sha512";
+
+const createHasher = (algorithm: string) => (value: Uint8Array) =>
+ Buffer.from(createHash(algorithm).update(value).digest() as Buffer);
+
+function getZeroes(zeros: number) {
+ return Buffer.alloc(zeros);
+}
+
+const sizes = {
+ md5: 16,
+ sha1: 20,
+ sha224: 28,
+ sha256: 32,
+ sha384: 48,
+ sha512: 64,
+ rmd160: 20,
+ ripemd160: 20,
+};
+
+function toBuffer(bufferable: HASH_DATA) {
+ if (bufferable instanceof Uint8Array || typeof bufferable === "string") {
+ return Buffer.from(bufferable as Uint8Array);
+ } else {
+ return Buffer.from(bufferable.buffer);
+ }
+}
+
+export class Hmac {
+ hash: (value: Uint8Array) => Buffer;
+ ipad1: Buffer;
+ opad: Buffer;
+ alg: string;
+ blocksize: number;
+ size: number;
+ ipad2: Buffer;
+
+ constructor(alg: Algorithms, key: Buffer, saltLen: number) {
+ this.hash = createHasher(alg);
+
+ const blocksize = alg === "sha512" || alg === "sha384" ? 128 : 64;
+
+ if (key.length > blocksize) {
+ key = this.hash(key);
+ } else if (key.length < blocksize) {
+ key = Buffer.concat([key, getZeroes(blocksize - key.length)], blocksize);
+ }
+
+ const ipad = Buffer.allocUnsafe(blocksize + sizes[alg]);
+ const opad = Buffer.allocUnsafe(blocksize + sizes[alg]);
+ for (let i = 0; i < blocksize; i++) {
+ ipad[i] = key[i] ^ 0x36;
+ opad[i] = key[i] ^ 0x5c;
+ }
+
+ const ipad1 = Buffer.allocUnsafe(blocksize + saltLen + 4);
+ ipad.copy(ipad1, 0, 0, blocksize);
+
+ this.ipad1 = ipad1;
+ this.ipad2 = ipad;
+ this.opad = opad;
+ this.alg = alg;
+ this.blocksize = blocksize;
+ this.size = sizes[alg];
+ }
+
+ run(data: Buffer, ipad: Buffer) {
+ data.copy(ipad, this.blocksize);
+ const h = this.hash(ipad);
+ h.copy(this.opad, this.blocksize);
+ return this.hash(this.opad);
+ }
+}
+
+/**
+ * @param iterations Needs to be higher or equal than zero
+ * @param keylen Needs to be higher or equal than zero but less than max allocation size (2^30)
+ * @param digest Algorithm to be used for encryption
+ */
+export function pbkdf2Sync(
+ password: HASH_DATA,
+ salt: HASH_DATA,
+ iterations: number,
+ keylen: number,
+ digest: Algorithms = "sha1",
+): Buffer {
+ if (typeof iterations !== "number" || iterations < 0) {
+ throw new TypeError("Bad iterations");
+ }
+ if (typeof keylen !== "number" || keylen < 0 || keylen > MAX_ALLOC) {
+ throw new TypeError("Bad key length");
+ }
+
+ const bufferedPassword = toBuffer(password);
+ const bufferedSalt = toBuffer(salt);
+
+ const hmac = new Hmac(digest, bufferedPassword, bufferedSalt.length);
+
+ const DK = Buffer.allocUnsafe(keylen);
+ const block1 = Buffer.allocUnsafe(bufferedSalt.length + 4);
+ bufferedSalt.copy(block1, 0, 0, bufferedSalt.length);
+
+ let destPos = 0;
+ const hLen = sizes[digest];
+ const l = Math.ceil(keylen / hLen);
+
+ for (let i = 1; i <= l; i++) {
+ block1.writeUInt32BE(i, bufferedSalt.length);
+
+ const T = hmac.run(block1, hmac.ipad1);
+ let U = T;
+
+ for (let j = 1; j < iterations; j++) {
+ U = hmac.run(U, hmac.ipad2);
+ for (let k = 0; k < hLen; k++) T[k] ^= U[k];
+ }
+
+ T.copy(DK, destPos);
+ destPos += hLen;
+ }
+
+ return DK;
+}
+
+/**
+ * @param iterations Needs to be higher or equal than zero
+ * @param keylen Needs to be higher or equal than zero but less than max allocation size (2^30)
+ * @param digest Algorithm to be used for encryption
+ */
+export function pbkdf2(
+ password: HASH_DATA,
+ salt: HASH_DATA,
+ iterations: number,
+ keylen: number,
+ digest: Algorithms = "sha1",
+ callback: (err: Error | null, derivedKey?: Buffer) => void,
+) {
+ setTimeout(() => {
+ let err = null,
+ res;
+ try {
+ res = pbkdf2Sync(password, salt, iterations, keylen, digest);
+ } catch (e) {
+ err = e;
+ }
+ if (err) {
+ callback(err instanceof Error ? err : new Error("[non-error thrown]"));
+ } else {
+ callback(null, res);
+ }
+ }, 0);
+}
+
+export default {
+ Hmac,
+ MAX_ALLOC,
+ pbkdf2,
+ pbkdf2Sync,
+};
diff --git a/ext/node/polyfills/internal/crypto/random.ts b/ext/node/polyfills/internal/crypto/random.ts
new file mode 100644
index 000000000..158ea40da
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/random.ts
@@ -0,0 +1,140 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license.
+
+import { notImplemented } from "internal:deno_node/polyfills/_utils.ts";
+import randomBytes from "internal:deno_node/polyfills/internal/crypto/_randomBytes.ts";
+import randomFill, {
+ randomFillSync,
+} from "internal:deno_node/polyfills/internal/crypto/_randomFill.ts";
+import randomInt from "internal:deno_node/polyfills/internal/crypto/_randomInt.ts";
+
+export { default as randomBytes } from "internal:deno_node/polyfills/internal/crypto/_randomBytes.ts";
+export {
+ default as randomFill,
+ randomFillSync,
+} from "internal:deno_node/polyfills/internal/crypto/_randomFill.ts";
+export { default as randomInt } from "internal:deno_node/polyfills/internal/crypto/_randomInt.ts";
+
+export type LargeNumberLike =
+ | ArrayBufferView
+ | SharedArrayBuffer
+ | ArrayBuffer
+ | bigint;
+
+export interface CheckPrimeOptions {
+ /**
+ * The number of Miller-Rabin probabilistic primality iterations to perform.
+ * When the value is 0 (zero), a number of checks is used that yields a false positive rate of at most 2-64 for random input.
+ * Care must be used when selecting a number of checks.
+ * Refer to the OpenSSL documentation for the BN_is_prime_ex function nchecks options for more details.
+ *
+ * @default 0
+ */
+ checks?: number | undefined;
+}
+
+export function checkPrime(
+ candidate: LargeNumberLike,
+ callback: (err: Error | null, result: boolean) => void,
+): void;
+export function checkPrime(
+ candidate: LargeNumberLike,
+ options: CheckPrimeOptions,
+ callback: (err: Error | null, result: boolean) => void,
+): void;
+export function checkPrime(
+ _candidate: LargeNumberLike,
+ _options?: CheckPrimeOptions | ((err: Error | null, result: boolean) => void),
+ _callback?: (err: Error | null, result: boolean) => void,
+) {
+ notImplemented("crypto.checkPrime");
+}
+
+export function checkPrimeSync(
+ _candidate: LargeNumberLike,
+ _options?: CheckPrimeOptions,
+): boolean {
+ notImplemented("crypto.checkPrimeSync");
+}
+
+export interface GeneratePrimeOptions {
+ add?: LargeNumberLike | undefined;
+ rem?: LargeNumberLike | undefined;
+ /**
+ * @default false
+ */
+ safe?: boolean | undefined;
+ bigint?: boolean | undefined;
+}
+
+export interface GeneratePrimeOptionsBigInt extends GeneratePrimeOptions {
+ bigint: true;
+}
+
+export interface GeneratePrimeOptionsArrayBuffer extends GeneratePrimeOptions {
+ bigint?: false | undefined;
+}
+
+export function generatePrime(
+ size: number,
+ callback: (err: Error | null, prime: ArrayBuffer) => void,
+): void;
+export function generatePrime(
+ size: number,
+ options: GeneratePrimeOptionsBigInt,
+ callback: (err: Error | null, prime: bigint) => void,
+): void;
+export function generatePrime(
+ size: number,
+ options: GeneratePrimeOptionsArrayBuffer,
+ callback: (err: Error | null, prime: ArrayBuffer) => void,
+): void;
+export function generatePrime(
+ size: number,
+ options: GeneratePrimeOptions,
+ callback: (err: Error | null, prime: ArrayBuffer | bigint) => void,
+): void;
+export function generatePrime(
+ _size: number,
+ _options?: unknown,
+ _callback?: unknown,
+) {
+ notImplemented("crypto.generatePrime");
+}
+
+export function generatePrimeSync(size: number): ArrayBuffer;
+export function generatePrimeSync(
+ size: number,
+ options: GeneratePrimeOptionsBigInt,
+): bigint;
+export function generatePrimeSync(
+ size: number,
+ options: GeneratePrimeOptionsArrayBuffer,
+): ArrayBuffer;
+export function generatePrimeSync(
+ size: number,
+ options: GeneratePrimeOptions,
+): ArrayBuffer | bigint;
+export function generatePrimeSync(
+ _size: number,
+ _options?:
+ | GeneratePrimeOptionsBigInt
+ | GeneratePrimeOptionsArrayBuffer
+ | GeneratePrimeOptions,
+): ArrayBuffer | bigint {
+ notImplemented("crypto.generatePrimeSync");
+}
+
+export const randomUUID = () => globalThis.crypto.randomUUID();
+
+export default {
+ checkPrime,
+ checkPrimeSync,
+ generatePrime,
+ generatePrimeSync,
+ randomUUID,
+ randomInt,
+ randomBytes,
+ randomFill,
+ randomFillSync,
+};
diff --git a/ext/node/polyfills/internal/crypto/scrypt.ts b/ext/node/polyfills/internal/crypto/scrypt.ts
new file mode 100644
index 000000000..1bdafb63d
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/scrypt.ts
@@ -0,0 +1,278 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+/*
+MIT License
+
+Copyright (c) 2018 cryptocoinjs
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+ */
+
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+import { pbkdf2Sync as pbkdf2 } from "internal:deno_node/polyfills/internal/crypto/pbkdf2.ts";
+import { HASH_DATA } from "internal:deno_node/polyfills/internal/crypto/types.ts";
+
+type Opts = Partial<{
+ N: number;
+ cost: number;
+ p: number;
+ parallelization: number;
+ r: number;
+ blockSize: number;
+ maxmem: number;
+}>;
+
+const fixOpts = (opts?: Opts) => {
+ const out = { N: 16384, p: 1, r: 8, maxmem: 32 << 20 };
+ if (!opts) return out;
+
+ if (opts.N) out.N = opts.N;
+ else if (opts.cost) out.N = opts.cost;
+
+ if (opts.p) out.p = opts.p;
+ else if (opts.parallelization) out.p = opts.parallelization;
+
+ if (opts.r) out.r = opts.r;
+ else if (opts.blockSize) out.r = opts.blockSize;
+
+ if (opts.maxmem) out.maxmem = opts.maxmem;
+
+ return out;
+};
+
+function blockxor(S: Buffer, Si: number, D: Buffer, Di: number, len: number) {
+ let i = -1;
+ while (++i < len) D[Di + i] ^= S[Si + i];
+}
+function arraycopy(
+ src: Buffer,
+ srcPos: number,
+ dest: Buffer,
+ destPos: number,
+ length: number,
+) {
+ src.copy(dest, destPos, srcPos, srcPos + length);
+}
+
+const R = (a: number, b: number) => (a << b) | (a >>> (32 - b));
+
+class ScryptRom {
+ B: Buffer;
+ r: number;
+ N: number;
+ p: number;
+ XY: Buffer;
+ V: Buffer;
+ B32: Int32Array;
+ x: Int32Array;
+ _X: Buffer;
+ constructor(b: Buffer, r: number, N: number, p: number) {
+ this.B = b;
+ this.r = r;
+ this.N = N;
+ this.p = p;
+ this.XY = Buffer.allocUnsafe(256 * r);
+ this.V = Buffer.allocUnsafe(128 * r * N);
+ this.B32 = new Int32Array(16); // salsa20_8
+ this.x = new Int32Array(16); // salsa20_8
+ this._X = Buffer.allocUnsafe(64); // blockmix_salsa8
+ }
+
+ run() {
+ const p = this.p | 0;
+ const r = this.r | 0;
+ for (let i = 0; i < p; i++) this.scryptROMix(i, r);
+
+ return this.B;
+ }
+
+ scryptROMix(i: number, r: number) {
+ const blockStart = i * 128 * r;
+ const offset = (2 * r - 1) * 64;
+ const blockLen = 128 * r;
+ const B = this.B;
+ const N = this.N | 0;
+ const V = this.V;
+ const XY = this.XY;
+ B.copy(XY, 0, blockStart, blockStart + blockLen);
+ for (let i1 = 0; i1 < N; i1++) {
+ XY.copy(V, i1 * blockLen, 0, blockLen);
+ this.blockmix_salsa8(blockLen);
+ }
+
+ let j: number;
+ for (let i2 = 0; i2 < N; i2++) {
+ j = XY.readUInt32LE(offset) & (N - 1);
+ blockxor(V, j * blockLen, XY, 0, blockLen);
+ this.blockmix_salsa8(blockLen);
+ }
+ XY.copy(B, blockStart, 0, blockLen);
+ }
+
+ blockmix_salsa8(blockLen: number) {
+ const BY = this.XY;
+ const r = this.r;
+ const _X = this._X;
+ arraycopy(BY, (2 * r - 1) * 64, _X, 0, 64);
+ let i;
+ for (i = 0; i < 2 * r; i++) {
+ blockxor(BY, i * 64, _X, 0, 64);
+ this.salsa20_8();
+ arraycopy(_X, 0, BY, blockLen + i * 64, 64);
+ }
+ for (i = 0; i < r; i++) {
+ arraycopy(BY, blockLen + i * 2 * 64, BY, i * 64, 64);
+ arraycopy(BY, blockLen + (i * 2 + 1) * 64, BY, (i + r) * 64, 64);
+ }
+ }
+
+ salsa20_8() {
+ const B32 = this.B32;
+ const B = this._X;
+ const x = this.x;
+
+ let i;
+ for (i = 0; i < 16; i++) {
+ B32[i] = (B[i * 4 + 0] & 0xff) << 0;
+ B32[i] |= (B[i * 4 + 1] & 0xff) << 8;
+ B32[i] |= (B[i * 4 + 2] & 0xff) << 16;
+ B32[i] |= (B[i * 4 + 3] & 0xff) << 24;
+ }
+
+ for (i = 0; i < 16; i++) x[i] = B32[i];
+
+ for (i = 0; i < 4; i++) {
+ x[4] ^= R(x[0] + x[12], 7);
+ x[8] ^= R(x[4] + x[0], 9);
+ x[12] ^= R(x[8] + x[4], 13);
+ x[0] ^= R(x[12] + x[8], 18);
+ x[9] ^= R(x[5] + x[1], 7);
+ x[13] ^= R(x[9] + x[5], 9);
+ x[1] ^= R(x[13] + x[9], 13);
+ x[5] ^= R(x[1] + x[13], 18);
+ x[14] ^= R(x[10] + x[6], 7);
+ x[2] ^= R(x[14] + x[10], 9);
+ x[6] ^= R(x[2] + x[14], 13);
+ x[10] ^= R(x[6] + x[2], 18);
+ x[3] ^= R(x[15] + x[11], 7);
+ x[7] ^= R(x[3] + x[15], 9);
+ x[11] ^= R(x[7] + x[3], 13);
+ x[15] ^= R(x[11] + x[7], 18);
+ x[1] ^= R(x[0] + x[3], 7);
+ x[2] ^= R(x[1] + x[0], 9);
+ x[3] ^= R(x[2] + x[1], 13);
+ x[0] ^= R(x[3] + x[2], 18);
+ x[6] ^= R(x[5] + x[4], 7);
+ x[7] ^= R(x[6] + x[5], 9);
+ x[4] ^= R(x[7] + x[6], 13);
+ x[5] ^= R(x[4] + x[7], 18);
+ x[11] ^= R(x[10] + x[9], 7);
+ x[8] ^= R(x[11] + x[10], 9);
+ x[9] ^= R(x[8] + x[11], 13);
+ x[10] ^= R(x[9] + x[8], 18);
+ x[12] ^= R(x[15] + x[14], 7);
+ x[13] ^= R(x[12] + x[15], 9);
+ x[14] ^= R(x[13] + x[12], 13);
+ x[15] ^= R(x[14] + x[13], 18);
+ }
+ for (i = 0; i < 16; i++) B32[i] += x[i];
+
+ let bi;
+
+ for (i = 0; i < 16; i++) {
+ bi = i * 4;
+ B[bi + 0] = (B32[i] >> 0) & 0xff;
+ B[bi + 1] = (B32[i] >> 8) & 0xff;
+ B[bi + 2] = (B32[i] >> 16) & 0xff;
+ B[bi + 3] = (B32[i] >> 24) & 0xff;
+ }
+ }
+
+ clean() {
+ this.XY.fill(0);
+ this.V.fill(0);
+ this._X.fill(0);
+ this.B.fill(0);
+ for (let i = 0; i < 16; i++) {
+ this.B32[i] = 0;
+ this.x[i] = 0;
+ }
+ }
+}
+
+export function scryptSync(
+ password: HASH_DATA,
+ salt: HASH_DATA,
+ keylen: number,
+ _opts?: Opts,
+): Buffer {
+ const { N, r, p, maxmem } = fixOpts(_opts);
+
+ const blen = p * 128 * r;
+
+ if (32 * r * (N + 2) * 4 + blen > maxmem) {
+ throw new Error("excedes max memory");
+ }
+
+ const b = pbkdf2(password, salt, 1, blen, "sha256");
+
+ const scryptRom = new ScryptRom(b, r, N, p);
+ const out = scryptRom.run();
+
+ const fin = pbkdf2(password, out, 1, keylen, "sha256");
+ scryptRom.clean();
+ return fin;
+}
+
+type Callback = (err: unknown, result?: Buffer) => void;
+
+export function scrypt(
+ password: HASH_DATA,
+ salt: HASH_DATA,
+ keylen: number,
+ _opts: Opts | null | Callback,
+ cb?: Callback,
+) {
+ if (!cb) {
+ cb = _opts as Callback;
+ _opts = null;
+ }
+ const { N, r, p, maxmem } = fixOpts(_opts as Opts);
+
+ const blen = p * 128 * r;
+ if (32 * r * (N + 2) * 4 + blen > maxmem) {
+ throw new Error("excedes max memory");
+ }
+
+ try {
+ const b = pbkdf2(password, salt, 1, blen, "sha256");
+
+ const scryptRom = new ScryptRom(b, r, N, p);
+ const out = scryptRom.run();
+ const result = pbkdf2(password, out, 1, keylen, "sha256");
+ scryptRom.clean();
+ cb(null, result);
+ } catch (err: unknown) {
+ return cb(err);
+ }
+}
+
+export default {
+ scrypt,
+ scryptSync,
+};
diff --git a/ext/node/polyfills/internal/crypto/sig.ts b/ext/node/polyfills/internal/crypto/sig.ts
new file mode 100644
index 000000000..6c163c8e5
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/sig.ts
@@ -0,0 +1,148 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license.
+
+import { notImplemented } from "internal:deno_node/polyfills/_utils.ts";
+import { validateString } from "internal:deno_node/polyfills/internal/validators.mjs";
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+import type { WritableOptions } from "internal:deno_node/polyfills/_stream.d.ts";
+import Writable from "internal:deno_node/polyfills/internal/streams/writable.mjs";
+import type {
+ BinaryLike,
+ BinaryToTextEncoding,
+ Encoding,
+ PrivateKeyInput,
+ PublicKeyInput,
+} from "internal:deno_node/polyfills/internal/crypto/types.ts";
+import { KeyObject } from "internal:deno_node/polyfills/internal/crypto/keys.ts";
+
+export type DSAEncoding = "der" | "ieee-p1363";
+
+export interface SigningOptions {
+ padding?: number | undefined;
+ saltLength?: number | undefined;
+ dsaEncoding?: DSAEncoding | undefined;
+}
+
+export interface SignPrivateKeyInput extends PrivateKeyInput, SigningOptions {}
+
+export interface SignKeyObjectInput extends SigningOptions {
+ key: KeyObject;
+}
+export interface VerifyPublicKeyInput extends PublicKeyInput, SigningOptions {}
+
+export interface VerifyKeyObjectInput extends SigningOptions {
+ key: KeyObject;
+}
+
+export type KeyLike = string | Buffer | KeyObject;
+
+export class Sign extends Writable {
+ constructor(algorithm: string, _options?: WritableOptions) {
+ validateString(algorithm, "algorithm");
+
+ super();
+
+ notImplemented("crypto.Sign");
+ }
+
+ sign(privateKey: KeyLike | SignKeyObjectInput | SignPrivateKeyInput): Buffer;
+ sign(
+ privateKey: KeyLike | SignKeyObjectInput | SignPrivateKeyInput,
+ outputFormat: BinaryToTextEncoding,
+ ): string;
+ sign(
+ _privateKey: KeyLike | SignKeyObjectInput | SignPrivateKeyInput,
+ _outputEncoding?: BinaryToTextEncoding,
+ ): Buffer | string {
+ notImplemented("crypto.Sign.prototype.sign");
+ }
+
+ update(data: BinaryLike): this;
+ update(data: string, inputEncoding: Encoding): this;
+ update(_data: BinaryLike | string, _inputEncoding?: Encoding): this {
+ notImplemented("crypto.Sign.prototype.update");
+ }
+}
+
+export class Verify extends Writable {
+ constructor(algorithm: string, _options?: WritableOptions) {
+ validateString(algorithm, "algorithm");
+
+ super();
+
+ notImplemented("crypto.Verify");
+ }
+
+ update(data: BinaryLike): this;
+ update(data: string, inputEncoding: Encoding): this;
+ update(_data: BinaryLike, _inputEncoding?: string): this {
+ notImplemented("crypto.Sign.prototype.update");
+ }
+
+ verify(
+ object: KeyLike | VerifyKeyObjectInput | VerifyPublicKeyInput,
+ signature: ArrayBufferView,
+ ): boolean;
+ verify(
+ object: KeyLike | VerifyKeyObjectInput | VerifyPublicKeyInput,
+ signature: string,
+ signatureEncoding?: BinaryToTextEncoding,
+ ): boolean;
+ verify(
+ _object: KeyLike | VerifyKeyObjectInput | VerifyPublicKeyInput,
+ _signature: ArrayBufferView | string,
+ _signatureEncoding?: BinaryToTextEncoding,
+ ): boolean {
+ notImplemented("crypto.Sign.prototype.sign");
+ }
+}
+
+export function signOneShot(
+ algorithm: string | null | undefined,
+ data: ArrayBufferView,
+ key: KeyLike | SignKeyObjectInput | SignPrivateKeyInput,
+): Buffer;
+export function signOneShot(
+ algorithm: string | null | undefined,
+ data: ArrayBufferView,
+ key: KeyLike | SignKeyObjectInput | SignPrivateKeyInput,
+ callback: (error: Error | null, data: Buffer) => void,
+): void;
+export function signOneShot(
+ _algorithm: string | null | undefined,
+ _data: ArrayBufferView,
+ _key: KeyLike | SignKeyObjectInput | SignPrivateKeyInput,
+ _callback?: (error: Error | null, data: Buffer) => void,
+): Buffer | void {
+ notImplemented("crypto.sign");
+}
+
+export function verifyOneShot(
+ algorithm: string | null | undefined,
+ data: ArrayBufferView,
+ key: KeyLike | VerifyKeyObjectInput | VerifyPublicKeyInput,
+ signature: ArrayBufferView,
+): boolean;
+export function verifyOneShot(
+ algorithm: string | null | undefined,
+ data: ArrayBufferView,
+ key: KeyLike | VerifyKeyObjectInput | VerifyPublicKeyInput,
+ signature: ArrayBufferView,
+ callback: (error: Error | null, result: boolean) => void,
+): void;
+export function verifyOneShot(
+ _algorithm: string | null | undefined,
+ _data: ArrayBufferView,
+ _key: KeyLike | VerifyKeyObjectInput | VerifyPublicKeyInput,
+ _signature: ArrayBufferView,
+ _callback?: (error: Error | null, result: boolean) => void,
+): boolean | void {
+ notImplemented("crypto.verify");
+}
+
+export default {
+ signOneShot,
+ verifyOneShot,
+ Sign,
+ Verify,
+};
diff --git a/ext/node/polyfills/internal/crypto/types.ts b/ext/node/polyfills/internal/crypto/types.ts
new file mode 100644
index 000000000..3bb9ec160
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/types.ts
@@ -0,0 +1,46 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license.
+
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+
+export type HASH_DATA = string | ArrayBufferView | Buffer;
+
+export type BinaryToTextEncoding = "base64" | "base64url" | "hex" | "binary";
+
+export type CharacterEncoding = "utf8" | "utf-8" | "utf16le" | "latin1";
+
+export type LegacyCharacterEncoding = "ascii" | "binary" | "ucs2" | "ucs-2";
+
+export type Encoding =
+ | BinaryToTextEncoding
+ | CharacterEncoding
+ | LegacyCharacterEncoding;
+
+export type ECDHKeyFormat = "compressed" | "uncompressed" | "hybrid";
+
+export type BinaryLike = string | ArrayBufferView;
+
+export type KeyFormat = "pem" | "der";
+
+export type KeyType =
+ | "rsa"
+ | "rsa-pss"
+ | "dsa"
+ | "ec"
+ | "ed25519"
+ | "ed448"
+ | "x25519"
+ | "x448";
+
+export interface PrivateKeyInput {
+ key: string | Buffer;
+ format?: KeyFormat | undefined;
+ type?: "pkcs1" | "pkcs8" | "sec1" | undefined;
+ passphrase?: string | Buffer | undefined;
+}
+
+export interface PublicKeyInput {
+ key: string | Buffer;
+ format?: KeyFormat | undefined;
+ type?: "pkcs1" | "spki" | undefined;
+}
diff --git a/ext/node/polyfills/internal/crypto/util.ts b/ext/node/polyfills/internal/crypto/util.ts
new file mode 100644
index 000000000..f9fce8b2d
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/util.ts
@@ -0,0 +1,129 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license.
+
+import { getCiphers } from "internal:deno_node/polyfills/_crypto/crypto_browserify/browserify_aes/mod.js";
+import { notImplemented } from "internal:deno_node/polyfills/_utils.ts";
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+import {
+ ERR_INVALID_ARG_TYPE,
+ hideStackFrames,
+} from "internal:deno_node/polyfills/internal/errors.ts";
+import {
+ isAnyArrayBuffer,
+ isArrayBufferView,
+} from "internal:deno_node/polyfills/internal/util/types.ts";
+import { crypto as constants } from "internal:deno_node/polyfills/internal_binding/constants.ts";
+import {
+ kHandle,
+ kKeyObject,
+} from "internal:deno_node/polyfills/internal/crypto/constants.ts";
+
+// TODO(kt3k): Generate this list from `digestAlgorithms`
+// of std/crypto/_wasm/mod.ts
+const digestAlgorithms = [
+ "blake2b256",
+ "blake2b384",
+ "blake2b",
+ "blake2s",
+ "blake3",
+ "keccak-224",
+ "keccak-256",
+ "keccak-384",
+ "keccak-512",
+ "sha384",
+ "sha3-224",
+ "sha3-256",
+ "sha3-384",
+ "sha3-512",
+ "shake128",
+ "shake256",
+ "tiger",
+ "rmd160",
+ "sha224",
+ "sha256",
+ "sha512",
+ "md4",
+ "md5",
+ "sha1",
+];
+
+let defaultEncoding = "buffer";
+
+export function setDefaultEncoding(val: string) {
+ defaultEncoding = val;
+}
+
+export function getDefaultEncoding(): string {
+ return defaultEncoding;
+}
+
+// This is here because many functions accepted binary strings without
+// any explicit encoding in older versions of node, and we don't want
+// to break them unnecessarily.
+export function toBuf(val: string | Buffer, encoding?: string): Buffer {
+ if (typeof val === "string") {
+ if (encoding === "buffer") {
+ encoding = "utf8";
+ }
+
+ return Buffer.from(val, encoding);
+ }
+
+ return val;
+}
+
+export const validateByteSource = hideStackFrames((val, name) => {
+ val = toBuf(val);
+
+ if (isAnyArrayBuffer(val) || isArrayBufferView(val)) {
+ return;
+ }
+
+ throw new ERR_INVALID_ARG_TYPE(
+ name,
+ ["string", "ArrayBuffer", "TypedArray", "DataView", "Buffer"],
+ val,
+ );
+});
+
+/**
+ * Returns an array of the names of the supported hash algorithms, such as 'sha1'.
+ */
+export function getHashes(): readonly string[] {
+ return digestAlgorithms;
+}
+
+export function getCurves(): readonly string[] {
+ notImplemented("crypto.getCurves");
+}
+
+export interface SecureHeapUsage {
+ total: number;
+ min: number;
+ used: number;
+ utilization: number;
+}
+
+export function secureHeapUsed(): SecureHeapUsage {
+ notImplemented("crypto.secureHeapUsed");
+}
+
+export function setEngine(_engine: string, _flags: typeof constants) {
+ notImplemented("crypto.setEngine");
+}
+
+export { getCiphers, kHandle, kKeyObject };
+
+export default {
+ getDefaultEncoding,
+ getHashes,
+ setDefaultEncoding,
+ getCiphers,
+ getCurves,
+ secureHeapUsed,
+ setEngine,
+ validateByteSource,
+ toBuf,
+ kHandle,
+ kKeyObject,
+};
diff --git a/ext/node/polyfills/internal/crypto/x509.ts b/ext/node/polyfills/internal/crypto/x509.ts
new file mode 100644
index 000000000..0722d7865
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/x509.ts
@@ -0,0 +1,186 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license.
+
+import { KeyObject } from "internal:deno_node/polyfills/internal/crypto/keys.ts";
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+import { ERR_INVALID_ARG_TYPE } from "internal:deno_node/polyfills/internal/errors.ts";
+import { isArrayBufferView } from "internal:deno_node/polyfills/internal/util/types.ts";
+import { notImplemented } from "internal:deno_node/polyfills/_utils.ts";
+import { BinaryLike } from "internal:deno_node/polyfills/internal/crypto/types.ts";
+
+// deno-lint-ignore no-explicit-any
+export type PeerCertificate = any;
+
+export interface X509CheckOptions {
+ /**
+ * @default 'always'
+ */
+ subject: "always" | "never";
+ /**
+ * @default true
+ */
+ wildcards: boolean;
+ /**
+ * @default true
+ */
+ partialWildcards: boolean;
+ /**
+ * @default false
+ */
+ multiLabelWildcards: boolean;
+ /**
+ * @default false
+ */
+ singleLabelSubdomains: boolean;
+}
+
+export class X509Certificate {
+ constructor(buffer: BinaryLike) {
+ if (typeof buffer === "string") {
+ buffer = Buffer.from(buffer);
+ }
+
+ if (!isArrayBufferView(buffer)) {
+ throw new ERR_INVALID_ARG_TYPE(
+ "buffer",
+ ["string", "Buffer", "TypedArray", "DataView"],
+ buffer,
+ );
+ }
+
+ notImplemented("crypto.X509Certificate");
+ }
+
+ get ca(): boolean {
+ notImplemented("crypto.X509Certificate.prototype.ca");
+
+ return false;
+ }
+
+ checkEmail(
+ _email: string,
+ _options?: Pick<X509CheckOptions, "subject">,
+ ): string | undefined {
+ notImplemented("crypto.X509Certificate.prototype.checkEmail");
+ }
+
+ checkHost(_name: string, _options?: X509CheckOptions): string | undefined {
+ notImplemented("crypto.X509Certificate.prototype.checkHost");
+ }
+
+ checkIP(_ip: string): string | undefined {
+ notImplemented("crypto.X509Certificate.prototype.checkIP");
+ }
+
+ checkIssued(_otherCert: X509Certificate): boolean {
+ notImplemented("crypto.X509Certificate.prototype.checkIssued");
+ }
+
+ checkPrivateKey(_privateKey: KeyObject): boolean {
+ notImplemented("crypto.X509Certificate.prototype.checkPrivateKey");
+ }
+
+ get fingerprint(): string {
+ notImplemented("crypto.X509Certificate.prototype.fingerprint");
+
+ return "";
+ }
+
+ get fingerprint256(): string {
+ notImplemented("crypto.X509Certificate.prototype.fingerprint256");
+
+ return "";
+ }
+
+ get fingerprint512(): string {
+ notImplemented("crypto.X509Certificate.prototype.fingerprint512");
+
+ return "";
+ }
+
+ get infoAccess(): string | undefined {
+ notImplemented("crypto.X509Certificate.prototype.infoAccess");
+
+ return "";
+ }
+
+ get issuer(): string {
+ notImplemented("crypto.X509Certificate.prototype.issuer");
+
+ return "";
+ }
+
+ get issuerCertificate(): X509Certificate | undefined {
+ notImplemented("crypto.X509Certificate.prototype.issuerCertificate");
+
+ return {} as X509Certificate;
+ }
+
+ get keyUsage(): string[] {
+ notImplemented("crypto.X509Certificate.prototype.keyUsage");
+
+ return [];
+ }
+
+ get publicKey(): KeyObject {
+ notImplemented("crypto.X509Certificate.prototype.publicKey");
+
+ return {} as KeyObject;
+ }
+
+ get raw(): Buffer {
+ notImplemented("crypto.X509Certificate.prototype.raw");
+
+ return {} as Buffer;
+ }
+
+ get serialNumber(): string {
+ notImplemented("crypto.X509Certificate.prototype.serialNumber");
+
+ return "";
+ }
+
+ get subject(): string {
+ notImplemented("crypto.X509Certificate.prototype.subject");
+
+ return "";
+ }
+
+ get subjectAltName(): string | undefined {
+ notImplemented("crypto.X509Certificate.prototype.subjectAltName");
+
+ return "";
+ }
+
+ toJSON(): string {
+ return this.toString();
+ }
+
+ toLegacyObject(): PeerCertificate {
+ notImplemented("crypto.X509Certificate.prototype.toLegacyObject");
+ }
+
+ toString(): string {
+ notImplemented("crypto.X509Certificate.prototype.toString");
+ }
+
+ get validFrom(): string {
+ notImplemented("crypto.X509Certificate.prototype.validFrom");
+
+ return "";
+ }
+
+ get validTo(): string {
+ notImplemented("crypto.X509Certificate.prototype.validTo");
+
+ return "";
+ }
+
+ verify(_publicKey: KeyObject): boolean {
+ notImplemented("crypto.X509Certificate.prototype.verify");
+ }
+}
+
+export default {
+ X509Certificate,
+};