mirror of
https://github.com/denoland/deno.git
synced 2024-11-24 15:19:26 -05:00
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>
This commit is contained in:
parent
3fbb31c3c1
commit
c3d670dbc9
7 changed files with 469 additions and 33 deletions
205
Cargo.lock
generated
205
Cargo.lock
generated
|
@ -243,6 +243,12 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce"
|
||||
|
||||
[[package]]
|
||||
name = "base16ct"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
|
||||
|
||||
[[package]]
|
||||
name = "base32"
|
||||
version = "0.4.0"
|
||||
|
@ -595,6 +601,18 @@ dependencies = [
|
|||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-bigint"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15"
|
||||
dependencies = [
|
||||
"generic-array 0.14.6",
|
||||
"rand_core 0.6.4",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
|
@ -877,15 +895,15 @@ dependencies = [
|
|||
"curve25519-dalek 2.1.3",
|
||||
"deno_core",
|
||||
"deno_web",
|
||||
"elliptic-curve",
|
||||
"elliptic-curve 0.12.3",
|
||||
"num-traits",
|
||||
"once_cell",
|
||||
"p256",
|
||||
"p384",
|
||||
"p256 0.11.1",
|
||||
"p384 0.11.2",
|
||||
"rand",
|
||||
"ring",
|
||||
"rsa",
|
||||
"sec1",
|
||||
"sec1 0.3.0",
|
||||
"serde",
|
||||
"serde_bytes",
|
||||
"sha1",
|
||||
|
@ -1137,6 +1155,7 @@ dependencies = [
|
|||
"digest 0.10.6",
|
||||
"dsa",
|
||||
"ecb",
|
||||
"elliptic-curve 0.13.4",
|
||||
"hex",
|
||||
"hkdf",
|
||||
"idna 0.3.0",
|
||||
|
@ -1150,6 +1169,9 @@ dependencies = [
|
|||
"num-integer",
|
||||
"num-traits",
|
||||
"once_cell",
|
||||
"p224",
|
||||
"p256 0.13.2",
|
||||
"p384 0.13.0",
|
||||
"path-clean",
|
||||
"pbkdf2",
|
||||
"rand",
|
||||
|
@ -1158,6 +1180,7 @@ dependencies = [
|
|||
"ripemd",
|
||||
"rsa",
|
||||
"scrypt",
|
||||
"secp256k1",
|
||||
"serde",
|
||||
"sha-1",
|
||||
"sha2",
|
||||
|
@ -1371,7 +1394,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de"
|
||||
dependencies = [
|
||||
"const-oid",
|
||||
"pem-rfc7468",
|
||||
"pem-rfc7468 0.6.0",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
|
@ -1382,6 +1405,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "82b10af9f9f9f2134a42d3f8aa74658660f2e0234b0eb81bd171df8aa32779ed"
|
||||
dependencies = [
|
||||
"const-oid",
|
||||
"pem-rfc7468 0.7.0",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
|
@ -1628,11 +1652,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c"
|
||||
dependencies = [
|
||||
"der 0.6.1",
|
||||
"elliptic-curve",
|
||||
"elliptic-curve 0.12.3",
|
||||
"rfc6979 0.3.1",
|
||||
"signature 1.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ecdsa"
|
||||
version = "0.16.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a48e5d537b8a30c0b023116d981b16334be1485af7ca68db3a2b7024cbc957fd"
|
||||
dependencies = [
|
||||
"der 0.7.3",
|
||||
"digest 0.10.6",
|
||||
"elliptic-curve 0.13.4",
|
||||
"rfc6979 0.4.0",
|
||||
"signature 2.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.8.1"
|
||||
|
@ -1645,18 +1682,39 @@ version = "0.12.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3"
|
||||
dependencies = [
|
||||
"base16ct",
|
||||
"crypto-bigint",
|
||||
"base16ct 0.1.1",
|
||||
"crypto-bigint 0.4.9",
|
||||
"der 0.6.1",
|
||||
"digest 0.10.6",
|
||||
"ff",
|
||||
"ff 0.12.1",
|
||||
"generic-array 0.14.6",
|
||||
"group",
|
||||
"group 0.12.1",
|
||||
"hkdf",
|
||||
"pem-rfc7468",
|
||||
"pem-rfc7468 0.6.0",
|
||||
"pkcs8 0.9.0",
|
||||
"rand_core 0.6.4",
|
||||
"sec1",
|
||||
"sec1 0.3.0",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "elliptic-curve"
|
||||
version = "0.13.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75c71eaa367f2e5d556414a8eea812bc62985c879748d6403edabd9cb03f16e7"
|
||||
dependencies = [
|
||||
"base16ct 0.2.0",
|
||||
"crypto-bigint 0.5.2",
|
||||
"digest 0.10.6",
|
||||
"ff 0.13.0",
|
||||
"generic-array 0.14.6",
|
||||
"group 0.13.0",
|
||||
"hkdf",
|
||||
"pem-rfc7468 0.7.0",
|
||||
"pkcs8 0.10.2",
|
||||
"rand_core 0.6.4",
|
||||
"sec1 0.7.1",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
@ -1828,6 +1886,16 @@ dependencies = [
|
|||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ff"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449"
|
||||
dependencies = [
|
||||
"rand_core 0.6.4",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.20"
|
||||
|
@ -2051,6 +2119,7 @@ checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9"
|
|||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2106,7 +2175,18 @@ version = "0.12.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7"
|
||||
dependencies = [
|
||||
"ff",
|
||||
"ff 0.12.1",
|
||||
"rand_core 0.6.4",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "group"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
|
||||
dependencies = [
|
||||
"ff 0.13.0",
|
||||
"rand_core 0.6.4",
|
||||
"subtle",
|
||||
]
|
||||
|
@ -3123,14 +3203,38 @@ version = "0.5.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4030760ffd992bef45b0ae3f10ce1aba99e33464c90d14dd7c039884963ddc7a"
|
||||
|
||||
[[package]]
|
||||
name = "p224"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30c06436d66652bc2f01ade021592c80a2aad401570a18aa18b82e440d2b9aa1"
|
||||
dependencies = [
|
||||
"ecdsa 0.16.6",
|
||||
"elliptic-curve 0.13.4",
|
||||
"primeorder",
|
||||
"sha2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "p256"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51f44edd08f51e2ade572f141051021c5af22677e42b7dd28a88155151c33594"
|
||||
dependencies = [
|
||||
"ecdsa",
|
||||
"elliptic-curve",
|
||||
"ecdsa 0.14.8",
|
||||
"elliptic-curve 0.12.3",
|
||||
"sha2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "p256"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b"
|
||||
dependencies = [
|
||||
"ecdsa 0.16.6",
|
||||
"elliptic-curve 0.13.4",
|
||||
"primeorder",
|
||||
"sha2",
|
||||
]
|
||||
|
||||
|
@ -3140,8 +3244,20 @@ version = "0.11.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfc8c5bf642dde52bb9e87c0ecd8ca5a76faac2eeed98dedb7c717997e1080aa"
|
||||
dependencies = [
|
||||
"ecdsa",
|
||||
"elliptic-curve",
|
||||
"ecdsa 0.14.8",
|
||||
"elliptic-curve 0.12.3",
|
||||
"sha2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "p384"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209"
|
||||
dependencies = [
|
||||
"ecdsa 0.16.6",
|
||||
"elliptic-curve 0.13.4",
|
||||
"primeorder",
|
||||
"sha2",
|
||||
]
|
||||
|
||||
|
@ -3244,6 +3360,15 @@ dependencies = [
|
|||
"base64ct",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pem-rfc7468"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.2.0"
|
||||
|
@ -3431,6 +3556,15 @@ dependencies = [
|
|||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "primeorder"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf8d3875361e28f7753baefef104386e7aa47642c93023356d97fdef4003bfb5"
|
||||
dependencies = [
|
||||
"elliptic-curve 0.13.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "1.3.1"
|
||||
|
@ -3689,7 +3823,7 @@ version = "0.3.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb"
|
||||
dependencies = [
|
||||
"crypto-bigint",
|
||||
"crypto-bigint 0.4.9",
|
||||
"hmac",
|
||||
"zeroize",
|
||||
]
|
||||
|
@ -3955,7 +4089,7 @@ version = "0.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928"
|
||||
dependencies = [
|
||||
"base16ct",
|
||||
"base16ct 0.1.1",
|
||||
"der 0.6.1",
|
||||
"generic-array 0.14.6",
|
||||
"pkcs8 0.9.0",
|
||||
|
@ -3963,6 +4097,39 @@ dependencies = [
|
|||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sec1"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48518a2b5775ba8ca5b46596aae011caa431e6ce7e4a67ead66d92f08884220e"
|
||||
dependencies = [
|
||||
"base16ct 0.2.0",
|
||||
"der 0.7.3",
|
||||
"generic-array 0.14.6",
|
||||
"pkcs8 0.10.2",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "secp256k1"
|
||||
version = "0.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f"
|
||||
dependencies = [
|
||||
"rand",
|
||||
"secp256k1-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "secp256k1-sys"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
version = "2.8.2"
|
||||
|
|
|
@ -139,6 +139,10 @@ tower-lsp = { version = "=0.17.0", features = ["proposed"] }
|
|||
url = { version = "2.3.1", features = ["serde", "expose_internals"] }
|
||||
uuid = { version = "1.3.0", features = ["v4"] }
|
||||
zstd = "=0.11.2"
|
||||
elliptic-curve = { version = "0.13.4", features = ["alloc", "arithmetic", "ecdh", "std", "pem"] }
|
||||
p224 = { version = "0.13.0", features = ["ecdh"] }
|
||||
p256 = { version = "0.13.2", features = ["ecdh"] }
|
||||
p384 = { version = "0.13.0", features = ["ecdh"] }
|
||||
|
||||
# crypto
|
||||
rsa = { version = "0.7.0", default-features = false, features = ["std", "pem", "hazmat"] } # hazmat needed for PrehashSigner in ext/node
|
||||
|
|
|
@ -24,6 +24,7 @@ deno_semver.workspace = true
|
|||
digest = { version = "0.10.5", features = ["core-api", "std"] }
|
||||
dsa = "0.6.1"
|
||||
ecb.workspace = true
|
||||
elliptic-curve.workspace = true
|
||||
hex.workspace = true
|
||||
hkdf.workspace = true
|
||||
idna = "0.3.0"
|
||||
|
@ -37,6 +38,9 @@ num-bigint-dig = "0.8.2"
|
|||
num-integer = "0.1.45"
|
||||
num-traits = "0.2.14"
|
||||
once_cell.workspace = true
|
||||
p224.workspace = true
|
||||
p256.workspace = true
|
||||
p384.workspace = true
|
||||
path-clean = "=0.1.0"
|
||||
pbkdf2 = "0.12.1"
|
||||
rand.workspace = true
|
||||
|
@ -45,6 +49,7 @@ ring.workspace = true
|
|||
ripemd = "0.1.3"
|
||||
rsa.workspace = true
|
||||
scrypt = "0.11.0"
|
||||
secp256k1 = { version = "0.27.0", features = ["rand-std"] }
|
||||
serde = "1.0.149"
|
||||
sha-1 = "0.10.0"
|
||||
sha2.workspace = true
|
||||
|
|
|
@ -240,6 +240,9 @@ deno_core::extension!(deno_node,
|
|||
ops::crypto::op_node_random_int,
|
||||
ops::crypto::op_node_scrypt_sync,
|
||||
ops::crypto::op_node_scrypt_async,
|
||||
ops::crypto::op_node_ecdh_generate_keys,
|
||||
ops::crypto::op_node_ecdh_compute_secret,
|
||||
ops::crypto::op_node_ecdh_compute_public_key,
|
||||
ops::crypto::x509::op_node_x509_parse,
|
||||
ops::crypto::x509::op_node_x509_ca,
|
||||
ops::crypto::x509::op_node_x509_check_email,
|
||||
|
@ -267,7 +270,6 @@ deno_core::extension!(deno_node,
|
|||
ops::zlib::op_zlib_init,
|
||||
ops::zlib::op_zlib_reset,
|
||||
op_node_build_os,
|
||||
|
||||
ops::require::op_require_init_paths,
|
||||
ops::require::op_require_node_module_paths<Env>,
|
||||
ops::require::op_require_proxy_path,
|
||||
|
|
|
@ -18,12 +18,18 @@ use rand::Rng;
|
|||
use std::future::Future;
|
||||
use std::rc::Rc;
|
||||
|
||||
use p224::NistP224;
|
||||
use p256::NistP256;
|
||||
use p384::NistP384;
|
||||
use rsa::padding::PaddingScheme;
|
||||
use rsa::pkcs8::DecodePrivateKey;
|
||||
use rsa::pkcs8::DecodePublicKey;
|
||||
use rsa::PublicKey;
|
||||
use rsa::RsaPrivateKey;
|
||||
use rsa::RsaPublicKey;
|
||||
use secp256k1::ecdh::SharedSecret;
|
||||
use secp256k1::Secp256k1;
|
||||
use secp256k1::SecretKey;
|
||||
|
||||
mod cipher;
|
||||
mod dh;
|
||||
|
@ -902,6 +908,165 @@ pub async fn op_node_scrypt_async(
|
|||
.await?
|
||||
}
|
||||
|
||||
#[op]
|
||||
pub fn op_node_ecdh_generate_keys(
|
||||
curve: &str,
|
||||
pubbuf: &mut [u8],
|
||||
privbuf: &mut [u8],
|
||||
) -> Result<ResourceId, AnyError> {
|
||||
let mut rng = rand::thread_rng();
|
||||
match curve {
|
||||
"secp256k1" => {
|
||||
let secp = Secp256k1::new();
|
||||
let (privkey, pubkey) = secp.generate_keypair(&mut rng);
|
||||
pubbuf.copy_from_slice(&pubkey.serialize_uncompressed());
|
||||
privbuf.copy_from_slice(&privkey.secret_bytes());
|
||||
|
||||
Ok(0)
|
||||
}
|
||||
"prime256v1" | "secp256r1" => {
|
||||
let privkey = elliptic_curve::SecretKey::<NistP256>::random(&mut rng);
|
||||
let pubkey = privkey.public_key();
|
||||
pubbuf.copy_from_slice(pubkey.to_sec1_bytes().as_ref());
|
||||
privbuf.copy_from_slice(privkey.to_nonzero_scalar().to_bytes().as_ref());
|
||||
Ok(0)
|
||||
}
|
||||
"secp384r1" => {
|
||||
let privkey = elliptic_curve::SecretKey::<NistP384>::random(&mut rng);
|
||||
let pubkey = privkey.public_key();
|
||||
pubbuf.copy_from_slice(pubkey.to_sec1_bytes().as_ref());
|
||||
privbuf.copy_from_slice(privkey.to_nonzero_scalar().to_bytes().as_ref());
|
||||
Ok(0)
|
||||
}
|
||||
"secp224r1" => {
|
||||
let privkey = elliptic_curve::SecretKey::<NistP224>::random(&mut rng);
|
||||
let pubkey = privkey.public_key();
|
||||
pubbuf.copy_from_slice(pubkey.to_sec1_bytes().as_ref());
|
||||
privbuf.copy_from_slice(privkey.to_nonzero_scalar().to_bytes().as_ref());
|
||||
Ok(0)
|
||||
}
|
||||
&_ => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[op]
|
||||
pub fn op_node_ecdh_compute_secret(
|
||||
curve: &str,
|
||||
this_priv: Option<ZeroCopyBuf>,
|
||||
their_pub: &mut [u8],
|
||||
secret: &mut [u8],
|
||||
) -> Result<(), AnyError> {
|
||||
match curve {
|
||||
"secp256k1" => {
|
||||
let this_secret_key = SecretKey::from_slice(
|
||||
this_priv.expect("no private key provided?").as_ref(),
|
||||
)
|
||||
.unwrap();
|
||||
let their_public_key =
|
||||
secp256k1::PublicKey::from_slice(their_pub).unwrap();
|
||||
let shared_secret =
|
||||
SharedSecret::new(&their_public_key, &this_secret_key);
|
||||
|
||||
secret.copy_from_slice(&shared_secret.secret_bytes());
|
||||
Ok(())
|
||||
}
|
||||
"prime256v1" | "secp256r1" => {
|
||||
let their_public_key =
|
||||
elliptic_curve::PublicKey::<NistP256>::from_sec1_bytes(their_pub)
|
||||
.expect("bad public key");
|
||||
let this_private_key = elliptic_curve::SecretKey::<NistP256>::from_slice(
|
||||
&this_priv.expect("must supply private key"),
|
||||
)
|
||||
.expect("bad private key");
|
||||
let shared_secret = elliptic_curve::ecdh::diffie_hellman(
|
||||
this_private_key.to_nonzero_scalar(),
|
||||
their_public_key.as_affine(),
|
||||
);
|
||||
secret.copy_from_slice(shared_secret.raw_secret_bytes());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
"secp384r1" => {
|
||||
let their_public_key =
|
||||
elliptic_curve::PublicKey::<NistP384>::from_sec1_bytes(their_pub)
|
||||
.expect("bad public key");
|
||||
let this_private_key = elliptic_curve::SecretKey::<NistP384>::from_slice(
|
||||
&this_priv.expect("must supply private key"),
|
||||
)
|
||||
.expect("bad private key");
|
||||
let shared_secret = elliptic_curve::ecdh::diffie_hellman(
|
||||
this_private_key.to_nonzero_scalar(),
|
||||
their_public_key.as_affine(),
|
||||
);
|
||||
secret.copy_from_slice(shared_secret.raw_secret_bytes());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
"secp224r1" => {
|
||||
let their_public_key =
|
||||
elliptic_curve::PublicKey::<NistP224>::from_sec1_bytes(their_pub)
|
||||
.expect("bad public key");
|
||||
let this_private_key = elliptic_curve::SecretKey::<NistP224>::from_slice(
|
||||
&this_priv.expect("must supply private key"),
|
||||
)
|
||||
.expect("bad private key");
|
||||
let shared_secret = elliptic_curve::ecdh::diffie_hellman(
|
||||
this_private_key.to_nonzero_scalar(),
|
||||
their_public_key.as_affine(),
|
||||
);
|
||||
secret.copy_from_slice(shared_secret.raw_secret_bytes());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
&_ => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[op]
|
||||
pub fn op_node_ecdh_compute_public_key(
|
||||
curve: &str,
|
||||
privkey: &[u8],
|
||||
pubkey: &mut [u8],
|
||||
) -> Result<(), AnyError> {
|
||||
match curve {
|
||||
"secp256k1" => {
|
||||
let secp = Secp256k1::new();
|
||||
let secret_key = SecretKey::from_slice(privkey).unwrap();
|
||||
let public_key =
|
||||
secp256k1::PublicKey::from_secret_key(&secp, &secret_key);
|
||||
|
||||
pubkey.copy_from_slice(&public_key.serialize_uncompressed());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
"prime256v1" | "secp256r1" => {
|
||||
let this_private_key =
|
||||
elliptic_curve::SecretKey::<NistP256>::from_slice(privkey)
|
||||
.expect("bad private key");
|
||||
let public_key = this_private_key.public_key();
|
||||
pubkey.copy_from_slice(public_key.to_sec1_bytes().as_ref());
|
||||
Ok(())
|
||||
}
|
||||
"secp384r1" => {
|
||||
let this_private_key =
|
||||
elliptic_curve::SecretKey::<NistP384>::from_slice(privkey)
|
||||
.expect("bad private key");
|
||||
let public_key = this_private_key.public_key();
|
||||
pubkey.copy_from_slice(public_key.to_sec1_bytes().as_ref());
|
||||
Ok(())
|
||||
}
|
||||
"secp224r1" => {
|
||||
let this_private_key =
|
||||
elliptic_curve::SecretKey::<NistP224>::from_slice(privkey)
|
||||
.expect("bad private key");
|
||||
let public_key = this_private_key.public_key();
|
||||
pubkey.copy_from_slice(public_key.to_sec1_bytes().as_ref());
|
||||
Ok(())
|
||||
}
|
||||
&_ => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn gen_prime(size: usize) -> ZeroCopyBuf {
|
||||
primes::Prime::generate(size).0.to_bytes_be().into()
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue