EVP_DecryptFinal_ex:bad decrypt when using Node.js
使用以下节点js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | var crypto = require('crypto'); var encrypt = function (input, password, callback) { var m = crypto.createHash('md5'); m.update(password); var key = m.digest('hex'); m = crypto.createHash('md5'); m.update(password + key); var iv = m.digest('hex'); console.log(iv); var data = new Buffer(input, 'utf8').toString('binary'); var cipher = crypto.createCipheriv('aes-256-cbc', key, iv.slice(0,16)); var encrypted = cipher.update(data, 'binary') + cipher.final('binary'); var encoded = new Buffer(encrypted, 'binary').toString('base64'); callback(encoded); }; var decrypt = function (input, password, callback) { // Convert urlsafe base64 to normal base64 input = input.replace(/\-/g, '+').replace(/_/g, '/'); // Convert from base64 to binary string var edata = new Buffer(input, 'base64').toString('binary'); // Create key from password var m = crypto.createHash('md5'); m.update(password); var key = m.digest('hex'); // Create iv from password and key m = crypto.createHash('md5'); m.update(password + key); var iv = m.digest('hex'); // Decipher encrypted data var decipher = crypto.createDecipheriv('aes-256-cbc', key, iv.slice(0,16)); var decrypted = decipher.update(edata, 'binary') + decipher.final('binary'); var plaintext = new Buffer(decrypted, 'binary').toString('utf8'); callback(plaintext); }; |
为了执行,我运行了这个:
1 2 3 4 5 6 | encrypt("uWeShxRrCKyK4pcs","secret", function (encoded) { console.log(encoded); decrypt(encoded,"secret", function (output) { console.log(output); }); }); |
加密似乎可以正常工作,但是当我尝试解密时,出现以下错误:
Error: error:06065064:digital envelope
routines:EVP_DecryptFinal_ex:bad decrypt
at Error (native)
at Decipheriv.Cipher.final (crypto.js:202:26)
我对密码学还很陌生,所以不知道为什么会收到此错误。 我现在只需要修复它。
您混合了两种不同的编码。看到
cipher.update(data[, input_encoding][, output_encoding])
和
cipher.final([output_encoding])
现在看看
1 | var encrypted = cipher.update(data, 'binary') + cipher.final('binary'); |
但应该是
1 | var encrypted = cipher.update(data, 'binary', 'binary') + cipher.final('binary'); |
问题是
无论如何,此代码有太多错误,您应该重新开始并仅使用经过高度评价的现有库。
-
为了达到语义安全性,您必须在密码文本之前添加一个随机IV。
-
密码的熵值较低,因此不能用作密钥。一次MD5调用不会改变这一事实。假定从密码派生密钥很慢,因此请使用已知的方案,例如PBKDF2,bcrypt,scrypt或Argon2(提高安全性),并具有较高的迭代计数/成本因子。不要忘记盐。
-
使用消息加密代码(例如HMAC-SHA256)以加密-然后-MAC方案对密文进行身份验证。否则,攻击者可能会操纵密文,您甚至无法检测到更改。使用填充Oracle攻击来丢失数据的第一步。
我发现原因是使用不同的密钥或iv进行加密和解密。我们必须使用与加密相同的密钥和iv来解密内容。唯一的解决方法是将iv和密钥保存在加密数据时使用的数组中,或者借助分隔符将iv&密钥与加密数据并置
范例一:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | function encrypt(text) { let cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(key), iv); let encrypted = cipher.update(text); encrypted = Buffer.concat([encrypted, cipher.final()]); return encrypted.toString('hex') + ':' + iv.toString('hex') + '=' + key.toString('hex'); //returns encryptedData:iv=key } function decrypt(text) { let iv = Buffer.from((text.split(':')[1]).split('=')[0], 'hex')//will return iv; let enKey = Buffer.from(text.split('=')[1], 'hex')//will return key; let encryptedText = Buffer.from(text.split(':')[0], 'hex');//returns encrypted Data let decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(enKey), iv); let decrypted = decipher.update(encryptedText); decrypted = Buffer.concat([decrypted, decipher.final()]); return decrypted.toString(); //returns decryptedData } |
示例二:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | function encrypt(text) { let cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(key), iv); let encrypted = cipher.update(text); encrypted = Buffer.concat([encrypted, cipher.final()]); return { "encryptedData": encrypted.toString('hex'), "iv" : iv.toString('hex'), "key" : key.toString('hex'); //returns an Array of key, iv & encryptedData } } function decrypt(text) { let iv = Buffer.from((text.iv, 'hex')//will return iv; let enKey = Buffer.from(text.key, 'hex')//will return key; let encryptedText = Buffer.from(text.encryptedData, 'hex');//returns encrypted Data let decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(enKey), iv); let decrypted = decipher.update(encryptedText); decrypted = Buffer.concat([decrypted, decipher.final()]); return decrypted.toString(); //returns decryptedData } |