0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-02-01 20:25:12 -05:00

fix(ext/node): support public key point encoding in ECDH.generateKeys() (#22976)

Towards https://github.com/denoland/deno/issues/22921

Co-authored-by: Divy Srivastava <dj.srivastava23@gmail.com>
This commit is contained in:
Satya Rohith 2024-03-18 13:20:10 +05:30 committed by GitHub
parent 9c5ddf7c69
commit becdad531f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 31 additions and 8 deletions

View file

@ -10,6 +10,7 @@ use deno_core::OpState;
use deno_core::ResourceId; use deno_core::ResourceId;
use deno_core::StringOrBuffer; use deno_core::StringOrBuffer;
use deno_core::ToJsBuffer; use deno_core::ToJsBuffer;
use elliptic_curve::sec1::ToEncodedPoint;
use hkdf::Hkdf; use hkdf::Hkdf;
use num_bigint::BigInt; use num_bigint::BigInt;
use num_bigint_dig::BigUint; use num_bigint_dig::BigUint;
@ -739,8 +740,6 @@ pub async fn op_node_dsa_generate_async(
fn ec_generate( fn ec_generate(
named_curve: &str, named_curve: &str,
) -> Result<(ToJsBuffer, ToJsBuffer), AnyError> { ) -> Result<(ToJsBuffer, ToJsBuffer), AnyError> {
use elliptic_curve::sec1::ToEncodedPoint;
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
// TODO(@littledivy): Support public key point encoding. // TODO(@littledivy): Support public key point encoding.
// Default is uncompressed. // Default is uncompressed.
@ -1054,14 +1053,16 @@ pub fn op_node_ecdh_generate_keys(
#[string] curve: &str, #[string] curve: &str,
#[buffer] pubbuf: &mut [u8], #[buffer] pubbuf: &mut [u8],
#[buffer] privbuf: &mut [u8], #[buffer] privbuf: &mut [u8],
#[string] format: &str,
) -> Result<ResourceId, AnyError> { ) -> Result<ResourceId, AnyError> {
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
let compress = format == "compressed";
match curve { match curve {
"secp256k1" => { "secp256k1" => {
let privkey = let privkey =
elliptic_curve::SecretKey::<k256::Secp256k1>::random(&mut rng); elliptic_curve::SecretKey::<k256::Secp256k1>::random(&mut rng);
let pubkey = privkey.public_key(); let pubkey = privkey.public_key();
pubbuf.copy_from_slice(pubkey.to_sec1_bytes().as_ref()); pubbuf.copy_from_slice(pubkey.to_encoded_point(compress).as_ref());
privbuf.copy_from_slice(privkey.to_nonzero_scalar().to_bytes().as_ref()); privbuf.copy_from_slice(privkey.to_nonzero_scalar().to_bytes().as_ref());
Ok(0) Ok(0)
@ -1069,21 +1070,21 @@ pub fn op_node_ecdh_generate_keys(
"prime256v1" | "secp256r1" => { "prime256v1" | "secp256r1" => {
let privkey = elliptic_curve::SecretKey::<NistP256>::random(&mut rng); let privkey = elliptic_curve::SecretKey::<NistP256>::random(&mut rng);
let pubkey = privkey.public_key(); let pubkey = privkey.public_key();
pubbuf.copy_from_slice(pubkey.to_sec1_bytes().as_ref()); pubbuf.copy_from_slice(pubkey.to_encoded_point(compress).as_ref());
privbuf.copy_from_slice(privkey.to_nonzero_scalar().to_bytes().as_ref()); privbuf.copy_from_slice(privkey.to_nonzero_scalar().to_bytes().as_ref());
Ok(0) Ok(0)
} }
"secp384r1" => { "secp384r1" => {
let privkey = elliptic_curve::SecretKey::<NistP384>::random(&mut rng); let privkey = elliptic_curve::SecretKey::<NistP384>::random(&mut rng);
let pubkey = privkey.public_key(); let pubkey = privkey.public_key();
pubbuf.copy_from_slice(pubkey.to_sec1_bytes().as_ref()); pubbuf.copy_from_slice(pubkey.to_encoded_point(compress).as_ref());
privbuf.copy_from_slice(privkey.to_nonzero_scalar().to_bytes().as_ref()); privbuf.copy_from_slice(privkey.to_nonzero_scalar().to_bytes().as_ref());
Ok(0) Ok(0)
} }
"secp224r1" => { "secp224r1" => {
let privkey = elliptic_curve::SecretKey::<NistP224>::random(&mut rng); let privkey = elliptic_curve::SecretKey::<NistP224>::random(&mut rng);
let pubkey = privkey.public_key(); let pubkey = privkey.public_key();
pubbuf.copy_from_slice(pubkey.to_sec1_bytes().as_ref()); pubbuf.copy_from_slice(pubkey.to_encoded_point(compress).as_ref());
privbuf.copy_from_slice(privkey.to_nonzero_scalar().to_bytes().as_ref()); privbuf.copy_from_slice(privkey.to_nonzero_scalar().to_bytes().as_ref());
Ok(0) Ok(0)
} }

View file

@ -1236,12 +1236,18 @@ export class ECDH {
generateKeys(encoding: BinaryToTextEncoding, format?: ECDHKeyFormat): string; generateKeys(encoding: BinaryToTextEncoding, format?: ECDHKeyFormat): string;
generateKeys( generateKeys(
encoding?: BinaryToTextEncoding, encoding?: BinaryToTextEncoding,
_format?: ECDHKeyFormat, format: ECDHKeyFormat = "uncompressed",
): Buffer | string { ): Buffer | string {
this.#pubbuf = Buffer.alloc(
format.trim() == "compressed"
? this.#curve.publicKeySizeCompressed
: this.#curve.publicKeySize,
);
op_node_ecdh_generate_keys( op_node_ecdh_generate_keys(
this.#curve.name, this.#curve.name,
this.#pubbuf, this.#pubbuf,
this.#privbuf, this.#privbuf,
format,
); );
if (encoding !== undefined) { if (encoding !== undefined) {

View file

@ -16,7 +16,7 @@ export type Encoding =
| CharacterEncoding | CharacterEncoding
| LegacyCharacterEncoding; | LegacyCharacterEncoding;
export type ECDHKeyFormat = "compressed" | "uncompressed" | "hybrid"; export type ECDHKeyFormat = "compressed" | "uncompressed";
export type BinaryLike = string | ArrayBufferView; export type BinaryLike = string | ArrayBufferView;

View file

@ -25,6 +25,7 @@ export type EllipticCurve = {
ephemeral: boolean; ephemeral: boolean;
privateKeySize: number; privateKeySize: number;
publicKeySize: number; publicKeySize: number;
publicKeySizeCompressed: number;
sharedSecretSize: number; sharedSecretSize: number;
}; };
@ -33,30 +34,35 @@ export const ellipticCurves: Array<EllipticCurve> = [
name: "secp256k1", name: "secp256k1",
privateKeySize: 32, privateKeySize: 32,
publicKeySize: 65, publicKeySize: 65,
publicKeySizeCompressed: 33,
sharedSecretSize: 32, sharedSecretSize: 32,
}, // Weierstrass-class EC used by Bitcoin }, // Weierstrass-class EC used by Bitcoin
{ {
name: "prime256v1", name: "prime256v1",
privateKeySize: 32, privateKeySize: 32,
publicKeySize: 65, publicKeySize: 65,
publicKeySizeCompressed: 33,
sharedSecretSize: 32, sharedSecretSize: 32,
}, // NIST P-256 EC }, // NIST P-256 EC
{ {
name: "secp256r1", name: "secp256r1",
privateKeySize: 32, privateKeySize: 32,
publicKeySize: 65, publicKeySize: 65,
publicKeySizeCompressed: 33,
sharedSecretSize: 32, sharedSecretSize: 32,
}, // NIST P-256 EC (same as above) }, // NIST P-256 EC (same as above)
{ {
name: "secp384r1", name: "secp384r1",
privateKeySize: 48, privateKeySize: 48,
publicKeySize: 97, publicKeySize: 97,
publicKeySizeCompressed: 49,
sharedSecretSize: 48, sharedSecretSize: 48,
}, // NIST P-384 EC }, // NIST P-384 EC
{ {
name: "secp224r1", name: "secp224r1",
privateKeySize: 28, privateKeySize: 28,
publicKeySize: 57, publicKeySize: 57,
publicKeySizeCompressed: 29,
sharedSecretSize: 28, sharedSecretSize: 28,
}, // NIST P-224 EC }, // NIST P-224 EC
]; ];

View file

@ -2,6 +2,7 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
import { import {
createECDH,
createHmac, createHmac,
createPrivateKey, createPrivateKey,
createPublicKey, createPublicKey,
@ -313,3 +314,12 @@ Deno.test("createPublicKey SPKI for DH", async function () {
assertEquals(pubKey.asymmetricKeyType, "ec"); assertEquals(pubKey.asymmetricKeyType, "ec");
assertEquals(privKey.asymmetricKeyType, "ec"); assertEquals(privKey.asymmetricKeyType, "ec");
}); });
Deno.test("ECDH generateKeys compressed", function () {
const ecdh = createECDH("secp256k1");
const publicKey = ecdh.generateKeys("binary", "compressed");
assertEquals(publicKey.length, 33);
const uncompressedKey = ecdh.generateKeys("binary");
assertEquals(uncompressedKey.length, 65);
});