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>