summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock10
-rw-r--r--Cargo.toml1
-rw-r--r--cli/tests/unit_node/crypto_cipher_test.ts64
-rw-r--r--ext/node/Cargo.toml1
-rw-r--r--ext/node/crypto/cipher.rs33
-rw-r--r--ext/node/polyfills/internal/crypto/cipher.ts10
6 files changed, 97 insertions, 22 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 90ab50377..31874a748 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1150,6 +1150,7 @@ dependencies = [
"cbc",
"deno_core",
"digest 0.10.6",
+ "ecb",
"hex",
"idna 0.3.0",
"indexmap",
@@ -1527,6 +1528,15 @@ dependencies = [
]
[[package]]
+name = "ecb"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17fd84ba81a904351ee27bbccb4aa2461e1cca04176a63ab4f8ca087757681a2"
+dependencies = [
+ "cipher",
+]
+
+[[package]]
name = "ecdsa"
version = "0.14.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index a277bec7c..b364a9cf4 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -90,6 +90,7 @@ console_static_text = "=0.7.1"
data-url = "=0.2.0"
dlopen = "0.1.8"
encoding_rs = "=0.8.31"
+ecb = "=0.1.1"
flate2 = "=1.0.24"
fs3 = "0.5.0"
futures = "0.3.21"
diff --git a/cli/tests/unit_node/crypto_cipher_test.ts b/cli/tests/unit_node/crypto_cipher_test.ts
index 3f740f40c..2c8cca256 100644
--- a/cli/tests/unit_node/crypto_cipher_test.ts
+++ b/cli/tests/unit_node/crypto_cipher_test.ts
@@ -17,6 +17,10 @@ const rsaPublicKey = Deno.readTextFileSync(
const input = new TextEncoder().encode("hello world");
+function zeros(length: number): Uint8Array {
+ return new Uint8Array(length);
+}
+
Deno.test({
name: "rsa public encrypt and private decrypt",
fn() {
@@ -52,7 +56,7 @@ Deno.test({
});
Deno.test({
- name: "createCipheriv - basic",
+ name: "createCipheriv - multiple chunk inputs",
fn() {
const cipher = crypto.createCipheriv(
"aes-128-cbc",
@@ -76,6 +80,31 @@ Deno.test({
});
Deno.test({
+ name: "createCipheriv - algorithms",
+ fn() {
+ const table = [
+ [
+ ["aes-128-cbc", 16, 16],
+ "66e94bd4ef8a2c3b884cfa59ca342b2ef795bd4a52e29ed713d313fa20e98dbca10cf66d0fddf3405370b4bf8df5bfb3",
+ "d5f65ecda64511e9d3d12206411ffd72",
+ ],
+ [
+ ["aes-128-ecb", 16, 0],
+ "66e94bd4ef8a2c3b884cfa59ca342b2e66e94bd4ef8a2c3b884cfa59ca342b2e66e94bd4ef8a2c3b884cfa59ca342b2e",
+ "baf823258ca2e6994f638daa3515e986",
+ ],
+ ] as const;
+ for (
+ const [[alg, keyLen, ivLen], expectedUpdate, expectedFinal] of table
+ ) {
+ const cipher = crypto.createCipheriv(alg, zeros(keyLen), zeros(ivLen));
+ assertEquals(cipher.update(zeros(50), undefined, "hex"), expectedUpdate);
+ assertEquals(cipher.final("hex"), expectedFinal);
+ }
+ },
+});
+
+Deno.test({
name: "createCipheriv - input encoding",
fn() {
const cipher = crypto.createCipheriv(
@@ -113,24 +142,25 @@ Deno.test({
});
Deno.test({
- name: "createDecipheriv - basic",
+ name: "createDecipheriv - algorithms",
fn() {
- const decipher = crypto.createDecipheriv(
- "aes-128-cbc",
- new Uint8Array(16),
- new Uint8Array(16),
- );
- assertEquals(
- decipher.update(
+ const table = [
+ [
+ ["aes-128-cbc", 16, 16],
"66e94bd4ef8a2c3b884cfa59ca342b2ef795bd4a52e29ed713d313fa20e98dbca10cf66d0fddf3405370b4bf8df5bfb347c78395e0d8ae2194da0a90abc9888a94ee48f6c78fcd518a941c3896102cb1e11901dde4a2f99fe4efc707e48c6aed",
- "hex",
- ),
- Buffer.alloc(80),
- );
- assertEquals(
- decipher.final(),
- Buffer.alloc(10), // Checks the padding
- );
+ ],
+ [
+ ["aes-128-ecb", 16, 0],
+ "66e94bd4ef8a2c3b884cfa59ca342b2e66e94bd4ef8a2c3b884cfa59ca342b2e66e94bd4ef8a2c3b884cfa59ca342b2e66e94bd4ef8a2c3b884cfa59ca342b2e66e94bd4ef8a2c3b884cfa59ca342b2ec29a917cbaf72fa9bc32129bb0d17663",
+ ],
+ ] as const;
+ for (
+ const [[alg, keyLen, ivLen], input] of table
+ ) {
+ const cipher = crypto.createDecipheriv(alg, zeros(keyLen), zeros(ivLen));
+ assertEquals(cipher.update(input, "hex"), Buffer.alloc(80));
+ assertEquals(cipher.final(), Buffer.alloc(10));
+ }
},
});
diff --git a/ext/node/Cargo.toml b/ext/node/Cargo.toml
index b555111cd..1cd742def 100644
--- a/ext/node/Cargo.toml
+++ b/ext/node/Cargo.toml
@@ -18,6 +18,7 @@ aes.workspace = true
cbc.workspace = true
deno_core.workspace = true
digest = { version = "0.10.5", features = ["core-api", "std"] }
+ecb.workspace = true
hex.workspace = true
idna = "0.3.0"
indexmap.workspace = true
diff --git a/ext/node/crypto/cipher.rs b/ext/node/crypto/cipher.rs
index 54cd61132..4f3f7f20d 100644
--- a/ext/node/crypto/cipher.rs
+++ b/ext/node/crypto/cipher.rs
@@ -7,6 +7,7 @@ use aes::cipher::KeyIvInit;
use deno_core::error::type_error;
use deno_core::error::AnyError;
use deno_core::Resource;
+use digest::KeyInit;
use std::borrow::Cow;
use std::cell::RefCell;
@@ -14,12 +15,14 @@ use std::rc::Rc;
enum Cipher {
Aes128Cbc(Box<cbc::Encryptor<aes::Aes128>>),
- // TODO(kt3k): add more algorithms Aes192Cbc, Aes256Cbc, Aes128ECB, Aes128GCM, etc.
+ Aes128Ecb(Box<ecb::Encryptor<aes::Aes128>>),
+ // TODO(kt3k): add more algorithms Aes192Cbc, Aes256Cbc, Aes128GCM, etc.
}
enum Decipher {
Aes128Cbc(Box<cbc::Decryptor<aes::Aes128>>),
- // TODO(kt3k): add more algorithms Aes192Cbc, Aes256Cbc, Aes128ECB, Aes128GCM, etc.
+ Aes128Ecb(Box<ecb::Decryptor<aes::Aes128>>),
+ // TODO(kt3k): add more algorithms Aes192Cbc, Aes256Cbc, Aes128GCM, etc.
}
pub struct CipherContext {
@@ -99,6 +102,7 @@ impl Cipher {
"aes-128-cbc" => {
Aes128Cbc(Box::new(cbc::Encryptor::new(key.into(), iv.into())))
}
+ "aes-128-ecb" => Aes128Ecb(Box::new(ecb::Encryptor::new(key.into()))),
_ => return Err(type_error(format!("Unknown cipher {algorithm_name}"))),
})
}
@@ -113,6 +117,12 @@ impl Cipher {
encryptor.encrypt_block_b2b_mut(input.into(), output.into());
}
}
+ Aes128Ecb(encryptor) => {
+ assert!(input.len() % 16 == 0);
+ for (input, output) in input.chunks(16).zip(output.chunks_mut(16)) {
+ encryptor.encrypt_block_b2b_mut(input.into(), output.into());
+ }
+ }
}
}
@@ -127,6 +137,12 @@ impl Cipher {
.map_err(|_| type_error("Cannot pad the input data"))?;
Ok(())
}
+ Aes128Ecb(encryptor) => {
+ let _ = (*encryptor)
+ .encrypt_padded_b2b_mut::<Pkcs7>(input, output)
+ .map_err(|_| type_error("Cannot pad the input data"))?;
+ Ok(())
+ }
}
}
}
@@ -142,6 +158,7 @@ impl Decipher {
"aes-128-cbc" => {
Aes128Cbc(Box::new(cbc::Decryptor::new(key.into(), iv.into())))
}
+ "aes-128-ecb" => Aes128Ecb(Box::new(ecb::Decryptor::new(key.into()))),
_ => return Err(type_error(format!("Unknown cipher {algorithm_name}"))),
})
}
@@ -156,6 +173,12 @@ impl Decipher {
decryptor.decrypt_block_b2b_mut(input.into(), output.into());
}
}
+ Aes128Ecb(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());
+ }
+ }
}
}
@@ -170,6 +193,12 @@ impl Decipher {
.map_err(|_| type_error("Cannot unpad the input data"))?;
Ok(())
}
+ Aes128Ecb(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/polyfills/internal/crypto/cipher.ts b/ext/node/polyfills/internal/crypto/cipher.ts
index 670c1bcce..050cf5904 100644
--- a/ext/node/polyfills/internal/crypto/cipher.ts
+++ b/ext/node/polyfills/internal/crypto/cipher.ts
@@ -18,7 +18,7 @@ import type {
} from "ext:deno_node/internal/crypto/types.ts";
import { getDefaultEncoding } from "ext:deno_node/internal/crypto/util.ts";
-const { ops } = globalThis.__bootstrap.core;
+const { ops, encode } = globalThis.__bootstrap.core;
export type CipherCCMTypes =
| "aes-128-ccm"
@@ -116,6 +116,10 @@ export interface DecipherOCB extends Decipher {
): this;
}
+function toU8(input: string | Uint8Array): Uint8Array {
+ return typeof input === "string" ? encode(input) : input;
+}
+
export class Cipheriv extends Transform implements Cipher {
/** CipherContext resource id */
#context: number;
@@ -141,7 +145,7 @@ export class Cipheriv extends Transform implements Cipher {
...options,
});
this.#cache = new BlockModeCache(false);
- this.#context = ops.op_node_create_cipheriv(cipher, key, iv);
+ this.#context = ops.op_node_create_cipheriv(cipher, toU8(key), toU8(iv));
}
final(encoding: string = getDefaultEncoding()): Buffer | string {
@@ -257,7 +261,7 @@ export class Decipheriv extends Transform implements Cipher {
...options,
});
this.#cache = new BlockModeCache(true);
- this.#context = ops.op_node_create_decipheriv(cipher, key, iv);
+ this.#context = ops.op_node_create_decipheriv(cipher, toU8(key), toU8(iv));
}
final(encoding: string = getDefaultEncoding()): Buffer | string {