/
githubmirror
/
deno
Обзор
Документация
Войти
/
githubmirror
/
deno
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
ext/node/polyfills/internal/crypto/diffiehellman.ts
1 680 строк
37 KB
Kenta Moriuchi
chore: make prefer-primordials lint an internal plugin (#35978)
23 июл 2026, 11:53
Не верифицирован
23 июл 2026, 11:53
5b55d08
Код
Авторство
О чём код?
// Copyright 2018-2026 the Deno authors. MIT license. // Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license. // deno-lint-ignore-file no-explicit-any (function () { const { core, primordials } = __bootstrap; const { ArrayBufferPrototypeGetByteLength, ArrayIsArray, ArrayPrototypeFind, ArrayPrototypeIncludes, DataViewPrototypeGetBuffer, DataViewPrototypeGetByteLength, DataViewPrototypeGetByteOffset, Error, ObjectPrototypeIsPrototypeOf, String, StringPrototypeIncludes, TypeError, TypeErrorPrototype, TypedArrayPrototypeGetBuffer, TypedArrayPrototypeGetByteLength, TypedArrayPrototypeGetByteOffset, } = primordials; const { op_node_dh_check, op_node_dh_compute_secret, op_node_dh_keys_generate_and_export, op_node_diffie_hellman, op_node_ecdh_compute_public_key, op_node_ecdh_compute_secret, op_node_ecdh_encode_pubkey, op_node_ecdh_generate_keys, op_node_ecdh_validate_private_key, op_node_ecdh_validate_public_key, op_node_gen_prime, } = core.ops; const { isAnyArrayBuffer, isArrayBufferView, isTypedArray, } = core.loadExtScript("ext:deno_node/internal/util/types.ts"); const { ERR_CRYPTO_ECDH_INVALID_FORMAT, ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY, ERR_CRYPTO_INCOMPATIBLE_KEY, ERR_CRYPTO_UNKNOWN_DH_GROUP, ERR_INVALID_ARG_TYPE, ERR_INVALID_ARG_VALUE, NodeError, } = core.loadExtScript("ext:deno_node/internal/errors.ts"); const { validateInt32, validateString, } = core.loadExtScript("ext:deno_node/internal/validators.mjs"); const { Buffer } = core.loadExtScript("ext:deno_node/internal/buffer.mjs"); const { deprecate } = core.loadExtScript("ext:deno_node/util.ts"); const { ellipticCurves, getDefaultEncoding, toBuf, } = core.loadExtScript("ext:deno_node/internal/crypto/util.ts"); const { getArrayBufferOrView, getKeyObjectHandle, kConsumePrivate, kConsumePublic, } = core.loadExtScript("ext:deno_node/internal/crypto/keys.ts"); const DH_GENERATOR = 2; // Returns the { buffer, byteOffset, byteLength } of an ArrayBufferView, using // the correct primordial getters depending on whether it is a TypedArray or // DataView. function getViewParts( view: ArrayBufferView, ): { ab: ArrayBufferLike; off: number; len: number } { if (isTypedArray(view)) { return { ab: TypedArrayPrototypeGetBuffer(view as any), off: TypedArrayPrototypeGetByteOffset(view as any), len: TypedArrayPrototypeGetByteLength(view as any), }; } return { ab: DataViewPrototypeGetBuffer(view as any), off: DataViewPrototypeGetByteOffset(view as any), len: DataViewPrototypeGetByteLength(view as any), }; } function DiffieHellman( sizeOrKey: number | string | ArrayBufferView, keyEncoding?: unknown, generator?: unknown, genEncoding?: unknown, ) { return new DiffieHellmanImpl( sizeOrKey, keyEncoding, generator, genEncoding, ); } class DiffieHellmanImpl { verifyError!: number; #prime: Buffer; #primeLength: number; #generator: Buffer; #privateKey: Buffer; #publicKey: Buffer; #publicKeyNeedsUpdate = false; constructor( sizeOrKey: number | string | ArrayBufferView, 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 any) && keyEncoding !== "buffer" ) { genEncoding = generator; generator = keyEncoding; keyEncoding = false; } const encoding = getDefaultEncoding(); keyEncoding = keyEncoding || encoding; genEncoding = genEncoding || encoding; if (typeof sizeOrKey !== "number") { if (isArrayBufferView(sizeOrKey) || isAnyArrayBuffer(sizeOrKey)) { if (isArrayBufferView(sizeOrKey)) { const parts = getViewParts(sizeOrKey as ArrayBufferView); this.#prime = Buffer.from(parts.ab, parts.off, parts.len); } else { this.#prime = Buffer.from( sizeOrKey, 0, ArrayBufferPrototypeGetByteLength(sizeOrKey as ArrayBuffer), ); } } else { 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_DH_MODULUS_TOO_SMALL", "modulus too small", ); } this.#prime = Buffer.from( TypedArrayPrototypeGetBuffer( op_node_gen_prime(this.#primeLength, false, null, null), ), ); } if (!generator) { generator = DH_GENERATOR; } if (typeof generator === "number") { validateInt32(generator, "generator"); if (generator <= 0 || generator >= 0x7fffffff) { throw new NodeError("ERR_OSSL_DH_BAD_GENERATOR", "bad generator"); } // Store with minimal byte representation, matching Node.js/OpenSSL behavior if (generator <= 0xff) { this.#generator = Buffer.alloc(1); this.#generator.writeUint8(generator); } else if (generator <= 0xffff) { this.#generator = Buffer.alloc(2); this.#generator.writeUint16BE(generator); } else { this.#generator = Buffer.alloc(4); 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); } this.#checkGenerator(); this.verifyError = op_node_dh_check(this.#prime, this.#generator); } #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 | string, inputEncoding?: any, outputEncoding?: any, ): Buffer | string { const buf = getArrayBufferOrView(otherPublicKey, "key", inputEncoding); if (buf.length === 0) { throw new NodeError( "ERR_CRYPTO_INVALID_KEYLEN", "Unspecified validation error", ); } const sharedSecret = op_node_dh_compute_secret( this.#prime, this.#privateKey, buf, ); // Zero-pad the shared secret to the length of the prime, per RFC 4346 let secretBuf = Buffer.from(TypedArrayPrototypeGetBuffer(sharedSecret)); const primeLen = this.#prime.length; if (secretBuf.length < primeLen) { const padded = Buffer.alloc(primeLen); secretBuf.copy(padded, primeLen - secretBuf.length); secretBuf = padded; } if (outputEncoding == undefined || outputEncoding == "buffer") { return secretBuf; } // deno-lint-ignore deno-internal/prefer-primordials -- Buffer.prototype.toString(encoding) has no primordial return secretBuf.toString(outputEncoding); } generateKeys(_encoding?: any): Buffer | string { const generator = this.#checkGenerator(); if (this.#privateKey && this.#publicKey && !this.#publicKeyNeedsUpdate) { // Both keys already exist and are up to date, no-op return this.#publicKey; } if (this.#privateKey) { // Private key set externally, compute public key from it const publicKey = op_node_dh_compute_secret( this.#prime, this.#privateKey, this.#generator, ); this.#publicKey = Buffer.from(TypedArrayPrototypeGetBuffer(publicKey)); this.#publicKeyNeedsUpdate = false; } else { // Generate both keys const keys = op_node_dh_keys_generate_and_export( this.#prime, this.#primeLength ?? 0, generator, ); this.#privateKey = Buffer.from(TypedArrayPrototypeGetBuffer(keys[0])); this.#publicKey = Buffer.from(TypedArrayPrototypeGetBuffer(keys[1])); this.#publicKeyNeedsUpdate = false; } return this.#publicKey; } getGenerator(encoding?: any): Buffer | string { if (encoding !== undefined && encoding != "buffer") { // deno-lint-ignore deno-internal/prefer-primordials -- Buffer.prototype.toString(encoding) has no primordial return this.#generator.toString(encoding); } return this.#generator; } getPrime(encoding?: any): Buffer | string { if (encoding !== undefined && encoding != "buffer") { // deno-lint-ignore deno-internal/prefer-primordials -- Buffer.prototype.toString(encoding) has no primordial return this.#prime.toString(encoding); } return this.#prime; } getPrivateKey(encoding?: any): Buffer | string { if (encoding !== undefined && encoding != "buffer") { // deno-lint-ignore deno-internal/prefer-primordials -- Buffer.prototype.toString(encoding) has no primordial return this.#privateKey.toString(encoding); } return this.#privateKey; } getPublicKey(encoding?: any): Buffer | string { if (encoding !== undefined && encoding != "buffer") { // deno-lint-ignore deno-internal/prefer-primordials -- Buffer.prototype.toString(encoding) has no primordial return this.#publicKey.toString(encoding); } return this.#publicKey; } setPrivateKey( privateKey: ArrayBufferView | string, encoding?: any, ) { if (encoding == undefined || encoding == "buffer") { this.#privateKey = Buffer.from(privateKey); } else { this.#privateKey = Buffer.from(privateKey, encoding); } // Mark public key as needing regeneration this.#publicKeyNeedsUpdate = true; } setPublicKey( publicKey: ArrayBufferView | string, encoding?: any, ) { if (encoding == undefined || encoding == "buffer") { this.#publicKey = Buffer.from(publicKey); } else { this.#publicKey = Buffer.from(publicKey, encoding); } } } const DH_GROUP_NAMES = [ "modp1", "modp2", "modp5", "modp14", "modp15", "modp16", "modp17", "modp18", ]; const DH_GROUPS = { "modp1": { // 768-bit prime from RFC 2409 prime: [ 0xFFFFFFFF, 0xFFFFFFFF, 0xC90FDAA2, 0x2168C234, 0xC4C6628B, 0x80DC1CD1, 0x29024E08, 0x8A67CC74, 0x020BBEA6, 0x3B139B22, 0x514A0879, 0x8E3404DD, 0xEF9519B3, 0xCD3A431B, 0x302B0A6D, 0xF25F1437, 0x4FE1356D, 0x6D51C245, 0xE485B576, 0x625E7EC6, 0xF44C42E9, 0xA63A3620, 0xFFFFFFFF, 0xFFFFFFFF, ], generator: 2, }, "modp2": { // 1024-bit prime from RFC 2409 prime: [ 0xFFFFFFFF, 0xFFFFFFFF, 0xC90FDAA2, 0x2168C234, 0xC4C6628B, 0x80DC1CD1, 0x29024E08, 0x8A67CC74, 0x020BBEA6, 0x3B139B22, 0x514A0879, 0x8E3404DD, 0xEF9519B3, 0xCD3A431B, 0x302B0A6D, 0xF25F1437, 0x4FE1356D, 0x6D51C245, 0xE485B576, 0x625E7EC6, 0xF44C42E9, 0xA637ED6B, 0x0BFF5CB6, 0xF406B7ED, 0xEE386BFB, 0x5A899FA5, 0xAE9F2411, 0x7C4B1FE6, 0x49286651, 0xECE65381, 0xFFFFFFFF, 0xFFFFFFFF, ], generator: 2, }, "modp5": { prime: [ 0xFFFFFFFF, 0xFFFFFFFF, 0xC90FDAA2, 0x2168C234, 0xC4C6628B, 0x80DC1CD1, 0x29024E08, 0x8A67CC74, 0x020BBEA6, 0x3B139B22, 0x514A0879, 0x8E3404DD, 0xEF9519B3, 0xCD3A431B, 0x302B0A6D, 0xF25F1437, 0x4FE1356D, 0x6D51C245, 0xE485B576, 0x625E7EC6, 0xF44C42E9, 0xA637ED6B, 0x0BFF5CB6, 0xF406B7ED, 0xEE386BFB, 0x5A899FA5, 0xAE9F2411, 0x7C4B1FE6, 0x49286651, 0xECE45B3D, 0xC2007CB8, 0xA163BF05, 0x98DA4836, 0x1C55D39A, 0x69163FA8, 0xFD24CF5F, 0x83655D23, 0xDCA3AD96, 0x1C62F356, 0x208552BB, 0x9ED52907, 0x7096966D, 0x670C354E, 0x4ABC9804, 0xF1746C08, 0xCA237327, 0xFFFFFFFF, 0xFFFFFFFF, ], generator: 2, }, "modp14": { prime: [ 0xFFFFFFFF, 0xFFFFFFFF, 0xC90FDAA2, 0x2168C234, 0xC4C6628B, 0x80DC1CD1, 0x29024E08, 0x8A67CC74, 0x020BBEA6, 0x3B139B22, 0x514A0879, 0x8E3404DD, 0xEF9519B3, 0xCD3A431B, 0x302B0A6D, 0xF25F1437, 0x4FE1356D, 0x6D51C245, 0xE485B576, 0x625E7EC6, 0xF44C42E9, 0xA637ED6B, 0x0BFF5CB6, 0xF406B7ED, 0xEE386BFB, 0x5A899FA5, 0xAE9F2411, 0x7C4B1FE6, 0x49286651, 0xECE45B3D, 0xC2007CB8, 0xA163BF05, 0x98DA4836, 0x1C55D39A, 0x69163FA8, 0xFD24CF5F, 0x83655D23, 0xDCA3AD96, 0x1C62F356, 0x208552BB, 0x9ED52907, 0x7096966D, 0x670C354E, 0x4ABC9804, 0xF1746C08, 0xCA18217C, 0x32905E46, 0x2E36CE3B, 0xE39E772C, 0x180E8603, 0x9B2783A2, 0xEC07A28F, 0xB5C55DF0, 0x6F4C52C9, 0xDE2BCBF6, 0x95581718, 0x3995497C, 0xEA956AE5, 0x15D22618, 0x98FA0510, 0x15728E5A, 0x8AACAA68, 0xFFFFFFFF, 0xFFFFFFFF, ], generator: 2, }, "modp15": { prime: [ 0xFFFFFFFF, 0xFFFFFFFF, 0xC90FDAA2, 0x2168C234, 0xC4C6628B, 0x80DC1CD1, 0x29024E08, 0x8A67CC74, 0x020BBEA6, 0x3B139B22, 0x514A0879, 0x8E3404DD, 0xEF9519B3, 0xCD3A431B, 0x302B0A6D, 0xF25F1437, 0x4FE1356D, 0x6D51C245, 0xE485B576, 0x625E7EC6, 0xF44C42E9, 0xA637ED6B, 0x0BFF5CB6, 0xF406B7ED, 0xEE386BFB, 0x5A899FA5, 0xAE9F2411, 0x7C4B1FE6, 0x49286651, 0xECE45B3D, 0xC2007CB8, 0xA163BF05, 0x98DA4836, 0x1C55D39A, 0x69163FA8, 0xFD24CF5F, 0x83655D23, 0xDCA3AD96, 0x1C62F356, 0x208552BB, 0x9ED52907, 0x7096966D, 0x670C354E, 0x4ABC9804, 0xF1746C08, 0xCA18217C, 0x32905E46, 0x2E36CE3B, 0xE39E772C, 0x180E8603, 0x9B2783A2, 0xEC07A28F, 0xB5C55DF0, 0x6F4C52C9, 0xDE2BCBF6, 0x95581718, 0x3995497C, 0xEA956AE5, 0x15D22618, 0x98FA0510, 0x15728E5A, 0x8AAAC42D, 0xAD33170D, 0x04507A33, 0xA85521AB, 0xDF1CBA64, 0xECFB8504, 0x58DBEF0A, 0x8AEA7157, 0x5D060C7D, 0xB3970F85, 0xA6E1E4C7, 0xABF5AE8C, 0xDB0933D7, 0x1E8C94E0, 0x4A25619D, 0xCEE3D226, 0x1AD2EE6B, 0xF12FFA06, 0xD98A0864, 0xD8760273, 0x3EC86A64, 0x521F2B18, 0x177B200C, 0xBBE11757, 0x7A615D6C, 0x770988C0, 0xBAD946E2, 0x08E24FA0, 0x74E5AB31, 0x43DB5BFC, 0xE0FD108E, 0x4B82D120, 0xA93AD2CA, 0xFFFFFFFF, 0xFFFFFFFF, ], generator: 2, }, "modp16": { prime: [ 0xFFFFFFFF, 0xFFFFFFFF, 0xC90FDAA2, 0x2168C234, 0xC4C6628B, 0x80DC1CD1, 0x29024E08, 0x8A67CC74, 0x020BBEA6, 0x3B139B22, 0x514A0879, 0x8E3404DD, 0xEF9519B3, 0xCD3A431B, 0x302B0A6D, 0xF25F1437, 0x4FE1356D, 0x6D51C245, 0xE485B576, 0x625E7EC6, 0xF44C42E9, 0xA637ED6B, 0x0BFF5CB6, 0xF406B7ED, 0xEE386BFB, 0x5A899FA5, 0xAE9F2411, 0x7C4B1FE6, 0x49286651, 0xECE45B3D, 0xC2007CB8, 0xA163BF05, 0x98DA4836, 0x1C55D39A, 0x69163FA8, 0xFD24CF5F, 0x83655D23, 0xDCA3AD96, 0x1C62F356, 0x208552BB, 0x9ED52907, 0x7096966D, 0x670C354E, 0x4ABC9804, 0xF1746C08, 0xCA18217C, 0x32905E46, 0x2E36CE3B, 0xE39E772C, 0x180E8603, 0x9B2783A2, 0xEC07A28F, 0xB5C55DF0, 0x6F4C52C9, 0xDE2BCBF6, 0x95581718, 0x3995497C, 0xEA956AE5, 0x15D22618, 0x98FA0510, 0x15728E5A, 0x8AAAC42D, 0xAD33170D, 0x04507A33, 0xA85521AB, 0xDF1CBA64, 0xECFB8504, 0x58DBEF0A, 0x8AEA7157, 0x5D060C7D, 0xB3970F85, 0xA6E1E4C7, 0xABF5AE8C, 0xDB0933D7, 0x1E8C94E0, 0x4A25619D, 0xCEE3D226, 0x1AD2EE6B, 0xF12FFA06, 0xD98A0864, 0xD8760273, 0x3EC86A64, 0x521F2B18, 0x177B200C, 0xBBE11757, 0x7A615D6C, 0x770988C0, 0xBAD946E2, 0x08E24FA0, 0x74E5AB31, 0x43DB5BFC, 0xE0FD108E, 0x4B82D120, 0xA9210801, 0x1A723C12, 0xA787E6D7, 0x88719A10, 0xBDBA5B26, 0x99C32718, 0x6AF4E23C, 0x1A946834, 0xB6150BDA, 0x2583E9CA, 0x2AD44CE8, 0xDBBBC2DB, 0x04DE8EF9, 0x2E8EFC14, 0x1FBECAA6, 0x287C5947, 0x4E6BC05D, 0x99B2964F, 0xA090C3A2, 0x233BA186, 0x515BE7ED, 0x1F612970, 0xCEE2D7AF, 0xB81BDD76, 0x2170481C, 0xD0069127, 0xD5B05AA9, 0x93B4EA98, 0x8D8FDDC1, 0x86FFB7DC, 0x90A6C08F, 0x4DF435C9, 0x34063199, 0xFFFFFFFF, 0xFFFFFFFF, ], generator: 2, }, "modp17": { prime: [ 0xFFFFFFFF, 0xFFFFFFFF, 0xC90FDAA2, 0x2168C234, 0xC4C6628B, 0x80DC1CD1, 0x29024E08, 0x8A67CC74, 0x020BBEA6, 0x3B139B22, 0x514A0879, 0x8E3404DD, 0xEF9519B3, 0xCD3A431B, 0x302B0A6D, 0xF25F1437, 0x4FE1356D, 0x6D51C245, 0xE485B576, 0x625E7EC6, 0xF44C42E9, 0xA637ED6B, 0x0BFF5CB6, 0xF406B7ED, 0xEE386BFB, 0x5A899FA5, 0xAE9F2411, 0x7C4B1FE6, 0x49286651, 0xECE45B3D, 0xC2007CB8, 0xA163BF05, 0x98DA4836, 0x1C55D39A, 0x69163FA8, 0xFD24CF5F, 0x83655D23, 0xDCA3AD96, 0x1C62F356, 0x208552BB, 0x9ED52907, 0x7096966D, 0x670C354E, 0x4ABC9804, 0xF1746C08, 0xCA18217C, 0x32905E46, 0x2E36CE3B, 0xE39E772C, 0x180E8603, 0x9B2783A2, 0xEC07A28F, 0xB5C55DF0, 0x6F4C52C9, 0xDE2BCBF6, 0x95581718, 0x3995497C, 0xEA956AE5, 0x15D22618, 0x98FA0510, 0x15728E5A, 0x8AAAC42D, 0xAD33170D, 0x04507A33, 0xA85521AB, 0xDF1CBA64, 0xECFB8504, 0x58DBEF0A, 0x8AEA7157, 0x5D060C7D, 0xB3970F85, 0xA6E1E4C7, 0xABF5AE8C, 0xDB0933D7, 0x1E8C94E0, 0x4A25619D, 0xCEE3D226, 0x1AD2EE6B, 0xF12FFA06, 0xD98A0864, 0xD8760273, 0x3EC86A64, 0x521F2B18, 0x177B200C, 0xBBE11757, 0x7A615D6C, 0x770988C0, 0xBAD946E2, 0x08E24FA0, 0x74E5AB31, 0x43DB5BFC, 0xE0FD108E, 0x4B82D120, 0xA9210801, 0x1A723C12, 0xA787E6D7, 0x88719A10, 0xBDBA5B26, 0x99C32718, 0x6AF4E23C, 0x1A946834, 0xB6150BDA, 0x2583E9CA, 0x2AD44CE8, 0xDBBBC2DB, 0x04DE8EF9, 0x2E8EFC14, 0x1FBECAA6, 0x287C5947, 0x4E6BC05D, 0x99B2964F, 0xA090C3A2, 0x233BA186, 0x515BE7ED, 0x1F612970, 0xCEE2D7AF, 0xB81BDD76, 0x2170481C, 0xD0069127, 0xD5B05AA9, 0x93B4EA98, 0x8D8FDDC1, 0x86FFB7DC, 0x90A6C08F, 0x4DF435C9, 0x34028492, 0x36C3FAB4, 0xD27C7026, 0xC1D4DCB2, 0x602646DE, 0xC9751E76, 0x3DBA37BD, 0xF8FF9406, 0xAD9E530E, 0xE5DB382F, 0x413001AE, 0xB06A53ED, 0x9027D831, 0x179727B0, 0x865A8918, 0xDA3EDBEB, 0xCF9B14ED, 0x44CE6CBA, 0xCED4BB1B, 0xDB7F1447, 0xE6CC254B, 0x33205151, 0x2BD7AF42, 0x6FB8F401, 0x378CD2BF, 0x5983CA01, 0xC64B92EC, 0xF032EA15, 0xD1721D03, 0xF482D7CE, 0x6E74FEF6, 0xD55E702F, 0x46980C82, 0xB5A84031, 0x900B1C9E, 0x59E7C97F, 0xBEC7E8F3, 0x23A97A7E, 0x36CC88BE, 0x0F1D45B7, 0xFF585AC5, 0x4BD407B2, 0x2B4154AA, 0xCC8F6D7E, 0xBF48E1D8, 0x14CC5ED2, 0x0F8037E0, 0xA79715EE, 0xF29BE328, 0x06A1D58B, 0xB7C5DA76, 0xF550AA3D, 0x8A1FBFF0, 0xEB19CCB1, 0xA313D55C, 0xDA56C9EC, 0x2EF29632, 0x387FE8D7, 0x6E3C0468, 0x043E8F66, 0x3F4860EE, 0x12BF2D5B, 0x0B7474D6, 0xE694F91E, 0x6DCC4024, 0xFFFFFFFF, 0xFFFFFFFF, ], generator: 2, }, "modp18": { prime: [ 0xFFFFFFFF, 0xFFFFFFFF, 0xC90FDAA2, 0x2168C234, 0xC4C6628B, 0x80DC1CD1, 0x29024E08, 0x8A67CC74, 0x020BBEA6, 0x3B139B22, 0x514A0879, 0x8E3404DD, 0xEF9519B3, 0xCD3A431B, 0x302B0A6D, 0xF25F1437, 0x4FE1356D, 0x6D51C245, 0xE485B576, 0x625E7EC6, 0xF44C42E9, 0xA637ED6B, 0x0BFF5CB6, 0xF406B7ED, 0xEE386BFB, 0x5A899FA5, 0xAE9F2411, 0x7C4B1FE6, 0x49286651, 0xECE45B3D, 0xC2007CB8, 0xA163BF05, 0x98DA4836, 0x1C55D39A, 0x69163FA8, 0xFD24CF5F, 0x83655D23, 0xDCA3AD96, 0x1C62F356, 0x208552BB, 0x9ED52907, 0x7096966D, 0x670C354E, 0x4ABC9804, 0xF1746C08, 0xCA18217C, 0x32905E46, 0x2E36CE3B, 0xE39E772C, 0x180E8603, 0x9B2783A2, 0xEC07A28F, 0xB5C55DF0, 0x6F4C52C9, 0xDE2BCBF6, 0x95581718, 0x3995497C, 0xEA956AE5, 0x15D22618, 0x98FA0510, 0x15728E5A, 0x8AAAC42D, 0xAD33170D, 0x04507A33, 0xA85521AB, 0xDF1CBA64, 0xECFB8504, 0x58DBEF0A, 0x8AEA7157, 0x5D060C7D, 0xB3970F85, 0xA6E1E4C7, 0xABF5AE8C, 0xDB0933D7, 0x1E8C94E0, 0x4A25619D, 0xCEE3D226, 0x1AD2EE6B, 0xF12FFA06, 0xD98A0864, 0xD8760273, 0x3EC86A64, 0x521F2B18, 0x177B200C, 0xBBE11757, 0x7A615D6C, 0x770988C0, 0xBAD946E2, 0x08E24FA0, 0x74E5AB31, 0x43DB5BFC, 0xE0FD108E, 0x4B82D120, 0xA9210801, 0x1A723C12, 0xA787E6D7, 0x88719A10, 0xBDBA5B26, 0x99C32718, 0x6AF4E23C, 0x1A946834, 0xB6150BDA, 0x2583E9CA, 0x2AD44CE8, 0xDBBBC2DB, 0x04DE8EF9, 0x2E8EFC14, 0x1FBECAA6, 0x287C5947, 0x4E6BC05D, 0x99B2964F, 0xA090C3A2, 0x233BA186, 0x515BE7ED, 0x1F612970, 0xCEE2D7AF, 0xB81BDD76, 0x2170481C, 0xD0069127, 0xD5B05AA9, 0x93B4EA98, 0x8D8FDDC1, 0x86FFB7DC, 0x90A6C08F, 0x4DF435C9, 0x34028492, 0x36C3FAB4, 0xD27C7026, 0xC1D4DCB2, 0x602646DE, 0xC9751E76, 0x3DBA37BD, 0xF8FF9406, 0xAD9E530E, 0xE5DB382F, 0x413001AE, 0xB06A53ED, 0x9027D831, 0x179727B0, 0x865A8918, 0xDA3EDBEB, 0xCF9B14ED, 0x44CE6CBA, 0xCED4BB1B, 0xDB7F1447, 0xE6CC254B, 0x33205151, 0x2BD7AF42, 0x6FB8F401, 0x378CD2BF, 0x5983CA01, 0xC64B92EC, 0xF032EA15, 0xD1721D03, 0xF482D7CE, 0x6E74FEF6, 0xD55E702F, 0x46980C82, 0xB5A84031, 0x900B1C9E, 0x59E7C97F, 0xBEC7E8F3, 0x23A97A7E, 0x36CC88BE, 0x0F1D45B7, 0xFF585AC5, 0x4BD407B2, 0x2B4154AA, 0xCC8F6D7E, 0xBF48E1D8, 0x14CC5ED2, 0x0F8037E0, 0xA79715EE, 0xF29BE328, 0x06A1D58B, 0xB7C5DA76, 0xF550AA3D, 0x8A1FBFF0, 0xEB19CCB1, 0xA313D55C, 0xDA56C9EC, 0x2EF29632, 0x387FE8D7, 0x6E3C0468, 0x043E8F66, 0x3F4860EE, 0x12BF2D5B, 0x0B7474D6, 0xE694F91E, 0x6DBE1159, 0x74A3926F, 0x12FEE5E4, 0x38777CB6, 0xA932DF8C, 0xD8BEC4D0, 0x73B931BA, 0x3BC832B6, 0x8D9DD300, 0x741FA7BF, 0x8AFC47ED, 0x2576F693, 0x6BA42466, 0x3AAB639C, 0x5AE4F568, 0x3423B474, 0x2BF1C978, 0x238F16CB, 0xE39D652D, 0xE3FDB8BE, 0xFC848AD9, 0x22222E04, 0xA4037C07, 0x13EB57A8, 0x1A23F0C7, 0x3473FC64, 0x6CEA306B, 0x4BCBC886, 0x2F8385DD, 0xFA9D4B7F, 0xA2C087E8, 0x79683303, 0xED5BDD3A, 0x062B3CF5, 0xB3A278A6, 0x6D2A13F8, 0x3F44F82D, 0xDF310EE0, 0x74AB6A36, 0x4597E899, 0xA0255DC1, 0x64F31CC5, 0x0846851D, 0xF9AB4819, 0x5DED7EA1, 0xB1D510BD, 0x7EE74D73, 0xFAF36BC3, 0x1ECFA268, 0x359046F4, 0xEB879F92, 0x4009438B, 0x481C6CD7, 0x889A002E, 0xD5EE382B, 0xC9190DA6, 0xFC026E47, 0x9558E447, 0x5677E9AA, 0x9E3050E2, 0x765694DF, 0xC81F56E8, 0x80B96E71, 0x60C980DD, 0x98EDD3DF, 0xFFFFFFFF, 0xFFFFFFFF, ], generator: 2, }, }; DiffieHellman.prototype = DiffieHellmanImpl.prototype; function DiffieHellmanGroup(name: string) { return new DiffieHellmanGroupImpl(name); } class DiffieHellmanGroupImpl { verifyError!: number; #diffiehellman: DiffieHellmanImpl; constructor(name: string) { if (!ArrayPrototypeIncludes(DH_GROUP_NAMES, name)) { throw new ERR_CRYPTO_UNKNOWN_DH_GROUP(); } const words = DH_GROUPS[name].prime; const buf = Buffer.alloc(words.length * 4); for (let i = 0; i < words.length; i++) { buf.writeUInt32BE(words[i], i * 4); } this.#diffiehellman = new DiffieHellmanImpl( buf, DH_GROUPS[name].generator, ); this.verifyError = 0; } computeSecret( otherPublicKey: ArrayBufferView | string, inputEncoding?: any, outputEncoding?: any, ): Buffer | string { return this.#diffiehellman.computeSecret( otherPublicKey, inputEncoding, outputEncoding, ); } generateKeys(encoding?: any): Buffer | string { return this.#diffiehellman.generateKeys(encoding); } getGenerator(encoding?: any): Buffer | string { return this.#diffiehellman.getGenerator(encoding); } getPrime(encoding?: any): Buffer | string { return this.#diffiehellman.getPrime(encoding); } getPrivateKey(encoding?: any): Buffer | string { return this.#diffiehellman.getPrivateKey(encoding); } getPublicKey(encoding?: any): Buffer | string { return this.#diffiehellman.getPublicKey(encoding); } } DiffieHellmanGroup.prototype = DiffieHellmanGroupImpl.prototype; DiffieHellmanGroup.prototype.constructor = DiffieHellmanGroup; function ECDH(curve: string) { return new ECDHImpl(curve); } function validateEcdhFormat(format: any): void { if ( format !== "compressed" && format !== "uncompressed" && format !== "hybrid" ) { throw new ERR_CRYPTO_ECDH_INVALID_FORMAT(String(format)); } } function ecdhEncode( buffer: Buffer, encoding?: any, ): Buffer | string { if (encoding === undefined || encoding === "buffer") { return buffer; } // deno-lint-ignore deno-internal/prefer-primordials -- Buffer.prototype.toString(encoding) has no primordial return buffer.toString(encoding); } class ECDHImpl { #curve: any; // the selected curve #privbuf: Buffer | null = null; // the private key #pubbuf: Buffer | null = null; // the public key constructor(curve: string) { validateString(curve, "curve"); const c = ArrayPrototypeFind(ellipticCurves, (x) => x.name == curve); if (c == undefined) { throw new Error("invalid curve"); } this.#curve = c; } static convertKey( key: any, curve: string, inputEncoding?: any, outputEncoding?: any, format?: any, ): Buffer | string { validateString(curve, "curve"); const buf = getArrayBufferOrView(key, "key", inputEncoding); let compress: boolean; if (format) { if (format === "compressed") { compress = true; } else if (format === "hybrid" || format === "uncompressed") { compress = false; } else { throw new ERR_CRYPTO_ECDH_INVALID_FORMAT(format); } } else { compress = false; } let result; try { result = Buffer.from( op_node_ecdh_encode_pubkey(curve, buf, compress), ); } catch (e) { if ( ObjectPrototypeIsPrototypeOf(TypeErrorPrototype, e) && (e as Error).message === "Unsupported curve" ) { throw new TypeError("Invalid EC curve name"); } throw new Error("Failed to convert Buffer to EC_POINT"); } if (format === "hybrid") { // Hybrid format: same as uncompressed but first byte is 06 or 07 // Get compressed form to determine parity const compressedBuf = Buffer.from( op_node_ecdh_encode_pubkey(curve, buf, true), ); // compressed first byte is 02 (even) or 03 (odd) // hybrid first byte is 06 (even) or 07 (odd) result[0] = compressedBuf[0] + 4; } if (outputEncoding && outputEncoding !== "buffer") { // deno-lint-ignore deno-internal/prefer-primordials -- Buffer.prototype.toString(encoding) has no primordial return result.toString(outputEncoding); } return result; } computeSecret( otherPublicKey: ArrayBufferView | string, inputEncoding?: any, outputEncoding?: any, ): Buffer | string { if (this.#privbuf === null) { throw new ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY(); } let otherBuf: Buffer; if (typeof otherPublicKey === "string") { otherBuf = Buffer.from(otherPublicKey, inputEncoding); } else { const parts = getViewParts(otherPublicKey); otherBuf = Buffer.from(parts.ab, parts.off, parts.len); } const secretBuf = Buffer.alloc(this.#curve.sharedSecretSize); try { op_node_ecdh_compute_secret( this.#curve.name, this.#privbuf, this.#pubbuf, otherBuf, secretBuf, ); } catch (e) { const err = e as any; if (err && err.message === "Invalid key pair") { throw new Error("Invalid key pair"); } throw new ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY(); } return ecdhEncode(secretBuf, outputEncoding ?? "buffer"); } generateKeys( encoding?: any, format: any = "uncompressed", ): Buffer | string { validateEcdhFormat(format); const pubbuf = Buffer.alloc( format == "compressed" ? this.#curve.publicKeySizeCompressed : this.#curve.publicKeySize, ); const privbuf = Buffer.alloc(this.#curve.privateKeySize); op_node_ecdh_generate_keys( this.#curve.name, pubbuf, privbuf, format, ); this.#pubbuf = pubbuf; this.#privbuf = privbuf; if (format === "hybrid") { const compressedBuf = Buffer.from(op_node_ecdh_encode_pubkey( this.#curve.name, pubbuf, true, )); pubbuf[0] = compressedBuf[0] + 4; } return ecdhEncode(pubbuf, encoding ?? "buffer"); } getPrivateKey(encoding?: any): Buffer | string { if (this.#privbuf === null) { throw new Error("Failed to get ECDH private key"); } return ecdhEncode(this.#privbuf, encoding ?? "buffer"); } getPublicKey( encoding?: any, format: any = "uncompressed", ): Buffer | string { if (this.#pubbuf === null) { throw new Error("Failed to get ECDH public key"); } validateEcdhFormat(format); const pubbuf = Buffer.from(op_node_ecdh_encode_pubkey( this.#curve.name, this.#pubbuf, format === "compressed", )); if (format === "hybrid") { const compressedBuf = Buffer.from(op_node_ecdh_encode_pubkey( this.#curve.name, this.#pubbuf, true, )); pubbuf[0] = compressedBuf[0] + 4; } return ecdhEncode(pubbuf, encoding ?? "buffer"); } setPrivateKey( privateKey: ArrayBufferView | string, encoding?: any, ): Buffer | string { let privbuf: Buffer; if (typeof privateKey === "string") { privbuf = Buffer.from(privateKey, encoding); } else { const parts = getViewParts(privateKey); privbuf = Buffer.from(parts.ab, parts.off, parts.len); } if (!op_node_ecdh_validate_private_key(this.#curve.name, privbuf)) { throw new Error("Private key is not valid for specified curve"); } const pubbuf = Buffer.alloc(this.#curve.publicKeySize); op_node_ecdh_compute_public_key(this.#curve.name, privbuf, pubbuf); this.#privbuf = privbuf; this.#pubbuf = pubbuf; return pubbuf; } setPublicKey( publicKey: ArrayBufferView | string, encoding?: any, ): void { let pubbuf: Buffer; if (typeof publicKey === "string") { pubbuf = Buffer.from(publicKey, encoding); } else { const parts = getViewParts(publicKey); pubbuf = Buffer.from(parts.ab, parts.off, parts.len); } if (!op_node_ecdh_validate_public_key(this.#curve.name, pubbuf)) { throw new Error("Failed to convert Buffer to EC_POINT"); } this.#pubbuf = pubbuf; } } ECDH.prototype = ECDHImpl.prototype; ECDH.convertKey = ECDHImpl.convertKey; ECDH.prototype.setPublicKey = deprecate( ECDHImpl.prototype.setPublicKey, "ecdh.setPublicKey() is deprecated.", "DEP0031", ); function statelessDH( privateKeyObject: KeyObject, publicKeyObject: KeyObject, ): Buffer { const privateKey = getKeyObjectHandle(privateKeyObject, kConsumePrivate); const publicKey = getKeyObjectHandle(publicKeyObject, kConsumePublic); const privType = privateKeyObject.asymmetricKeyType; const pubType = publicKeyObject.asymmetricKeyType; if ( privType !== undefined && pubType !== undefined && privType !== pubType ) { throw new ERR_CRYPTO_INCOMPATIBLE_KEY( "key types for Diffie-Hellman", `${privType} and ${pubType}`, ); } try { const bytes = op_node_diffie_hellman(privateKey, publicKey); return Buffer.from(bytes); } catch (err) { const e = err as Error & { code?: string }; if (e && typeof e.message === "string") { if ( StringPrototypeIncludes(e.message, "mismatching domain parameters") ) { e.code = "ERR_OSSL_MISMATCHING_DOMAIN_PARAMETERS"; } else if ( StringPrototypeIncludes(e.message, "failed during derivation") ) { e.code = "ERR_OSSL_FAILED_DURING_DERIVATION"; } } throw e; } } function diffieHellman( options: { privateKey: KeyObject; publicKey: KeyObject; }, callback?: (err: Error | null, secret?: Buffer) => void, ): Buffer | void { if (callback !== undefined && typeof callback !== "function") { throw new ERR_INVALID_ARG_TYPE("callback", "function", callback); } if ( typeof options !== "object" || options === null || ArrayIsArray(options) ) { throw new ERR_INVALID_ARG_TYPE("options", "object", options); } if (!options.privateKey) { throw new ERR_INVALID_ARG_VALUE("options.privateKey", options.privateKey); } if (!options.publicKey) { throw new ERR_INVALID_ARG_VALUE("options.publicKey", options.publicKey); } if (callback) { try { const secret = statelessDH(options.privateKey, options.publicKey); callback(null, secret); } catch (err) { callback(err as Error); } return; } return statelessDH(options.privateKey, options.publicKey); } return { DiffieHellman, DiffieHellmanGroup, ECDH, diffieHellman, default: { DiffieHellman, DiffieHellmanGroup, ECDH, diffieHellman, }, }; })();