7

你们可能知道,扩展 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 的开发主版本(应该是 7.1.0 alpha 3)。

4

3 回答 3

3

另一个经过测试的解决方案采用并返回 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 文档

于 2019-02-14T19:14:37.590 回答
1

有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;
}
于 2018-04-03T13:26:39.800 回答
1

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

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

mcrypt_encrypt并且openssl_encrypt不会在给定相同的明文和密钥的情况下输出相同的密文。

此外,mcrypt在 PHP 7.1 中已弃用,未删除...因此您可以更新到 7.1 而无需从更改mcryptopenssl...但通常删除是个好主意mcrypt

于 2016-11-28T19:17:22.690 回答