用openssl_encrypt替换mcrypt_encrypt

时间:2016-07-13 18:24:24

标签: php mcrypt php-openssl

你们可能知道,扩展名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个字符)
  3. 任何人都有类似的问题(或知道如何修复它?)

    BTW:我正在使用PHP的开发大师版本(假设是7.1.0 alpha 3)。

3 个答案:

答案 0 :(得分:1)

你应该真正摆脱使用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

答案 1 :(得分:0)

有两个问题:

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

    1. 将OPENSSL_ZERO_PADDING标志添加到openssl_encrypt / openssl_decrypt
    2. 如果输入字符串长度不是块长度的倍数,则附加到输入字符串零字符“\ 0”[aka chr(0)];
    3. 据说这可以解决问题:

      // 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;
      }
      

答案 2 :(得分:0)

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

//Return encrypted string
public function stringEncrypt ($plainText, $cryptKey = '7R7zX2Urc7qvjhkr') {

  $length   = 8;
  $cstrong  = true;
  $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中的内容