From 8fdade79daffaa4b5b42c90b80df3b8604e97b32 Mon Sep 17 00:00:00 2001 From: Luca Casonato Date: Mon, 13 Dec 2021 18:45:08 +0100 Subject: refactor(ext/crypto): generateKey rust cleanup (#13069) --- ext/crypto/generate_key.rs | 147 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 ext/crypto/generate_key.rs (limited to 'ext/crypto/generate_key.rs') diff --git a/ext/crypto/generate_key.rs b/ext/crypto/generate_key.rs new file mode 100644 index 000000000..3f9df44a1 --- /dev/null +++ b/ext/crypto/generate_key.rs @@ -0,0 +1,147 @@ +use std::cell::RefCell; +use std::rc::Rc; + +use deno_core::error::AnyError; +use deno_core::OpState; +use deno_core::ZeroCopyBuf; +use elliptic_curve::rand_core::OsRng; +use num_traits::FromPrimitive; +use ring::rand::SecureRandom; +use ring::signature::EcdsaKeyPair; +use rsa::pkcs1::ToRsaPrivateKey; +use rsa::BigUint; +use rsa::RsaPrivateKey; +use serde::Deserialize; + +use crate::shared::*; + +// Allowlist for RSA public exponents. +lazy_static::lazy_static! { + static ref PUB_EXPONENT_1: BigUint = BigUint::from_u64(3).unwrap(); + static ref PUB_EXPONENT_2: BigUint = BigUint::from_u64(65537).unwrap(); +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase", tag = "algorithm")] +pub enum GenerateKeyOptions { + #[serde(rename = "RSA", rename_all = "camelCase")] + Rsa { + modulus_length: u32, + #[serde(with = "serde_bytes")] + public_exponent: Vec, + }, + #[serde(rename = "EC", rename_all = "camelCase")] + Ec { named_curve: EcNamedCurve }, + #[serde(rename = "AES", rename_all = "camelCase")] + Aes { length: usize }, + #[serde(rename = "HMAC", rename_all = "camelCase")] + Hmac { + hash: ShaHash, + length: Option, + }, +} + +pub async fn op_crypto_generate_key( + _state: Rc>, + opts: GenerateKeyOptions, + _: (), +) -> Result { + let fun = || match opts { + GenerateKeyOptions::Rsa { + modulus_length, + public_exponent, + } => generate_key_rsa(modulus_length, &public_exponent), + GenerateKeyOptions::Ec { named_curve } => generate_key_ec(named_curve), + GenerateKeyOptions::Aes { length } => generate_key_aes(length), + GenerateKeyOptions::Hmac { hash, length } => { + generate_key_hmac(hash, length) + } + }; + let buf = tokio::task::spawn_blocking(fun).await.unwrap()?; + Ok(buf.into()) +} + +fn generate_key_rsa( + modulus_length: u32, + public_exponent: &[u8], +) -> Result, AnyError> { + let exponent = BigUint::from_bytes_be(public_exponent); + if exponent != *PUB_EXPONENT_1 && exponent != *PUB_EXPONENT_2 { + return Err(operation_error("Bad public exponent")); + } + + let mut rng = OsRng; + + let private_key = + RsaPrivateKey::new_with_exp(&mut rng, modulus_length as usize, &exponent) + .map_err(|_| operation_error("Failed to generate RSA key"))?; + + let private_key = private_key + .to_pkcs1_der() + .map_err(|_| operation_error("Failed to serialize RSA key"))?; + + Ok(private_key.as_ref().to_vec()) +} + +fn generate_key_ec(named_curve: EcNamedCurve) -> Result, AnyError> { + let curve = match named_curve { + EcNamedCurve::P256 => &ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING, + EcNamedCurve::P384 => &ring::signature::ECDSA_P384_SHA384_FIXED_SIGNING, + }; + + let rng = ring::rand::SystemRandom::new(); + + let pkcs8 = EcdsaKeyPair::generate_pkcs8(curve, &rng) + .map_err(|_| operation_error("Failed to generate EC key"))?; + + Ok(pkcs8.as_ref().to_vec()) +} + +fn generate_key_aes(length: usize) -> Result, AnyError> { + if length % 8 != 0 || length > 256 { + return Err(operation_error("Invalid AES key length")); + } + + let mut key = vec![0u8; length / 8]; + let rng = ring::rand::SystemRandom::new(); + rng + .fill(&mut key) + .map_err(|_| operation_error("Failed to generate key"))?; + + Ok(key) +} + +fn generate_key_hmac( + hash: ShaHash, + length: Option, +) -> Result, AnyError> { + let hash = match hash { + ShaHash::Sha1 => &ring::hmac::HMAC_SHA1_FOR_LEGACY_USE_ONLY, + ShaHash::Sha256 => &ring::hmac::HMAC_SHA256, + ShaHash::Sha384 => &ring::hmac::HMAC_SHA384, + ShaHash::Sha512 => &ring::hmac::HMAC_SHA512, + }; + + let length = if let Some(length) = length { + if length % 8 != 0 { + return Err(operation_error("Invalid HMAC key length")); + } + + let length = length / 8; + if length > ring::digest::MAX_BLOCK_LEN { + return Err(operation_error("Invalid HMAC key length")); + } + + length + } else { + hash.digest_algorithm().block_len + }; + + let rng = ring::rand::SystemRandom::new(); + let mut key = vec![0u8; length]; + rng + .fill(&mut key) + .map_err(|_| operation_error("Failed to generate key"))?; + + Ok(key) +} -- cgit v1.2.3