summaryrefslogtreecommitdiff
path: root/ext/node/crypto/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'ext/node/crypto/mod.rs')
-rw-r--r--ext/node/crypto/mod.rs272
1 files changed, 272 insertions, 0 deletions
diff --git a/ext/node/crypto/mod.rs b/ext/node/crypto/mod.rs
index 26392da4c..d224b40f7 100644
--- a/ext/node/crypto/mod.rs
+++ b/ext/node/crypto/mod.rs
@@ -10,8 +10,10 @@ use deno_core::StringOrBuffer;
use deno_core::ZeroCopyBuf;
use hkdf::Hkdf;
use num_bigint::BigInt;
+use num_traits::FromPrimitive;
use rand::distributions::Distribution;
use rand::distributions::Uniform;
+use rand::thread_rng;
use rand::Rng;
use std::future::Future;
use std::rc::Rc;
@@ -24,6 +26,7 @@ use rsa::RsaPrivateKey;
use rsa::RsaPublicKey;
mod cipher;
+mod dh;
mod digest;
mod primes;
pub mod x509;
@@ -534,6 +537,275 @@ pub async fn op_node_hkdf_async(
.await?
}
+use rsa::pkcs1::EncodeRsaPrivateKey;
+use rsa::pkcs1::EncodeRsaPublicKey;
+
+use self::primes::Prime;
+
+fn generate_rsa(
+ modulus_length: usize,
+ public_exponent: usize,
+) -> Result<(ZeroCopyBuf, ZeroCopyBuf), AnyError> {
+ let mut rng = rand::thread_rng();
+ let private_key = RsaPrivateKey::new_with_exp(
+ &mut rng,
+ modulus_length,
+ &rsa::BigUint::from_usize(public_exponent).unwrap(),
+ )?;
+ let public_key = private_key.to_public_key();
+ let private_key_der = private_key.to_pkcs1_der()?.as_bytes().to_vec();
+ let public_key_der = public_key.to_pkcs1_der()?.to_vec();
+
+ Ok((private_key_der.into(), public_key_der.into()))
+}
+
+#[op]
+pub fn op_node_generate_rsa(
+ modulus_length: usize,
+ public_exponent: usize,
+) -> Result<(ZeroCopyBuf, ZeroCopyBuf), AnyError> {
+ generate_rsa(modulus_length, public_exponent)
+}
+
+#[op]
+pub async fn op_node_generate_rsa_async(
+ modulus_length: usize,
+ public_exponent: usize,
+) -> Result<(ZeroCopyBuf, ZeroCopyBuf), AnyError> {
+ tokio::task::spawn_blocking(move || {
+ generate_rsa(modulus_length, public_exponent)
+ })
+ .await?
+}
+
+fn dsa_generate(
+ modulus_length: usize,
+ divisor_length: usize,
+) -> Result<(ZeroCopyBuf, ZeroCopyBuf), AnyError> {
+ let mut rng = rand::thread_rng();
+ use dsa::pkcs8::EncodePrivateKey;
+ use dsa::pkcs8::EncodePublicKey;
+ use dsa::Components;
+ use dsa::KeySize;
+ use dsa::SigningKey;
+
+ let key_size = match (modulus_length, divisor_length) {
+ #[allow(deprecated)]
+ (1024, 160) => KeySize::DSA_1024_160,
+ (2048, 224) => KeySize::DSA_2048_224,
+ (2048, 256) => KeySize::DSA_2048_256,
+ (3072, 256) => KeySize::DSA_3072_256,
+ _ => return Err(type_error("Invalid modulus_length or divisor_length")),
+ };
+ let components = Components::generate(&mut rng, key_size);
+ let signing_key = SigningKey::generate(&mut rng, components);
+ let verifying_key = signing_key.verifying_key();
+
+ Ok((
+ signing_key
+ .to_pkcs8_der()
+ .map_err(|_| type_error("Not valid pkcs8"))?
+ .as_bytes()
+ .to_vec()
+ .into(),
+ verifying_key
+ .to_public_key_der()
+ .map_err(|_| type_error("Not valid spki"))?
+ .to_vec()
+ .into(),
+ ))
+}
+
+#[op]
+pub fn op_node_dsa_generate(
+ modulus_length: usize,
+ divisor_length: usize,
+) -> Result<(ZeroCopyBuf, ZeroCopyBuf), AnyError> {
+ dsa_generate(modulus_length, divisor_length)
+}
+
+#[op]
+pub async fn op_node_dsa_generate_async(
+ modulus_length: usize,
+ divisor_length: usize,
+) -> Result<(ZeroCopyBuf, ZeroCopyBuf), AnyError> {
+ tokio::task::spawn_blocking(move || {
+ dsa_generate(modulus_length, divisor_length)
+ })
+ .await?
+}
+
+fn ec_generate(
+ named_curve: &str,
+) -> Result<(ZeroCopyBuf, ZeroCopyBuf), AnyError> {
+ use ring::signature::EcdsaKeyPair;
+ use ring::signature::KeyPair;
+
+ let curve = match named_curve {
+ "P-256" => &ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING,
+ "P-384" => &ring::signature::ECDSA_P384_SHA384_FIXED_SIGNING,
+ _ => return Err(type_error("Unsupported named curve")),
+ };
+
+ let rng = ring::rand::SystemRandom::new();
+
+ let pkcs8 = EcdsaKeyPair::generate_pkcs8(curve, &rng)
+ .map_err(|_| type_error("Failed to generate EC key"))?;
+
+ let public_key = EcdsaKeyPair::from_pkcs8(curve, pkcs8.as_ref())
+ .map_err(|_| type_error("Failed to generate EC key"))?
+ .public_key()
+ .as_ref()
+ .to_vec();
+ Ok((pkcs8.as_ref().to_vec().into(), public_key.into()))
+}
+
+#[op]
+pub fn op_node_ec_generate(
+ named_curve: &str,
+) -> Result<(ZeroCopyBuf, ZeroCopyBuf), AnyError> {
+ ec_generate(named_curve)
+}
+
+#[op]
+pub async fn op_node_ec_generate_async(
+ named_curve: String,
+) -> Result<(ZeroCopyBuf, ZeroCopyBuf), AnyError> {
+ tokio::task::spawn_blocking(move || ec_generate(&named_curve)).await?
+}
+
+fn ed25519_generate() -> Result<(ZeroCopyBuf, ZeroCopyBuf), AnyError> {
+ use ring::signature::Ed25519KeyPair;
+ use ring::signature::KeyPair;
+
+ let mut rng = thread_rng();
+ let mut seed = vec![0u8; 32];
+ rng.fill(seed.as_mut_slice());
+
+ let pair = Ed25519KeyPair::from_seed_unchecked(&seed)
+ .map_err(|_| type_error("Failed to generate Ed25519 key"))?;
+
+ let public_key = pair.public_key().as_ref().to_vec();
+ Ok((seed.into(), public_key.into()))
+}
+
+#[op]
+pub fn op_node_ed25519_generate() -> Result<(ZeroCopyBuf, ZeroCopyBuf), AnyError>
+{
+ ed25519_generate()
+}
+
+#[op]
+pub async fn op_node_ed25519_generate_async(
+) -> Result<(ZeroCopyBuf, ZeroCopyBuf), AnyError> {
+ tokio::task::spawn_blocking(ed25519_generate).await?
+}
+
+fn x25519_generate() -> Result<(ZeroCopyBuf, ZeroCopyBuf), AnyError> {
+ // u-coordinate of the base point.
+ const X25519_BASEPOINT_BYTES: [u8; 32] = [
+ 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+ ];
+
+ let mut pkey = [0; 32];
+
+ let mut rng = thread_rng();
+ rng.fill(pkey.as_mut_slice());
+
+ let pkey_copy = pkey.to_vec();
+ // https://www.rfc-editor.org/rfc/rfc7748#section-6.1
+ // pubkey = x25519(a, 9) which is constant-time Montgomery ladder.
+ // https://eprint.iacr.org/2014/140.pdf page 4
+ // https://eprint.iacr.org/2017/212.pdf algorithm 8
+ // pubkey is in LE order.
+ let pubkey = x25519_dalek::x25519(pkey, X25519_BASEPOINT_BYTES);
+
+ Ok((pkey_copy.into(), pubkey.to_vec().into()))
+}
+
+#[op]
+pub fn op_node_x25519_generate() -> Result<(ZeroCopyBuf, ZeroCopyBuf), AnyError>
+{
+ x25519_generate()
+}
+
+#[op]
+pub async fn op_node_x25519_generate_async(
+) -> Result<(ZeroCopyBuf, ZeroCopyBuf), AnyError> {
+ tokio::task::spawn_blocking(x25519_generate).await?
+}
+
+fn dh_generate_group(
+ group_name: &str,
+) -> Result<(ZeroCopyBuf, ZeroCopyBuf), AnyError> {
+ let dh = match group_name {
+ "modp5" => dh::DiffieHellman::group::<dh::Modp1536>(),
+ "modp14" => dh::DiffieHellman::group::<dh::Modp2048>(),
+ "modp15" => dh::DiffieHellman::group::<dh::Modp3072>(),
+ "modp16" => dh::DiffieHellman::group::<dh::Modp4096>(),
+ "modp17" => dh::DiffieHellman::group::<dh::Modp6144>(),
+ "modp18" => dh::DiffieHellman::group::<dh::Modp8192>(),
+ _ => return Err(type_error("Unsupported group name")),
+ };
+
+ Ok((
+ dh.private_key.into_vec().into(),
+ dh.public_key.into_vec().into(),
+ ))
+}
+
+#[op]
+pub fn op_node_dh_generate_group(
+ group_name: &str,
+) -> Result<(ZeroCopyBuf, ZeroCopyBuf), AnyError> {
+ dh_generate_group(group_name)
+}
+
+#[op]
+pub async fn op_node_dh_generate_group_async(
+ group_name: String,
+) -> Result<(ZeroCopyBuf, ZeroCopyBuf), AnyError> {
+ tokio::task::spawn_blocking(move || dh_generate_group(&group_name)).await?
+}
+
+fn dh_generate(
+ prime: Option<&[u8]>,
+ prime_len: usize,
+ generator: usize,
+) -> Result<(ZeroCopyBuf, ZeroCopyBuf), AnyError> {
+ let prime = prime
+ .map(|p| p.into())
+ .unwrap_or_else(|| Prime::generate(prime_len));
+ let dh = dh::DiffieHellman::new(prime, generator);
+
+ Ok((
+ dh.private_key.into_vec().into(),
+ dh.public_key.into_vec().into(),
+ ))
+}
+
+#[op]
+pub fn op_node_dh_generate(
+ prime: Option<&[u8]>,
+ prime_len: usize,
+ generator: usize,
+) -> Result<(ZeroCopyBuf, ZeroCopyBuf), AnyError> {
+ dh_generate(prime, prime_len, generator)
+}
+
+#[op]
+pub async fn op_node_dh_generate_async(
+ prime: Option<ZeroCopyBuf>,
+ prime_len: usize,
+ generator: usize,
+) -> Result<(ZeroCopyBuf, ZeroCopyBuf), AnyError> {
+ tokio::task::spawn_blocking(move || {
+ dh_generate(prime.as_deref(), prime_len, generator)
+ })
+ .await?
+}
+
#[op]
pub fn op_node_random_int(min: i32, max: i32) -> Result<i32, AnyError> {
let mut rng = rand::thread_rng();