diff options
author | Divy Srivastava <dj.srivastava23@gmail.com> | 2022-01-05 20:42:30 +0530 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-01-05 20:42:30 +0530 |
commit | c74eb7a889322e88173cb044a670602d124fcc67 (patch) | |
tree | b5502919639a3f1b6285e8c44dcb4e0465d530f1 /ext/crypto/encrypt.rs | |
parent | 9778545048a9908f62c24b93ae3ec0762e3db2d9 (diff) |
feat(ext/crypto): implement AES-GCM encryption (#13119)
Diffstat (limited to 'ext/crypto/encrypt.rs')
-rw-r--r-- | ext/crypto/encrypt.rs | 82 |
1 files changed, 80 insertions, 2 deletions
diff --git a/ext/crypto/encrypt.rs b/ext/crypto/encrypt.rs index 99f4762d0..f1d88438b 100644 --- a/ext/crypto/encrypt.rs +++ b/ext/crypto/encrypt.rs @@ -6,6 +6,13 @@ use crate::shared::*; use aes::cipher::NewCipher; use aes::BlockEncrypt; use aes::NewBlockCipher; +use aes_gcm::aead::generic_array::typenum::U12; +use aes_gcm::aes::Aes192; +use aes_gcm::AeadInPlace; +use aes_gcm::Aes128Gcm; +use aes_gcm::Aes256Gcm; +use aes_gcm::NewAead; +use aes_gcm::Nonce; use ctr::Ctr; use block_modes::BlockMode; @@ -53,6 +60,15 @@ pub enum EncryptAlgorithm { iv: Vec<u8>, 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, + }, #[serde(rename = "AES-CTR", rename_all = "camelCase")] AesCtr { #[serde(with = "serde_bytes")] @@ -74,6 +90,12 @@ pub async fn op_crypto_encrypt( EncryptAlgorithm::AesCbc { iv, length } => { encrypt_aes_cbc(key, length, iv, &data) } + EncryptAlgorithm::AesGcm { + iv, + additional_data, + length, + tag_length, + } => encrypt_aes_gcm(key, length, tag_length, iv, additional_data, &data), EncryptAlgorithm::AesCtr { counter, ctr_length, @@ -89,7 +111,7 @@ fn encrypt_rsa_oaep( hash: ShaHash, label: Vec<u8>, data: &[u8], -) -> Result<Vec<u8>, deno_core::anyhow::Error> { +) -> Result<Vec<u8>, AnyError> { let label = String::from_utf8_lossy(&label).to_string(); let public_key = key.as_rsa_public_key()?; @@ -129,7 +151,7 @@ fn encrypt_aes_cbc( length: usize, iv: Vec<u8>, data: &[u8], -) -> Result<Vec<u8>, deno_core::anyhow::Error> { +) -> Result<Vec<u8>, AnyError> { let key = key.as_secret_key()?; let ciphertext = match length { 128 => { @@ -161,6 +183,62 @@ fn encrypt_aes_cbc( Ok(ciphertext) } +fn encrypt_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 mut ciphertext = data.to_vec(); + let tag = match length { + 128 => { + let cipher = Aes128Gcm::new_from_slice(key) + .map_err(|_| operation_error("Encryption failed"))?; + cipher + .encrypt_in_place_detached(nonce, &additional_data, &mut ciphertext) + .map_err(|_| operation_error("Encryption failed"))? + } + 192 => { + type Aes192Gcm = aes_gcm::AesGcm<Aes192, U12>; + + let cipher = Aes192Gcm::new_from_slice(key) + .map_err(|_| operation_error("Encryption failed"))?; + cipher + .encrypt_in_place_detached(nonce, &additional_data, &mut ciphertext) + .map_err(|_| operation_error("Encryption failed"))? + } + 256 => { + let cipher = Aes256Gcm::new_from_slice(key) + .map_err(|_| operation_error("Encryption failed"))?; + cipher + .encrypt_in_place_detached(nonce, &additional_data, &mut ciphertext) + .map_err(|_| operation_error("Encryption failed"))? + } + _ => return Err(type_error("invalid length")), + }; + + // Truncated tag to the specified tag length. + // `tag` is fixed to be 16 bytes long and (tag_length / 8) is always <= 16 + let tag = &tag[..(tag_length / 8)]; + + // C | T + ciphertext.extend_from_slice(tag); + + Ok(ciphertext) +} + fn encrypt_aes_ctr_gen<B, F>( key: &[u8], counter: &[u8], |