Php 将带有Blowfish和ECB的mcrypt迁移到OpenSSL
我一辈子都不知道如何将遗留的mcrypt代码迁移到OpenSSL。我让它为CBC的河豚和CBC的Rijndael工作,但ECB的河豚一直在逃避我 是的,我读了,我尝试了零填充数据,而不是零填充数据,零填充键,循环键和它们的任何组合,但似乎没有任何效果 这是我的代码:Php 将带有Blowfish和ECB的mcrypt迁移到OpenSSL,php,encryption,openssl,mcrypt,Php,Encryption,Openssl,Mcrypt,我一辈子都不知道如何将遗留的mcrypt代码迁移到OpenSSL。我让它为CBC的河豚和CBC的Rijndael工作,但ECB的河豚一直在逃避我 是的,我读了,我尝试了零填充数据,而不是零填充数据,零填充键,循环键和它们的任何组合,但似乎没有任何效果 这是我的代码: <?php function encrypt_with_mcrypt($data, $key) { return mcrypt_encrypt(MCRYPT_BLOWFISH, $key, $data, MCR
<?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)));
mcrypt库/包装器默认为零字节填充(仅在需要时),而OpenSSL库/包装器默认为PKCS#5填充。这意味着单个块的填充方式不同,因此将显示不同的密文块
一个常见的技巧是在不进行任何解密的情况下解密生成的密文,然后通过查看明文+十六进制填充来检查填充字节 这将向您展示:
5z0q3xNnokw=
666f6f6261720000
对于mcrypt和
1zyqavq7sCk=
666f6f6261720202
对于OpenSSL
使用需要加密多个块的更大的明文消息也会向您表明,除了最后一个块之外,加密工作进展顺利
当且仅当mcrypt输入不是8字节的倍数(Blowfish的块大小)时,首先对数据进行零填充,然后使用
OPENSSL\u zero\u PADDING
作为填充模式
请注意,查看源代码显示,出于某些未指定的原因,OPENSSL\u ZERO\u PADDING
似乎表示“无填充”对于包装器和OPENSSL\u NO\u PADDING
似乎与其他设置冲突-我认为这是PHP OPENSSL包装器API开发人员的一个相当糟糕的设计和实现错误
更多信息可以在下面找到,显示API如何填充/取消填充(或忘记填充/取消填充,具体取决于您所处的位置)。我没有太多要补充的内容,只是我认为最好能显示一些说明其文字的代码
mcrypt
添加零以将明文填充到8字节BF blocksize的倍数,可通过打印明文和解密密文的十六进制转储来显示:
$key = "supersecretkey";
$data = "foobar";
$ctxt = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, $data, MCRYPT_MODE_ECB);
$ptxt = mcrypt_decrypt(MCRYPT_BLOWFISH, $key, $ctxt, MCRYPT_MODE_ECB);
echo bin2hex($data).PHP_EOL;
echo bin2hex($ptxt).PHP_EOL;
提供以下十六进制转储:
666f6f626172
666f6f6261720000
openssl
默认情况下使用PKCS#5填充,在这种情况下,在块的末尾添加2个字节,值为2:
$key = "supersecretkey";
$data = "foobar";
$opts = OPENSSL_RAW_DATA | OPENSSL_DONT_ZERO_PAD_KEY;
$ctxt = openssl_encrypt($data, 'BF-ECB', $key, $opts);
$ptxt = mcrypt_decrypt(MCRYPT_BLOWFISH, $key, $ctxt, MCRYPT_MODE_ECB);
echo bin2hex($data).PHP_EOL;
echo bin2hex($ptxt).PHP_EOL;
给予
通过手动添加填充字节,可以使mcrypt
和openssl
的密文保持一致。注意OPENSSL\u ZERO\u PADDING
选项和添加的“\0\0”
:
给出:
e73d2adf1367a24c
e73d2adf1367a24c
或者,在使用mcrypt
时,在末尾手动插入PKCS#5个填充字节:
$key = "supersecretkey";
$data = "foobar";
$ctxt_mc = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, $data."\2\2", MCRYPT_MODE_ECB);
$opts = OPENSSL_RAW_DATA | OPENSSL_DONT_ZERO_PAD_KEY;
$ctxt_os = openssl_encrypt($data, 'BF-ECB', $key, $opts);
echo bin2hex($ctxt_mc).PHP_EOL;
echo bin2hex($ctxt_os).PHP_EOL;
给予
最后,尝试在禁用填充且长度不是块大小倍数的情况下调用openssl\u encrypt()
:
$key = "supersecretkey";
$data = "foobar";
$opts = OPENSSL_RAW_DATA | OPENSSL_DONT_ZERO_PAD_KEY | OPENSSL_ZERO_PADDING;
$ctxt = openssl_encrypt($data, 'BF-ECB', $key, $opts);
echo(openssl_error_string().PHP_EOL)
给予
备注:名称
OPENSSL\u ZERO\u PADDING
令人困惑,但它的意思是“无填充”。您可能想使用该标志,但该标志不适用于openssl\u encrypt()
。其值为,与OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING
相同。相反,.学习一个男人如何钓鱼,你的卡加克会一直被鱼线困住,这个男人会对你大喊大叫:p“使用OPENSSL\u ZERO\u填充可能会导致麻烦,因为OPENSSL总是填充”:我相信这是不正确的。在这种情况下,PHP到OpenSSL的粘合层显式禁用填充,在这种情况下,如果明文长度不是8字节的倍数,OpenSSL\u encrypt()
调用将失败。是的,我同意你所说的一切,除了那一句话。出于教育目的,我还写了一个补充答案,简要地介绍了这个问题,但在其他方面支持你的答案。谢谢:-)。支持PHP OpenSSL包装器API的一点是:函数的文档中提到了OpenSSL\u ZERO\u PADDING
而不是OpenSSL\u NO\u PADDING
。同样,openssl\u public\u encrypt()
提到了openssl\u NO\u PADDING
而不是openssl\u ZERO\u PADDING
。但这仍然让所有人感到困惑。
e73d2adf1367a24c
e73d2adf1367a24c
$key = "supersecretkey";
$data = "foobar";
$ctxt_mc = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, $data."\2\2", MCRYPT_MODE_ECB);
$opts = OPENSSL_RAW_DATA | OPENSSL_DONT_ZERO_PAD_KEY;
$ctxt_os = openssl_encrypt($data, 'BF-ECB', $key, $opts);
echo bin2hex($ctxt_mc).PHP_EOL;
echo bin2hex($ctxt_os).PHP_EOL;
d73caa6afabbb029
d73caa6afabbb029
$key = "supersecretkey";
$data = "foobar";
$opts = OPENSSL_RAW_DATA | OPENSSL_DONT_ZERO_PAD_KEY | OPENSSL_ZERO_PADDING;
$ctxt = openssl_encrypt($data, 'BF-ECB', $key, $opts);
echo(openssl_error_string().PHP_EOL)
error:0607F08A:digital envelope routines:EVP_EncryptFinal_ex:data not multiple of block length