mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 15:04:11 -05:00
fix(ext/node): add CipherIv.setAutoPadding()
(#24940)
Co-Authored-By: Luca Casonato <hello@lcas.dev> Fixes https://github.com/denoland/deno/issues/21804 Ref https://github.com/denoland/deno/issues/20924 --------- Signed-off-by: Divy Srivastava <dj.srivastava23@gmail.com> Co-authored-by: Luca Casonato <hello@lcas.dev>
This commit is contained in:
parent
2f6da40bd6
commit
0d1beed2e3
4 changed files with 146 additions and 31 deletions
|
@ -232,6 +232,7 @@ deno_core::extension!(deno_node,
|
|||
ops::crypto::op_node_decipheriv_decrypt,
|
||||
ops::crypto::op_node_decipheriv_final,
|
||||
ops::crypto::op_node_decipheriv_set_aad,
|
||||
ops::crypto::op_node_decipheriv_take,
|
||||
ops::crypto::op_node_dh_compute_secret,
|
||||
ops::crypto::op_node_diffie_hellman,
|
||||
ops::crypto::op_node_ecdh_compute_public_key,
|
||||
|
|
|
@ -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::generic_array::GenericArray;
|
||||
use digest::KeyInit;
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
@ -65,13 +66,14 @@ impl CipherContext {
|
|||
|
||||
pub fn r#final(
|
||||
self,
|
||||
auto_pad: bool,
|
||||
input: &[u8],
|
||||
output: &mut [u8],
|
||||
) -> Result<Tag, AnyError> {
|
||||
Rc::try_unwrap(self.cipher)
|
||||
.map_err(|_| type_error("Cipher context is already in use"))?
|
||||
.into_inner()
|
||||
.r#final(input, output)
|
||||
.r#final(auto_pad, input, output)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,6 +94,7 @@ impl DecipherContext {
|
|||
|
||||
pub fn r#final(
|
||||
self,
|
||||
auto_pad: bool,
|
||||
input: &[u8],
|
||||
output: &mut [u8],
|
||||
auth_tag: &[u8],
|
||||
|
@ -99,7 +102,7 @@ impl DecipherContext {
|
|||
Rc::try_unwrap(self.decipher)
|
||||
.map_err(|_| type_error("Decipher context is already in use"))?
|
||||
.into_inner()
|
||||
.r#final(input, output, auth_tag)
|
||||
.r#final(auto_pad, input, output, auth_tag)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -209,42 +212,82 @@ impl Cipher {
|
|||
}
|
||||
|
||||
/// r#final encrypts the last block of the input data.
|
||||
fn r#final(self, input: &[u8], output: &mut [u8]) -> Result<Tag, AnyError> {
|
||||
fn r#final(
|
||||
self,
|
||||
auto_pad: bool,
|
||||
input: &[u8],
|
||||
output: &mut [u8],
|
||||
) -> Result<Tag, AnyError> {
|
||||
assert!(input.len() < 16);
|
||||
use Cipher::*;
|
||||
match self {
|
||||
Aes128Cbc(encryptor) => {
|
||||
match (self, auto_pad) {
|
||||
(Aes128Cbc(encryptor), true) => {
|
||||
let _ = (*encryptor)
|
||||
.encrypt_padded_b2b_mut::<Pkcs7>(input, output)
|
||||
.map_err(|_| type_error("Cannot pad the input data"))?;
|
||||
Ok(None)
|
||||
}
|
||||
Aes128Ecb(encryptor) => {
|
||||
(Aes128Cbc(mut encryptor), false) => {
|
||||
encryptor.encrypt_block_b2b_mut(
|
||||
GenericArray::from_slice(input),
|
||||
GenericArray::from_mut_slice(output),
|
||||
);
|
||||
Ok(None)
|
||||
}
|
||||
(Aes128Ecb(encryptor), true) => {
|
||||
let _ = (*encryptor)
|
||||
.encrypt_padded_b2b_mut::<Pkcs7>(input, output)
|
||||
.map_err(|_| type_error("Cannot pad the input data"))?;
|
||||
Ok(None)
|
||||
}
|
||||
Aes192Ecb(encryptor) => {
|
||||
(Aes128Ecb(mut encryptor), false) => {
|
||||
encryptor.encrypt_block_b2b_mut(
|
||||
GenericArray::from_slice(input),
|
||||
GenericArray::from_mut_slice(output),
|
||||
);
|
||||
Ok(None)
|
||||
}
|
||||
(Aes192Ecb(encryptor), true) => {
|
||||
let _ = (*encryptor)
|
||||
.encrypt_padded_b2b_mut::<Pkcs7>(input, output)
|
||||
.map_err(|_| type_error("Cannot pad the input data"))?;
|
||||
Ok(None)
|
||||
}
|
||||
Aes256Ecb(encryptor) => {
|
||||
(Aes192Ecb(mut encryptor), false) => {
|
||||
encryptor.encrypt_block_b2b_mut(
|
||||
GenericArray::from_slice(input),
|
||||
GenericArray::from_mut_slice(output),
|
||||
);
|
||||
Ok(None)
|
||||
}
|
||||
(Aes256Ecb(encryptor), true) => {
|
||||
let _ = (*encryptor)
|
||||
.encrypt_padded_b2b_mut::<Pkcs7>(input, output)
|
||||
.map_err(|_| type_error("Cannot pad the input data"))?;
|
||||
Ok(None)
|
||||
}
|
||||
Aes128Gcm(cipher) => Ok(Some(cipher.finish().to_vec())),
|
||||
Aes256Gcm(cipher) => Ok(Some(cipher.finish().to_vec())),
|
||||
Aes256Cbc(encryptor) => {
|
||||
(Aes256Ecb(mut encryptor), false) => {
|
||||
encryptor.encrypt_block_b2b_mut(
|
||||
GenericArray::from_slice(input),
|
||||
GenericArray::from_mut_slice(output),
|
||||
);
|
||||
Ok(None)
|
||||
}
|
||||
(Aes128Gcm(cipher), _) => Ok(Some(cipher.finish().to_vec())),
|
||||
(Aes256Gcm(cipher), _) => Ok(Some(cipher.finish().to_vec())),
|
||||
(Aes256Cbc(encryptor), true) => {
|
||||
let _ = (*encryptor)
|
||||
.encrypt_padded_b2b_mut::<Pkcs7>(input, output)
|
||||
.map_err(|_| type_error("Cannot pad the input data"))?;
|
||||
Ok(None)
|
||||
}
|
||||
(Aes256Cbc(mut encryptor), false) => {
|
||||
encryptor.encrypt_block_b2b_mut(
|
||||
GenericArray::from_slice(input),
|
||||
GenericArray::from_mut_slice(output),
|
||||
);
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -345,41 +388,70 @@ impl Decipher {
|
|||
/// r#final decrypts the last block of the input data.
|
||||
fn r#final(
|
||||
self,
|
||||
auto_pad: bool,
|
||||
input: &[u8],
|
||||
output: &mut [u8],
|
||||
auth_tag: &[u8],
|
||||
) -> Result<(), AnyError> {
|
||||
use Decipher::*;
|
||||
match self {
|
||||
Aes128Cbc(decryptor) => {
|
||||
match (self, auto_pad) {
|
||||
(Aes128Cbc(decryptor), true) => {
|
||||
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) => {
|
||||
(Aes128Cbc(mut decryptor), false) => {
|
||||
decryptor.decrypt_block_b2b_mut(
|
||||
GenericArray::from_slice(input),
|
||||
GenericArray::from_mut_slice(output),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
(Aes128Ecb(decryptor), true) => {
|
||||
assert!(input.len() == 16);
|
||||
let _ = (*decryptor)
|
||||
.decrypt_padded_b2b_mut::<Pkcs7>(input, output)
|
||||
.map_err(|_| type_error("Cannot unpad the input data"))?;
|
||||
Ok(())
|
||||
}
|
||||
Aes192Ecb(decryptor) => {
|
||||
(Aes128Ecb(mut decryptor), false) => {
|
||||
decryptor.decrypt_block_b2b_mut(
|
||||
GenericArray::from_slice(input),
|
||||
GenericArray::from_mut_slice(output),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
(Aes192Ecb(decryptor), true) => {
|
||||
assert!(input.len() == 16);
|
||||
let _ = (*decryptor)
|
||||
.decrypt_padded_b2b_mut::<Pkcs7>(input, output)
|
||||
.map_err(|_| type_error("Cannot unpad the input data"))?;
|
||||
Ok(())
|
||||
}
|
||||
Aes256Ecb(decryptor) => {
|
||||
(Aes192Ecb(mut decryptor), false) => {
|
||||
decryptor.decrypt_block_b2b_mut(
|
||||
GenericArray::from_slice(input),
|
||||
GenericArray::from_mut_slice(output),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
(Aes256Ecb(decryptor), true) => {
|
||||
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) => {
|
||||
(Aes256Ecb(mut decryptor), false) => {
|
||||
decryptor.decrypt_block_b2b_mut(
|
||||
GenericArray::from_slice(input),
|
||||
GenericArray::from_mut_slice(output),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
(Aes128Gcm(decipher), true) => {
|
||||
let tag = decipher.finish();
|
||||
if tag.as_slice() == auth_tag {
|
||||
Ok(())
|
||||
|
@ -387,7 +459,10 @@ impl Decipher {
|
|||
Err(type_error("Failed to authenticate data"))
|
||||
}
|
||||
}
|
||||
Aes256Gcm(decipher) => {
|
||||
(Aes128Gcm(_), false) => Err(type_error(
|
||||
"setAutoPadding(false) not supported for Aes256Gcm yet",
|
||||
)),
|
||||
(Aes256Gcm(decipher), true) => {
|
||||
let tag = decipher.finish();
|
||||
if tag.as_slice() == auth_tag {
|
||||
Ok(())
|
||||
|
@ -395,13 +470,23 @@ impl Decipher {
|
|||
Err(type_error("Failed to authenticate data"))
|
||||
}
|
||||
}
|
||||
Aes256Cbc(decryptor) => {
|
||||
(Aes256Gcm(_), false) => Err(type_error(
|
||||
"setAutoPadding(false) not supported for Aes256Gcm yet",
|
||||
)),
|
||||
(Aes256Cbc(decryptor), true) => {
|
||||
assert!(input.len() == 16);
|
||||
let _ = (*decryptor)
|
||||
.decrypt_padded_b2b_mut::<Pkcs7>(input, output)
|
||||
.map_err(|_| type_error("Cannot unpad the input data"))?;
|
||||
Ok(())
|
||||
}
|
||||
(Aes256Cbc(mut decryptor), false) => {
|
||||
decryptor.decrypt_block_b2b_mut(
|
||||
GenericArray::from_slice(input),
|
||||
GenericArray::from_mut_slice(output),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -262,13 +262,14 @@ pub fn op_node_cipheriv_encrypt(
|
|||
pub fn op_node_cipheriv_final(
|
||||
state: &mut OpState,
|
||||
#[smi] rid: u32,
|
||||
auto_pad: bool,
|
||||
#[buffer] input: &[u8],
|
||||
#[buffer] output: &mut [u8],
|
||||
#[anybuffer] output: &mut [u8],
|
||||
) -> Result<Option<Vec<u8>>, AnyError> {
|
||||
let context = state.resource_table.take::<cipher::CipherContext>(rid)?;
|
||||
let context = Rc::try_unwrap(context)
|
||||
.map_err(|_| type_error("Cipher context is already in use"))?;
|
||||
context.r#final(input, output)
|
||||
context.r#final(auto_pad, input, output)
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
|
@ -317,17 +318,29 @@ pub fn op_node_decipheriv_decrypt(
|
|||
}
|
||||
|
||||
#[op2(fast)]
|
||||
pub fn op_node_decipheriv_take(
|
||||
state: &mut OpState,
|
||||
#[smi] rid: u32,
|
||||
) -> Result<(), AnyError> {
|
||||
let context = state.resource_table.take::<cipher::DecipherContext>(rid)?;
|
||||
Rc::try_unwrap(context)
|
||||
.map_err(|_| type_error("Cipher context is already in use"))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[op2]
|
||||
pub fn op_node_decipheriv_final(
|
||||
state: &mut OpState,
|
||||
#[smi] rid: u32,
|
||||
auto_pad: bool,
|
||||
#[buffer] input: &[u8],
|
||||
#[buffer] output: &mut [u8],
|
||||
#[anybuffer] output: &mut [u8],
|
||||
#[buffer] auth_tag: &[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, auth_tag)
|
||||
context.r#final(auto_pad, input, output, auth_tag)
|
||||
}
|
||||
|
||||
#[op2]
|
||||
|
|
|
@ -17,6 +17,7 @@ import {
|
|||
op_node_decipheriv_decrypt,
|
||||
op_node_decipheriv_final,
|
||||
op_node_decipheriv_set_aad,
|
||||
op_node_decipheriv_take,
|
||||
op_node_private_decrypt,
|
||||
op_node_private_encrypt,
|
||||
op_node_public_encrypt,
|
||||
|
@ -163,6 +164,8 @@ export class Cipheriv extends Transform implements Cipher {
|
|||
|
||||
#authTag?: Buffer;
|
||||
|
||||
#autoPadding = true;
|
||||
|
||||
constructor(
|
||||
cipher: string,
|
||||
key: CipherKey,
|
||||
|
@ -191,8 +194,13 @@ export class Cipheriv extends Transform implements Cipher {
|
|||
|
||||
final(encoding: string = getDefaultEncoding()): Buffer | string {
|
||||
const buf = new Buffer(16);
|
||||
|
||||
if (!this.#autoPadding && this.#cache.cache.byteLength != 16) {
|
||||
throw new Error("Invalid final block size");
|
||||
}
|
||||
const maybeTag = op_node_cipheriv_final(
|
||||
this.#context,
|
||||
this.#autoPadding,
|
||||
this.#cache.cache,
|
||||
buf,
|
||||
);
|
||||
|
@ -217,8 +225,8 @@ export class Cipheriv extends Transform implements Cipher {
|
|||
return this;
|
||||
}
|
||||
|
||||
setAutoPadding(_autoPadding?: boolean): this {
|
||||
notImplemented("crypto.Cipheriv.prototype.setAutoPadding");
|
||||
setAutoPadding(autoPadding?: boolean): this {
|
||||
this.#autoPadding = !!autoPadding;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -299,6 +307,8 @@ export class Decipheriv extends Transform implements Cipher {
|
|||
/** DecipherContext resource id */
|
||||
#context: number;
|
||||
|
||||
#autoPadding = true;
|
||||
|
||||
/** ciphertext data cache */
|
||||
#cache: BlockModeCache;
|
||||
|
||||
|
@ -333,18 +343,23 @@ export class Decipheriv extends Transform implements Cipher {
|
|||
}
|
||||
|
||||
final(encoding: string = getDefaultEncoding()): Buffer | string {
|
||||
if (!this.#needsBlockCache || this.#cache.cache.byteLength === 0) {
|
||||
op_node_decipheriv_take(this.#context);
|
||||
return encoding === "buffer" ? Buffer.from([]) : "";
|
||||
}
|
||||
if (this.#cache.cache.byteLength != 16) {
|
||||
throw new Error("Invalid final block size");
|
||||
}
|
||||
|
||||
let buf = new Buffer(16);
|
||||
op_node_decipheriv_final(
|
||||
this.#context,
|
||||
this.#autoPadding,
|
||||
this.#cache.cache,
|
||||
buf,
|
||||
this.#authTag || NO_TAG,
|
||||
);
|
||||
|
||||
if (!this.#needsBlockCache) {
|
||||
return encoding === "buffer" ? Buffer.from([]) : "";
|
||||
}
|
||||
|
||||
buf = buf.subarray(0, 16 - buf.at(-1)); // Padded in Pkcs7 mode
|
||||
return encoding === "buffer" ? buf : buf.toString(encoding);
|
||||
}
|
||||
|
@ -364,8 +379,9 @@ export class Decipheriv extends Transform implements Cipher {
|
|||
return this;
|
||||
}
|
||||
|
||||
setAutoPadding(_autoPadding?: boolean): this {
|
||||
notImplemented("crypto.Decipheriv.prototype.setAutoPadding");
|
||||
setAutoPadding(autoPadding?: boolean): this {
|
||||
this.#autoPadding = Boolean(autoPadding);
|
||||
return this;
|
||||
}
|
||||
|
||||
update(
|
||||
|
|
Loading…
Reference in a new issue