如果密码错误,Node 的加密解密是否总是会抛出错误?

Does Node's crypto decipher always throw an error if the password is wrong?

我正在创建一个类似游戏的小功能以供娱乐(因此不需要超级安全)。

在服务器上,我使用秘密密码加密:

const key = crypto.createCipher('aes-256-cbc', 'secret')
let encryption = key.update('cheerio', 'utf8', 'hex')
encryption += key.final('hex')

在客户端,我希望用户猜测密码(在这个例子中是secret),像这样:

try {
    const key = crypto.createDecipher('aes-256-cbc', guess)
    let decryption = key.update(encryption, 'hex', 'utf8')
    decryption += key.final('utf8')
 }
catch(err) {
    console.log("err", err)
 }

问题是,如果 guess 失败,这个 总是 会抛出错误,还是我需要将它与我的短语 ('cheerio' )? (我还没有猜到不会引发错误的东西。)

我觉得前者会提供额外的安全层,因为这样既有密码又有密码,而如果我在客户端进行比较,密码就会暴露在代码中。

不,当guess失败时并不总是产生错误。

错误原因(error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt),是解密时填充错误,here. The crypto module uses PKCS7 padding by default. In this padding variant each padding byte has the value that corresponds to the number of padding bytes, e.g. 01, 0202, 030303, 04040404 etc., see here详解。使用不正确的密码解密将导致 random/corrupted 明文。它的结尾通常不会对应于有效的 PKCS7 填充,这会导致错误。然而,偶然可能会产生明文,其结尾与有效的 PKCS7 填充相匹配。在这种情况下,不会引发错误。例如。终止明文的 01 字节将与 PKCS7 填充兼容,随机密码发生这种情况的概率为 1/256。 0202同理,概率为1/65536,以此类推

如果在解密过程中禁用填充 (key.setAutoPadding(false)),则可以轻松验证这一点。然后不会引发错误。这同样适用于使用隐式禁用填充的流密码模式(例如 CTR)。

这意味着即使在没有产生错误的情况下,也需要与明文进行比较。

请注意,createCipher(顺便说一下,已弃用)从密码中派生出密钥和 IV。相同的密码(因此相同的密钥和 IV)将为相同的明文生成相同的密文。因此,密文的比较与明文的比较具有相同的目的。

还有一点,updatefinal的结果必须拼接起来,否则结果一般是不完整的,即encryption = key.final('hex')中的=必须是替换为 +=,尽管这可能只是一个错字。解密也是一样。