mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 15:04:11 -05:00
fix(ext/node): add aes-128-ecb algorithm support (#18412)
This commit is contained in:
parent
255b06d793
commit
70e2e8f2dd
6 changed files with 97 additions and 22 deletions
10
Cargo.lock
generated
10
Cargo.lock
generated
|
@ -1150,6 +1150,7 @@ dependencies = [
|
||||||
"cbc",
|
"cbc",
|
||||||
"deno_core",
|
"deno_core",
|
||||||
"digest 0.10.6",
|
"digest 0.10.6",
|
||||||
|
"ecb",
|
||||||
"hex",
|
"hex",
|
||||||
"idna 0.3.0",
|
"idna 0.3.0",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
|
@ -1526,6 +1527,15 @@ dependencies = [
|
||||||
"memmap2",
|
"memmap2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ecb"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "17fd84ba81a904351ee27bbccb4aa2461e1cca04176a63ab4f8ca087757681a2"
|
||||||
|
dependencies = [
|
||||||
|
"cipher",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ecdsa"
|
name = "ecdsa"
|
||||||
version = "0.14.8"
|
version = "0.14.8"
|
||||||
|
|
|
@ -90,6 +90,7 @@ console_static_text = "=0.7.1"
|
||||||
data-url = "=0.2.0"
|
data-url = "=0.2.0"
|
||||||
dlopen = "0.1.8"
|
dlopen = "0.1.8"
|
||||||
encoding_rs = "=0.8.31"
|
encoding_rs = "=0.8.31"
|
||||||
|
ecb = "=0.1.1"
|
||||||
flate2 = "=1.0.24"
|
flate2 = "=1.0.24"
|
||||||
fs3 = "0.5.0"
|
fs3 = "0.5.0"
|
||||||
futures = "0.3.21"
|
futures = "0.3.21"
|
||||||
|
|
|
@ -17,6 +17,10 @@ const rsaPublicKey = Deno.readTextFileSync(
|
||||||
|
|
||||||
const input = new TextEncoder().encode("hello world");
|
const input = new TextEncoder().encode("hello world");
|
||||||
|
|
||||||
|
function zeros(length: number): Uint8Array {
|
||||||
|
return new Uint8Array(length);
|
||||||
|
}
|
||||||
|
|
||||||
Deno.test({
|
Deno.test({
|
||||||
name: "rsa public encrypt and private decrypt",
|
name: "rsa public encrypt and private decrypt",
|
||||||
fn() {
|
fn() {
|
||||||
|
@ -52,7 +56,7 @@ Deno.test({
|
||||||
});
|
});
|
||||||
|
|
||||||
Deno.test({
|
Deno.test({
|
||||||
name: "createCipheriv - basic",
|
name: "createCipheriv - multiple chunk inputs",
|
||||||
fn() {
|
fn() {
|
||||||
const cipher = crypto.createCipheriv(
|
const cipher = crypto.createCipheriv(
|
||||||
"aes-128-cbc",
|
"aes-128-cbc",
|
||||||
|
@ -75,6 +79,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({
|
Deno.test({
|
||||||
name: "createCipheriv - input encoding",
|
name: "createCipheriv - input encoding",
|
||||||
fn() {
|
fn() {
|
||||||
|
@ -113,24 +142,25 @@ Deno.test({
|
||||||
});
|
});
|
||||||
|
|
||||||
Deno.test({
|
Deno.test({
|
||||||
name: "createDecipheriv - basic",
|
name: "createDecipheriv - algorithms",
|
||||||
fn() {
|
fn() {
|
||||||
const decipher = crypto.createDecipheriv(
|
const table = [
|
||||||
"aes-128-cbc",
|
[
|
||||||
new Uint8Array(16),
|
["aes-128-cbc", 16, 16],
|
||||||
new Uint8Array(16),
|
|
||||||
);
|
|
||||||
assertEquals(
|
|
||||||
decipher.update(
|
|
||||||
"66e94bd4ef8a2c3b884cfa59ca342b2ef795bd4a52e29ed713d313fa20e98dbca10cf66d0fddf3405370b4bf8df5bfb347c78395e0d8ae2194da0a90abc9888a94ee48f6c78fcd518a941c3896102cb1e11901dde4a2f99fe4efc707e48c6aed",
|
"66e94bd4ef8a2c3b884cfa59ca342b2ef795bd4a52e29ed713d313fa20e98dbca10cf66d0fddf3405370b4bf8df5bfb347c78395e0d8ae2194da0a90abc9888a94ee48f6c78fcd518a941c3896102cb1e11901dde4a2f99fe4efc707e48c6aed",
|
||||||
"hex",
|
],
|
||||||
),
|
[
|
||||||
Buffer.alloc(80),
|
["aes-128-ecb", 16, 0],
|
||||||
);
|
"66e94bd4ef8a2c3b884cfa59ca342b2e66e94bd4ef8a2c3b884cfa59ca342b2e66e94bd4ef8a2c3b884cfa59ca342b2e66e94bd4ef8a2c3b884cfa59ca342b2e66e94bd4ef8a2c3b884cfa59ca342b2ec29a917cbaf72fa9bc32129bb0d17663",
|
||||||
assertEquals(
|
],
|
||||||
decipher.final(),
|
] as const;
|
||||||
Buffer.alloc(10), // Checks the padding
|
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));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ aes.workspace = true
|
||||||
cbc.workspace = true
|
cbc.workspace = true
|
||||||
deno_core.workspace = true
|
deno_core.workspace = true
|
||||||
digest = { version = "0.10.5", features = ["core-api", "std"] }
|
digest = { version = "0.10.5", features = ["core-api", "std"] }
|
||||||
|
ecb.workspace = true
|
||||||
hex.workspace = true
|
hex.workspace = true
|
||||||
idna = "0.3.0"
|
idna = "0.3.0"
|
||||||
indexmap.workspace = true
|
indexmap.workspace = true
|
||||||
|
|
|
@ -7,6 +7,7 @@ use aes::cipher::KeyIvInit;
|
||||||
use deno_core::error::type_error;
|
use deno_core::error::type_error;
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
use deno_core::Resource;
|
use deno_core::Resource;
|
||||||
|
use digest::KeyInit;
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
@ -14,12 +15,14 @@ use std::rc::Rc;
|
||||||
|
|
||||||
enum Cipher {
|
enum Cipher {
|
||||||
Aes128Cbc(Box<cbc::Encryptor<aes::Aes128>>),
|
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 {
|
enum Decipher {
|
||||||
Aes128Cbc(Box<cbc::Decryptor<aes::Aes128>>),
|
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 {
|
pub struct CipherContext {
|
||||||
|
@ -99,6 +102,7 @@ impl Cipher {
|
||||||
"aes-128-cbc" => {
|
"aes-128-cbc" => {
|
||||||
Aes128Cbc(Box::new(cbc::Encryptor::new(key.into(), iv.into())))
|
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}"))),
|
_ => return Err(type_error(format!("Unknown cipher {algorithm_name}"))),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -113,6 +117,12 @@ impl Cipher {
|
||||||
encryptor.encrypt_block_b2b_mut(input.into(), output.into());
|
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"))?;
|
.map_err(|_| type_error("Cannot pad the input data"))?;
|
||||||
Ok(())
|
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" => {
|
"aes-128-cbc" => {
|
||||||
Aes128Cbc(Box::new(cbc::Decryptor::new(key.into(), iv.into())))
|
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}"))),
|
_ => return Err(type_error(format!("Unknown cipher {algorithm_name}"))),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -156,6 +173,12 @@ impl Decipher {
|
||||||
decryptor.decrypt_block_b2b_mut(input.into(), output.into());
|
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"))?;
|
.map_err(|_| type_error("Cannot unpad the input data"))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Aes128Ecb(decryptor) => {
|
||||||
|
let _ = (*decryptor)
|
||||||
|
.decrypt_padded_b2b_mut::<Pkcs7>(input, output)
|
||||||
|
.map_err(|_| type_error("Cannot unpad the input data"))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ import type {
|
||||||
} from "ext:deno_node/internal/crypto/types.ts";
|
} from "ext:deno_node/internal/crypto/types.ts";
|
||||||
import { getDefaultEncoding } from "ext:deno_node/internal/crypto/util.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 =
|
export type CipherCCMTypes =
|
||||||
| "aes-128-ccm"
|
| "aes-128-ccm"
|
||||||
|
@ -116,6 +116,10 @@ export interface DecipherOCB extends Decipher {
|
||||||
): this;
|
): this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toU8(input: string | Uint8Array): Uint8Array {
|
||||||
|
return typeof input === "string" ? encode(input) : input;
|
||||||
|
}
|
||||||
|
|
||||||
export class Cipheriv extends Transform implements Cipher {
|
export class Cipheriv extends Transform implements Cipher {
|
||||||
/** CipherContext resource id */
|
/** CipherContext resource id */
|
||||||
#context: number;
|
#context: number;
|
||||||
|
@ -141,7 +145,7 @@ export class Cipheriv extends Transform implements Cipher {
|
||||||
...options,
|
...options,
|
||||||
});
|
});
|
||||||
this.#cache = new BlockModeCache(false);
|
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 {
|
final(encoding: string = getDefaultEncoding()): Buffer | string {
|
||||||
|
@ -257,7 +261,7 @@ export class Decipheriv extends Transform implements Cipher {
|
||||||
...options,
|
...options,
|
||||||
});
|
});
|
||||||
this.#cache = new BlockModeCache(true);
|
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 {
|
final(encoding: string = getDefaultEncoding()): Buffer | string {
|
||||||
|
|
Loading…
Reference in a new issue