我能够使用node.js密码模块使用“aes-256-cbc”算法使用密码和解密类加密和解密消息,如下所示:
var crypto = require('crypto');
var cipherKey = crypto.randomBytes(32); // aes-256 => key length is 256 bits => 32 bytes
var cipherIV = crypto.randomBytes(16); // aes block size = initialization vector size = 128 bits => 16 bytes
var cipher = crypto.createCipheriv('aes-256-cbc', cipherKey, cipherIV);
var message = 'Hello world';
var encrypted = cipher.update(message, 'utf8', 'hex') + cipher.final('hex');
console.log('Encrypted \'' + message + '\' as \'' + encrypted + '\' with key \''+ cipherKey.toString('hex') + '\' and IV \'' + cipherIV.toString('hex') + '\'');
// Outputs: Encrypted 'Hello world' as '2b8559ce4227c3c3c200ea126cb50957' with key '50f7a656cfa3c4f90796a972b2f6eedf41b589da705fdec95b9d25c180c16cf0' and IV '6b28c13d63af14cf05059a2a2caf370c'
var decipher = crypto.createDecipheriv('aes-256-cbc', cipherKey, cipherIV);
var decrypted = decipher.update(encrypted, 'hex', 'utf8') + decipher.final('utf8');
console.log('Decrypted \'' + encrypted + '\' as \'' + decrypted + '\' with key \''+ cipherKey.toString('hex') + '\' and IV \'' + cipherIV.toString('hex') + '\'');
// Outputs: Decrypted '2b8559ce4227c3c3c200ea126cb50957' as 'Hello world' with key '50f7a656cfa3c4f90796a972b2f6eedf41b589da705fdec95b9d25c180c16cf0' and IV '6b28c13d63af14cf05059a2a2caf370c'
但是,当我试图使用错误的密钥解密消息时,可能是天真的,说明攻击者将无法解密消息,除非密钥是已知的,否则我将得到Error: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt at Decipheriv.final (internal/crypto/cipher.js:164:28)
。
var differentCipherKey = crypto.randomBytes(32);
var decipherDifferentKey = crypto.createDecipheriv('aes-256-cbc', differentCipherKey, cipherIV);
decrypted = decipherDifferentKey.update(encrypted, 'hex', 'utf8') + decipherDifferentKey.final('utf8');
我希望得到的是难以理解的文字。bad decrypt
在其他方面也有特色,所以无论是关于openssl版本在加密和解密之间的不匹配,还是在同一种情况下过短的初始化向量,我相信我的情况是不同的。AES是否知道加密文本是用不同的密钥生成的?
在节点v12.13.0上进行测试,在Windows10上测试,在运行v10.16.0的repl.it中也进行测试。
编辑:,如答案中所建议的,问题是默认填充,为了查看无法理解的输出,需要手动禁用密码、解密和衬垫上的自动填充:
var requirePadding = 16 - Buffer.byteLength(message, 'utf8');
var paddedMessage = Buffer.alloc(requirePadding, 0).toString('utf8') + message;
cipher.setAutoPadding(false)
发布于 2020-02-05 18:19:48
另一个答案正确地指出了这个问题是一个填充问题。我可以这样总结这个问题:
N
)。在执行decipher.setAutoPadding(false)
之前,您可以使用update
关闭此检查。但是,请注意,这将包括您的解密输出中的填充。下面是一个使用修改的repl.it实例的setAutoPadding
。
发布于 2020-02-05 17:43:40
CBC模式需要填充,您没有定义填充模式,但是库为您应用了一个默认模式。默认的是PKCS7Padding,它支持块大小从1到256字节不等。
每个填充有一个特定的格式,这样就可以从解密文本中唯一地删除它,而不会有歧义。例如,如果明文缺少两个字符来匹配AES中的块大小(16字节),那么PKCS7填充将添加0202
(十六进制),表示添加了2个字符,每个字符都具有添加字符数的值。如果5缺少0505050505
等,在下面的xy
是一个字节。
xyxyxyxyxyxyxyxyxyxyxyxyxyxyxy01
xyxyxyxyxyxyxyxyxyxyxyxyxyxy0202
xyxyxyxyxyxyxyxyxyxyxyxyxy030303
...
xyxy0E0E0E0E0E0E0E0E0E0E0E0E0E0E
xy0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F
如果最后一个块是一个完整的块,则一个完全填充的新块。
xyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxy 10101010101010101010101010101010
解密后,首先检查填充。如果填充没有rfc 2315中指定的正确格式,则可以说存在填充错误。
在本例中,库解密时检查填充,并警告您这一点。为了防止填充oracle攻击,您不会收到不正确的填充警告。你的解密效果很差。
库知道关键结果是否有效的填充,仅此而已。即使在完整性有用的情况下,也可能有一个以上的键产生有效的填充。
在现代密码学中,我们不再使用CBC模式。我们更喜欢认证加密(AE)模式,如AES-GCM或ChaCha20-Poly1305。AE模式在一个包中提供机密性、完整性和身份验证。
Galois计数器模式(GCM),内部使用CTR模式,其中没有填充,因此它们不受填充甲骨文攻击。
https://stackoverflow.com/questions/60080965
复制相似问题