summaryrefslogtreecommitdiff
path: root/ext/crypto/decrypt.rs
diff options
context:
space:
mode:
authorDivy Srivastava <dj.srivastava23@gmail.com>2022-01-14 14:18:53 +0530
committerGitHub <noreply@github.com>2022-01-14 14:18:53 +0530
commit919ded1a0b3439ef0d2d3134603bf5840ea0a170 (patch)
tree9ce91bff89b9e3c525f357b4e4b686d5f4edbff0 /ext/crypto/decrypt.rs
parenteda6e58520276786bd87e411d0284eb56d9686a6 (diff)
feat(ext/crypto): implement AES-GCM decryption (#13319)
Diffstat (limited to 'ext/crypto/decrypt.rs')
-rw-r--r--ext/crypto/decrypt.rs100
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)
+}