解密AES256密码时出现“错误的最终块长度”错误

3

我遇到了与这个帖子中提到的问题完全相同,即在使用AES加密和解密时。

crypto.js:202
var ret = this._handle.final(); ^ Error: error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length
at Error (native)
at Decipher.Cipher.final (crypto.js:202:26)

这是我的加密和解密函数:

var config = {
cryptkey: crypto.createHash('sha256').update('Nixnogen').digest(),
iv: "a2xhcgAAAAAAAAAA"
};

function encryptText(text){
    console.log(config.cryptkey);
        var cipher = crypto.createCipheriv('aes-256-cbc', config.cryptkey, config.iv);
        var crypted = cipher.update(text,'utf8','binary');
        crypted += cipher.final('binary');
    crypted = new Buffer(crypted, 'binary').toString('base64');
        return crypted;
}

function decryptText(text){
    console.log(config.cryptkey);
        if (text === null || typeof text === 'undefined' || text === '') {return text;};
    text = new Buffer(text, 'base64').toString('binary');
        var decipher = crypto.createDecipheriv('aes-256-cbc', config.cryptkey, config.iv);
        var dec = decipher.update(text,'binary','utf8');
        dec += decipher.final('utf8');
        return dec;
}

我在我的package.json中设置了"node": ">=0.10.0"

有人能告诉我如何解决这个问题吗?我已经尝试了线程中提到的解决方案,但它们都对我不起作用。

更新:

我已经尝试了线程中提到的解决方案,但它们都对我不起作用。我认为可能有一个不同的解决方案,因此决定创建一个新的线程,而不是污染现有的线程。另外,如果我在现有的线程上继续进行,可能会混淆未来的候选人的正确解决方案。

更新2:

对于线程中提到的第二个解决方案,我有以下代码,但它也给我同样的错误:

function encryptText(text){
    console.log(config.cryptkey);
        var cipher = crypto.createCipheriv('aes-256-cbc', config.cryptkey, config.iv);
    return Buffer.concat([
        cipher.update(text),
        cipher.final()
    ]);
}

function decryptText(text){
    console.log(config.cryptkey);
        if (text === null || typeof text === 'undefined' || text === '') {return text;};
        var decipher = crypto.createDecipheriv('aes-256-cbc', config.cryptkey, config.iv);
    return Buffer.concat([
        decipher.update(text),
        decipher.final()
    ]);
}

此外,我正在使用这些函数作为mongoose中我的mongodb数据库字段的读取器和设置器。我认为这样做不会引起任何问题,但我仍然觉得提一下比较好。
更新3:
我正在尝试加密Facebook访问令牌并解密已加密的Facebook访问令牌。
要重现错误, 您可以尝试加密此令牌:
ASDFGHJKLO0cBACJDJoc25hkZAzcOfxhTBVpHRva4hnflYEwAHshZCi2qMihYXpS2fIDGsqAcAlfHLLo273OWImZAfo9TMYZCbuZABJkzPoo4HZA8HRJVCRACe6IunmBSMAEgGVv8KCLKIbL6Gf7HJy9PplEni2iJ06VoZBv0fKXUvkp1k7gWYMva1ZAyBsWiDiKChjq3Yh1ZCdWWEDRFGTHYJ
加密将正常工作,并且您将获得一个加密字符串。
现在尝试解密之前步骤中获得的加密字符串,您会收到错误提示。

你能提供更多可重现的情况吗?你使用的是哪个Node版本?你要加密的数据是什么?在一个短字符串上运行你的示例代码对我来说很好用。 - loganfsmyth
你能否尝试在加密后立即将crypted的值转换为十六进制,并将其与解密前的text进行比较,同样以十六进制表示?它们是否匹配?请使用第一个代码片段。 - Maarten Bodewes
是的,你说“你会得到一个加密字符串”,但除非该字符串是十六进制的,否则你的问题几乎肯定与如何将数据转换为字符串以及再次转换回来有关。加密数据是二进制的,不应该被视为字符串。这正是更新#2中的代码解决的问题所在。 - loganfsmyth
1
哪里有一个十六进制字符串?你的代码中没有将其转换为十六进制,这是我要说的一部分。我需要你在代码中提供一个100%可复现的示例。我已经多次要求提供一个完整的代码示例,但你只给出了一些只有在我自己摸索时才能复现的书面指导。如果你希望别人回答你的问题,就需要尽可能地提供帮助。请给我一些确切的JS代码,我可以运行以100%复现这个问题?不要使用mongoose,也不要添加其他东西,只需简单的JS代码。 - loganfsmyth
找到了问题。当我们使用mongoose在mongodb中进行更新时,它没有使用setter,在获取数据时却使用getter来解密文本。这个链接帮助我解决了这个问题 http://stackoverflow.com/questions/18837173/mongoose-setters-only-get-called-when-create-a-new-doc - dark_shadow
显示剩余11条评论
1个回答

6
这个问题已经两年了,但是因为有很多人看过,所以我希望这个答案仍然对那些可能遇到这个问题的人有用。
问题在于encryptText工作正常,但它并没有返回一个字符串,而是返回了一个Buffer。而decryptText期望得到一个字符串,不是一个Buffer,所以它试图像读取Buffer一样读取它,导致你收到了错误信息。
解决方法很简单。我们只需要在加密文本时将Buffer序列化为字符串,在解密文本时反序列化我们接收到的加密字符串即可。
在这个例子中,我使用base64编码,因为它在表示二进制数据时相当紧凑。
var config = {
  cryptkey: crypto.createHash('sha256').update('Nixnogen').digest(),
  iv: 'a2xhcgAAAAAAAAAA'
}

function encryptText (text) {
  console.log(config.cryptkey)
  var cipher = crypto.createCipheriv('aes-256-cbc', config.cryptkey, config.iv)
  return Buffer.concat([
    cipher.update(text),
    cipher.final()
  ]).toString('base64') // Output base64 string
}

function decryptText (text) {
  console.log(config.cryptkey)
  if (text === null || typeof text === 'undefined' || text === '') {
    return text
  }
  var decipher = crypto.createDecipheriv('aes-256-cbc', config.cryptkey, config.iv)
  return Buffer.concat([
    decipher.update(text, 'base64'), // Expect `text` to be a base64 string
    decipher.final()
  ]).toString()
}

var encrypted = encryptText('text') // 8xXuS7jLG6crqJFHHB5J5A==
var decrypted = decryptText(encrypted) // text

干得好,我花了几个小时才找到这个。 - LessQuesar
请问你能帮我解决这个问题吗?https://stackoverflow.com/questions/68287507/decrypting-selling-partner-api-reports - nats

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接