AES-256 CBC 加密在 Ruby/PHP 中成功,但使用 CryptoJS 解密失败
AES-256 CBC encryption succeeds in Ruby/PHP, but decryption fails with CryptoJS
我可以用 AES-256 CBC 加密 PHP 或 Ruby 中的字符串(使用 gem symmetric-encryption)并得到相同的结果。
<?php
openssl_encrypt(
'Hello!', 'aes-256-cbc', '1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF', 0, '1234567890ABCDEF1234567890ABCDEF'
); // => 'BAd5fmmMTvRE4Ohvf3GpCw=='
ruby_cipher = SymmetricEncryption::Cipher.new(key: "1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF", iv: "1234567890ABCDEF1234567890ABCDEF", cipher_name: 'aes-256-cbc')
ruby_cipher.encrypt("Hello!") # => "BAd5fmmMTvRE4Ohvf3GpCw=="
但我无法使用 Javascript 解密相同的字符串,使用 CryptoJS。据我可以解释文档:
var encrypted = CryptoJS.AES.encrypt("Message", key, { iv: iv });
var decrypted = CryptoJS.AES.decrypt("Message", key, { iv: iv });
在 my jsfiddle 或此处查看我失败的尝试:
var key = CryptoJS.enc.Hex.parse("1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF");
var iv = CryptoJS.enc.Hex.parse"1234567890ABCDEF1234567890ABCDEF");
var ruby_encrypted = "BAd5fmmMTvRE4Ohvf3GpCw=="; // Output from the Ruby encryption
var js_encrypted = CryptoJS.AES.encrypt("Hello!", key, { iv: iv }); // Test to confirm that CryptoJS can decrypt its own encrypted
var ruby_decrypted = CryptoJS.AES.decrypt(ruby_encrypted, key, { iv: iv }); // Object { words: Array[4], sigBytes: -129 }
var js_decrypted = CryptoJS.AES.decrypt(js_encrypted, key, { iv: iv }); // Object { words: Array[4], sigBytes: 6 }
console.log(ruby_decrypted.toString(CryptoJS.enc.Utf8)); //
console.log(js_decrypted.toString(CryptoJS.enc.Utf8)); // Hello!
知道解密失败的原因吗?
PHP 和 Ruby 将密钥和 IV 作为二进制字符串。他们不认为它是十六进制编码的,这意味着只会使用 64 个字符密钥的前 32 个字符。 OpenSSL 静默地只使用它需要的字节数并且不会抛出错误(在这种情况下它应该抛出错误)。
你可能想要在 CryptoJS 中使用这样的东西:
var key = CryptoJS.enc.Utf8.parse("1234567890ABCDEF1234567890ABCDEF");
var iv = CryptoJS.enc.Utf8.parse("1234567890ABCDEF");
所以,虽然这个密钥里面有256位,但安全性实际上只有128位,因为在一个十六进制编码的字符串中,每个字符只有4位。
我可以用 AES-256 CBC 加密 PHP 或 Ruby 中的字符串(使用 gem symmetric-encryption)并得到相同的结果。
<?php
openssl_encrypt(
'Hello!', 'aes-256-cbc', '1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF', 0, '1234567890ABCDEF1234567890ABCDEF'
); // => 'BAd5fmmMTvRE4Ohvf3GpCw=='
ruby_cipher = SymmetricEncryption::Cipher.new(key: "1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF", iv: "1234567890ABCDEF1234567890ABCDEF", cipher_name: 'aes-256-cbc')
ruby_cipher.encrypt("Hello!") # => "BAd5fmmMTvRE4Ohvf3GpCw=="
但我无法使用 Javascript 解密相同的字符串,使用 CryptoJS。据我可以解释文档:
var encrypted = CryptoJS.AES.encrypt("Message", key, { iv: iv });
var decrypted = CryptoJS.AES.decrypt("Message", key, { iv: iv });
在 my jsfiddle 或此处查看我失败的尝试:
var key = CryptoJS.enc.Hex.parse("1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF");
var iv = CryptoJS.enc.Hex.parse"1234567890ABCDEF1234567890ABCDEF");
var ruby_encrypted = "BAd5fmmMTvRE4Ohvf3GpCw=="; // Output from the Ruby encryption
var js_encrypted = CryptoJS.AES.encrypt("Hello!", key, { iv: iv }); // Test to confirm that CryptoJS can decrypt its own encrypted
var ruby_decrypted = CryptoJS.AES.decrypt(ruby_encrypted, key, { iv: iv }); // Object { words: Array[4], sigBytes: -129 }
var js_decrypted = CryptoJS.AES.decrypt(js_encrypted, key, { iv: iv }); // Object { words: Array[4], sigBytes: 6 }
console.log(ruby_decrypted.toString(CryptoJS.enc.Utf8)); //
console.log(js_decrypted.toString(CryptoJS.enc.Utf8)); // Hello!
知道解密失败的原因吗?
PHP 和 Ruby 将密钥和 IV 作为二进制字符串。他们不认为它是十六进制编码的,这意味着只会使用 64 个字符密钥的前 32 个字符。 OpenSSL 静默地只使用它需要的字节数并且不会抛出错误(在这种情况下它应该抛出错误)。
你可能想要在 CryptoJS 中使用这样的东西:
var key = CryptoJS.enc.Utf8.parse("1234567890ABCDEF1234567890ABCDEF");
var iv = CryptoJS.enc.Utf8.parse("1234567890ABCDEF");
所以,虽然这个密钥里面有256位,但安全性实际上只有128位,因为在一个十六进制编码的字符串中,每个字符只有4位。