diff options
author | Divy Srivastava <dj.srivastava23@gmail.com> | 2021-12-20 20:37:36 +0530 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-20 16:07:36 +0100 |
commit | 04fe5130036c4a587ae60972136d8b0efa4e5831 (patch) | |
tree | 7d642b52cd0acac924711f0fe94a622ce27c3821 | |
parent | 17d81ad2ef0001f862ba0a324e2f4d28f1cfdc78 (diff) |
refactor(ext/crypto): cleanup decrypt code (#13120)
-rw-r--r-- | ext/crypto/00_crypto.js | 4 | ||||
-rw-r--r-- | ext/crypto/decrypt.rs | 155 | ||||
-rw-r--r-- | ext/crypto/lib.rs | 126 |
3 files changed, 160 insertions, 125 deletions
diff --git a/ext/crypto/00_crypto.js b/ext/crypto/00_crypto.js index f15238b3a..ca7960427 100644 --- a/ext/crypto/00_crypto.js +++ b/ext/crypto/00_crypto.js @@ -572,7 +572,7 @@ // 3-5. const hashAlgorithm = key[_algorithm].hash.name; - const plainText = await core.opAsync("op_crypto_decrypt_key", { + const plainText = await core.opAsync("op_crypto_decrypt", { key: keyData, algorithm: "RSA-OAEP", hash: hashAlgorithm, @@ -593,7 +593,7 @@ ); } - const plainText = await core.opAsync("op_crypto_decrypt_key", { + const plainText = await core.opAsync("op_crypto_decrypt", { key: keyData, algorithm: "AES-CBC", iv: normalizedAlgorithm.iv, diff --git a/ext/crypto/decrypt.rs b/ext/crypto/decrypt.rs new file mode 100644 index 000000000..f487d7e34 --- /dev/null +++ b/ext/crypto/decrypt.rs @@ -0,0 +1,155 @@ +use std::cell::RefCell; +use std::rc::Rc; + +use crate::shared::*; +use block_modes::BlockMode; +use deno_core::error::custom_error; +use deno_core::error::AnyError; +use deno_core::OpState; +use deno_core::ZeroCopyBuf; +use rsa::pkcs1::FromRsaPrivateKey; +use rsa::PaddingScheme; +use serde::Deserialize; +use sha1::Digest; +use sha1::Sha1; +use sha2::Sha256; +use sha2::Sha384; +use sha2::Sha512; + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct DecryptOptions { + key: RawKeyData, + #[serde(flatten)] + algorithm: DecryptAlgorithm, +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase", tag = "algorithm")] +pub enum DecryptAlgorithm { + #[serde(rename = "RSA-OAEP")] + RsaOaep { + hash: ShaHash, + #[serde(with = "serde_bytes")] + label: Vec<u8>, + }, + #[serde(rename = "AES-CBC", rename_all = "camelCase")] + AesCbc { + #[serde(with = "serde_bytes")] + iv: Vec<u8>, + length: usize, + }, +} + +pub async fn op_crypto_decrypt( + _state: Rc<RefCell<OpState>>, + opts: DecryptOptions, + data: ZeroCopyBuf, +) -> Result<ZeroCopyBuf, AnyError> { + let key = opts.key; + let fun = move || match opts.algorithm { + DecryptAlgorithm::RsaOaep { hash, label } => { + decrypt_rsa_oaep(key, hash, label, &data) + } + DecryptAlgorithm::AesCbc { iv, length } => { + decrypt_aes_cbc(key, length, iv, &data) + } + }; + let buf = tokio::task::spawn_blocking(fun).await.unwrap()?; + Ok(buf.into()) +} + +fn decrypt_rsa_oaep( + key: RawKeyData, + hash: ShaHash, + label: Vec<u8>, + data: &[u8], +) -> Result<Vec<u8>, deno_core::anyhow::Error> { + let key = key.as_rsa_private_key()?; + + let private_key = rsa::RsaPrivateKey::from_pkcs1_der(key)?; + let label = Some(String::from_utf8_lossy(&label).to_string()); + + let padding = match hash { + ShaHash::Sha1 => PaddingScheme::OAEP { + digest: Box::new(Sha1::new()), + mgf_digest: Box::new(Sha1::new()), + label, + }, + ShaHash::Sha256 => PaddingScheme::OAEP { + digest: Box::new(Sha256::new()), + mgf_digest: Box::new(Sha256::new()), + label, + }, + ShaHash::Sha384 => PaddingScheme::OAEP { + digest: Box::new(Sha384::new()), + mgf_digest: Box::new(Sha384::new()), + label, + }, + ShaHash::Sha512 => PaddingScheme::OAEP { + digest: Box::new(Sha512::new()), + mgf_digest: Box::new(Sha512::new()), + label, + }, + }; + + private_key + .decrypt(padding, data) + .map_err(|e| custom_error("DOMExceptionOperationError", e.to_string())) +} + +fn decrypt_aes_cbc( + key: RawKeyData, + length: usize, + iv: Vec<u8>, + data: &[u8], +) -> Result<Vec<u8>, deno_core::anyhow::Error> { + let key = key.as_secret_key()?; + + // 2. + let plaintext = match length { + 128 => { + // Section 10.3 Step 2 of RFC 2315 https://www.rfc-editor.org/rfc/rfc2315 + type Aes128Cbc = + block_modes::Cbc<aes::Aes128, block_modes::block_padding::Pkcs7>; + let cipher = Aes128Cbc::new_from_slices(key, &iv)?; + + cipher.decrypt_vec(data).map_err(|_| { + custom_error( + "DOMExceptionOperationError", + "Decryption failed".to_string(), + ) + })? + } + 192 => { + // Section 10.3 Step 2 of RFC 2315 https://www.rfc-editor.org/rfc/rfc2315 + type Aes192Cbc = + block_modes::Cbc<aes::Aes192, block_modes::block_padding::Pkcs7>; + let cipher = Aes192Cbc::new_from_slices(key, &iv)?; + + cipher.decrypt_vec(data).map_err(|_| { + custom_error( + "DOMExceptionOperationError", + "Decryption failed".to_string(), + ) + })? + } + 256 => { + // Section 10.3 Step 2 of RFC 2315 https://www.rfc-editor.org/rfc/rfc2315 + type Aes256Cbc = + block_modes::Cbc<aes::Aes256, block_modes::block_padding::Pkcs7>; + let cipher = Aes256Cbc::new_from_slices(key, &iv)?; + + cipher.decrypt_vec(data).map_err(|_| { + custom_error( + "DOMExceptionOperationError", + "Decryption failed".to_string(), + ) + })? + } + _ => unreachable!(), + }; + + // 6. + Ok(plaintext) +} diff --git a/ext/crypto/lib.rs b/ext/crypto/lib.rs index 1bca433ff..c509cedd7 100644 --- a/ext/crypto/lib.rs +++ b/ext/crypto/lib.rs @@ -16,7 +16,6 @@ use std::cell::RefCell; use std::num::NonZeroU32; use std::rc::Rc; -use block_modes::BlockMode; use p256::elliptic_curve::sec1::FromEncodedPoint; use p256::pkcs8::FromPrivateKey; use rand::rngs::OsRng; @@ -52,6 +51,7 @@ use std::path::PathBuf; pub use rand; // Re-export rand +mod decrypt; mod encrypt; mod export_key; mod generate_key; @@ -59,6 +59,7 @@ mod import_key; mod key; mod shared; +pub use crate::decrypt::op_crypto_decrypt; pub use crate::encrypt::op_crypto_encrypt; pub use crate::export_key::op_crypto_export_key; pub use crate::generate_key::op_crypto_generate_key; @@ -91,7 +92,7 @@ pub fn init(maybe_seed: Option<u64>) -> Extension { ("op_crypto_import_key", op_sync(op_crypto_import_key)), ("op_crypto_export_key", op_sync(op_crypto_export_key)), ("op_crypto_encrypt", op_async(op_crypto_encrypt)), - ("op_crypto_decrypt_key", op_async(op_crypto_decrypt_key)), + ("op_crypto_decrypt", op_async(op_crypto_decrypt)), ("op_crypto_subtle_digest", op_async(op_crypto_subtle_digest)), ("op_crypto_random_uuid", op_sync(op_crypto_random_uuid)), ]) @@ -779,127 +780,6 @@ impl<'a> TryFrom<rsa::pkcs8::der::asn1::Any<'a>> } } -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct DecryptArg { - key: KeyData, - algorithm: Algorithm, - // RSA-OAEP - hash: Option<CryptoHash>, - label: Option<ZeroCopyBuf>, - // AES-CBC - iv: Option<ZeroCopyBuf>, - length: Option<usize>, -} - -pub async fn op_crypto_decrypt_key( - _state: Rc<RefCell<OpState>>, - args: DecryptArg, - zero_copy: ZeroCopyBuf, -) -> Result<ZeroCopyBuf, AnyError> { - let data = &*zero_copy; - let algorithm = args.algorithm; - - match algorithm { - Algorithm::RsaOaep => { - let private_key: RsaPrivateKey = - RsaPrivateKey::from_pkcs1_der(&*args.key.data)?; - let label = args.label.map(|l| String::from_utf8_lossy(&*l).to_string()); - let padding = match args - .hash - .ok_or_else(|| type_error("Missing argument hash".to_string()))? - { - CryptoHash::Sha1 => PaddingScheme::OAEP { - digest: Box::new(Sha1::new()), - mgf_digest: Box::new(Sha1::new()), - label, - }, - CryptoHash::Sha256 => PaddingScheme::OAEP { - digest: Box::new(Sha256::new()), - mgf_digest: Box::new(Sha256::new()), - label, - }, - CryptoHash::Sha384 => PaddingScheme::OAEP { - digest: Box::new(Sha384::new()), - mgf_digest: Box::new(Sha384::new()), - label, - }, - CryptoHash::Sha512 => PaddingScheme::OAEP { - digest: Box::new(Sha512::new()), - mgf_digest: Box::new(Sha512::new()), - label, - }, - }; - - Ok( - private_key - .decrypt(padding, data) - .map_err(|e| { - custom_error("DOMExceptionOperationError", e.to_string()) - })? - .into(), - ) - } - Algorithm::AesCbc => { - let key = &*args.key.data; - let length = args - .length - .ok_or_else(|| type_error("Missing argument length".to_string()))?; - let iv = args - .iv - .ok_or_else(|| type_error("Missing argument iv".to_string()))?; - - // 2. - let plaintext = match length { - 128 => { - // Section 10.3 Step 2 of RFC 2315 https://www.rfc-editor.org/rfc/rfc2315 - type Aes128Cbc = - block_modes::Cbc<aes::Aes128, block_modes::block_padding::Pkcs7>; - let cipher = Aes128Cbc::new_from_slices(key, &iv)?; - - cipher.decrypt_vec(data).map_err(|_| { - custom_error( - "DOMExceptionOperationError", - "Decryption failed".to_string(), - ) - })? - } - 192 => { - // Section 10.3 Step 2 of RFC 2315 https://www.rfc-editor.org/rfc/rfc2315 - type Aes192Cbc = - block_modes::Cbc<aes::Aes192, block_modes::block_padding::Pkcs7>; - let cipher = Aes192Cbc::new_from_slices(key, &iv)?; - - cipher.decrypt_vec(data).map_err(|_| { - custom_error( - "DOMExceptionOperationError", - "Decryption failed".to_string(), - ) - })? - } - 256 => { - // Section 10.3 Step 2 of RFC 2315 https://www.rfc-editor.org/rfc/rfc2315 - type Aes256Cbc = - block_modes::Cbc<aes::Aes256, block_modes::block_padding::Pkcs7>; - let cipher = Aes256Cbc::new_from_slices(key, &iv)?; - - cipher.decrypt_vec(data).map_err(|_| { - custom_error( - "DOMExceptionOperationError", - "Decryption failed".to_string(), - ) - })? - } - _ => unreachable!(), - }; - - // 6. - Ok(plaintext.into()) - } - _ => Err(type_error("Unsupported algorithm".to_string())), - } -} - pub fn op_crypto_random_uuid( state: &mut OpState, _: (), |