Node: crypto, bad decrypt

Created on 10 Sep 2015  路  13Comments  路  Source: nodejs/node

I have decrypt some string which was encrypt by 3des ecb,but fail.
for example:

var crypto = require('crypto');
var theCipher = "ccZmMULq3tlzAY+iafZz+96xz+qFsAuGpEjhN7CckJTcdBT03fgobfSVGCGYzILyPNSA3e3msUqHUTCpv8kRnWvFdLv9c+GTEhg+Lj5dOThGDHtkQX2j5bd6Eubw9/l+Lcwj0PeyW0ZoVkB5Nnp1yCnmKAn2Euliq+IurgthT+wln6cQmTjXfL4IB5VxwUEb72FcbeiCfbKxa+MxxbcQTCpli3ErSptwdp9on2k87JTPFqyyMmMRFA9VgOXpHNe43IwFzME01DyHZ+Rp/eQguTmY9FtkFIZeD2e2nrbbDbW6tlk/KOtdhGVIlIGMPNS5m8LYqlrGZlJU3JythEy+J0z1wW1owjVe9Yto2OtUe8WeKI744enBKAX4FnD4My7+/XRjbF5kf6loT9lqeMCdXFb3LDej3GVcKWbJuZjXmD4="
var key = "abcdefghijklmnopqrstuvwx"
var decrypt = crypto.createDecipheriv('des-ede3', key, "");
var s = decrypt.update(theCipher, 'base64', 'utf8');
console.log(s + decrypt.final('utf8'));

the orgin str is a utf8 string.
then it doesn't work:

Error: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
at Error (native)
at Decipheriv.Cipher.final (crypto.js:202:26)
at Object. (/usr/node/a.js:13:11)
at Module._compile (module.js:460:26)
at Object.Module._extensions..js (module.js:478:10)
at Module.load (module.js:355:32)
at Function.Module._load (module.js:310:12)
at Function.Module.runMain (module.js:501:10)
at startup (node.js:129:16)
at node.js:814:3

is there anything wrong? any body can help?

and I try something like this:

crypto question

Most helpful comment

Ok, so the problem is in padding. This is actually a common issue when users are encrypting in one language and decrypting in another. By default node uses PKCS padding, but Python uses null-byte padding instead. So calling decrypt.setAutoPadding(false); after you create the decipher instance will make it work as expected:

var crypto = require('crypto');
var theCipher = "ccZmMULq3tlzAY+iafZz+96xz+qFsAuGpEjhN7CckJTcdBT03fgobfSVGCGYzILyPNSA3e3msUqHUTCpv8kRnWvFdLv9c+GTEhg+Lj5dOThGDHtkQX2j5bd6Eubw9/l+Lcwj0PeyW0ZoVkB5Nnp1yCnmKAn2Euliq+IurgthT+wln6cQmTjXfL4IB5VxwUEb72FcbeiCfbKxa+MxxbcQTCpli3ErSptwdp9on2k87JTPFqyyMmMRFA9VgOXpHNe43IwFzME01DyHZ+Rp/eQguTmY9FtkFIZeD2e2nrbbDbW6tlk/KOtdhGVIlIGMPNS5m8LYqlrGZlJU3JythEy+J0z1wW1owjVe9Yto2OtUe8WeKI744enBKAX4FnD4My7+/XRjbF5kf6loT9lqeMCdXFb3LDej3GVcKWbJuZjXmD4="
var key = "abcdefghijklmnopqrstuvwx"
var decrypt = crypto.createDecipheriv('des-ede3', key, "");
decrypt.setAutoPadding(false);
var s = decrypt.update(theCipher, 'base64', 'utf8');
console.log(s + decrypt.final('utf8'));

All 13 comments

Have you verified that the key is correct? I think it may be wrong.

For example, this works just fine:

var key = "abcdefghijklmnopqrstuvwx";

var pt = "hello world!";

var encrypt = crypto.createCipheriv('des-ede3', key, "");
var theCipher = encrypt.update(pt, 'utf8', 'base64');
theCipher += encrypt.final('base64');

var decrypt = crypto.createDecipheriv('des-ede3', key, "");
var s = decrypt.update(theCipher, 'base64', 'utf8');
console.log(s + decrypt.final('utf8'));
// outputs:
// hello world!

@mscdex thinks a lot for helping me!
yes, when I encrypt in nodejs is correct, I can decrypt as your code.
actually, the encrypt code is python, the key is ok! code like this:

from Crypto.Cipher import DES3
import base64
pt = "hello world!"
APPKEY = "abcdefghijklmnopqrstuvwx"
DES3_CIPHER = DES3.new(APPKEY, DES3.MODE_ECB)
cipher = DES3_CIPHER.encrypt(pt)
result = base64.b64encode(cipher)

I have read the python crypto's code, and found nothing special.
send the result to nodejs through http. and decrypt like before, and failed.
maybe there is something different from python and nodejs.
In python, the result can be decrypt like this:

str = base64.b64decode(result)
origin = DES3_CIPHER.decrypt(str)

but I have to decrypt it in nodejs. what a pity!
thanks again for helping me!

Ok, so the problem is in padding. This is actually a common issue when users are encrypting in one language and decrypting in another. By default node uses PKCS padding, but Python uses null-byte padding instead. So calling decrypt.setAutoPadding(false); after you create the decipher instance will make it work as expected:

