From a4a44e2ad0542cba4b82c5699af512f86f1512a6 Mon Sep 17 00:00:00 2001 From: Nathan Whitaker Date: Fri, 10 Jan 2025 15:48:55 -0800 Subject: [PATCH 1/2] implement `aes-128-ctr` and `aes-256-ctr` --- Cargo.lock | 1 + Cargo.toml | 1 + ext/crypto/Cargo.toml | 2 +- ext/node/Cargo.toml | 1 + ext/node/ops/crypto/cipher.rs | 50 ++++++++++++++++++++ ext/node/polyfills/internal/crypto/cipher.ts | 6 ++- 6 files changed, 58 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1f13898fe07ec8..748e9956a699f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1993,6 +1993,7 @@ dependencies = [ "bytes", "cbc", "const-oid", + "ctr", "data-encoding", "deno_core", "deno_error", diff --git a/Cargo.toml b/Cargo.toml index 48abe48305bfb6..ee4ef147e64e3c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -110,6 +110,7 @@ bytes = "1.4.0" cache_control = "=0.2.0" capacity_builder = "0.5.0" cbc = { version = "=0.1.2", features = ["alloc"] } +ctr = { version = "0.9.2", features = ["alloc"] } # Note: Do not use the "clock" feature of chrono, as it links us to CoreFoundation on macOS. # Instead use util::time::utc_now() chrono = { version = "0.4", default-features = false, features = ["std", "serde"] } diff --git a/ext/crypto/Cargo.toml b/ext/crypto/Cargo.toml index c9876105e57298..00e08e733ca725 100644 --- a/ext/crypto/Cargo.toml +++ b/ext/crypto/Cargo.toml @@ -20,7 +20,7 @@ aes-kw = { version = "0.2.1", features = ["alloc"] } base64.workspace = true cbc.workspace = true const-oid = "0.9.0" -ctr = "0.9.1" +ctr.workspace = true curve25519-dalek = "4.1.3" deno_core.workspace = true deno_error.workspace = true diff --git a/ext/node/Cargo.toml b/ext/node/Cargo.toml index 6cd2b328663f3e..16cd416593bca9 100644 --- a/ext/node/Cargo.toml +++ b/ext/node/Cargo.toml @@ -27,6 +27,7 @@ brotli.workspace = true bytes.workspace = true cbc.workspace = true const-oid = "0.9.5" +ctr.workspace = true data-encoding.workspace = true deno_core.workspace = true deno_error.workspace = true diff --git a/ext/node/ops/crypto/cipher.rs b/ext/node/ops/crypto/cipher.rs index a12f36e04acd80..a5fd50616a933c 100644 --- a/ext/node/ops/crypto/cipher.rs +++ b/ext/node/ops/crypto/cipher.rs @@ -8,6 +8,7 @@ use aes::cipher::block_padding::Pkcs7; use aes::cipher::BlockDecryptMut; use aes::cipher::BlockEncryptMut; use aes::cipher::KeyIvInit; +use aes::cipher::StreamCipher; use deno_core::Resource; use digest::generic_array::GenericArray; use digest::KeyInit; @@ -25,6 +26,8 @@ enum Cipher { Aes128Gcm(Box), Aes256Gcm(Box), Aes256Cbc(Box>), + Aes128Ctr(Box>), + Aes256Ctr(Box>), // TODO(kt3k): add more algorithms Aes192Cbc, etc. } @@ -36,6 +39,8 @@ enum Decipher { Aes128Gcm(Box), Aes256Gcm(Box), Aes256Cbc(Box>), + Aes256Ctr(Box>), + Aes128Ctr(Box>), // TODO(kt3k): add more algorithms Aes192Cbc, Aes128GCM, etc. } @@ -211,6 +216,24 @@ impl Cipher { Aes256Cbc(Box::new(cbc::Encryptor::new(key.into(), iv.into()))) } + "aes-256-ctr" => { + if key.len() != 32 { + return Err(CipherError::InvalidKeyLength); + } + if iv.len() != 16 { + return Err(CipherError::InvalidInitializationVector); + } + Aes256Ctr(Box::new(ctr::Ctr128BE::new(key.into(), iv.into()))) + } + "aes-128-ctr" => { + if key.len() != 16 { + return Err(CipherError::InvalidKeyLength); + } + if iv.len() != 16 { + return Err(CipherError::InvalidInitializationVector); + } + Aes128Ctr(Box::new(ctr::Ctr128BE::new(key.into(), iv.into()))) + } _ => return Err(CipherError::UnknownCipher(algorithm_name.to_string())), }) } @@ -270,6 +293,12 @@ impl Cipher { encryptor.encrypt_block_b2b_mut(input.into(), output.into()); } } + Aes256Ctr(encryptor) => { + encryptor.apply_keystream_b2b(input, output).unwrap(); + } + Aes128Ctr(encryptor) => { + encryptor.apply_keystream_b2b(input, output).unwrap(); + } } } @@ -350,6 +379,7 @@ impl Cipher { ); Ok(None) } + (Aes256Ctr(_) | Aes128Ctr(_), _) => Ok(None), } } @@ -405,6 +435,12 @@ impl Decipher { "aes-128-ecb" => Aes128Ecb(Box::new(ecb::Decryptor::new(key.into()))), "aes-192-ecb" => Aes192Ecb(Box::new(ecb::Decryptor::new(key.into()))), "aes-256-ecb" => Aes256Ecb(Box::new(ecb::Decryptor::new(key.into()))), + "aes-256-ctr" => { + Aes256Ctr(Box::new(ctr::Ctr128BE::new(key.into(), iv.into()))) + } + "aes-128-ctr" => { + Aes128Ctr(Box::new(ctr::Ctr128BE::new(key.into(), iv.into()))) + } "aes-128-gcm" => { let decipher = aead_gcm_stream::AesGcm::::new(key.into(), iv); @@ -488,6 +524,12 @@ impl Decipher { decryptor.decrypt_block_b2b_mut(input.into(), output.into()); } } + Aes256Ctr(decryptor) => { + decryptor.apply_keystream_b2b(input, output).unwrap(); + } + Aes128Ctr(decryptor) => { + decryptor.apply_keystream_b2b(input, output).unwrap(); + } } } @@ -593,6 +635,14 @@ impl Decipher { ); Ok(()) } + (Aes256Ctr(mut decryptor), _) => { + decryptor.apply_keystream_b2b(input, output).unwrap(); + Ok(()) + } + (Aes128Ctr(mut decryptor), _) => { + decryptor.apply_keystream_b2b(input, output).unwrap(); + Ok(()) + } } } } diff --git a/ext/node/polyfills/internal/crypto/cipher.ts b/ext/node/polyfills/internal/crypto/cipher.ts index dd1698f46ecfb9..2d6d62a7f0f281 100644 --- a/ext/node/polyfills/internal/crypto/cipher.ts +++ b/ext/node/polyfills/internal/crypto/cipher.ts @@ -187,7 +187,8 @@ export class Cipheriv extends Transform implements Cipher { this.#cache = new BlockModeCache(false); this.#context = op_node_create_cipheriv(cipher, toU8(key), toU8(iv)); this.#needsBlockCache = - !(cipher == "aes-128-gcm" || cipher == "aes-256-gcm"); + !(cipher == "aes-128-gcm" || cipher == "aes-256-gcm" || + cipher == "aes-128-ctr" || cipher == "aes-256-ctr"); if (this.#context == 0) { throw new TypeError("Unknown cipher"); } @@ -345,7 +346,8 @@ export class Decipheriv extends Transform implements Cipher { this.#cache = new BlockModeCache(this.#autoPadding); this.#context = op_node_create_decipheriv(cipher, toU8(key), toU8(iv)); this.#needsBlockCache = - !(cipher == "aes-128-gcm" || cipher == "aes-256-gcm"); + !(cipher == "aes-128-gcm" || cipher == "aes-256-gcm" || + cipher == "aes-128-ctr" || cipher == "aes-256-ctr"); if (this.#context == 0) { throw new TypeError("Unknown cipher"); } From c09deecac1a510482f40c9002a37e3b6ef8c803a Mon Sep 17 00:00:00 2001 From: Nathan Whitaker Date: Fri, 10 Jan 2025 19:01:01 -0800 Subject: [PATCH 2/2] fmt --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ee4ef147e64e3c..da992fc398893f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -110,12 +110,12 @@ bytes = "1.4.0" cache_control = "=0.2.0" capacity_builder = "0.5.0" cbc = { version = "=0.1.2", features = ["alloc"] } -ctr = { version = "0.9.2", features = ["alloc"] } # Note: Do not use the "clock" feature of chrono, as it links us to CoreFoundation on macOS. # Instead use util::time::utc_now() chrono = { version = "0.4", default-features = false, features = ["std", "serde"] } color-print = "0.3.5" console_static_text = "=0.8.1" +ctr = { version = "0.9.2", features = ["alloc"] } dashmap = "5.5.3" data-encoding = "2.3.3" data-url = "=0.3.1"