Skip to content

Commit 0d1beed

Browse files
fix(ext/node): add CipherIv.setAutoPadding() (#24940)
Co-Authored-By: Luca Casonato <[email protected]> Fixes #21804 Ref #20924 --------- Signed-off-by: Divy Srivastava <[email protected]> Co-authored-by: Luca Casonato <[email protected]>
1 parent 2f6da40 commit 0d1beed

File tree

4 files changed

+146
-31
lines changed

4 files changed

+146
-31
lines changed

ext/node/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ deno_core::extension!(deno_node,
232232
ops::crypto::op_node_decipheriv_decrypt,
233233
ops::crypto::op_node_decipheriv_final,
234234
ops::crypto::op_node_decipheriv_set_aad,
235+
ops::crypto::op_node_decipheriv_take,
235236
ops::crypto::op_node_dh_compute_secret,
236237
ops::crypto::op_node_diffie_hellman,
237238
ops::crypto::op_node_ecdh_compute_public_key,

ext/node/ops/crypto/cipher.rs

Lines changed: 104 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use aes::cipher::KeyIvInit;
77
use deno_core::error::type_error;
88
use deno_core::error::AnyError;
99
use deno_core::Resource;
10+
use digest::generic_array::GenericArray;
1011
use digest::KeyInit;
1112

1213
use std::borrow::Cow;
@@ -65,13 +66,14 @@ impl CipherContext {
6566

6667
pub fn r#final(
6768
self,
69+
auto_pad: bool,
6870
input: &[u8],
6971
output: &mut [u8],
7072
) -> Result<Tag, AnyError> {
7173
Rc::try_unwrap(self.cipher)
7274
.map_err(|_| type_error("Cipher context is already in use"))?
7375
.into_inner()
74-
.r#final(input, output)
76+
.r#final(auto_pad, input, output)
7577
}
7678
}
7779

@@ -92,14 +94,15 @@ impl DecipherContext {
9294

9395
pub fn r#final(
9496
self,
97+
auto_pad: bool,
9598
input: &[u8],
9699
output: &mut [u8],
97100
auth_tag: &[u8],
98101
) -> Result<(), AnyError> {
99102
Rc::try_unwrap(self.decipher)
100103
.map_err(|_| type_error("Decipher context is already in use"))?
101104
.into_inner()
102-
.r#final(input, output, auth_tag)
105+
.r#final(auto_pad, input, output, auth_tag)
103106
}
104107
}
105108

@@ -209,42 +212,82 @@ impl Cipher {
209212
}
210213

