diff options
author | Divy Srivastava <dj.srivastava23@gmail.com> | 2022-01-14 14:18:53 +0530 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-01-14 14:18:53 +0530 |
commit | 919ded1a0b3439ef0d2d3134603bf5840ea0a170 (patch) | |
tree | 9ce91bff89b9e3c525f357b4e4b686d5f4edbff0 /ext/crypto/decrypt.rs | |
parent | eda6e58520276786bd87e411d0284eb56d9686a6 (diff) |
feat(ext/crypto): implement AES-GCM decryption (#13319)
Diffstat (limited to 'ext/crypto/decrypt.rs')
-rw-r--r-- | ext/crypto/decrypt.rs | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/ext/crypto/decrypt.rs b/ext/crypto/decrypt.rs index 90916f9c3..9f1157608 100644 --- a/ext/crypto/decrypt.rs +++ b/ext/crypto/decrypt.rs @@ -2,8 +2,16 @@ use std::cell::RefCell; use std::rc::Rc; use crate::shared::*; +use aes::cipher::generic_array::GenericArray; +use aes::Aes192; use aes::BlockEncrypt; use aes::NewBlockCipher; +use aes_gcm::AeadCore; +use aes_gcm::AeadInPlace; +use aes_gcm::Aes128Gcm; +use aes_gcm::Aes256Gcm; +use aes_gcm::NewAead; +use aes_gcm::Nonce; use block_modes::BlockMode; use ctr::cipher::NewCipher; use ctr::cipher::StreamCipher; @@ -17,6 +25,7 @@ use deno_core::error::type_error; use deno_core::error::AnyError; use deno_core::OpState; use deno_core::ZeroCopyBuf; +use elliptic_curve::consts::U12; use rsa::pkcs1::FromRsaPrivateKey; use rsa::PaddingScheme; use serde::Deserialize; @@ -56,8 +65,19 @@ pub enum DecryptAlgorithm { ctr_length: usize, key_length: usize, }, + #[serde(rename = "AES-GCM", rename_all = "camelCase")] + AesGcm { + #[serde(with = "serde_bytes")] + iv: Vec<u8>, + #[serde(with = "serde_bytes")] + additional_data: Option<Vec<u8>>, + length: usize, + tag_length: usize, + }, } +type Aes192Gcm = aes_gcm::AesGcm<Aes192, U12>; + pub async fn op_crypto_decrypt( _state: Rc<RefCell<OpState>>, opts: DecryptOptions, @@ -76,6 +96,12 @@ pub async fn op_crypto_decrypt( ctr_length, key_length, } => decrypt_aes_ctr(key, key_length, &counter, ctr_length, &data), + DecryptAlgorithm::AesGcm { + iv, + additional_data, + length, + tag_length, + } => decrypt_aes_gcm(key, length, tag_length, iv, additional_data, &data), }; let buf = tokio::task::spawn_blocking(fun).await.unwrap()?; Ok(buf.into()) @@ -195,6 +221,30 @@ where Ok(plaintext) } +fn decrypt_aes_gcm_gen<B>( + key: &[u8], + tag: &GenericArray<u8, <B as AeadCore>::TagSize>, + nonce: &GenericArray<u8, <B as AeadCore>::NonceSize>, + additional_data: Vec<u8>, + plaintext: &mut [u8], +) -> Result<(), AnyError> +where + B: AeadInPlace + NewAead, +{ + let cipher = + B::new_from_slice(key).map_err(|_| operation_error("Decryption failed"))?; + cipher + .decrypt_in_place_detached( + nonce, + additional_data.as_slice(), + plaintext, + tag, + ) + .map_err(|_| operation_error("Decryption failed"))?; + + Ok(()) +} + fn decrypt_aes_ctr( key: RawKeyData, key_length: usize, @@ -228,3 +278,53 @@ fn decrypt_aes_ctr( )), } } + +fn decrypt_aes_gcm( + key: RawKeyData, + length: usize, + tag_length: usize, + iv: Vec<u8>, + additional_data: Option<Vec<u8>>, + data: &[u8], +) -> Result<Vec<u8>, AnyError> { + let key = key.as_secret_key()?; + let additional_data = additional_data.unwrap_or_default(); + + // Fixed 96-bit nonce + if iv.len() != 12 { + return Err(type_error("iv length not equal to 12")); + } + + let nonce = Nonce::from_slice(&iv); + + let sep = data.len() - (tag_length / 8); + let tag = &data[sep..]; + // The actual ciphertext, called plaintext because it is reused in place. + let mut plaintext = data[..sep].to_vec(); + match length { + 128 => decrypt_aes_gcm_gen::<Aes128Gcm>( + key, + tag.into(), + nonce, + additional_data, + &mut plaintext, + )?, + 192 => decrypt_aes_gcm_gen::<Aes192Gcm>( + key, + tag.into(), + nonce, + additional_data, + &mut plaintext, + )?, + 256 => decrypt_aes_gcm_gen::<Aes256Gcm>( + key, + tag.into(), + nonce, + additional_data, + &mut plaintext, + )?, + _ => return Err(type_error("invalid length")), + }; + + Ok(plaintext) +} |