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:
parent
9c5ddf7c69
commit
becdad531f
5 changed files with 31 additions and 8 deletions
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
];
|
];
|
||||||
|
|
|
@ -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);
|
||||||
|
});
|
||||||
|
|
Loading…
Add table
Reference in a new issue