deno icon indicating copy to clipboard operation
deno copied to clipboard

Bug: Panic with deno `std/node/crypto` `createDecipheriv`

Open Dewep opened this issue 1 year ago • 1 comments

$> RUST_BACKTRACE=full deno run cipher.ts 
customData my-custom-data
cipherResult 3ffb093fd383730c2d4b75f066414ed1
decipherResult my-custom-data

============================================================
Deno has panicked. This is a bug in Deno. Please report this
at https://github.com/denoland/deno/issues/new.
If you can reliably reproduce this panic, include the
reproduction steps and re-run with the RUST_BACKTRACE=1 env
var set and include the backtrace in your report.

Platform: linux x86_64
Version: 1.45.2
Args: ["deno", "run", "cipher.ts"]

thread 'main' panicked at ext/node/ops/crypto/cipher.rs:399:9:
assertion failed: input.len() == 16
stack backtrace:
   0:     0x5c85148795c5 - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h1e1a1972118942ad
   1:     0x5c85148ac1db - core::fmt::write::hc090a2ffd6b28c4a
   2:     0x5c85148738df - std::io::Write::write_fmt::h8898bac6ff039a23
   3:     0x5c851487939e - std::sys_common::backtrace::print::ha96650907276675e
   4:     0x5c851487ad19 - std::panicking::default_hook::{{closure}}::h215c2a0a8346e0e0
   5:     0x5c851487aa5d - std::panicking::default_hook::h207342be97478370
   6:     0x5c8514decba3 - deno::setup_panic_hook::{{closure}}::h45bf1fb3ded7309c
   7:     0x5c851487b356 - std::panicking::rust_panic_with_hook::hac8bdceee1e4fe2c
   8:     0x5c851487b0cb - std::panicking::begin_panic_handler::{{closure}}::h00d785e82757ce3c
   9:     0x5c8514879a89 - std::sys_common::backtrace::__rust_end_short_backtrace::h1628d957bcd06996
  10:     0x5c851487ae37 - rust_begin_unwind
  11:     0x5c85148a9093 - core::panicking::panic_fmt::hdc63834ffaaefae5
  12:     0x5c85148a913c - core::panicking::panic::h75b3c9209f97d725
  13:     0x5c8515b3aa6c - deno_node::ops::crypto::cipher::DecipherContext::final::h9e91e645b7e4535e
  14:     0x5c8515bb0872 - deno_node::ops::crypto::op_node_decipheriv_final::op_node_decipheriv_final::v8_fn_ptr::h4ff7befea965f7fc
  15:     0x5c851467b6df - Builtins_CallApiCallbackGeneric

File cipher.ts:

import { randomBytes, createHash, createCipheriv, createDecipheriv } from 'node:crypto'
import { Buffer } from 'node:buffer'

// generate random iv/key hashes
const ivHash = randomBytes(21).toString('hex')
const keyHash = randomBytes(21).toString('hex')

const resizedIV = Buffer.allocUnsafe(16)
const iv = createHash('sha256').update(ivHash).digest()
iv.copy(resizedIV)
const key = createHash('sha256').update(keyHash).digest()

// Data to cipher
const customData = 'my-custom-data'
console.log('customData', customData)

// Cipher
const cipher = createCipheriv('aes256', key, resizedIV)
const cipherResult = [
  cipher.update(customData, 'binary', 'hex'),
  cipher.final('hex'),
].join('')
console.log('cipherResult', cipherResult)

// Normal decipher
const decipher = createDecipheriv('aes256', key, resizedIV)
const decipherResult = [
  decipher.update(cipherResult, 'hex', 'binary'),
  decipher.final('binary'),
].join('')
console.log('decipherResult', decipherResult)

// Incorrect decipher
try {
  const cipherBadResult = cipherResult.slice(0, cipherResult.length - 1)
  const decipher2 = createDecipheriv('aes256', key, resizedIV)
  const decipherBadResult = [
    decipher2.update(cipherBadResult, 'hex', 'binary'),
    decipher2.final('binary'),
  ].join('')
  console.log('decipherBadResult', decipherBadResult)
} catch (err) {
  console.warn('Unable to catch the error...', err)
}

When providing an incorrect data to the createDecipheriv, the .final('binary') is crashing deno, without being able to catch the error.

Deno is up to date (v1.45.2)

Dewep avatar Jul 13 '24 09:07 Dewep

Smaller file to reproduce the panic:

// deno run xxxx.ts
import { createHash, createDecipheriv } from 'node:crypto'
import { Buffer } from 'node:buffer'

const resizedIV = Buffer.allocUnsafe(16)
const iv = createHash('sha256').update('798aa3c053a45f3f3c6693caed03d197e04c415754').digest()
iv.copy(resizedIV)
const key = createHash('sha256').update('c95f6f9d2fe5193922a17d3ba4c1b9fa6df60bd05b').digest()

const decipher = createDecipheriv('aes256', key, resizedIV)
console.log('update', decipher.update('419de07673c2285e988962af979cebd', 'hex', 'binary'))
console.log('final', decipher.final('binary'))

Dewep avatar Jul 13 '24 09:07 Dewep

Fixed by #24957. This throws an error now:

$ deno -V
deno 1.45.5+8288434

$ node repro.mjs
update <Buffer d8 52 6d 63 bf c4 ac 7f e3 89 10 00 34 d4 f8 27>
node:internal/crypto/cipher:184
  const ret = this[kHandle].final();
                            ^

Error: error:1C80006B:Provider routines::wrong final block length
    at Decipheriv.final (node:internal/crypto/cipher:184:29)
    at file:///home/divy/gh/deno/repro.mjs:11:31
    at ModuleJob.run (node:internal/modules/esm/module_job:262:25)
    at async ModuleLoader.import (node:internal/modules/esm/loader:475:24)
    at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:109:5) {
  library: 'Provider routines',
  reason: 'wrong final block length',
  code: 'ERR_OSSL_WRONG_FINAL_BLOCK_LENGTH'
}

Node.js v22.2.0

$ deno run -A repro.mjs
update <Buffer d8 52 6d 63 bf c4 ac 7f e3 89 10 00 34 d4 f8 27>
error: Uncaught (in promise) Error: Invalid final block size
console.log('final', decipher.final('binary'))
                              ^
    at Decipheriv.final (ext:deno_node/internal/crypto/cipher.ts:159:13)
    at file:///home/divy/gh/deno/repro.mjs:11:31

littledivy avatar Aug 11 '24 05:08 littledivy