【问题标题】:Encrypting with Perl CBC and decrypting with PHP mcrypt使用 Perl CBC 加密并使用 PHP mcrypt 解密
【发布时间】:2023-03-03 12:12:01
【问题描述】:

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

$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;

任何帮助,正确方向的指针,将不胜感激。如果我需要提供更多信息,请告诉我。

【问题讨论】:

    标签: php perl mcrypt


    【解决方案1】:

    此答案适用于 Crypt::CBC 的加盐模式,而不是 randomIV 模式,但这是我在搜索解决方案时最终进入的页面,因此其他可能也有。

    当使用这个 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,如果有的话,它可能会吃掉结束换行符。

    【讨论】:

      【解决方案2】:

      那也没用。我感觉 Perl 的 CBC::Crypt 做的事情与 PHP 的 mcrypt 函数有很大不同。我一直在尝试在我的 PHP 目录中找到 mcrypt 函数的源代码来比较它们,但还没有运气。

      【讨论】:

        【解决方案3】:

        我认为要使用的 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;
        

        【讨论】:

          猜你喜欢
          • 2016-07-25
          • 2015-11-10
          • 2014-02-06
          • 2010-10-13
          • 2011-08-31
          • 2013-12-28
          • 1970-01-01
          • 2019-04-13
          • 1970-01-01
          相关资源
          最近更新 更多