summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authorLevente Kurusa <lkurusa@kernelstuff.org>2023-05-15 19:41:53 +0200
committerGitHub <noreply@github.com>2023-05-15 19:41:53 +0200
commit3356173d00486ffda99f3907de97489ac79c70dd (patch)
treea5a027bb846011ecd055386dda66a6c69979d920 /ext
parentbfe93c6e814b5ba27e9bd356359910ff3c3f49bd (diff)
feat(node/crypto): Diffie Hellman Support (#18943)
Support crypto.DiffieHellman class in ext/node/crypto
Diffstat (limited to 'ext')
-rw-r--r--ext/node/lib.rs2
-rw-r--r--ext/node/ops/crypto/dh.rs2
-rw-r--r--ext/node/ops/crypto/mod.rs25
-rw-r--r--ext/node/polyfills/internal/crypto/diffiehellman.ts151
4 files changed, 155 insertions, 25 deletions
diff --git a/ext/node/lib.rs b/ext/node/lib.rs
index e01954109..aed325c93 100644
--- a/ext/node/lib.rs
+++ b/ext/node/lib.rs
@@ -170,6 +170,8 @@ deno_core::extension!(deno_node,
ops::crypto::op_node_dh_generate_group,
ops::crypto::op_node_dh_generate_group_async,
ops::crypto::op_node_dh_generate,
+ ops::crypto::op_node_dh_generate2,
+ ops::crypto::op_node_dh_compute_secret,
ops::crypto::op_node_dh_generate_async,
ops::crypto::op_node_verify,
ops::crypto::op_node_random_int,
diff --git a/ext/node/ops/crypto/dh.rs b/ext/node/ops/crypto/dh.rs
index 4da9a01bf..8b756d9a2 100644
--- a/ext/node/ops/crypto/dh.rs
+++ b/ext/node/ops/crypto/dh.rs
@@ -63,7 +63,7 @@ impl DiffieHellman {
}
pub fn new(prime: Prime, generator: usize) -> Self {
- let private_key = PrivateKey::new(32);
+ let private_key = PrivateKey::new(prime.bits());
let generator = BigUint::from_usize(generator).unwrap();
let public_key = private_key.compute_public_key(&generator, &prime);
diff --git a/ext/node/ops/crypto/mod.rs b/ext/node/ops/crypto/mod.rs
index 0f8feb2a9..05f2d34f7 100644
--- a/ext/node/ops/crypto/mod.rs
+++ b/ext/node/ops/crypto/mod.rs
@@ -11,6 +11,7 @@ use deno_core::StringOrBuffer;
use deno_core::ZeroCopyBuf;
use hkdf::Hkdf;
use num_bigint::BigInt;
+use num_bigint_dig::BigUint;
use num_traits::FromPrimitive;
use rand::distributions::Distribution;
use rand::distributions::Uniform;
@@ -788,6 +789,30 @@ pub fn op_node_dh_generate(
dh_generate(prime, prime_len, generator)
}
+// TODO(lev): This duplication should be avoided.
+#[op]
+pub fn op_node_dh_generate2(
+ prime: ZeroCopyBuf,
+ prime_len: usize,
+ generator: usize,
+) -> Result<(ZeroCopyBuf, ZeroCopyBuf), AnyError> {
+ dh_generate(Some(prime).as_deref(), prime_len, generator)
+}
+
+#[op]
+pub fn op_node_dh_compute_secret(
+ prime: ZeroCopyBuf,
+ private_key: ZeroCopyBuf,
+ their_public_key: ZeroCopyBuf,
+) -> Result<ZeroCopyBuf, AnyError> {
+ let pubkey: BigUint = BigUint::from_bytes_be(their_public_key.as_ref());
+ let privkey: BigUint = BigUint::from_bytes_be(private_key.as_ref());
+ let primei: BigUint = BigUint::from_bytes_be(prime.as_ref());
+ let shared_secret: BigUint = pubkey.modpow(&privkey, &primei);
+
+ Ok(shared_secret.to_bytes_be().into())
+}
+
#[op]
pub async fn op_node_dh_generate_async(
prime: Option<ZeroCopyBuf>,
diff --git a/ext/node/polyfills/internal/crypto/diffiehellman.ts b/ext/node/polyfills/internal/crypto/diffiehellman.ts
index 62a802126..2531c07c7 100644
--- a/ext/node/polyfills/internal/crypto/diffiehellman.ts
+++ b/ext/node/polyfills/internal/crypto/diffiehellman.ts
@@ -6,7 +6,10 @@ import {
isAnyArrayBuffer,
isArrayBufferView,
} from "ext:deno_node/internal/util/types.ts";
-import { ERR_INVALID_ARG_TYPE } from "ext:deno_node/internal/errors.ts";
+import {
+ ERR_INVALID_ARG_TYPE,
+ NodeError,
+} from "ext:deno_node/internal/errors.ts";
import {
validateInt32,
validateString,
@@ -32,9 +35,14 @@ const DH_GENERATOR = 2;
export class DiffieHellman {
verifyError!: number;
+ #prime: Buffer;
+ #primeLength: number;
+ #generator: Buffer;
+ #privateKey: Buffer;
+ #publicKey: Buffer;
constructor(
- sizeOrKey: unknown,
+ sizeOrKey: number | string | ArrayBufferView,
keyEncoding?: unknown,
generator?: unknown,
genEncoding?: unknown,
@@ -71,24 +79,68 @@ export class DiffieHellman {
genEncoding = genEncoding || encoding;
if (typeof sizeOrKey !== "number") {
- sizeOrKey = toBuf(sizeOrKey as string, keyEncoding as string);
+ this.#prime = toBuf(sizeOrKey as string, keyEncoding as string);
+ } else {
+ // The supplied parameter is our primeLength, generate a suitable prime.
+ this.#primeLength = sizeOrKey as number;
+ if (this.#primeLength < 2) {
+ throw new NodeError("ERR_OSSL_BN_BITS_TOO_SMALL", "bits too small");
+ }
+
+ this.#prime = Buffer.from(
+ ops.op_node_gen_prime(this.#primeLength).buffer,
+ );
}
if (!generator) {
- generator = DH_GENERATOR;
+ // While the commonly used cyclic group generators for DH are 2 and 5, we
+ // need this a buffer, because, well.. Node.
+ this.#generator = Buffer.alloc(4);
+ this.#generator.writeUint32BE(DH_GENERATOR);
} else if (typeof generator === "number") {
validateInt32(generator, "generator");
+ this.#generator = Buffer.alloc(4);
+ if (generator <= 0 || generator >= 0x7fffffff) {
+ throw new NodeError("ERR_OSSL_DH_BAD_GENERATOR", "bad generator");
+ }
+ this.#generator.writeUint32BE(generator);
} else if (typeof generator === "string") {
generator = toBuf(generator, genEncoding as string);
+ this.#generator = generator;
} else if (!isArrayBufferView(generator) && !isAnyArrayBuffer(generator)) {
throw new ERR_INVALID_ARG_TYPE(
"generator",
["number", "string", "ArrayBuffer", "Buffer", "TypedArray", "DataView"],
generator,
);
+ } else {
+ this.#generator = Buffer.from(generator);
}
- notImplemented("crypto.DiffieHellman");
+ this.#checkGenerator();
+
+ // TODO(lev): actually implement this value
+ this.verifyError = 0;
+ }
+
+ #checkGenerator(): number {
+ let generator: number;
+
+ if (this.#generator.length == 0) {
+ throw new NodeError("ERR_OSSL_DH_BAD_GENERATOR", "bad generator");
+ } else if (this.#generator.length == 1) {
+ generator = this.#generator.readUint8();
+ } else if (this.#generator.length == 2) {
+ generator = this.#generator.readUint16BE();
+ } else {
+ generator = this.#generator.readUint32BE();
+ }
+
+ if (generator != 2 && generator != 5) {
+ throw new NodeError("ERR_OSSL_DH_BAD_GENERATOR", "bad generator");
+ }
+
+ return generator;
}
computeSecret(otherPublicKey: ArrayBufferView): Buffer;
@@ -106,59 +158,110 @@ export class DiffieHellman {
outputEncoding: BinaryToTextEncoding,
): string;
computeSecret(
- _otherPublicKey: ArrayBufferView | string,
- _inputEncoding?: BinaryToTextEncoding,
- _outputEncoding?: BinaryToTextEncoding,
+ otherPublicKey: ArrayBufferView | string,
+ inputEncoding?: BinaryToTextEncoding,
+ outputEncoding?: BinaryToTextEncoding,
): Buffer | string {
- notImplemented("crypto.DiffieHellman.prototype.computeSecret");
+ let buf;
+ if (inputEncoding != undefined && inputEncoding != "buffer") {
+ buf = Buffer.from(otherPublicKey.buffer, inputEncoding);
+ } else {
+ buf = Buffer.from(otherPublicKey.buffer);
+ }
+
+ const sharedSecret = ops.op_node_dh_compute_secret(
+ this.#prime,
+ this.#privateKey,
+ buf,
+ );
+
+ if (outputEncoding == undefined || outputEncoding == "buffer") {
+ return Buffer.from(sharedSecret.buffer);
+ }
+
+ return Buffer.from(sharedSecret.buffer).toString(outputEncoding);
}
generateKeys(): Buffer;
generateKeys(encoding: BinaryToTextEncoding): string;
generateKeys(_encoding?: BinaryToTextEncoding): Buffer | string {
- notImplemented("crypto.DiffieHellman.prototype.generateKeys");
+ const generator = this.#checkGenerator();
+ const [privateKey, publicKey] = ops.op_node_dh_generate2(
+ this.#prime,
+ this.#primeLength,
+ generator,
+ );
+
+ this.#privateKey = Buffer.from(privateKey.buffer);
+ this.#publicKey = Buffer.from(publicKey.buffer);
+
+ return this.#publicKey;
}
getGenerator(): Buffer;
getGenerator(encoding: BinaryToTextEncoding): string;
- getGenerator(_encoding?: BinaryToTextEncoding): Buffer | string {
- notImplemented("crypto.DiffieHellman.prototype.getGenerator");
+ getGenerator(encoding?: BinaryToTextEncoding): Buffer | string {
+ if (encoding !== undefined && encoding != "buffer") {
+ return this.#generator.toString(encoding);
+ }
+
+ return this.#generator;
}
getPrime(): Buffer;
getPrime(encoding: BinaryToTextEncoding): string;
- getPrime(_encoding?: BinaryToTextEncoding): Buffer | string {
- notImplemented("crypto.DiffieHellman.prototype.getPrime");
+ getPrime(encoding?: BinaryToTextEncoding): Buffer | string {
+ if (encoding !== undefined && encoding != "buffer") {
+ return this.#prime.toString(encoding);
+ }
+
+ return this.#prime;
}
getPrivateKey(): Buffer;
getPrivateKey(encoding: BinaryToTextEncoding): string;
- getPrivateKey(_encoding?: BinaryToTextEncoding): Buffer | string {
- notImplemented("crypto.DiffieHellman.prototype.getPrivateKey");
+ getPrivateKey(encoding?: BinaryToTextEncoding): Buffer | string {
+ if (encoding !== undefined && encoding != "buffer") {
+ return this.#privateKey.toString(encoding);
+ }
+
+ return this.#privateKey;
}
getPublicKey(): Buffer;
getPublicKey(encoding: BinaryToTextEncoding): string;
- getPublicKey(_encoding?: BinaryToTextEncoding): Buffer | string {
- notImplemented("crypto.DiffieHellman.prototype.getPublicKey");
+ getPublicKey(encoding?: BinaryToTextEncoding): Buffer | string {
+ if (encoding !== undefined && encoding != "buffer") {
+ return this.#publicKey.toString(encoding);
+ }
+
+ return this.#publicKey;
}
setPrivateKey(privateKey: ArrayBufferView): void;
setPrivateKey(privateKey: string, encoding: BufferEncoding): void;
setPrivateKey(
- _privateKey: ArrayBufferView | string,
- _encoding?: BufferEncoding,
+ privateKey: ArrayBufferView | string,
+ encoding?: BufferEncoding,
) {
- notImplemented("crypto.DiffieHellman.prototype.setPrivateKey");
+ if (encoding == undefined || encoding == "buffer") {
+ this.#privateKey = Buffer.from(privateKey);
+ } else {
+ this.#privateKey = Buffer.from(privateKey, encoding);
+ }
}
setPublicKey(publicKey: ArrayBufferView): void;
setPublicKey(publicKey: string, encoding: BufferEncoding): void;
setPublicKey(
- _publicKey: ArrayBufferView | string,
- _encoding?: BufferEncoding,
+ publicKey: ArrayBufferView | string,
+ encoding?: BufferEncoding,
) {
- notImplemented("crypto.DiffieHellman.prototype.setPublicKey");
+ if (encoding == undefined || encoding == "buffer") {
+ this.#publicKey = Buffer.from(publicKey);
+ } else {
+ this.#publicKey = Buffer.from(publicKey, encoding);
+ }
}
}