var crypto = require('crypto');
var theCipher = "ccZmMULq3tlzAY+iafZz+96xz+qFsAuGpEjhN7CckJTcdBT03fgobfSVGCGYzILyPNSA3e3msUqHUTCpv8kRnWvFdLv9c+GTEhg+Lj5dOThGDHtkQX2j5bd6Eubw9/l+Lcwj0PeyW0ZoVkB5Nnp1yCnmKAn2Euliq+IurgthT+wln6cQmTjXfL4IB5VxwUEb72FcbeiCfbKxa+MxxbcQTCpli3ErSptwdp9on2k87JTPFqyyMmMRFA9VgOXpHNe43IwFzME01DyHZ+Rp/eQguTmY9FtkFIZeD2e2nrbbDbW6tlk/KOtdhGVIlIGMPNS5m8LYqlrGZlJU3JythEy+J0z1wW1owjVe9Yto2OtUe8WeKI744enBKAX4FnD4My7+/XRjbF5kf6loT9lqeMCdXFb3LDej3GVcKWbJuZjXmD4="
var key = "abcdefghijklmnopqrstuvwx"
var decrypt = crypto.createDecipheriv('des-ede3', key, "");
decrypt.setAutoPadding(false);
var s = decrypt.update(theCipher, 'base64', 'utf8');
console.log(s + decrypt.final('utf8'));

thanks a lot!
it works!!!!!
nodejs commune is excellect!

The docs are at https://github.com/nodejs/node/blob/master/doc/api/crypto.markdown#ciphersetautopaddingauto_paddingtrue and they do indeed mention null padding as "non-standard padding". I didn't see any obvious necessary edits to those docs.

that's ok! I have read the docs many time, I just don't know python crypt default padding mode, so it's not a nodejs question!
thanks for focusing!

let iv = ""; let cipher = crypto.createCipheriv(algorithm, key, iv);
maybe u can try this, add a vector

@nokisnojok Can you open a new issue if you think you found a bug? Please update the test so it fails where you expect it to pass.

We have had issues with the same kind of issue but between Windows and MAC when encrypting/decrypting.
Adding the decrypt.setAutoPadding(false); as suggested above adds four EOT characters (hex: 0A) to the end of the decrypted file.
Logging out the data to encrypt no EOT characters are present so they are added in the encrypt or the decrypt stages. I have no clue where they come from and it only happens if you encrypt on Windows and decrypt on MAC or v.v.

Same here. I get Error: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt

If I add setAutoPadding(false) I just get Error: incorrect header check at Unzip.zlibOnError (zlib.js:153:15) instead.

Currently this system is used and is working in PHP, same user and password, and I'm trying to port it over to nodejs using opentoken 1.0.12 link.

I'm running LTS v10.15.3

My solution:
In the line where I perform the encryption and decrypt procedure: decrypt.update (text)
I added the following: decrypt.update (text, 'binary')
Then everything went alright o /

odiegovalin

My solution:
In the line where I perform the encryption and decrypt procedure: decrypt.update (text)
I added the following: decrypt.update (text, 'binary')
Then everything went alright o /

odiegovalin

Just here?

var decipher = crypto.createDecipheriv(cipher, decryptionKey, iv);
decipher.setAutoPadding(false); // automatically remove PKCS padding
var zd1 = decipher.update(payloadCipherText, 'binary');

All that seems to do is make it presume a String as input, which it converts to Binary, and then returns a Buffer. Since it defaults to Binary input and returns a Buffer I don't see what difference that makes...

Just in case it helps, I came across the bad decrypt error when writing an SNMPv3 library (https://github.com/markabrahams/node-net-snmp) and testing against the Linux Net-SNMP agent. Not exactly the same conditions (I was using DES-CBC with Buffers), but the fix I employed may help someone.

I found that decipher.setAutoPadding(false) caused failure in cases where the decipher.final() would be successful, but was required in the case where decipher.final() would fail without it (this would happen about 10% of the time - possibly 1 in 8 according to plaintext lengths but I didn't completely verify that). So the workaround code I employed was:

decipher = crypto.createDecipheriv (cbcProtocol, decryptionKey, iv);
decryptedPdu = decipher.update (encryptedPdu);
// This try-catch is a workaround for a seemingly incorrect error condition
// - where sometimes a decrypt error is thrown with decipher.final()
// It replaces this line which should have been sufficient:
// decryptedPdu = Buffer.concat ([decryptedPdu, decipher.final()]);
try {
    decryptedPdu = Buffer.concat ([decryptedPdu, decipher.final()]);
} catch (error) {
    // console.log("Decrypt error: " + error);
    // Try again with auto padding disabled
    decipher = crypto.createDecipheriv (cbcProtocol, decryptionKey, iv);
    decipher.setAutoPadding(false);
    decryptedPdu = decipher.update (encryptedPdu);
    decryptedPdu = Buffer.concat ([decryptedPdu, decipher.final()]);
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

vsemozhetbyt picture vsemozhetbyt  路  3Comments

ksushilmaurya picture ksushilmaurya  路  3Comments

sandeepks1 picture sandeepks1  路  3Comments

willnwhite picture willnwhite  路  3Comments

fanjunzhi picture fanjunzhi  路  3Comments