211214
/// r#final encrypts the last block of the input data.
212-
fn r#final(self, input: &[u8], output: &mut [u8]) -> Result<Tag, AnyError> {
215+
fn r#final(
216+
self,
217+
auto_pad: bool,
218+
input: &[u8],
219+
output: &mut [u8],
220+
) -> Result<Tag, AnyError> {
213221
assert!(input.len() < 16);
214222
use Cipher::*;
215-
match self {
216-
Aes128Cbc(encryptor) => {
223+
match (self, auto_pad) {
224+
(Aes128Cbc(encryptor), true) => {
217225
let _ = (*encryptor)
218226
.encrypt_padded_b2b_mut::<Pkcs7>(input, output)
219227
.map_err(|_| type_error("Cannot pad the input data"))?;
220228
Ok(None)
221229
}
222-
Aes128Ecb(encryptor) => {
230+
(Aes128Cbc(mut encryptor), false) => {
231+
encryptor.encrypt_block_b2b_mut(
232+
GenericArray::from_slice(input),
233+
GenericArray::from_mut_slice(output),
234+
);
235+
Ok(None)
236+
}
237+
(Aes128Ecb(encryptor), true) => {
223238
let _ = (*encryptor)
224239
.encrypt_padded_b2b_mut::<Pkcs7>(input, output)
225240
.map_err(|_| type_error("Cannot pad the input data"))?;
226241
Ok(None)
227242
}
228-
Aes192Ecb(encryptor) => {
243+
(Aes128Ecb(mut encryptor), false) => {
244+
encryptor.encrypt_block_b2b_mut(
245+
GenericArray::from_slice(input),
246+
GenericArray::from_mut_slice(output),
247+
);
248+
Ok(None)
249+
}
250+
(Aes192Ecb(encryptor), true) => {
229251
let _ = (*encryptor)
230252
.encrypt_padded_b2b_mut::<Pkcs7>(input, output)
231253
.map_err(|_| type_error("Cannot pad the input data"))?;
232254
Ok(None)
233255
}
234-
Aes256Ecb(encryptor) => {
256+
(Aes192Ecb(mut encryptor), false) => {
257+
encryptor.encrypt_block_b2b_mut(
258+
GenericArray::from_slice(input),
259+
GenericArray::from_mut_slice(output),
260+
);
261+
Ok(None)
262+
}
263+
(Aes256Ecb(encryptor), true) => {
235264
let _ = (*encryptor)
236265
.encrypt_padded_b2b_mut::<Pkcs7>(input, output)
237266
.map_err(|_| type_error("Cannot pad the input data"))?;
238267
Ok(None)
239268
}
240-
Aes128Gcm(cipher) => Ok(Some(cipher.finish().to_vec())),
241-
Aes256Gcm(cipher) => Ok(Some(cipher.finish().to_vec())),
242-
Aes256Cbc(encryptor) => {
269+
(Aes256Ecb(mut encryptor), false) => {
270+
encryptor.encrypt_block_b2b_mut(
271+
GenericArray::from_slice(input),
272+
GenericArray::from_mut_slice(output),
273+
);
274+
Ok(None)
275+
}
276+
(Aes128Gcm(cipher), _) => Ok(Some(cipher.finish().to_vec())),
277+
(Aes256Gcm(cipher), _) => Ok(Some(cipher.finish().to_vec())),
278+
(Aes256Cbc(encryptor), true) => {
243279
let _ = (*encryptor)
244280
.encrypt_padded_b2b_mut::<Pkcs7>(input, output)
245281
.map_err(|_| type_error("Cannot pad the input data"))?;
246282
Ok(None)
247283
}
284+
(Aes256Cbc(mut encryptor), false) => {
285+
encryptor.encrypt_block_b2b_mut(
286+
GenericArray::from_slice(input),
287+
GenericArray::from_mut_slice(output),
288+
);
289+
Ok(None)
290+
}
248291
}
249292
}
250293
}
@@ -345,63 +388,105 @@ impl Decipher {
345388
/// r#final decrypts the last block of the input data.
346389
fn r#final(
347390
self,
391+
auto_pad: bool,
348392
input: &[u8],
349393
output: &mut [u8],
350394
auth_tag: &[u8],
351395
) -> Result<(), AnyError> {
352396
use Decipher::*;
353-
match self {
354-
Aes128Cbc(decryptor) => {
397+
match (self, auto_pad) {
398+
(Aes128Cbc(decryptor), true) => {
355399
assert!(input.len() == 16);
356400
let _ = (*decryptor)
357401
.decrypt_padded_b2b_mut::<Pkcs7>(input, output)
358402
.map_err(|_| type_error("Cannot unpad the input data"))?;
359403
Ok(())
360404
}
361-
Aes128Ecb(decryptor) => {
405+
(Aes128Cbc(mut decryptor), false) => {
406+
decryptor.decrypt_block_b2b_mut(
407+
GenericArray::from_slice(input),
408+
GenericArray::from_mut_slice(output),
409+
);
410+
Ok(())
411+
}
412+
(Aes128Ecb(decryptor), true) => {
362413
assert!(input.len() == 16);
363414
let _ = (*decryptor)
364415
.decrypt_padded_b2b_mut::<Pkcs7>(input, output)
365416
.map_err(|_| type_error("Cannot unpad the input data"))?;
366417
Ok(())
367418
}
368-
Aes192Ecb(decryptor) => {
419+
(Aes128Ecb(mut decryptor), false) => {
420+
decryptor.decrypt_block_b2b_mut(
421+
GenericArray::from_slice(input),
422+
GenericArray::from_mut_slice(output),
423+
);
424+
Ok(())
425+
}
426+
(Aes192Ecb(decryptor), true) => {
369427
assert!(input.len() == 16);
370428
let _ = (*decryptor)
371429
.decrypt_padded_b2b_mut::<Pkcs7>(input, output)
372430
.map_err(|_| type_error("Cannot unpad the input data"))?;
373431
Ok(())
374432
}
375-
Aes256Ecb(decryptor) => {
433+
(Aes192Ecb(mut decryptor), false) => {
434+
decryptor.decrypt_block_b2b_mut(
435+
GenericArray::from_slice(input),
436+
GenericArray::from_mut_slice(output),
437+
);
438+
Ok(())
439+
}
440+
(Aes256Ecb(decryptor), true) => {
376441
assert!(input.len() == 16);
377442
let _ = (*decryptor)
378443
.decrypt_padded_b2b_mut::<Pkcs7>(input, output)
379444
.map_err(|_| type_error("Cannot unpad the input data"))?;
380445
Ok(())
381446
}
382-
Aes128Gcm(decipher) => {
447+
(Aes256Ecb(mut decryptor), false) => {
448+
decryptor.decrypt_block_b2b_mut(
449+
GenericArray::from_slice(input),
450+
GenericArray::from_mut_slice(output),
451+
);
452+
Ok(())
453+
}
454+
(Aes128Gcm(decipher), true) => {
383455
let tag = decipher.finish();
384456
if tag.as_slice() == auth_tag {
385457
Ok(())
386458
} else {
387459
Err(type_error("Failed to authenticate data"))
388460
}
389461
}
390-
Aes256Gcm(decipher) => {
462+
(Aes128Gcm(_), false) => Err(type_error(
463+
"setAutoPadding(false) not supported for Aes256Gcm yet",
464+
)),
465+
(Aes256Gcm(decipher), true) => {
391466
let tag = decipher.finish();
392467
if tag.as_slice() == auth_tag {
393468
Ok(())
394469
} else {
395470
Err(type_error("Failed to authenticate data"))
396471
}
397472
}
398-
Aes256Cbc(decryptor) => {
473+
(Aes256Gcm(_), false) => Err(type_error(
474+
"setAutoPadding(false) not supported for Aes256Gcm yet",
475+
)),
476+
(Aes256Cbc(decryptor), true) => {
399477
assert!(input.len() == 16);
400478
let _ = (*decryptor)
401479
.decrypt_padded_b2b_mut::<Pkcs7>(input, output)
402480
.map_err(|_| type_error("Cannot unpad the input data"))?;
403481
Ok(())
404482
}
483+
(Aes256Cbc(mut decryptor), false) => {
484+
decryptor.decrypt_block_b2b_mut(
485+
GenericArray::from_slice(input),
486+
GenericArray::from_mut_slice(output),
487+
);
488+
Ok(())
489+
}
405490
}
406491
}
407492
}

ext/node/ops/crypto/mod.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -262,13 +262,14 @@ pub fn op_node_cipheriv_encrypt(
262262
pub fn op_node_cipheriv_final(
263263
state: &mut OpState,
264264
#[smi] rid: u32,
265+
auto_pad: bool,
265266
#[buffer] input: &[u8],
266-
#[buffer] output: &mut [u8],
267+
#[anybuffer] output: &mut [u8],
267268
) -> Result<Option<Vec<u8>>, AnyError> {
268269
let context = state.resource_table.take::<cipher::CipherContext>(rid)?;
269270
let context = Rc::try_unwrap(context)
270271
.map_err(|_| type_error("Cipher context is already in use"))?;
271-
context.r#final(input, output)
272+
context.r#final(auto_pad, input, output)
272273
}
273274

274275
#[op2(fast)]
@@ -317,17 +318,29 @@ pub fn op_node_decipheriv_decrypt(
317318
}
318319

319320
#[op2(fast)]
321+
pub fn op_node_decipheriv_take(
322+
state: &mut OpState,
323+
#[smi] rid: u32,
324+
) -> Result<(), AnyError> {
325+
let context = state.resource_table.take::<cipher::DecipherContext>(rid)?;
326+
Rc::try_unwrap(context)
327+
.map_err(|_| type_error("Cipher context is already in use"))?;
328+
Ok(())
329+
}
330+
331+
#[op2]
320332
pub fn op_node_decipheriv_final(
321333
state: &mut OpState,
322334
#[smi] rid: u32,
335+
auto_pad: bool,
323336
#[buffer] input: &[u8],
324-
#[buffer] output: &mut [u8],
337+
#[anybuffer] output: &mut [u8],
325338
#[buffer] auth_tag: &[u8],
326339
) -> Result<(), AnyError> {
327340
let context = state.resource_table.take::<cipher::DecipherContext>(rid)?;
328341
let context = Rc::try_unwrap(context)
329342
.map_err(|_| type_error("Cipher context is already in use"))?;
330-
context.r#final(input, output, auth_tag)
343+
context.r#final(auto_pad, input, output, auth_tag)
331344
}
332345

333346
#[op2]

ext/node/polyfills/internal/crypto/cipher.ts

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
op_node_decipheriv_decrypt,
1818
op_node_decipheriv_final,
1919
op_node_decipheriv_set_aad,
20+
op_node_decipheriv_take,
2021
op_node_private_decrypt,
2122
op_node_private_encrypt,
2223
op_node_public_encrypt,
@@ -163,6 +164,8 @@ export class Cipheriv extends Transform implements Cipher {
163164

164165
#authTag?: Buffer;
165166

167+
#autoPadding = true;
168+
166169
constructor(
167170
cipher: string,
168171
key: CipherKey,
@@ -191,8 +194,13 @@ export class Cipheriv extends Transform implements Cipher {
191194

192195
final(encoding: string = getDefaultEncoding()): Buffer | string {
193196
const buf = new Buffer(16);
197+
198+
if (!this.#autoPadding && this.#cache.cache.byteLength != 16) {
199+
throw new Error("Invalid final block size");
200+
}
194201
const maybeTag = op_node_cipheriv_final(
195202
this.#context,
203+
this.#autoPadding,
196204
this.#cache.cache,
197205
buf,
198206
);
@@ -217,8 +225,8 @@ export class Cipheriv extends Transform implements Cipher {
217225
return this;
218226
}
219227

220-
setAutoPadding(_autoPadding?: boolean): this {
221-
notImplemented("crypto.Cipheriv.prototype.setAutoPadding");
228+
setAutoPadding(autoPadding?: boolean): this {
229+
this.#autoPadding = !!autoPadding;
222230
return this;
223231
}
224232

@@ -299,6 +307,8 @@ export class Decipheriv extends Transform implements Cipher {
299307
/** DecipherContext resource id */
300308
#context: number;
301309

310+
#autoPadding = true;
311+
302312
/** ciphertext data cache */
303313
#cache: BlockModeCache;
304314

@@ -333,18 +343,23 @@ export class Decipheriv extends Transform implements Cipher {
333343
}
334344

335345
final(encoding: string = getDefaultEncoding()): Buffer | string {
346+
if (!this.#needsBlockCache || this.#cache.cache.byteLength === 0) {
347+
op_node_decipheriv_take(this.#context);
348+
return encoding === "buffer" ? Buffer.from([]) : "";
349+
}
350+
if (this.#cache.cache.byteLength != 16) {
351+
throw new Error("Invalid final block size");
352+
}
353+
336354
let buf = new Buffer(16);
337355
op_node_decipheriv_final(
338356
this.#context,
357+
this.#autoPadding,
339358
this.#cache.cache,
340359
buf,
341360
this.#authTag || NO_TAG,
342361
);
343362

344-
if (!this.#needsBlockCache) {
345-
return encoding === "buffer" ? Buffer.from([]) : "";
346-
}
347-
348363
buf = buf.subarray(0, 16 - buf.at(-1)); // Padded in Pkcs7 mode
349364
return encoding === "buffer" ? buf : buf.toString(encoding);
350365
}
@@ -364,8 +379,9 @@ export class Decipheriv extends Transform implements Cipher {
364379
return this;
365380
}
366381

367-
setAutoPadding(_autoPadding?: boolean): this {
368-
notImplemented("crypto.Decipheriv.prototype.setAutoPadding");
382+
setAutoPadding(autoPadding?: boolean): this {
383+
this.#autoPadding = Boolean(autoPadding);
384+
return this;
369385
}
370386

371387
update(

0 commit comments

Comments
 (0)