我想知道如何在perl和php中为3DES加密返回相同的值。PHP代码如下:
$bytes = array(0,0,0,0,0,0,0,0);
$iv = implode(array_map("chr", $bytes));
$ciphertext = mcrypt_encrypt(MCRYPT_3DES, base64_decode('Mk9m98IfEblmPfrpsawt7BmxObt98Jev'), '0000001920', MCRYPT_MODE_CBC, $iv);
echo base64_encode($ciphertext);
结果是:"A/VCTXA6q/x/emW0zzlSDg=="
perl代码是:
use Crypt::CBC;
$cipher = Crypt::CBC->new( -key => decode_base64('Mk9m98IfEblmPfrpsawt7BmxObt98Jev'),
-cipher => 'DES_EDE3',
-iv => pack("H*","0000000000000000"),
-literal_key => 1,
-header => 'none'
);
$ciphertext = $cipher->encrypt("0000001920");
print encode_base64($ciphertext, '');
结果是:"A/VCTXA6q/y9g7ypgqlWIg=="
结果非常相似,我在perl代码中做错了什么?
您没有使用相同的填充机制。
如果你仔细阅读PHP的mcrypt_encrypt的参考页面,你会在数据参数旁边看到以下注释:
如果数据的大小不是n*块大小,则数据将填充"''0"。
现在,如果您还阅读了Perls-Crypt::CBC的引用页面,您会注意到它们有几个填充方法(由-padding
参数定义)。默认值是PKCS#5,它不同于只填充0x00
。
现在,如果将填充更改为"null"
,Perl将打印与PHP相同的内容。所以你的代码应该是这样的:
use MIME::Base64;
use Crypt::CBC;
$cipher = Crypt::CBC->new( -key => decode_base64('Mk9m98IfEblmPfrpsawt7BmxObt98Jev'),
-cipher => 'DES_EDE3',
-iv => pack("H*","0000000000000000"),
-padding => "null",
-literal_key => 1,
-header => 'none'
);
$ciphertext = $cipher->encrypt("0000001920");
print encode_base64($ciphertext, '');
或者,你可以在PHP中实现PKCS#5,这必须由你自己完成,因为PHP默认情况下不包括它(搜索PHP PKCS#5,你可能会找到一些可以使用的代码片段,甚至在一个PHP文档注释中有一个简单的PKCS#55函数)。