EVP_DecryptFinal_ex:bad 使用 Node.js 时解密
EVP_DecryptFinal_ex:bad decrypt when using Node.js
使用以下节点js:
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);
};
执行我运行这个:
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)
我对密码学还很陌生,所以真的不知道为什么会收到此错误。我只需要暂时修复它。
您混淆了两种不同的编码。参见
和
现在看看
var encrypted = cipher.update(data, 'binary') + cipher.final('binary');
但应该是
var encrypted = cipher.update(data, 'binary', 'binary') + cipher.final('binary');
问题是 cipher.update(data, 'binary')
输出的缓冲区会自动字符串化为十六进制编码的字符串,而不是 "binary" 字符串。
无论如何,这段代码有太多错误,您应该重新开始并简单地使用一个非常自以为是的现有库。
你必须有一个随机IV,它被添加到密文前面,以达到语义安全。
密码熵低,不能作为密钥使用。一次 MD5 调用不会改变这一事实。从密码派生密钥应该很慢,因此使用已知的方案,如 PBKDF2、bcrypt、scrypt 或 Argon2(提高安全性),具有高迭代 count/cost 因子。别忘了放盐。
在先加密后MAC方案中使用消息验证码(例如HMAC-SHA256)验证您的密文。否则,攻击者可能会操纵密文,而您甚至无法检测到更改。使用填充 oracle 攻击丢失数据的第一步。
我找到了原因,是使用不同的 key's 或 iv's 进行加密和解密。我们必须使用用于加密的相同密钥和 iv 来解密内容。唯一的解决方法是将 iv & key 保存在加密数据期间使用的数组中,或者借助分隔符
将 iv & key 与加密数据连接起来
示例一:
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
}
示例二:
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
}
因为这个问题是第一个出现在 Google 上的问题,所以这里有另一个解决方案。
万一 link 出现故障,就我而言,我必须更新解密功能以添加
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);
// Added this line here
decipher.setAutoPadding(false);
let decrypted = decipher.update(encryptedText);
decrypted = Buffer.concat([decrypted, decipher.final()]);
return decrypted.toString();
//returns decryptedData
}
使用以下节点js:
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);
};
执行我运行这个:
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)
我对密码学还很陌生,所以真的不知道为什么会收到此错误。我只需要暂时修复它。
您混淆了两种不同的编码。参见
和
现在看看
var encrypted = cipher.update(data, 'binary') + cipher.final('binary');
但应该是
var encrypted = cipher.update(data, 'binary', 'binary') + cipher.final('binary');
问题是 cipher.update(data, 'binary')
输出的缓冲区会自动字符串化为十六进制编码的字符串,而不是 "binary" 字符串。
无论如何,这段代码有太多错误,您应该重新开始并简单地使用一个非常自以为是的现有库。
你必须有一个随机IV,它被添加到密文前面,以达到语义安全。
密码熵低,不能作为密钥使用。一次 MD5 调用不会改变这一事实。从密码派生密钥应该很慢,因此使用已知的方案,如 PBKDF2、bcrypt、scrypt 或 Argon2(提高安全性),具有高迭代 count/cost 因子。别忘了放盐。
在先加密后MAC方案中使用消息验证码(例如HMAC-SHA256)验证您的密文。否则,攻击者可能会操纵密文,而您甚至无法检测到更改。使用填充 oracle 攻击丢失数据的第一步。
我找到了原因,是使用不同的 key's 或 iv's 进行加密和解密。我们必须使用用于加密的相同密钥和 iv 来解密内容。唯一的解决方法是将 iv & key 保存在加密数据期间使用的数组中,或者借助分隔符
将 iv & key 与加密数据连接起来示例一:
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
}
示例二:
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
}
因为这个问题是第一个出现在 Google 上的问题,所以这里有另一个解决方案。
万一 link 出现故障,就我而言,我必须更新解密功能以添加
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);
// Added this line here
decipher.setAutoPadding(false);
let decrypted = decipher.update(encryptedText);
decrypted = Buffer.concat([decrypted, decipher.final()]);
return decrypted.toString();
//returns decryptedData
}