diff options
Diffstat (limited to 'ext/node/ops/crypto/cipher.rs')
-rw-r--r-- | ext/node/ops/crypto/cipher.rs | 128 |
1 files changed, 120 insertions, 8 deletions
diff --git a/ext/node/ops/crypto/cipher.rs b/ext/node/ops/crypto/cipher.rs index 4f3f7f20d..717c12752 100644 --- a/ext/node/ops/crypto/cipher.rs +++ b/ext/node/ops/crypto/cipher.rs @@ -13,15 +13,24 @@ use std::borrow::Cow; use std::cell::RefCell; use std::rc::Rc; +type Tag = Option<Vec<u8>>; + +type Aes128Gcm = aead_gcm_stream::AesGcm<aes::Aes128>; +type Aes256Gcm = aead_gcm_stream::AesGcm<aes::Aes256>; + enum Cipher { Aes128Cbc(Box<cbc::Encryptor<aes::Aes128>>), Aes128Ecb(Box<ecb::Encryptor<aes::Aes128>>), - // TODO(kt3k): add more algorithms Aes192Cbc, Aes256Cbc, Aes128GCM, etc. + Aes128Gcm(Box<Aes128Gcm>), + Aes256Gcm(Box<Aes256Gcm>), + // TODO(kt3k): add more algorithms Aes192Cbc, Aes256Cbc, etc. } enum Decipher { Aes128Cbc(Box<cbc::Decryptor<aes::Aes128>>), Aes128Ecb(Box<ecb::Decryptor<aes::Aes128>>), + Aes128Gcm(Box<Aes128Gcm>), + Aes256Gcm(Box<Aes256Gcm>), // TODO(kt3k): add more algorithms Aes192Cbc, Aes256Cbc, Aes128GCM, etc. } @@ -40,6 +49,10 @@ impl CipherContext { }) } + pub fn set_aad(&self, aad: &[u8]) { + self.cipher.borrow_mut().set_aad(aad); + } + pub fn encrypt(&self, input: &[u8], output: &mut [u8]) { self.cipher.borrow_mut().encrypt(input, output); } @@ -48,7 +61,7 @@ impl CipherContext { self, input: &[u8], output: &mut [u8], - ) -> Result<(), AnyError> { + ) -> Result<Tag, AnyError> { Rc::try_unwrap(self.cipher) .map_err(|_| type_error("Cipher context is already in use"))? .into_inner() @@ -63,6 +76,10 @@ impl DecipherContext { }) } + pub fn set_aad(&self, aad: &[u8]) { + self.decipher.borrow_mut().set_aad(aad); + } + pub fn decrypt(&self, input: &[u8], output: &mut [u8]) { self.decipher.borrow_mut().decrypt(input, output); } @@ -71,11 +88,12 @@ impl DecipherContext { self, input: &[u8], output: &mut [u8], + auth_tag: &[u8], ) -> Result<(), AnyError> { Rc::try_unwrap(self.decipher) .map_err(|_| type_error("Decipher context is already in use"))? .into_inner() - .r#final(input, output) + .r#final(input, output, auth_tag) } } @@ -103,10 +121,37 @@ impl Cipher { Aes128Cbc(Box::new(cbc::Encryptor::new(key.into(), iv.into()))) } "aes-128-ecb" => Aes128Ecb(Box::new(ecb::Encryptor::new(key.into()))), + "aes-128-gcm" => { + let mut cipher = + aead_gcm_stream::AesGcm::<aes::Aes128>::new(key.into()); + cipher.init(iv.try_into()?); + + Aes128Gcm(Box::new(cipher)) + } + "aes-256-gcm" => { + let mut cipher = + aead_gcm_stream::AesGcm::<aes::Aes256>::new(key.into()); + cipher.init(iv.try_into()?); + + Aes256Gcm(Box::new(cipher)) + } _ => return Err(type_error(format!("Unknown cipher {algorithm_name}"))), }) } + fn set_aad(&mut self, aad: &[u8]) { + use Cipher::*; + match self { + Aes128Gcm(cipher) => { + cipher.set_aad(aad); + } + Aes256Gcm(cipher) => { + cipher.set_aad(aad); + } + _ => {} + } + } + /// encrypt encrypts the data in the middle of the input. fn encrypt(&mut self, input: &[u8], output: &mut [u8]) { use Cipher::*; @@ -123,11 +168,19 @@ impl Cipher { encryptor.encrypt_block_b2b_mut(input.into(), output.into()); } } + Aes128Gcm(cipher) => { + output[..input.len()].copy_from_slice(input); + cipher.encrypt(output); + } + Aes256Gcm(cipher) => { + output[..input.len()].copy_from_slice(input); + cipher.encrypt(output); + } } } /// r#final encrypts the last block of the input data. - fn r#final(self, input: &[u8], output: &mut [u8]) -> Result<(), AnyError> { + fn r#final(self, input: &[u8], output: &mut [u8]) -> Result<Tag, AnyError> { assert!(input.len() < 16); use Cipher::*; match self { @@ -135,14 +188,16 @@ impl Cipher { let _ = (*encryptor) .encrypt_padded_b2b_mut::<Pkcs7>(input, output) .map_err(|_| type_error("Cannot pad the input data"))?; - Ok(()) + Ok(None) } Aes128Ecb(encryptor) => { let _ = (*encryptor) .encrypt_padded_b2b_mut::<Pkcs7>(input, output) .map_err(|_| type_error("Cannot pad the input data"))?; - Ok(()) + Ok(None) } + Aes128Gcm(cipher) => Ok(Some(cipher.finish().to_vec())), + Aes256Gcm(cipher) => Ok(Some(cipher.finish().to_vec())), } } } @@ -159,10 +214,37 @@ impl Decipher { Aes128Cbc(Box::new(cbc::Decryptor::new(key.into(), iv.into()))) } "aes-128-ecb" => Aes128Ecb(Box::new(ecb::Decryptor::new(key.into()))), + "aes-128-gcm" => { + let mut decipher = + aead_gcm_stream::AesGcm::<aes::Aes128>::new(key.into()); + decipher.init(iv.try_into()?); + + Aes128Gcm(Box::new(decipher)) + } + "aes-256-gcm" => { + let mut decipher = + aead_gcm_stream::AesGcm::<aes::Aes256>::new(key.into()); + decipher.init(iv.try_into()?); + + Aes256Gcm(Box::new(decipher)) + } _ => return Err(type_error(format!("Unknown cipher {algorithm_name}"))), }) } + fn set_aad(&mut self, aad: &[u8]) { + use Decipher::*; + match self { + Aes128Gcm(decipher) => { + decipher.set_aad(aad); + } + Aes256Gcm(decipher) => { + decipher.set_aad(aad); + } + _ => {} + } + } + /// decrypt decrypts the data in the middle of the input. fn decrypt(&mut self, input: &[u8], output: &mut [u8]) { use Decipher::*; @@ -179,26 +261,56 @@ impl Decipher { decryptor.decrypt_block_b2b_mut(input.into(), output.into()); } } + Aes128Gcm(decipher) => { + output[..input.len()].copy_from_slice(input); + decipher.decrypt(output); + } + Aes256Gcm(decipher) => { + output[..input.len()].copy_from_slice(input); + decipher.decrypt(output); + } } } /// r#final decrypts the last block of the input data. - fn r#final(self, input: &[u8], output: &mut [u8]) -> Result<(), AnyError> { - assert!(input.len() == 16); + fn r#final( + self, + input: &[u8], + output: &mut [u8], + auth_tag: &[u8], + ) -> Result<(), AnyError> { use Decipher::*; match self { Aes128Cbc(decryptor) => { + assert!(input.len() == 16); let _ = (*decryptor) .decrypt_padded_b2b_mut::<Pkcs7>(input, output) .map_err(|_| type_error("Cannot unpad the input data"))?; Ok(()) } Aes128Ecb(decryptor) => { + assert!(input.len() == 16); let _ = (*decryptor) .decrypt_padded_b2b_mut::<Pkcs7>(input, output) .map_err(|_| type_error("Cannot unpad the input data"))?; Ok(()) } + Aes128Gcm(decipher) => { + let tag = decipher.finish(); + if tag.as_slice() == auth_tag { + Ok(()) + } else { + Err(type_error("Failed to authenticate data")) + } + } + Aes256Gcm(decipher) => { + let tag = decipher.finish(); + if tag.as_slice() == auth_tag { + Ok(()) + } else { + Err(type_error("Failed to authenticate data")) + } + } } } } |