Home > Net >  Decrypting AES-256-CBC Cipher using Node.js
Decrypting AES-256-CBC Cipher using Node.js

Time:07-06

I'm trying to decrypt an AES-256-CBC ciphertext from a web service using Node.js but can't seem to make it work and honestly lost.

  const raw = `{
    "iv":"uUwGJgxslfYiahji3 e2jA==",
    "docMimeType":"text\/xml",
    "doc":"1XLjWZlMMrgcpR6QtfwExQSOOPag1BJZTo1QEkcDrY6PFesWoVw8xrbHFsEYyMVDeemzk 5kBnb3\r\nqBmcUtkSFs7zDsxjYZkkEU9nyq1jXFz99fGylIealw37FPMaK0gviXESRO5AHMs46tpgSQcuWX0Z\r\nV7 mnTvjmaRHi4p1Cvg8aYfDO1aIWWWjAwOTCyopyCwribbGoEdiYDc5pERHpw=="
  }`;

  const cleanedEncryptedDataAsJsonStr = raw.replace(/\r?\n|\r/g, " ")

  const data = JSON.parse(cleanedEncryptedDataAsJsonStr)
  const ivBase64 = data.iv
  const iv = Buffer.from(ivBase64, 'base64').toString('hex').substring(0, 16)

  const plainKey = 'PHilheaLthDuMmyciPHerKeyS'
  const hashKey = crypto.createHash('sha256');
  hashKey.update(plainKey)
  const key = hashKey.digest('hex').substring(0, 32)

  let encrypted = Buffer.from(data.doc, 'base64').toString('hex')
  const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv)
  let decrypted = decipher.update(encrypted, 'hex', 'utf-8')
  decrypted  = decipher.final('utf-8')

so I'm receiving a json object which contains the iv and the encrypted data(doc), and I have a copy of the cipher key which according to the docs needs to be hashed during the decryption.

doc: base64 encoding of the encrypted data
iv: base64 encoded value of initialization vector during encryption

When I run my code, the error is:
Error: error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length and also not sure on how to handle \r\n in the raw json string.

The decrypted message should be:
<eEMPLOYERS ASOF="07-02-2022"><employer pPEN="110474000002" pEmployerName="JOSE A TERAMOTO ODM" pEmployerAddress="ORANBO, PASIG CITY"/></eEMPLOYERS

CodePudding user response:

There are the following issues in the code:

  • IV and key must not be hex encoded.
  • The default PKCS#7 padding must be disabled since Zero padding was applied during encryption (if desired, explicitly remove the trailing 0x00 padding bytes).

Fixed code:

var crypto = require('crypto')

const raw = `{
    "iv":"uUwGJgxslfYiahji3 e2jA==",
    "docMimeType":"text\/xml",
    "doc":"1XLjWZlMMrgcpR6QtfwExQSOOPag1BJZTo1QEkcDrY6PFesWoVw8xrbHFsEYyMVDeemzk 5kBnb3\r\nqBmcUtkSFs7zDsxjYZkkEU9nyq1jXFz99fGylIealw37FPMaK0gviXESRO5AHMs46tpgSQcuWX0Z\r\nV7 mnTvjmaRHi4p1Cvg8aYfDO1aIWWWjAwOTCyopyCwribbGoEdiYDc5pERHpw=="
  }`;

const cleanedEncryptedDataAsJsonStr = raw.replace(/\r?\n|\r/g, " ") 

const data = JSON.parse(cleanedEncryptedDataAsJsonStr)
const ivBase64 = data.iv
const iv = Buffer.from(ivBase64, 'base64') // .toString('hex').substring(0, 16) // Fix 1: no hex encoding

const plainKey = 'PHilheaLthDuMmyciPHerKeyS'
const hashKey = crypto.createHash('sha256')
hashKey.update(plainKey)
const key = hashKey.digest() // .digest('hex').substring(0, 32) // Fix 2: no hex encoding

let encrypted = Buffer.from(data.doc, 'base64').toString('hex')
const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv)
decipher.setAutoPadding(false) // Fix 3: disable default PKCS#7 padding
let decrypted = decipher.update(encrypted, 'hex', 'utf-8')
decrypted  = decipher.final('utf-8')

console.log(decrypted) // plaintext zero-padded, if necessary remove trailing 0x00 values, e.g. as in the following:
console.log(decrypted.replace(new RegExp("\0 $"), "")) // <eEMPLOYERS ESOF="07-02-2022"><employer pPEN="110474000002" pEmployerName="JOSE A TERAMOTO ODM" pEmployerAddress="ORANBO, PASIG CITY"/></eEMPLOYERS>
  • Related