我不能为我的生活弄清楚如何将我的传统mcrypt代码迁移到OpenSSL.我得到了CBC的Blowfish和CBC的Rijndael,但是欧洲央行的Blowfish正在躲避我.
是的,我读了Moving from mcrypt with Blowfish & ECB to OpenSSL,我尝试对数据进行零填充,而不是对数据进行零填充,对键进行零填充,在键上循环以及它们的任何组合,似乎没有任何效果.
这是我的代码:
<?PHP
function encrypt_with_mcrypt($data, $key) {
return mcrypt_encrypt(MCRYPT_BLOWFISH, $key, $data, MCRYPT_MODE_ECB);
}
function encrypt_with_openssl($data, $key) {
return openssl_encrypt($data, 'BF-ECB', $key, OPENSSL_RAW_DATA | OPENSSL_DONT_ZERO_PAD_KEY);
}
$data = 'foobar';
$key = 'supersecretkey';
var_dump(base64_encode(encrypt_with_mcrypt($data, $key)));
var_dump(base64_encode(encrypt_with_openssl($data, $key)));
这是输出:
test.PHP:13:
string(12) "5z0q3xNnokw="
test.PHP:14:
string(12) "1zyqavq7sCk="
解决方法:
mcrypt库/包装器默认为零字节填充(仅在需要时),而OpenSSL库/包装器默认为PKCS#5填充.这意味着单个块以不同方式填充,因此将显示不同的密文块.
一个常见的技巧是在没有任何取消填充的情况下解密生成的密文,然后通过查看十六进制中的明文填充来检查填充字节.
这将告诉你:
5z0q3xNnokw=
666f6f6261720000
对于mcrypt和
1zyqavq7sCk=
666f6f6261720202
对于OpenSSL.
使用需要加密多个块的较大明文消息也会向您显示除最后一个块之外加密正常.
当且仅当mcrypt输入不是8字节的倍数(Blowfish的块大小)时,首先对数据进行零填充,然后使用OPENSSL_ZERO_PADDING作为填充模式.
请注意,查看源代码显示OPENSSL_ZERO_PADDING出于某些未指定的原因似乎意味着包装器的“无填充”,并且OPENSSL_NO_PADDING似乎确实与其他设置冲突 – 我认为这是一个相当糟糕的设计和实现错误的开发人员PHP OpenSSL包装器API.
更多信息可以在the great research performed by Reinier找到,它显示了API如何填充/取消填充(或忘记填充/取消填充,具体取决于您的位置).