diff options
Diffstat (limited to 'ext/node/crypto')
-rw-r--r-- | ext/node/crypto/cipher.rs | 73 | ||||
-rw-r--r-- | ext/node/crypto/mod.rs | 43 |
2 files changed, 113 insertions, 3 deletions
diff --git a/ext/node/crypto/cipher.rs b/ext/node/crypto/cipher.rs index 0833cb591..54cd61132 100644 --- a/ext/node/crypto/cipher.rs +++ b/ext/node/crypto/cipher.rs @@ -1,6 +1,7 @@ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. use aes::cipher::block_padding::Pkcs7; +use aes::cipher::BlockDecryptMut; use aes::cipher::BlockEncryptMut; use aes::cipher::KeyIvInit; use deno_core::error::type_error; @@ -17,8 +18,8 @@ enum Cipher { } enum Decipher { - // TODO(kt3k): implement Deciphers - // Aes128Cbc(Box<cbc::Decryptor<aes::Aes128>>), + Aes128Cbc(Box<cbc::Decryptor<aes::Aes128>>), + // TODO(kt3k): add more algorithms Aes192Cbc, Aes256Cbc, Aes128ECB, Aes128GCM, etc. } pub struct CipherContext { @@ -26,7 +27,7 @@ pub struct CipherContext { } pub struct DecipherContext { - _decipher: Rc<RefCell<Decipher>>, + decipher: Rc<RefCell<Decipher>>, } impl CipherContext { @@ -52,6 +53,29 @@ impl CipherContext { } } +impl DecipherContext { + pub fn new(algorithm: &str, key: &[u8], iv: &[u8]) -> Result<Self, AnyError> { + Ok(Self { + decipher: Rc::new(RefCell::new(Decipher::new(algorithm, key, iv)?)), + }) + } + + pub fn decrypt(&self, input: &[u8], output: &mut [u8]) { + self.decipher.borrow_mut().decrypt(input, output); + } + + pub fn r#final( + self, + input: &[u8], + output: &mut [u8], + ) -> Result<(), AnyError> { + Rc::try_unwrap(self.decipher) + .map_err(|_| type_error("Decipher context is already in use"))? + .into_inner() + .r#final(input, output) + } +} + impl Resource for CipherContext { fn name(&self) -> Cow<str> { "cryptoCipher".into() @@ -106,3 +130,46 @@ impl Cipher { } } } + +impl Decipher { + fn new( + algorithm_name: &str, + key: &[u8], + iv: &[u8], + ) -> Result<Self, AnyError> { + use Decipher::*; + Ok(match algorithm_name { + "aes-128-cbc" => { + Aes128Cbc(Box::new(cbc::Decryptor::new(key.into(), iv.into()))) + } + _ => return Err(type_error(format!("Unknown cipher {algorithm_name}"))), + }) + } + + /// decrypt decrypts the data in the middle of the input. + fn decrypt(&mut self, input: &[u8], output: &mut [u8]) { + use Decipher::*; + match self { + Aes128Cbc(decryptor) => { + assert!(input.len() % 16 == 0); + for (input, output) in input.chunks(16).zip(output.chunks_mut(16)) { + decryptor.decrypt_block_b2b_mut(input.into(), output.into()); + } + } + } + } + + /// 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); + use Decipher::*; + match self { + Aes128Cbc(decryptor) => { + let _ = (*decryptor) + .decrypt_padded_b2b_mut::<Pkcs7>(input, output) + .map_err(|_| type_error("Cannot unpad the input data"))?; + Ok(()) + } + } + } +} diff --git a/ext/node/crypto/mod.rs b/ext/node/crypto/mod.rs index 3e6af9b4b..53d064d86 100644 --- a/ext/node/crypto/mod.rs +++ b/ext/node/crypto/mod.rs @@ -197,3 +197,46 @@ pub fn op_node_cipheriv_final( .map_err(|_| type_error("Cipher context is already in use"))?; context.r#final(input, output) } + +#[op(fast)] +pub fn op_node_create_decipheriv( + state: &mut OpState, + algorithm: &str, + key: &[u8], + iv: &[u8], +) -> u32 { + state.resource_table.add( + match cipher::DecipherContext::new(algorithm, key, iv) { + Ok(context) => context, + Err(_) => return 0, + }, + ) +} + +#[op(fast)] +pub fn op_node_decipheriv_decrypt( + state: &mut OpState, + rid: u32, + input: &[u8], + output: &mut [u8], +) -> bool { + let context = match state.resource_table.get::<cipher::DecipherContext>(rid) { + Ok(context) => context, + Err(_) => return false, + }; + context.decrypt(input, output); + true +} + +#[op] +pub fn op_node_decipheriv_final( + state: &mut OpState, + rid: u32, + input: &[u8], + output: &mut [u8], +) -> Result<(), AnyError> { + let context = state.resource_table.take::<cipher::DecipherContext>(rid)?; + let context = Rc::try_unwrap(context) + .map_err(|_| type_error("Cipher context is already in use"))?; + context.r#final(input, output) +} |