diff options
author | Levente Kurusa <lkurusa@kernelstuff.org> | 2023-04-27 18:31:35 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-27 18:31:35 +0200 |
commit | c3d670dbc992ffaff02cd8df82335ee41e88596e (patch) | |
tree | c25719c6d367052aa61b77df18b0fd293ae84934 /ext/node/polyfills | |
parent | 3fbb31c3c1f85011db9cc616dab0ef113342d7dd (diff) |
feat(node/crypto): Elliptic Curve Diffie-Hellman (ECDH) support (#18832)
- ECDH class
- crypto.createECDH()
- Supported curves:
- secp256k1
- prime256v1 / secp256r1
- secp384r1
- secp224r1
Co-authored-by: Bartek IwaĆczuk <biwanczuk@gmail.com>
Diffstat (limited to 'ext/node/polyfills')
-rw-r--r-- | ext/node/polyfills/internal/crypto/diffiehellman.ts | 75 | ||||
-rw-r--r-- | ext/node/polyfills/internal/crypto/util.ts | 44 |
2 files changed, 106 insertions, 13 deletions
diff --git a/ext/node/polyfills/internal/crypto/diffiehellman.ts b/ext/node/polyfills/internal/crypto/diffiehellman.ts index 3aa1f8080..62a802126 100644 --- a/ext/node/polyfills/internal/crypto/diffiehellman.ts +++ b/ext/node/polyfills/internal/crypto/diffiehellman.ts @@ -13,6 +13,8 @@ import { } from "ext:deno_node/internal/validators.mjs"; import { Buffer } from "ext:deno_node/buffer.ts"; import { + EllipticCurve, + ellipticCurves, getDefaultEncoding, toBuf, } from "ext:deno_node/internal/crypto/util.ts"; @@ -24,6 +26,8 @@ import type { import { KeyObject } from "ext:deno_node/internal/crypto/keys.ts"; import type { BufferEncoding } from "ext:deno_node/_global.d.ts"; +const { ops } = Deno.core; + const DH_GENERATOR = 2; export class DiffieHellman { @@ -219,10 +223,21 @@ export class DiffieHellmanGroup { } export class ECDH { + #curve: EllipticCurve; // the selected curve + #privbuf: Buffer; // the private key + #pubbuf: Buffer; // the public key + constructor(curve: string) { validateString(curve, "curve"); - notImplemented("crypto.ECDH"); + const c = ellipticCurves.find((x) => x.name == curve); + if (c == undefined) { + throw new Error("invalid curve"); + } + + this.#curve = c; + this.#pubbuf = Buffer.alloc(this.#curve.publicKeySize); + this.#privbuf = Buffer.alloc(this.#curve.privateKeySize); } static convertKey( @@ -250,44 +265,80 @@ export class ECDH { outputEncoding: BinaryToTextEncoding, ): string; computeSecret( - _otherPublicKey: ArrayBufferView | string, + otherPublicKey: ArrayBufferView | string, _inputEncoding?: BinaryToTextEncoding, _outputEncoding?: BinaryToTextEncoding, ): Buffer | string { - notImplemented("crypto.ECDH.prototype.computeSecret"); + const secretBuf = Buffer.alloc(this.#curve.sharedSecretSize); + + ops.op_node_ecdh_compute_secret( + this.#curve.name, + this.#privbuf, + otherPublicKey, + secretBuf, + ); + + return secretBuf; } generateKeys(): Buffer; generateKeys(encoding: BinaryToTextEncoding, format?: ECDHKeyFormat): string; generateKeys( - _encoding?: BinaryToTextEncoding, + encoding?: BinaryToTextEncoding, _format?: ECDHKeyFormat, ): Buffer | string { - notImplemented("crypto.ECDH.prototype.generateKeys"); + ops.op_node_ecdh_generate_keys( + this.#curve.name, + this.#pubbuf, + this.#privbuf, + ); + + if (encoding !== undefined) { + return this.#pubbuf.toString(encoding); + } + return this.#pubbuf; } getPrivateKey(): Buffer; getPrivateKey(encoding: BinaryToTextEncoding): string; - getPrivateKey(_encoding?: BinaryToTextEncoding): Buffer | string { - notImplemented("crypto.ECDH.prototype.getPrivateKey"); + getPrivateKey(encoding?: BinaryToTextEncoding): Buffer | string { + if (encoding !== undefined) { + return this.#privbuf.toString(encoding); + } + return this.#privbuf; } getPublicKey(): Buffer; getPublicKey(encoding: BinaryToTextEncoding, format?: ECDHKeyFormat): string; getPublicKey( - _encoding?: BinaryToTextEncoding, + encoding?: BinaryToTextEncoding, _format?: ECDHKeyFormat, ): Buffer | string { - notImplemented("crypto.ECDH.prototype.getPublicKey"); + if (encoding !== undefined) { + return this.#pubbuf.toString(encoding); + } + return this.#pubbuf; } setPrivateKey(privateKey: ArrayBufferView): void; setPrivateKey(privateKey: string, encoding: BinaryToTextEncoding): void; setPrivateKey( - _privateKey: ArrayBufferView | string, - _encoding?: BinaryToTextEncoding, + privateKey: ArrayBufferView | string, + encoding?: BinaryToTextEncoding, ): Buffer | string { - notImplemented("crypto.ECDH.prototype.setPrivateKey"); + this.#privbuf = privateKey; + this.#pubbuf = Buffer.alloc(this.#curve.publicKeySize); + + ops.op_node_ecdh_compute_public_key( + this.#curve.name, + this.#privbuf, + this.#pubbuf, + ); + + if (encoding !== undefined) { + return this.#pubbuf.toString(encoding); + } + return this.#pubbuf; } } diff --git a/ext/node/polyfills/internal/crypto/util.ts b/ext/node/polyfills/internal/crypto/util.ts index ccb772631..2e269b7fa 100644 --- a/ext/node/polyfills/internal/crypto/util.ts +++ b/ext/node/polyfills/internal/crypto/util.ts @@ -46,6 +46,47 @@ const digestAlgorithms = [ "sha1", ]; +export type EllipticCurve = { + name: string; + ephemeral: boolean; + privateKeySize: number; + publicKeySize: number; + sharedSecretSize: number; +}; + +export const ellipticCurves: Array<EllipticCurve> = [ + { + name: "secp256k1", + privateKeySize: 32, + publicKeySize: 65, + sharedSecretSize: 32, + }, // Weierstrass-class EC used by Bitcoin + { + name: "prime256v1", + privateKeySize: 32, + publicKeySize: 65, + sharedSecretSize: 32, + }, // NIST P-256 EC + { + name: "secp256r1", + privateKeySize: 32, + publicKeySize: 65, + sharedSecretSize: 32, + }, // NIST P-256 EC (same as above) + { + name: "secp384r1", + privateKeySize: 48, + publicKeySize: 97, + sharedSecretSize: 48, + }, // NIST P-384 EC + { + name: "secp224r1", + privateKeySize: 28, + publicKeySize: 57, + sharedSecretSize: 28, + }, // NIST P-224 EC +]; + // deno-fmt-ignore const supportedCiphers = [ "aes-128-ecb", "aes-192-ecb", @@ -114,8 +155,9 @@ export function getHashes(): readonly string[] { return digestAlgorithms; } +const curveNames = ellipticCurves.map((x) => x.name); export function getCurves(): readonly string[] { - notImplemented("crypto.getCurves"); + return curveNames; } export interface SecureHeapUsage { |