Skip to content

Commit

Permalink
add decipher auto pad
Browse files Browse the repository at this point in the history
  • Loading branch information
lucacasonato committed Aug 8, 2024
1 parent d4f1eb1 commit f1f202c
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 27 deletions.
98 changes: 78 additions & 20 deletions ext/node/ops/crypto/cipher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,15 @@ impl DecipherContext {

pub fn r#final(
self,
auto_pad: bool,
input: &[u8],
output: &mut [u8],
auth_tag: &[u8],
) -> Result<(), AnyError> {
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)
}
}

Expand Down Expand Up @@ -211,7 +212,12 @@ impl Cipher {
}

/// r#final encrypts the last block of the input data.
fn r#final(self, auto_pad: bool, 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, auto_pad) {
Expand All @@ -222,8 +228,10 @@ impl Cipher {
Ok(None)
}
(Aes128Cbc(mut encryptor), false) => {
encryptor
.encrypt_block_b2b_mut(GenericArray::from_slice(input), GenericArray::from_mut_slice(output));
encryptor.encrypt_block_b2b_mut(
GenericArray::from_slice(input),
GenericArray::from_mut_slice(output),
);
Ok(None)
}
(Aes128Ecb(encryptor), true) => {
Expand All @@ -233,8 +241,10 @@ impl Cipher {
Ok(None)
}
(Aes128Ecb(mut encryptor), false) => {
encryptor
.encrypt_block_b2b_mut(GenericArray::from_slice(input), GenericArray::from_mut_slice(output));
encryptor.encrypt_block_b2b_mut(
GenericArray::from_slice(input),
GenericArray::from_mut_slice(output),
);
Ok(None)
}
(Aes192Ecb(encryptor), true) => {
Expand All @@ -244,8 +254,10 @@ impl Cipher {
Ok(None)
}
(Aes192Ecb(mut encryptor), false) => {
encryptor
.encrypt_block_b2b_mut(GenericArray::from_slice(input), GenericArray::from_mut_slice(output));
encryptor.encrypt_block_b2b_mut(
GenericArray::from_slice(input),
GenericArray::from_mut_slice(output),
);
Ok(None)
}
(Aes256Ecb(encryptor), true) => {
Expand All @@ -255,8 +267,10 @@ impl Cipher {
Ok(None)
}
(Aes256Ecb(mut encryptor), false) => {
encryptor
.encrypt_block_b2b_mut(GenericArray::from_slice(input), GenericArray::from_mut_slice(output));
encryptor.encrypt_block_b2b_mut(
GenericArray::from_slice(input),
GenericArray::from_mut_slice(output),
);
Ok(None)
}
(Aes128Gcm(cipher), _) => Ok(Some(cipher.finish().to_vec())),
Expand All @@ -268,8 +282,10 @@ impl Cipher {
Ok(None)
}
(Aes256Cbc(mut encryptor), false) => {
encryptor
.encrypt_block_b2b_mut(GenericArray::from_slice(input), GenericArray::from_mut_slice(output));
encryptor.encrypt_block_b2b_mut(
GenericArray::from_slice(input),
GenericArray::from_mut_slice(output),
);
Ok(None)
}
}
Expand Down Expand Up @@ -372,63 +388,105 @@ 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) => {
let _ = 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) => {
let _ = 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(())
} else {
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(())
} else {
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(())
}
}
}
}
3 changes: 2 additions & 1 deletion ext/node/ops/crypto/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,14 +316,15 @@ pub fn op_node_decipheriv_decrypt(
pub fn op_node_decipheriv_final(
state: &mut OpState,
#[smi] rid: u32,
auto_pad: bool,
#[buffer] input: &[u8],
#[buffer] 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]
Expand Down
19 changes: 13 additions & 6 deletions ext/node/polyfills/internal/crypto/cipher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,8 @@ export class Decipheriv extends Transform implements Cipher {
/** DecipherContext resource id */
#context: number;

#autoPadding = true;

/** ciphertext data cache */
#cache: BlockModeCache;

Expand Down Expand Up @@ -339,18 +341,22 @@ export class Decipheriv extends Transform implements Cipher {
}

final(encoding: string = getDefaultEncoding()): Buffer | string {
if (!this.#needsBlockCache || this.#cache.cache.byteLength === 0) {
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);
}
Expand All @@ -370,8 +376,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(
Expand Down

0 comments on commit f1f202c

Please sign in to comment.