summaryrefslogtreecommitdiff
path: root/ext/node/polyfills/internal/crypto
diff options
context:
space:
mode:
authorLuca Casonato <hello@lcas.dev>2024-08-07 08:43:58 +0200
committerGitHub <noreply@github.com>2024-08-07 08:43:58 +0200
commit4fa8869f2487749a9f190cb3047f4f3e6d571f27 (patch)
tree640c13e45e0bf1c63340c15f64b08b614ddcf120 /ext/node/polyfills/internal/crypto
parent9a83efa04b6e733ca0fdbf9e780c4b77f0d9f4be (diff)
feat(ext/node): rewrite crypto keys (#24463)
This completely rewrites how we handle key material in ext/node. Changes in this PR: - **Signing** - RSA - RSA-PSS 🆕 - DSA 🆕 - EC - ED25519 🆕 - **Verifying** - RSA - RSA-PSS 🆕 - DSA 🆕 - EC 🆕 - ED25519 🆕 - **Private key import** - Passphrase encrypted private keys 🆕 - RSA - PEM - DER (PKCS#1) 🆕 - DER (PKCS#8) 🆕 - RSA-PSS - PEM - DER (PKCS#1) 🆕 - DER (PKCS#8) 🆕 - DSA 🆕 - EC - PEM - DER (SEC1) 🆕 - DER (PKCS#8) 🆕 - X25519 🆕 - ED25519 🆕 - DH - **Public key import** - RSA - PEM - DER (PKCS#1) 🆕 - DER (PKCS#8) 🆕 - RSA-PSS 🆕 - DSA 🆕 - EC 🆕 - X25519 🆕 - ED25519 🆕 - DH 🆕 - **Private key export** - RSA 🆕 - DSA 🆕 - EC 🆕 - X25519 🆕 - ED25519 🆕 - DH 🆕 - **Public key export** - RSA - DSA 🆕 - EC 🆕 - X25519 🆕 - ED25519 🆕 - DH 🆕 - **Key pair generation** - Overhauled, but supported APIs unchanged This PR adds a lot of new individual functionality. But most importantly because of the new key material representation, it is now trivial to add new algorithms (as shown by this PR). Now, when adding a new algorithm, it is also widely supported - for example previously we supported ED25519 key pair generation, but we could not import, export, sign or verify with ED25519. We can now do all of those things.
Diffstat (limited to 'ext/node/polyfills/internal/crypto')
-rw-r--r--ext/node/polyfills/internal/crypto/_keys.ts10
-rw-r--r--ext/node/polyfills/internal/crypto/_randomFill.mjs33
-rw-r--r--ext/node/polyfills/internal/crypto/cipher.ts4
-rw-r--r--ext/node/polyfills/internal/crypto/diffiehellman.ts4
-rw-r--r--ext/node/polyfills/internal/crypto/hash.ts25
-rw-r--r--ext/node/polyfills/internal/crypto/hkdf.ts10
-rw-r--r--ext/node/polyfills/internal/crypto/keygen.ts117
-rw-r--r--ext/node/polyfills/internal/crypto/keys.ts558
-rw-r--r--ext/node/polyfills/internal/crypto/sig.ts63
-rw-r--r--ext/node/polyfills/internal/crypto/types.ts3
10 files changed, 579 insertions, 248 deletions
diff --git a/ext/node/polyfills/internal/crypto/_keys.ts b/ext/node/polyfills/internal/crypto/_keys.ts
index 9da91f022..e79986245 100644
--- a/ext/node/polyfills/internal/crypto/_keys.ts
+++ b/ext/node/polyfills/internal/crypto/_keys.ts
@@ -1,19 +1,25 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This file is here because to break a circular dependency between streams and
+// crypto.
+
// TODO(petamoriken): enable prefer-primordials for node polyfills
// deno-lint-ignore-file prefer-primordials
import { kKeyObject } from "ext:deno_node/internal/crypto/constants.ts";
+import type { KeyObject } from "ext:deno_node/internal/crypto/keys.ts";
export const kKeyType = Symbol("kKeyType");
-export function isKeyObject(obj: unknown): boolean {
+export function isKeyObject(obj: unknown): obj is KeyObject {
return (
obj != null && (obj as Record<symbol, unknown>)[kKeyType] !== undefined
);
}
-export function isCryptoKey(obj: unknown): boolean {
+export function isCryptoKey(
+ obj: unknown,
+): obj is CryptoKey {
return (
obj != null && (obj as Record<symbol, unknown>)[kKeyObject] !== undefined
);
diff --git a/ext/node/polyfills/internal/crypto/_randomFill.mjs b/ext/node/polyfills/internal/crypto/_randomFill.mjs
index e53918b39..808ab4565 100644
--- a/ext/node/polyfills/internal/crypto/_randomFill.mjs
+++ b/ext/node/polyfills/internal/crypto/_randomFill.mjs
@@ -3,14 +3,9 @@
// TODO(petamoriken): enable prefer-primordials for node polyfills
// deno-lint-ignore-file prefer-primordials
-import {
- op_node_generate_secret,
- op_node_generate_secret_async,
-} from "ext:core/ops";
-
-import {
- MAX_SIZE as kMaxUint32,
-} from "ext:deno_node/internal/crypto/_randomBytes.ts";
+import { op_node_fill_random, op_node_fill_random_async } from "ext:core/ops";
+
+import { MAX_SIZE as kMaxUint32 } from "ext:deno_node/internal/crypto/_randomBytes.ts";
import { Buffer } from "node:buffer";
import { isAnyArrayBuffer, isArrayBufferView } from "node:util/types";
import { ERR_INVALID_ARG_TYPE } from "ext:deno_node/internal/errors.ts";
@@ -37,12 +32,7 @@ function assertSize(size, offset, length) {
}
}
-export default function randomFill(
- buf,
- offset,
- size,
- cb,
-) {
+export default function randomFill(buf, offset, size, cb) {
if (typeof offset === "function") {
cb = offset;
offset = 0;
@@ -55,14 +45,11 @@ export default function randomFill(
assertOffset(offset, buf.length);
assertSize(size, offset, buf.length);
- op_node_generate_secret_async(Math.floor(size))
- .then(
- (randomData) => {
- const randomBuf = Buffer.from(randomData.buffer);
- randomBuf.copy(buf, offset, 0, size);
- cb(null, buf);
- },
- );
+ op_node_fill_random_async(Math.floor(size)).then((randomData) => {
+ const randomBuf = Buffer.from(randomData.buffer);
+ randomBuf.copy(buf, offset, 0, size);
+ cb(null, buf);
+ });
}
export function randomFillSync(buf, offset = 0, size) {
@@ -89,7 +76,7 @@ export function randomFillSync(buf, offset = 0, size) {
const bytes = isAnyArrayBuffer(buf)
? new Uint8Array(buf, offset, size)
: new Uint8Array(buf.buffer, buf.byteOffset + offset, size);
- op_node_generate_secret(bytes);
+ op_node_fill_random(bytes);
return buf;
}
diff --git a/ext/node/polyfills/internal/crypto/cipher.ts b/ext/node/polyfills/internal/crypto/cipher.ts
index f8a46896d..d83d4fa8f 100644
--- a/ext/node/polyfills/internal/crypto/cipher.ts
+++ b/ext/node/polyfills/internal/crypto/cipher.ts
@@ -41,7 +41,9 @@ import {
isArrayBufferView,
} from "ext:deno_node/internal/util/types.ts";
-export function isStringOrBuffer(val) {
+export function isStringOrBuffer(
+ val: unknown,
+): val is string | Buffer | ArrayBuffer | ArrayBufferView {
return typeof val === "string" ||
isArrayBufferView(val) ||
isAnyArrayBuffer(val) ||
diff --git a/ext/node/polyfills/internal/crypto/diffiehellman.ts b/ext/node/polyfills/internal/crypto/diffiehellman.ts
index 6058433ba..16a1f2498 100644
--- a/ext/node/polyfills/internal/crypto/diffiehellman.ts
+++ b/ext/node/polyfills/internal/crypto/diffiehellman.ts
@@ -6,7 +6,7 @@
import {
op_node_dh_compute_secret,
- op_node_dh_generate2,
+ op_node_dh_keys_generate_and_export,
op_node_ecdh_compute_public_key,
op_node_ecdh_compute_secret,
op_node_ecdh_encode_pubkey,
@@ -198,7 +198,7 @@ export class DiffieHellman {
generateKeys(encoding: BinaryToTextEncoding): string;
generateKeys(_encoding?: BinaryToTextEncoding): Buffer | string {
const generator = this.#checkGenerator();
- const [privateKey, publicKey] = op_node_dh_generate2(
+ const [privateKey, publicKey] = op_node_dh_keys_generate_and_export(
this.#prime,
this.#primeLength ?? 0,
generator,
diff --git a/ext/node/polyfills/internal/crypto/hash.ts b/ext/node/polyfills/internal/crypto/hash.ts
index 2e040be25..c42ca3989 100644
--- a/ext/node/polyfills/internal/crypto/hash.ts
+++ b/ext/node/polyfills/internal/crypto/hash.ts
@@ -6,6 +6,7 @@
import {
op_node_create_hash,
+ op_node_export_secret_key,
op_node_get_hashes,
op_node_hash_clone,
op_node_hash_digest,
@@ -32,7 +33,6 @@ import type {
Encoding,
} from "ext:deno_node/internal/crypto/types.ts";
import {
- getKeyMaterial,
KeyObject,
prepareSecretKey,
} from "ext:deno_node/internal/crypto/keys.ts";
@@ -46,7 +46,10 @@ import {
getDefaultEncoding,
toBuf,
} from "ext:deno_node/internal/crypto/util.ts";
-import { isArrayBufferView } from "ext:deno_node/internal/util/types.ts";
+import {
+ isAnyArrayBuffer,
+ isArrayBufferView,
+} from "ext:deno_node/internal/util/types.ts";
const { ReflectApply, ObjectSetPrototypeOf } = primordials;
@@ -217,22 +220,28 @@ class HmacImpl extends Transform {
validateString(hmac, "hmac");
- const u8Key = key instanceof KeyObject
- ? getKeyMaterial(key)
- : prepareSecretKey(key, options?.encoding) as Buffer;
+ key = prepareSecretKey(key, options?.encoding);
+ let keyData;
+ if (isArrayBufferView(key)) {
+ keyData = key;
+ } else if (isAnyArrayBuffer(key)) {
+ keyData = new Uint8Array(key);
+ } else {
+ keyData = op_node_export_secret_key(key);
+ }
const alg = hmac.toLowerCase();
this.#algorithm = alg;
const blockSize = (alg === "sha512" || alg === "sha384") ? 128 : 64;
- const keySize = u8Key.length;
+ const keySize = keyData.length;
let bufKey: Buffer;
if (keySize > blockSize) {
const hash = new Hash(alg, options);
- bufKey = hash.update(u8Key).digest() as Buffer;
+ bufKey = hash.update(keyData).digest() as Buffer;
} else {
- bufKey = Buffer.concat([u8Key, this.#ZEROES], blockSize);
+ bufKey = Buffer.concat([keyData, this.#ZEROES], blockSize);
}
this.#ipad = Buffer.allocUnsafe(blockSize);
diff --git a/ext/node/polyfills/internal/crypto/hkdf.ts b/ext/node/polyfills/internal/crypto/hkdf.ts
index cca40a3c6..cb1dbee46 100644
--- a/ext/node/polyfills/internal/crypto/hkdf.ts
+++ b/ext/node/polyfills/internal/crypto/hkdf.ts
@@ -18,13 +18,12 @@ import {
hideStackFrames,
} from "ext:deno_node/internal/errors.ts";
import {
+ kHandle,
toBuf,
validateByteSource,
} from "ext:deno_node/internal/crypto/util.ts";
import {
createSecretKey,
- getKeyMaterial,
- isKeyObject,
KeyObject,
} from "ext:deno_node/internal/crypto/keys.ts";
import type { BinaryLike } from "ext:deno_node/internal/crypto/types.ts";
@@ -33,10 +32,11 @@ import {
isAnyArrayBuffer,
isArrayBufferView,
} from "ext:deno_node/internal/util/types.ts";
+import { isKeyObject } from "ext:deno_node/internal/crypto/_keys.ts";
const validateParameters = hideStackFrames((hash, key, salt, info, length) => {
validateString(hash, "digest");
- key = getKeyMaterial(prepareKey(key));
+ key = prepareKey(key);
validateByteSource(salt, "salt");
validateByteSource(info, "info");
@@ -111,7 +111,7 @@ export function hkdf(
hash = hash.toLowerCase();
- op_node_hkdf_async(hash, key, salt, info, length)
+ op_node_hkdf_async(hash, key[kHandle], salt, info, length)
.then((okm) => callback(null, okm.buffer))
.catch((err) => callback(new ERR_CRYPTO_INVALID_DIGEST(err), undefined));
}
@@ -135,7 +135,7 @@ export function hkdfSync(
const okm = new Uint8Array(length);
try {
- op_node_hkdf(hash, key, salt, info, okm);
+ op_node_hkdf(hash, key[kHandle], salt, info, okm);
} catch (e) {
throw new ERR_CRYPTO_INVALID_DIGEST(e);
}
diff --git a/ext/node/polyfills/internal/crypto/keygen.ts b/ext/node/polyfills/internal/crypto/keygen.ts
index dd5d5ad7e..4e2543cd9 100644
--- a/ext/node/polyfills/internal/crypto/keygen.ts
+++ b/ext/node/polyfills/internal/crypto/keygen.ts
@@ -10,7 +10,6 @@ import {
PrivateKeyObject,
PublicKeyObject,
SecretKeyObject,
- setOwnedKey,
} from "ext:deno_node/internal/crypto/keys.ts";
import { notImplemented } from "ext:deno_node/_utils.ts";
import {
@@ -32,22 +31,26 @@ import { Buffer } from "node:buffer";
import { KeyFormat, KeyType } from "ext:deno_node/internal/crypto/types.ts";
import {
- op_node_dh_generate,
- op_node_dh_generate_async,
- op_node_dh_generate_group,
- op_node_dh_generate_group_async,
- op_node_dsa_generate,
- op_node_dsa_generate_async,
- op_node_ec_generate,
- op_node_ec_generate_async,
- op_node_ed25519_generate,
- op_node_ed25519_generate_async,
- op_node_generate_rsa,
- op_node_generate_rsa_async,
- op_node_generate_secret,
- op_node_generate_secret_async,
- op_node_x25519_generate,
- op_node_x25519_generate_async,
+ op_node_generate_dh_group_key,
+ op_node_generate_dh_group_key_async,
+ op_node_generate_dh_key,
+ op_node_generate_dh_key_async,
+ op_node_generate_dsa_key,
+ op_node_generate_dsa_key_async,
+ op_node_generate_ec_key,
+ op_node_generate_ec_key_async,
+ op_node_generate_ed25519_key,
+ op_node_generate_ed25519_key_async,
+ op_node_generate_rsa_key,
+ op_node_generate_rsa_key_async,
+ op_node_generate_rsa_pss_key,
+ op_node_generate_rsa_pss_key_async,
+ op_node_generate_secret_key,
+ op_node_generate_secret_key_async,
+ op_node_generate_x25519_key,
+ op_node_generate_x25519_key_async,
+ op_node_get_private_key_from_pair,
+ op_node_get_public_key_from_pair,
} from "ext:core/ops";
function validateGenerateKey(
@@ -82,10 +85,11 @@ export function generateKeySync(
validateGenerateKey(type, options);
const { length } = options;
- const key = new Uint8Array(Math.floor(length / 8));
- op_node_generate_secret(key);
+ const len = Math.floor(length / 8);
- return new SecretKeyObject(setOwnedKey(key));
+ const handle = op_node_generate_secret_key(len);
+
+ return new SecretKeyObject(handle);
}
export function generateKey(
@@ -99,11 +103,11 @@ export function generateKey(
validateFunction(callback, "callback");
const { length } = options;
- op_node_generate_secret_async(Math.floor(length / 8)).then(
- (key) => {
- callback(null, new SecretKeyObject(setOwnedKey(key)));
- },
- );
+ const len = Math.floor(length / 8);
+
+ op_node_generate_secret_key_async(len).then((handle) => {
+ callback(null, new SecretKeyObject(handle));
+ });
}
export interface BasePrivateKeyEncodingOptions<T extends KeyFormat> {
@@ -565,9 +569,12 @@ export function generateKeyPair(
privateKey: any,
) => void,
) {
- createJob(kAsync, type, options).then(([privateKey, publicKey]) => {
- privateKey = new PrivateKeyObject(setOwnedKey(privateKey), { type });
- publicKey = new PublicKeyObject(setOwnedKey(publicKey), { type });
+ createJob(kAsync, type, options).then((pair) => {
+ const privateKeyHandle = op_node_get_private_key_from_pair(pair);
+ const publicKeyHandle = op_node_get_public_key_from_pair(pair);
+
+ const privateKey = new PrivateKeyObject(privateKeyHandle);
+ const publicKey = new PublicKeyObject(publicKeyHandle);
if (typeof options === "object" && options !== null) {
const { publicKeyEncoding, privateKeyEncoding } = options as any;
@@ -766,10 +773,13 @@ export function generateKeyPairSync(
):
| KeyPairKeyObjectResult
| KeyPairSyncResult<string | Buffer, string | Buffer> {
- let [privateKey, publicKey] = createJob(kSync, type, options);
+ const pair = createJob(kSync, type, options);
+
+ const privateKeyHandle = op_node_get_private_key_from_pair(pair);
+ const publicKeyHandle = op_node_get_public_key_from_pair(pair);
- privateKey = new PrivateKeyObject(setOwnedKey(privateKey), { type });
- publicKey = new PublicKeyObject(setOwnedKey(publicKey), { type });
+ let privateKey = new PrivateKeyObject(privateKeyHandle);
+ let publicKey = new PublicKeyObject(publicKeyHandle);
if (typeof options === "object" && options !== null) {
const { publicKeyEncoding, privateKeyEncoding } = options as any;
@@ -812,12 +822,12 @@ function createJob(mode, type, options) {
if (type === "rsa") {
if (mode === kSync) {
- return op_node_generate_rsa(
+ return op_node_generate_rsa_key(
modulusLength,
publicExponent,
);
} else {
- return op_node_generate_rsa_async(
+ return op_node_generate_rsa_key_async(
modulusLength,
publicExponent,
);
@@ -867,14 +877,20 @@ function createJob(mode, type, options) {
}
if (mode === kSync) {
- return op_node_generate_rsa(
+ return op_node_generate_rsa_pss_key(
modulusLength,
publicExponent,
+ hashAlgorithm,
+ mgf1HashAlgorithm ?? mgf1Hash,
+ saltLength,
);
} else {
- return op_node_generate_rsa_async(
+ return op_node_generate_rsa_pss_key_async(
modulusLength,
publicExponent,
+ hashAlgorithm,
+ mgf1HashAlgorithm ?? mgf1Hash,
+ saltLength,
);
}
}
@@ -891,12 +907,13 @@ function createJob(mode, type, options) {
}
if (mode === kSync) {
- return op_node_dsa_generate(modulusLength, divisorLength);
+ return op_node_generate_dsa_key(modulusLength, divisorLength);
+ } else {
+ return op_node_generate_dsa_key_async(
+ modulusLength,
+ divisorLength,
+ );
}
- return op_node_dsa_generate_async(
- modulusLength,
- divisorLength,
- );
}
case "ec": {
validateObject(options, "options");
@@ -913,22 +930,22 @@ function createJob(mode, type, options) {
}
if (mode === kSync) {
- return op_node_ec_generate(namedCurve);
+ return op_node_generate_ec_key(namedCurve);
} else {
- return op_node_ec_generate_async(namedCurve);
+ return op_node_generate_ec_key_async(namedCurve);
}
}
case "ed25519": {
if (mode === kSync) {
- return op_node_ed25519_generate();
+ return op_node_generate_ed25519_key();
}
- return op_node_ed25519_generate_async();
+ return op_node_generate_ed25519_key_async();
}
case "x25519": {
if (mode === kSync) {
- return op_node_x25519_generate();
+ return op_node_generate_x25519_key();
}
- return op_node_x25519_generate_async();
+ return op_node_generate_x25519_key_async();
}
case "ed448":
case "x448": {
@@ -952,9 +969,9 @@ function createJob(mode, type, options) {
validateString(group, "options.group");
if (mode === kSync) {
- return op_node_dh_generate_group(group);
+ return op_node_generate_dh_group_key(group);
} else {
- return op_node_dh_generate_group_async(group);
+ return op_node_generate_dh_group_key_async(group);
}
}
@@ -979,9 +996,9 @@ function createJob(mode, type, options) {
const g = generator == null ? 2 : generator;
if (mode === kSync) {
- return op_node_dh_generate(prime, primeLength ?? 0, g);
+ return op_node_generate_dh_key(prime, primeLength ?? 0, g);
} else {
- return op_node_dh_generate_async(
+ return op_node_generate_dh_key_async(
prime,
primeLength ?? 0,
g,
diff --git a/ext/node/polyfills/internal/crypto/keys.ts b/ext/node/polyfills/internal/crypto/keys.ts
index 26cd86b44..31d674e67 100644
--- a/ext/node/polyfills/internal/crypto/keys.ts
+++ b/ext/node/polyfills/internal/crypto/keys.ts
@@ -14,16 +14,24 @@ const {
import {
op_node_create_private_key,
op_node_create_public_key,
- op_node_export_rsa_public_pem,
- op_node_export_rsa_spki_der,
+ op_node_create_secret_key,
+ op_node_derive_public_key_from_private_key,
+ op_node_export_private_key_der,
+ op_node_export_private_key_pem,
+ op_node_export_public_key_der,
+ op_node_export_public_key_pem,
+ op_node_export_secret_key,
+ op_node_export_secret_key_b64url,
+ op_node_get_asymmetric_key_details,
+ op_node_get_asymmetric_key_type,
+ op_node_get_symmetric_key_size,
+ op_node_key_type,
} from "ext:core/ops";
-import {
- kHandle,
- kKeyObject,
-} from "ext:deno_node/internal/crypto/constants.ts";
+import { kHandle } from "ext:deno_node/internal/crypto/constants.ts";
import { isStringOrBuffer } from "ext:deno_node/internal/crypto/cipher.ts";
import {
+ ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS,
ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE,
ERR_INVALID_ARG_TYPE,
ERR_INVALID_ARG_VALUE,
@@ -41,23 +49,21 @@ import {
} from "ext:deno_node/internal/util/types.ts";
import { hideStackFrames } from "ext:deno_node/internal/errors.ts";
import {
- isCryptoKey as isCryptoKey_,
- isKeyObject as isKeyObject_,
+ isCryptoKey,
+ isKeyObject,
kKeyType,
} from "ext:deno_node/internal/crypto/_keys.ts";
import {
validateObject,
validateOneOf,
} from "ext:deno_node/internal/validators.mjs";
-import {
- forgivingBase64UrlEncode as encodeToBase64Url,
-} from "ext:deno_web/00_infra.js";
+import { BufferEncoding } from "ext:deno_node/_global.d.ts";
export const getArrayBufferOrView = hideStackFrames(
(
- buffer,
- name,
- encoding,
+ buffer: ArrayBufferView | ArrayBuffer | string | Buffer,
+ name: string,
+ encoding?: BufferEncoding | "buffer",
):
| ArrayBuffer
| SharedArrayBuffer
@@ -144,32 +150,30 @@ export interface JwkKeyExportOptions {
format: "jwk";
}
-export function isKeyObject(obj: unknown): obj is KeyObject {
- return isKeyObject_(obj);
+export enum KeyHandleContext {
+ kConsumePublic = 0,
+ kConsumePrivate = 1,
+ kCreatePublic = 2,
+ kCreatePrivate = 3,
}
-export function isCryptoKey(
- obj: unknown,
-): obj is { type: string; [kKeyObject]: KeyObject } {
- return isCryptoKey_(obj);
-}
+export const kConsumePublic = KeyHandleContext.kConsumePublic;
+export const kConsumePrivate = KeyHandleContext.kConsumePrivate;
+export const kCreatePublic = KeyHandleContext.kCreatePublic;
+export const kCreatePrivate = KeyHandleContext.kCreatePrivate;
-function copyBuffer(input: string | Buffer | ArrayBufferView) {
- if (typeof input === "string") return Buffer.from(input);
- return (
- (ArrayBuffer.isView(input)
- ? new Uint8Array(input.buffer, input.byteOffset, input.byteLength)
- : new Uint8Array(input)).slice()
- );
+function isJwk(obj: unknown): obj is { kty: unknown } {
+ // @ts-ignore this is fine
+ return typeof obj === "object" && obj != null && obj.kty !== undefined;
}
-const KEY_STORE = new WeakMap();
+export type KeyObjectHandle = { ___keyObjectHandle: true };
export class KeyObject {
[kKeyType]: KeyObjectType;
- [kHandle]: unknown;
+ [kHandle]: KeyObjectHandle;
- constructor(type: KeyObjectType, handle: unknown) {
+ constructor(type: KeyObjectType, handle: KeyObjectHandle) {
if (type !== "secret" && type !== "public" && type !== "private") {
throw new ERR_INVALID_ARG_VALUE("type", type);
}
@@ -184,7 +188,6 @@ export class KeyObject {
get symmetricKeySize(): number | undefined {
notImplemented("crypto.KeyObject.prototype.symmetricKeySize");
-
return undefined;
}
@@ -192,7 +195,6 @@ export class KeyObject {
if (!isCryptoKey(key)) {
throw new ERR_INVALID_ARG_TYPE("key", "CryptoKey", key);
}
-
notImplemented("crypto.KeyObject.prototype.from");
}
@@ -212,12 +214,13 @@ export class KeyObject {
export(options?: KeyExportOptions<"der">): Buffer;
export(options?: JwkKeyExportOptions): JsonWebKey;
export(_options?: unknown): string | Buffer | JsonWebKey {
- notImplemented("crypto.KeyObject.prototype.asymmetricKeyType");
+ notImplemented("crypto.KeyObject.prototype.export");
}
}
ObjectDefineProperties(KeyObject.prototype, {
[SymbolToStringTag]: {
+ // @ts-expect-error __proto__ is magic
__proto__: null,
configurable: true,
value: "KeyObject",
@@ -229,48 +232,356 @@ export interface JsonWebKeyInput {
format: "jwk";
}
-export function prepareAsymmetricKey(key) {
- if (isStringOrBuffer(key)) {
- return { format: "pem", data: getArrayBufferOrView(key, "key") };
- } else if (isKeyObject(key)) {
+function getKeyObjectHandle(key: KeyObject, ctx: KeyHandleContext) {
+ if (ctx === kCreatePrivate) {
+ throw new ERR_INVALID_ARG_TYPE(
+ "key",
+ ["string", "ArrayBuffer", "Buffer", "TypedArray", "DataView"],
+ key,
+ );
+ }
+
+ if (key.type !== "private") {
+ if (ctx === kConsumePrivate || ctx === kCreatePublic) {
+ throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE(key.type, "private");
+ }
+ if (key.type !== "public") {
+ throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE(
+ key.type,
+ "private or public",
+ );
+ }
+ }
+
+ return key[kHandle];
+}
+
+export function prepareAsymmetricKey(
+ key:
+ | string
+ | ArrayBuffer
+ | Buffer
+ | ArrayBufferView
+ | KeyObject
+ | CryptoKey
+ | PrivateKeyInput
+ | PublicKeyInput
+ | JsonWebKeyInput,
+ ctx: KeyHandleContext,
+):
+ | { handle: KeyObjectHandle; format?: "jwk" }
+ | {
+ data: ArrayBuffer | ArrayBufferView;
+ format: KeyFormat;
+ type: "pkcs1" | "spki" | "pkcs8" | "sec1" | undefined;
+ passphrase: Buffer | ArrayBuffer | ArrayBufferView | undefined;
+ } {
+ if (isKeyObject(key)) {
+ // Best case: A key object, as simple as that.
+ return {
+ // @ts-ignore __proto__ is magic
+ __proto__: null,
+ handle: getKeyObjectHandle(key, ctx),
+ };
+ } else if (isCryptoKey(key)) {
+ notImplemented("using CryptoKey as input");
+ } else if (isStringOrBuffer(key)) {
+ // Expect PEM by default, mostly for backward compatibility.
return {
- // Assumes that asymmetric keys are stored as PEM.
+ // @ts-ignore __proto__ is magic
+ __proto__: null,
format: "pem",
- data: getKeyMaterial(key),
+ data: getArrayBufferOrView(key, "key"),
};
- } else if (typeof key == "object") {
- const { key: data, encoding, format, type } = key;
+ } else if (typeof key === "object") {
+ const { key: data, format } = key;
+ // The 'key' property can be a KeyObject as well to allow specifying
+ // additional options such as padding along with the key.
+ if (isKeyObject(data)) {
+ return {
+ // @ts-ignore __proto__ is magic
+ __proto__: null,
+ handle: getKeyObjectHandle(data, ctx),
+ };
+ } else if (isCryptoKey(data)) {
+ notImplemented("using CryptoKey as input");
+ } else if (isJwk(data) && format === "jwk") {
+ notImplemented("using JWK as input");
+ }
+ // Either PEM or DER using PKCS#1 or SPKI.
if (!isStringOrBuffer(data)) {
- throw new TypeError("Invalid key type");
+ throw new ERR_INVALID_ARG_TYPE(
+ "key.key",
+ getKeyTypes(ctx !== kCreatePrivate),
+ data,
+ );
}
+ const isPublic = (ctx === kConsumePrivate || ctx === kCreatePrivate)
+ ? false
+ : undefined;
return {
- data: getArrayBufferOrView(data, "key", encoding),
- format: format ?? "pem",
- encoding,
- type,
+ data: getArrayBufferOrView(
+ data,
+ "key",
+ (key as PrivateKeyInput | PublicKeyInput).encoding,
+ ),
+ ...parseKeyEncoding(key, undefined, isPublic),
};
}
+ throw new ERR_INVALID_ARG_TYPE(
+ "key",
+ getKeyTypes(ctx !== kCreatePrivate),
+ key,
+ );
+}
+
+function parseKeyEncoding(
+ enc: {
+ cipher?: string;
+ passphrase?: string | Buffer | ArrayBuffer | ArrayBufferView;
+ encoding?: BufferEncoding | "buffer";
+ format?: string;
+ type?: string;
+ },
+ keyType: string | undefined,
+ isPublic: boolean | undefined,
+ objName?: string,
+): {
+ format: KeyFormat;
+ type: "pkcs1" | "spki" | "pkcs8" | "sec1" | undefined;
+ passphrase: Buffer | ArrayBuffer | ArrayBufferView | undefined;
+ cipher: string | undefined;
+} {
+ if (enc === null || typeof enc !== "object") {
+ throw new ERR_INVALID_ARG_TYPE("options", "object", enc);
+ }
+
+ const isInput = keyType === undefined;
+
+ const {
+ format,
+ type,
+ } = parseKeyFormatAndType(enc, keyType, isPublic, objName);
+
+ let cipher, passphrase, encoding;
+ if (isPublic !== true) {
+ ({ cipher, passphrase, encoding } = enc);
+
+ if (!isInput) {
+ if (cipher != null) {
+ if (typeof cipher !== "string") {
+ throw new ERR_INVALID_ARG_VALUE(option("cipher", objName), cipher);
+ }
+ if (
+ format === "der" &&
+ (type === "pkcs1" || type === "sec1")
+ ) {
+ throw new ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS(
+ type,
+ "does not support encryption",
+ );
+ }
+ } else if (passphrase !== undefined) {
+ throw new ERR_INVALID_ARG_VALUE(option("cipher", objName), cipher);
+ }
+ }
- throw new TypeError("Invalid key type");
+ if (
+ (isInput && passphrase !== undefined &&
+ !isStringOrBuffer(passphrase)) ||
+ (!isInput && cipher != null && !isStringOrBuffer(passphrase))
+ ) {
+ throw new ERR_INVALID_ARG_VALUE(
+ option("passphrase", objName),
+ passphrase,
+ );
+ }
+ }
+
+ if (passphrase !== undefined) {
+ passphrase = getArrayBufferOrView(passphrase, "key.passphrase", encoding);
+ }
+
+ return {
+ // @ts-ignore __proto__ is magic
+ __proto__: null,
+ format,
+ type,
+ cipher,
+ passphrase,
+ };
+}
+
+function option(name: string, objName?: string) {
+ return objName === undefined
+ ? `options.${name}`
+ : `options.${objName}.${name}`;
+}
+
+function parseKeyFormatAndType(
+ enc: { format?: string; type?: string },
+ keyType: string | undefined,
+ isPublic: boolean | undefined,
+ objName?: string,
+): {
+ format: KeyFormat;
+ type: "pkcs1" | "spki" | "pkcs8" | "sec1" | undefined;
+} {
+ const { format: formatStr, type: typeStr } = enc;
+
+ const isInput = keyType === undefined;
+ const format = parseKeyFormat(
+ formatStr,
+ isInput ? "pem" : undefined,
+ option("format", objName),
+ );
+
+ const type = parseKeyType(
+ typeStr,
+ !isInput || format === "der",
+ keyType,
+ isPublic,
+ option("type", objName),
+ );
+
+ return {
+ // @ts-ignore __proto__ is magic
+ __proto__: null,
+ format,
+ type,
+ };
+}
+
+function parseKeyFormat(
+ formatStr: string | undefined,
+ defaultFormat: KeyFormat | undefined,
+ optionName: string,
+): KeyFormat {
+ if (formatStr === undefined && defaultFormat !== undefined) {
+ return defaultFormat;
+ } else if (formatStr === "pem") {
+ return "pem";
+ } else if (formatStr === "der") {
+ return "der";
+ }
+ throw new ERR_INVALID_ARG_VALUE(optionName, formatStr);
+}
+
+function parseKeyType(
+ typeStr: string | undefined,
+ required: boolean,
+ keyType: string | undefined,
+ isPublic: boolean | undefined,
+ optionName: string,
+): "pkcs1" | "spki" | "pkcs8" | "sec1" | undefined {
+ if (typeStr === undefined && !required) {
+ return undefined;
+ } else if (typeStr === "pkcs1") {
+ if (keyType !== undefined && keyType !== "rsa") {
+ throw new ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS(
+ typeStr,
+ "can only be used for RSA keys",
+ );
+ }
+ return "pkcs1";
+ } else if (typeStr === "spki" && isPublic !== false) {
+ return "spki";
+ } else if (typeStr === "pkcs8" && isPublic !== true) {
+ return "pkcs8";
+ } else if (typeStr === "sec1" && isPublic !== true) {
+ if (keyType !== undefined && keyType !== "ec") {
+ throw new ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS(
+ typeStr,
+ "can only be used for EC keys",
+ );
+ }
+ return "sec1";
+ }
+ throw new ERR_INVALID_ARG_VALUE(optionName, typeStr);
+}
+
+// Parses the public key encoding based on an object. keyType must be undefined
+// when this is used to parse an input encoding and must be a valid key type if
+// used to parse an output encoding.
+function parsePublicKeyEncoding(
+ enc: {
+ cipher?: string;
+ passphrase?: string | Buffer | ArrayBuffer | ArrayBufferView;
+ encoding?: BufferEncoding | "buffer";
+ format?: string;
+ type?: string;
+ },
+ keyType: string | undefined,
+ objName?: string,
+) {
+ return parseKeyEncoding(enc, keyType, keyType ? true : undefined, objName);
+}
+
+// Parses the private key encoding based on an object. keyType must be undefined
+// when this is used to parse an input encoding and must be a valid key type if
+// used to parse an output encoding.
+function parsePrivateKeyEncoding(
+ enc: {
+ cipher?: string;
+ passphrase?: string | Buffer | ArrayBuffer | ArrayBufferView;
+ encoding?: BufferEncoding | "buffer";
+ format?: string;
+ type?: string;
+ },
+ keyType: string | undefined,
+ objName?: string,
+) {
+ return parseKeyEncoding(enc, keyType, false, objName);
}
export function createPrivateKey(
key: PrivateKeyInput | string | Buffer | JsonWebKeyInput,
): PrivateKeyObject {
- const { data, format, type } = prepareAsymmetricKey(key);
- const details = op_node_create_private_key(data, format, type);
- const handle = setOwnedKey(copyBuffer(data));
- return new PrivateKeyObject(handle, details);
+ const res = prepareAsymmetricKey(key, kCreatePrivate);
+ if ("handle" in res) {
+ const type = op_node_key_type(res.handle);
+ if (type === "private") {
+ return new PrivateKeyObject(res.handle);
+ } else {
+ throw new TypeError(`Can not create private key from ${type} key`);
+ }
+ } else {
+ const handle = op_node_create_private_key(
+ res.data,
+ res.format,
+ res.type ?? "",
+ res.passphrase,
+ );
+ return new PrivateKeyObject(handle);
+ }
}
export function createPublicKey(
key: PublicKeyInput | string | Buffer | JsonWebKeyInput,
): PublicKeyObject {
- const { data, format, type } = prepareAsymmetricKey(key);
- const details = op_node_create_public_key(data, format, type);
- const handle = setOwnedKey(copyBuffer(data));
- return new PublicKeyObject(handle, details);
+ const res = prepareAsymmetricKey(
+ key,
+ kCreatePublic,
+ );
+ if ("handle" in res) {
+ const type = op_node_key_type(res.handle);
+ if (type === "private") {
+ const handle = op_node_derive_public_key_from_private_key(res.handle);
+ return new PublicKeyObject(handle);
+ } else if (type === "public") {
+ return new PublicKeyObject(res.handle);
+ } else {
+ throw new TypeError(`Can not create private key from ${type} key`);
+ }
+ } else {
+ const handle = op_node_create_public_key(
+ res.data,
+ res.format,
+ res.type ?? "",
+ );
+ return new PublicKeyObject(handle);
+ }
}
function getKeyTypes(allowKeyObject: boolean, bufferOnly = false) {
@@ -292,10 +603,10 @@ function getKeyTypes(allowKeyObject: boolean, bufferOnly = false) {
}
export function prepareSecretKey(
- key: string | ArrayBufferView | ArrayBuffer | KeyObject,
+ key: string | ArrayBufferView | ArrayBuffer | KeyObject | CryptoKey,
encoding: string | undefined,
bufferOnly = false,
-) {
+): Buffer | ArrayBuffer | ArrayBufferView | KeyObjectHandle {
if (!bufferOnly) {
if (isKeyObject(key)) {
if (key.type !== "secret") {
@@ -303,10 +614,7 @@ export function prepareSecretKey(
}
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];
+ notImplemented("using CryptoKey as input");
}
}
if (
@@ -325,21 +633,20 @@ export function prepareSecretKey(
}
export class SecretKeyObject extends KeyObject {
- constructor(handle: unknown) {
+ constructor(handle: KeyObjectHandle) {
super("secret", handle);
}
get symmetricKeySize() {
- return KEY_STORE.get(this[kHandle]).byteLength;
+ return op_node_get_symmetric_key_size(this[kHandle]);
}
get asymmetricKeyType() {
return undefined;
}
- export(): Buffer;
- export(options?: JwkKeyExportOptions): JsonWebKey {
- const key = KEY_STORE.get(this[kHandle]);
+ export(options?: { format?: "buffer" | "jwk" }): Buffer | JsonWebKey {
+ let format: "buffer" | "jwk" = "buffer";
if (options !== undefined) {
validateObject(options, "options");
validateOneOf(
@@ -347,111 +654,102 @@ export class SecretKeyObject extends KeyObject {
"options.format",
[undefined, "buffer", "jwk"],
);
- if (options.format === "jwk") {
+ format = options.format ?? "buffer";
+ }
+ switch (format) {
+ case "buffer":
+ return Buffer.from(op_node_export_secret_key(this[kHandle]));
+ case "jwk":
return {
kty: "oct",
- k: encodeToBase64Url(key),
+ k: op_node_export_secret_key_b64url(this[kHandle]),
};
- }
}
- return key.slice();
}
}
-const kAsymmetricKeyType = Symbol("kAsymmetricKeyType");
-const kAsymmetricKeyDetails = Symbol("kAsymmetricKeyDetails");
-
class AsymmetricKeyObject extends KeyObject {
- constructor(type: KeyObjectType, handle: unknown, details: unknown) {
+ constructor(type: KeyObjectType, handle: KeyObjectHandle) {
super(type, handle);
- this[kAsymmetricKeyType] = details.type;
- this[kAsymmetricKeyDetails] = { ...details };
}
get asymmetricKeyType() {
- return this[kAsymmetricKeyType];
+ return op_node_get_asymmetric_key_type(this[kHandle]);
}
get asymmetricKeyDetails() {
- return this[kAsymmetricKeyDetails];
+ return op_node_get_asymmetric_key_details(this[kHandle]);
}
}
export class PrivateKeyObject extends AsymmetricKeyObject {
- constructor(handle: unknown, details: unknown) {
- super("private", handle, details);
+ constructor(handle: KeyObjectHandle) {
+ super("private", handle);
}
- export(_options: unknown) {
- notImplemented("crypto.PrivateKeyObject.prototype.export");
+ export(options: JwkKeyExportOptions | KeyExportOptions<KeyFormat>) {
+ if (options && options.format === "jwk") {
+ notImplemented("jwk private key export not implemented");
+ }
+ const {
+ format,
+ type,
+ } = parsePrivateKeyEncoding(options, this.asymmetricKeyType);
+
+ if (format === "pem") {
+ return op_node_export_private_key_pem(this[kHandle], type);
+ } else {
+ return Buffer.from(op_node_export_private_key_der(this[kHandle], type));
+ }
}
}
export class PublicKeyObject extends AsymmetricKeyObject {
- constructor(handle: unknown, details: unknown) {
- super("public", handle, details);
+ constructor(handle: KeyObjectHandle) {
+ super("public", handle);
}
- export(options: unknown) {
- const key = KEY_STORE.get(this[kHandle]);
- switch (this.asymmetricKeyType) {
- case "rsa":
- case "rsa-pss": {
- switch (options.format) {
- case "pem":
- return op_node_export_rsa_public_pem(key);
- case "der": {
- if (options.type == "pkcs1") {
- return key;
- } else {
- return op_node_export_rsa_spki_der(key);
- }
- }
- default:
- throw new TypeError(`exporting ${options.type} is not implemented`);
- }
- }
- default:
- throw new TypeError(
- `exporting ${this.asymmetricKeyType} is not implemented`,
- );
+ export(options: JwkKeyExportOptions | KeyExportOptions<KeyFormat>) {
+ if (options && options.format === "jwk") {
+ notImplemented("jwk public key export not implemented");
}
- }
-}
-
-export function setOwnedKey(key: Uint8Array): unknown {
- const handle = {};
- KEY_STORE.set(handle, key);
- return handle;
-}
+ const {
+ format,
+ type,
+ } = parsePublicKeyEncoding(options, this.asymmetricKeyType);
-export function getKeyMaterial(key: KeyObject): Uint8Array {
- return KEY_STORE.get(key[kHandle]);
+ if (format === "pem") {
+ return op_node_export_public_key_pem(this[kHandle], type);
+ } else {
+ return Buffer.from(op_node_export_public_key_der(this[kHandle], type));
+ }
+ }
}
-export function createSecretKey(key: ArrayBufferView): KeyObject;
-export function createSecretKey(
- key: string,
- encoding: string,
-): KeyObject;
export function createSecretKey(
- key: string | ArrayBufferView,
+ key: string | ArrayBufferView | ArrayBuffer | KeyObject | CryptoKey,
encoding?: string,
): KeyObject {
- key = prepareSecretKey(key, encoding, true);
- const handle = setOwnedKey(copyBuffer(key));
- return new SecretKeyObject(handle);
+ const preparedKey = prepareSecretKey(key, encoding, true);
+ if (isArrayBufferView(preparedKey) || isAnyArrayBuffer(preparedKey)) {
+ const handle = op_node_create_secret_key(preparedKey);
+ return new SecretKeyObject(handle);
+ } else {
+ const type = op_node_key_type(preparedKey);
+ if (type === "secret") {
+ return new SecretKeyObject(preparedKey);
+ } else {
+ throw new TypeError(`can not create secret key from ${type} key`);
+ }
+ }
}
export default {
createPrivateKey,
createPublicKey,
createSecretKey,
- isKeyObject,
- isCryptoKey,
KeyObject,
prepareSecretKey,
- setOwnedKey,
SecretKeyObject,
PrivateKeyObject,
PublicKeyObject,
diff --git a/ext/node/polyfills/internal/crypto/sig.ts b/ext/node/polyfills/internal/crypto/sig.ts
index 473670d2a..c711c7193 100644
--- a/ext/node/polyfills/internal/crypto/sig.ts
+++ b/ext/node/polyfills/internal/crypto/sig.ts
@@ -4,9 +4,13 @@
// TODO(petamoriken): enable prefer-primordials for node polyfills
// deno-lint-ignore-file prefer-primordials
-import { op_node_sign, op_node_verify } from "ext:core/ops";
+import {
+ op_node_create_private_key,
+ op_node_create_public_key,
+ op_node_sign,
+ op_node_verify,
+} from "ext:core/ops";
-import { notImplemented } from "ext:deno_node/_utils.ts";
import {
validateFunction,
validateString,
@@ -22,12 +26,12 @@ import type {
PublicKeyInput,
} from "ext:deno_node/internal/crypto/types.ts";
import {
+ kConsumePrivate,
+ kConsumePublic,
KeyObject,
prepareAsymmetricKey,
} from "ext:deno_node/internal/crypto/keys.ts";
-import { createHash, Hash } from "ext:deno_node/internal/crypto/hash.ts";
-import { KeyFormat, KeyType } from "ext:deno_node/internal/crypto/types.ts";
-import { isArrayBufferView } from "ext:deno_node/internal/util/types.ts";
+import { createHash } from "ext:deno_node/internal/crypto/hash.ts";
import { ERR_CRYPTO_SIGN_KEY_REQUIRED } from "ext:deno_node/internal/errors.ts";
export type DSAEncoding = "der" | "ieee-p1363";
@@ -72,16 +76,26 @@ export class SignImpl extends Writable {
}
sign(
- privateKey: BinaryLike | SignKeyObjectInput | SignPrivateKeyInput,
+ // deno-lint-ignore no-explicit-any
+ privateKey: any,
encoding?: BinaryToTextEncoding,
): Buffer | string {
- const { data, format, type } = prepareAsymmetricKey(privateKey);
+ const res = prepareAsymmetricKey(privateKey, kConsumePrivate);
+ let handle;
+ if ("handle" in res) {
+ handle = res.handle;
+ } else {
+ handle = op_node_create_private_key(
+ res.data,
+ res.format,
+ res.type ?? "",
+ res.passphrase,
+ );
+ }
const ret = Buffer.from(op_node_sign(
+ handle,
this.hash.digest(),
this.#digestType,
- data!,
- type,
- format,
));
return encoding ? ret.toString(encoding) : ret;
}
@@ -127,32 +141,27 @@ export class VerifyImpl extends Writable {
}
verify(
- publicKey: BinaryLike | VerifyKeyObjectInput | VerifyPublicKeyInput,
+ // deno-lint-ignore no-explicit-any
+ publicKey: any,
signature: BinaryLike,
encoding?: BinaryToTextEncoding,
): boolean {
- let keyData: BinaryLike;
- let keyType: KeyType;
- let keyFormat: KeyFormat;
- if (typeof publicKey === "string" || isArrayBufferView(publicKey)) {
- // if the key is BinaryLike, interpret it as a PEM encoded RSA key
- // deno-lint-ignore no-explicit-any
- keyData = publicKey as any;
- keyType = "rsa";
- keyFormat = "pem";
+ const res = prepareAsymmetricKey(publicKey, kConsumePublic);
+ let handle;
+ if ("handle" in res) {
+ handle = res.handle;
} else {
- // TODO(kt3k): Add support for the case when publicKey is a KeyObject,
- // CryptoKey, etc
- notImplemented(
- "crypto.Verify.prototype.verify with non BinaryLike input",
+ handle = op_node_create_public_key(
+ res.data,
+ res.format,
+ res.type ?? "",
+ res.passphrase,
);
}
return op_node_verify(
+ handle,
this.hash.digest(),
this.#digestType,
- keyData!,
- keyType,
- keyFormat,
Buffer.from(signature, encoding),
);
}
diff --git a/ext/node/polyfills/internal/crypto/types.ts b/ext/node/polyfills/internal/crypto/types.ts
index 45c0ea286..17b15127e 100644
--- a/ext/node/polyfills/internal/crypto/types.ts
+++ b/ext/node/polyfills/internal/crypto/types.ts
@@ -1,6 +1,7 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
// Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license.
+import { BufferEncoding } from "ext:deno_node/_global.d.ts";
import { Buffer } from "../../buffer.ts";
export type HASH_DATA = string | ArrayBufferView | Buffer | ArrayBuffer;
@@ -34,6 +35,7 @@ export type KeyType =
export interface PrivateKeyInput {
key: string | Buffer;
+ encoding: BufferEncoding | "buffer";
format?: KeyFormat | undefined;
type?: "pkcs1" | "pkcs8" | "sec1" | undefined;
passphrase?: string | Buffer | undefined;
@@ -41,6 +43,7 @@ export interface PrivateKeyInput {
export interface PublicKeyInput {
key: string | Buffer;
+ encoding: BufferEncoding | "buffer";
format?: KeyFormat | undefined;
type?: "pkcs1" | "spki" | undefined;
}