summaryrefslogtreecommitdiff
path: root/ext/crypto/generate_key.rs
diff options
context:
space:
mode:
authorLuca Casonato <hello@lcas.dev>2021-12-13 18:45:08 +0100
committerGitHub <noreply@github.com>2021-12-13 18:45:08 +0100
commit8fdade79daffaa4b5b42c90b80df3b8604e97b32 (patch)
treeff0b38cbb922bdebebf1a58b9ef567dd38afba41 /ext/crypto/generate_key.rs
parent308813ae29763512a8be1044b31b8d5dad36c38c (diff)
refactor(ext/crypto): generateKey rust cleanup (#13069)
Diffstat (limited to 'ext/crypto/generate_key.rs')
-rw-r--r--ext/crypto/generate_key.rs147
1 files changed, 147 insertions, 0 deletions
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<u8>,
+ },
+ #[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<usize>,
+ },
+}
+
+pub async fn op_crypto_generate_key(
+ _state: Rc<RefCell<OpState>>,
+ opts: GenerateKeyOptions,
+ _: (),
+) -> Result<ZeroCopyBuf, AnyError> {
+ 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<Vec<u8>, 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<Vec<u8>, 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<Vec<u8>, 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<usize>,
+) -> Result<Vec<u8>, 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)
+}