【问题标题】:Replacing mcrypt_encrypt using MCRYPT_RIJNDAEL_256 with openssl_encrypt使用 MCRYPT_RIJNDAEL_256 将 mcrypt_encrypt 替换为 openssl_encrypt
【发布时间】:2016-11-16 11:35:49
【问题描述】:

你们可能知道,扩展 mcrypt 将在 php 7.1 上被弃用。

我用来维护一个“遗留”应用程序,我希望最终迁移到这个版本,所以我运行了测试并验证我无法再获得 100% 的覆盖率,因为有一段代码使用以下内容代码:

$key = 'sA*(DH';

// initialization vector
$iv = md5(md5($key));
$output = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($key), $string,     MCRYPT_MODE_CBC, $iv));

我尝试使用此代码将这段代码移植到 openssl_encrypt

$key = md5('sA*(DH');
$iv = md5($key);
echo base64_encode(openssl_encrypt($data, "aes-256-cbc", $key, OPENSSL_RAW_DATA, $iv));

但是我有两个问题:

  1. IV 长度应该是 16 个字符(md5 给了我 32 个字符),所以我收到了 PHP 警告
  2. 输出不一样(即使我截断为 16 个字符)

有人遇到过类似的问题(或知道如何解决吗?)

顺便说一句:我正在使用 PHP 的 dev master 版本(应该是 7.1.0 alpha 3)。

【问题讨论】:

    标签: php mcrypt php-openssl


    【解决方案1】:

    又一个经过测试的解决方案采用并返回 ANSI 文本,用 openssl_encrypt() 和 openssl_decrypt() 替换 Mcrypt 函数:

    //Return encrypted string
    public function stringEncrypt ($plainText, $cryptKey = '7R7zX2Urc7qvjhkr') {
    
      $cipher   = 'aes-128-cbc';
    
      if (in_array($cipher, openssl_get_cipher_methods()))
      {
        $ivlen = openssl_cipher_iv_length($cipher);
        $iv = openssl_random_pseudo_bytes($ivlen);
        $ciphertext_raw = openssl_encrypt(
          $plainText, $cipher, $cryptKey, $options=OPENSSL_RAW_DATA, $iv);
        $hmac = hash_hmac('sha256', $ciphertext_raw, $cryptKey, $as_binary=true);
        $encodedText = base64_encode( $iv.$hmac.$ciphertext_raw );
      }
    
      return $encodedText;
    }
    
    
    //Return decrypted string
    public function stringDecrypt ($encodedText, $cryptKey = '7R7zX2Urc7qvjhkr') {
    
      $c = base64_decode($encodedText);
      $cipher   = 'aes-128-cbc';
    
      if (in_array($cipher, openssl_get_cipher_methods()))
      {
        $ivlen = openssl_cipher_iv_length($cipher);
        $iv = substr($c, 0, $ivlen);
        $hmac = substr($c, $ivlen, $sha2len=32);
        $ivlenSha2len = $ivlen+$sha2len;
        $ciphertext_raw = substr($c, $ivlen+$sha2len);
        $plainText = openssl_decrypt(
          $ciphertext_raw, $cipher, $cryptKey, $options=OPENSSL_RAW_DATA, $iv);
      }
    
      return $plainText;
    }
    

    更多阅读openssl documentation

    【讨论】:

      【解决方案2】:

      有两个问题:

      1. MCrypt 使用零填充,而 Openssl 默认使用 PKCS#7
      2. Openssl 需要输入字符串具有适当的长度(块长度的倍数)

      解决这个问题:

      1. 将 OPENSSL_ZERO_PADDING 标志添加到 openssl_encrypt/openssl_decrypt
      2. 如果输入字符串长度不是块长度的倍数,则将零字符附加到输入字符串“\0”[aka chr(0)];

      话虽如此,这应该可以解决问题:

      // key/iv in ASCII binary data, $str base64
      function decrypt_stuff($key, $str, $iv) {
          // $plaintext_dec = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, base64_decode($str), MCRYPT_MODE_CBC, $iv);
          $plaintext_dec = openssl_decrypt(base64_decode($str), "aes-256-cbc", $key,  OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $iv);
          return $plaintext_dec;
      }
      
      // key/iv in ascii binary data, $str ascii
      function encrypt_stuff($key, $str, $iv) {
          // $ciphertext = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $str, MCRYPT_MODE_CBC, $iv));
          if (($l = (strlen($str) & 15)) > 0) { $str .= str_repeat(chr(0), 16 - $l); }
          $ciphertext = base64_encode(openssl_encrypt($str, "aes-256-cbc", $key,  OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $iv));
          return $ciphertext;
      }
      

      【讨论】:

      • 您好,感谢您的回答。你试过用 32 字节长的 $iv 吗?我不断收到的错误是 IV 比所需的 16 个字节长,并且 IV 将被截断。
      • IV 应该与块具有相同的长度(在我们的例子中是 16 字节)...更多详细信息请参见此处:security.stackexchange.com/questions/90848/…
      【解决方案3】:

      你真的应该改掉使用 md5 做任何事情的习惯。

      $iv = openssl_random_pseudo_bytes(16);
      $key = substr(hash('sha256', 'sA*(DH'), 0, 32)
      

      mcrypt_encryptopenssl_encrypt 在明文和密钥相同的情况下不会输出相同的密文。

      另外,mcrypt 在 PHP 7.1 中已弃用,未删除...因此您可以更新到 7.1,而无需从 mcrypt 更改为 openssl ...但最好删除 mcrypt一般。

      【讨论】:

      • 感谢您的回答,但原始代码不是我的,我真的没有使用 md5。试试这个,谢谢。
      猜你喜欢
      • 2021-09-22
      • 2017-09-14
      • 2018-02-05
      • 2016-09-12
      • 2017-05-02
      • 2018-08-29
      • 1970-01-01
      • 2017-06-23
      相关资源
      最近更新 更多