2010-04-09 121 views
1

我有一个用Perl Crypt :: CBC(Rijndael,cbc)加密的加密字符串。原始明文使用Crypt :: CBC的encrypt_hex()方法加密。用Perl CBC加密并用PHP解密mcrypt

$encrypted_string = '52616e646f6d49567b2c89810ceddbe8d182c23ba5f6562a418e318b803a370ea25a6a8cbfe82bc6362f790821dce8441a790a7d25d3d9ea29f86e6685d0796d'; 

我有使用的32个字符的键。

mcrypt被成功编译到PHP中,但我很难试图解密PHP中的字符串。我不断收到乱码。

如果我解压缩('H *',$ encrypted_string),我看到'RandomIV'后面跟着看起来像是二进制的。

我似乎无法正确提取IV并分隔实际的加密消息。我知道我没有提供我的信息,但我不知道还有什么可以开始的。

$cipher = 'rijndael-256'; 
$cipher_mode = 'cbc'; 

$td = mcrypt_module_open($cipher, '', $cipher_mode, ''); 

$key = '32 characters'; // Does this need to converted to something else before being passed? 
$iv = ?? // Not sure how to extract this from $encrypted_string. 
$token = ?? // Should be a sub-string of $encrypted_string, correct? 

mcrypt_generic_init($td, $key, $iv); 
$clear = rtrim(mdecrypt_generic($td, $token), ''); 
mcrypt_generic_deinit($td); 
mcrypt_module_close($td); 

echo $clear; 

任何帮助,指针在正确的方向,将不胜感激。让我知道是否需要提供更多信息。

回答

2

我认为使用的IV只是由CBC :: Crypt随机生成的。如果我是正确的,并正确读取文档,它是解压缩字符串的32个第一个字节。

与良好的键试试这个:

$cipher = 'rijndael-256'; 
$cipher_mode = 'cbc'; 

$td = mcrypt_module_open($cipher, '', $cipher_mode, ''); 

$key = '32 characters'; // Does this need to converted to something else before being passed? 

$unpacked = pack('H*', '52616e646f6d49567b2c89810ceddbe8d182c23ba5f6562a418e318b803a370ea25a6a8cbfe82bc6362f790821dce8441a790a7d25d3d9ea29f86e6685d0796d'); 


$iv = substr($unpacked, 0, 32); 
$token = substr($unpacked, 32); 

mcrypt_generic_init($td, $key, $iv); 
$clear = rtrim(mdecrypt_generic($td, $token), ''); 
mcrypt_generic_deinit($td); 
mcrypt_module_close($td); 

echo $clear; 
0

这也不能工作。我有一种感觉,Perl的CBC :: Crypt与PHP的mcrypt函数有很大不同。我一直在试图找到我的PHP目录中的mcrypt函数的源代码来比较它们,但没有运气。

1

这个答案适用于Crypt :: CBC的盐渍模式,而不是随机的IV模式,但这是我在搜索解决方案时最终找到的页面,所以其他人也可能会这样做。

当使用这种Perl代码:

my $cipher = Crypt::CBC->new(
       -key => $password, 
       -cipher => 'Rijndael', 
       -salt => 1, 
       -header => 'salt', 
      ) || die "Couldn't create CBC object"; 
    $string = $cipher->encrypt_hex($input); 

(或甚至无盐和它默认具有这些值报头) Perl将创建意味着是OpenSSL的兼容的散列。 我没有找到任何知道如何阅读这个的PHP方法,所以这里是我自己的CBC.pm中解码的PHP版本。 我提取密钥和iv,然后让mcrypt完成这项工作。

function cred_decrypt($input, $password) 
{ 
    /************************* Inspired by Crypt/CBC.pm *******************************/ 
    $input = pack('H*', $input); 
    if (substr($input, 0, 8) != 'Salted__') { 
    die("Invalid hash header, expected 'Salted__', found '".substr($input, 0, 8)."'"); 
    } 
    $salt = substr($input, 8, 8); 
    $input = substr($input, 16); 

    $key_len = 32; 
    $iv_len = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC); 

    $data = ''; 
    $d = ''; 
    while (strlen($data) < $key_len+$iv_len) { 
    $d = md5($d . $password . $salt, TRUE); 
    $data .= $d; 
    } 
    $key = substr($data, 0, $key_len); 
    $iv = substr($data, $key_len, $iv_len); 
    /**********************************************************************************/ 

    return rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $input, MCRYPT_MODE_CBC, $iv), "\0\n\3"); 
} 

注意:rtrim是需要在我的情况下,它可能会吃结束换行符,如果有的话。