mcrypt已被弃用,有什么替代方案?

Pie*_*iet 87 php encryption passwords mcrypt php-7

不推荐使用的mcrypt-extension 将根据此处发布的评论在PHP 7.2中删除.所以我正在寻找一种加密密码的替代方法.

现在我正在使用类似的东西

mcrypt_encrypt(MCRYPT_RIJNDAEL_128, md5($key, true), $string, MCRYPT_MODE_CBC, $iv)
Run Code Online (Sandbox Code Playgroud)

我需要您对加密密码的最佳/最强方式的意见,加密密码当然应该由PHP 7.xx支持,并且还应该是可解密的,因为我的客户确实想要选择"恢复"他们的密码而不生成新的密码一.

Phi*_*hil 40

散列密码是最佳做法,因此它们不可解密.这使得可能获得对您的数据库或文件的访问权的攻击者更加困难.

如果您必须加密数据并使其可解密,请访问https://paragonie.com/white-paper/2015-secure-php-data-encryption获取安全加密/解密指南.总结一下这个链接:

  • 使用Libsodium - PHP扩展
  • 如果您不能使用Libsodium,请使用defuse/php-encryption - 直接PHP代码
  • 如果您不能使用Libsodium或defuse/php-encryption,请使用OpenSSL - 许多服务器已经安装了这个.如果没有,可以用--with-openssl [= DIR]编译

  • 应该首先尝试 openssl 因为它很常见,而 libsodium 不是。除非有问题,否则不应使用原始 php,除非所有本机扩展都已失效 (2认同)

ken*_*orb 24

正如@rqLizard建议的那样,您可以使用openssl_encrypt/ openssl_decryptPHP函数,它提供了更好的替代方法来实现AES(高级加密标准),也称为Rijndael加密.

根据以下Scott在php.net上的评论:

如果您在2015年编写代码来加密/加密数据,则应使用openssl_encrypt()openssl_decrypt().底层库(libmcrypt)自2007年以来就已被放弃,其性能远远超过OpenSSL(它利用AES-NI现代处理器并且是高速缓存定时安全的).

此外,MCRYPT_RIJNDAEL_256它不是AES-256,它是Rijndael分组密码的不同变体.如果你想AES-256mcrypt,你必须使用MCRYPT_RIJNDAEL_128一个32字节的密钥.OpenSSL使您更明显地使用哪种模式(即aes-128-cbcvs aes-256-ctr).

OpenSSL还使用带有CBC模式的PKCS7填充而不是mcrypt的NULL字节填充.因此,mcrypt更有可能使您的代码容易受到填充oracle攻击而不是OpenSSL.

最后,如果您没有验证您的密文(加密然后MAC),那么您做错了.

进一步阅读:

代码示例

示例#1

适用于PHP 7.1+的GCM模式示例中的AES认证加密

<?php
//$key should have been previously generated in a cryptographically safe way, like openssl_random_pseudo_bytes
$plaintext = "message to be encrypted";
$cipher = "aes-128-gcm";
if (in_array($cipher, openssl_get_cipher_methods()))
{
    $ivlen = openssl_cipher_iv_length($cipher);
    $iv = openssl_random_pseudo_bytes($ivlen);
    $ciphertext = openssl_encrypt($plaintext, $cipher, $key, $options=0, $iv, $tag);
    //store $cipher, $iv, and $tag for decryption later
    $original_plaintext = openssl_decrypt($ciphertext, $cipher, $key, $options=0, $iv, $tag);
    echo $original_plaintext."\n";
}
?>
Run Code Online (Sandbox Code Playgroud)

例#2

适用于PHP 5.6+的AES认证加密示例

<?php
//$key previously generated safely, ie: openssl_random_pseudo_bytes
$plaintext = "message to be encrypted";
$ivlen = openssl_cipher_iv_length($cipher="AES-128-CBC");
$iv = openssl_random_pseudo_bytes($ivlen);
$ciphertext_raw = openssl_encrypt($plaintext, $cipher, $key, $options=OPENSSL_RAW_DATA, $iv);
$hmac = hash_hmac('sha256', $ciphertext_raw, $key, $as_binary=true);
$ciphertext = base64_encode( $iv.$hmac.$ciphertext_raw );

//decrypt later....
$c = base64_decode($ciphertext);
$ivlen = openssl_cipher_iv_length($cipher="AES-128-CBC");
$iv = substr($c, 0, $ivlen);
$hmac = substr($c, $ivlen, $sha2len=32);
$ciphertext_raw = substr($c, $ivlen+$sha2len);
$original_plaintext = openssl_decrypt($ciphertext_raw, $cipher, $key, $options=OPENSSL_RAW_DATA, $iv);
$calcmac = hash_hmac('sha256', $ciphertext_raw, $key, $as_binary=true);
if (hash_equals($hmac, $calcmac))//PHP 5.6+ timing attack safe comparison
{
    echo $original_plaintext."\n";
}
?>
Run Code Online (Sandbox Code Playgroud)

例#3

基于以上示例,我更改了以下用于加密用户会话ID的代码:

class Session {

  /**
   * Encrypts the session ID and returns it as a base 64 encoded string.
   *
   * @param $session_id
   * @return string
   */
  public function encrypt($session_id) {
    // Get the MD5 hash salt as a key.
    $key = $this->_getSalt();
    // For an easy iv, MD5 the salt again.
    $iv = $this->_getIv();
    // Encrypt the session ID.
    $encrypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $session_id, MCRYPT_MODE_CBC, $iv);
    // Base 64 encode the encrypted session ID.
    $encryptedSessionId = base64_encode($encrypt);
    // Return it.
    return $encryptedSessionId;
  }

  /**
   * Decrypts a base 64 encoded encrypted session ID back to its original form.
   *
   * @param $encryptedSessionId
   * @return string
   */
  public function decrypt($encryptedSessionId) {
    // Get the MD5 hash salt as a key.
    $key = $this->_getSalt();
    // For an easy iv, MD5 the salt again.
    $iv = $this->_getIv();
    // Decode the encrypted session ID from base 64.
    $decoded = base64_decode($encryptedSessionId);
    // Decrypt the string.
    $decryptedSessionId = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $decoded, MCRYPT_MODE_CBC, $iv);
    // Trim the whitespace from the end.
    $session_id = rtrim($decryptedSessionId, "\0");
    // Return it.
    return $session_id;
  }

  public function _getIv() {
    return md5($this->_getSalt());
  }

  public function _getSalt() {
    return md5($this->drupal->drupalGetHashSalt());
  }

}
Run Code Online (Sandbox Code Playgroud)

成:

class Session {

  const SESS_CIPHER = 'aes-128-cbc';

  /**
   * Encrypts the session ID and returns it as a base 64 encoded string.
   *
   * @param $session_id
   * @return string
   */
  public function encrypt($session_id) {
    // Get the MD5 hash salt as a key.
    $key = $this->_getSalt();
    // For an easy iv, MD5 the salt again.
    $iv = $this->_getIv();
    // Encrypt the session ID.
    $ciphertext = openssl_encrypt($session_id, self::SESS_CIPHER, $key, $options=OPENSSL_RAW_DATA, $iv);
    // Base 64 encode the encrypted session ID.
    $encryptedSessionId = base64_encode($ciphertext);
    // Return it.
    return $encryptedSessionId;
  }

  /**
   * Decrypts a base 64 encoded encrypted session ID back to its original form.
   *
   * @param $encryptedSessionId
   * @return string
   */
  public function decrypt($encryptedSessionId) {
    // Get the Drupal hash salt as a key.
    $key = $this->_getSalt();
    // Get the iv.
    $iv = $this->_getIv();
    // Decode the encrypted session ID from base 64.
    $decoded = base64_decode($encryptedSessionId, TRUE);
    // Decrypt the string.
    $decryptedSessionId = openssl_decrypt($decoded, self::SESS_CIPHER, $key, $options=OPENSSL_RAW_DATA, $iv);
    // Trim the whitespace from the end.
    $session_id = rtrim($decryptedSessionId, '\0');
    // Return it.
    return $session_id;
  }

  public function _getIv() {
    $ivlen = openssl_cipher_iv_length(self::SESS_CIPHER);
    return substr(md5($this->_getSalt()), 0, $ivlen);
  }

  public function _getSalt() {
    return $this->drupal->drupalGetHashSalt();
  }

}
Run Code Online (Sandbox Code Playgroud)

为了澄清,上面的更改不是真正的转换,因为两个加密使用不同的块大小和不同的加密数据.此外,默认填充不同,MCRYPT_RIJNDAEL仅支持非标准空填充.@zaph


附加说明(来自@ zaph的评论):

  • Rijndael算法128(MCRYPT_RIJNDAEL_128)等同于AES,但是Rijndael算法256(MCRYPT_RIJNDAEL_256)是不 AES-256作为256指定的256位的块尺寸,而AES仅具有一个块大小:128比特.因此,MCRYPT_RIJNDAEL_256由于mcrypt开发人员的选择,基本上Rijndael的块大小为256位()被错误地命名.@zaph
  • 块大小为256的Rijndael可能不如128位块大小安全,因为后者有更多的评论和使用.其次,互操作性受到阻碍,因为AES通常是可用的,其中块大小为256位的Rijndael不是.
  • Rijndael使用不同块大小的加密产生不同的加密数据.

    例如,MCRYPT_RIJNDAEL_256(不等效于AES-256)定义了Rijndael分组密码的不同变体,其大小为256位,密钥大小基于传入密钥,其中aes-256-cbcRijndael的块大小为128位,密钥大小为256位.因此,他们使用不同的块大小产生完全不同的加密数据,因为mcrypt使用该数字来指定块大小,其中OpenSSL使用该数字来指定密钥大小(AES只有一个块大小为128位).所以基本上AES是Rijndael,块大小为128位,密钥大小为128,192和256位.因此,最好使用AES,在OpenSSL中称为Rijndael 128.


Pen*_*m10 9

Rijndael的纯PHP实现与phpseclib一起存在,可以作为作曲家软件包使用,并且可以在PHP 7.3上运行(由我测试)。

phpseclib文档上有一个页面,在您输入基本变量(密码,模式,密钥大小,位大小)之后,该页面会生成示例代码。它为Rijndael,ECB,256、256输出以下内容:

用mycrypt编写的代码

$decoded = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, ENCRYPT_KEY, $term, MCRYPT_MODE_ECB);
Run Code Online (Sandbox Code Playgroud)

在图书馆这样工作

$rijndael = new \phpseclib\Crypt\Rijndael(\phpseclib\Crypt\Rijndael::MODE_ECB);
$rijndael->setKey(ENCRYPT_KEY);
$rijndael->setKeyLength(256);
$rijndael->disablePadding();
$rijndael->setBlockLength(256);

$decoded = $rijndael->decrypt($term);
Run Code Online (Sandbox Code Playgroud)

*原$termbase64_decoded


小智 5

您可以使用phpseclib pollyfill软件包。您不能使用open ssl或libsodium通过rijndael 256进行加密/解密。另一个问题是,您不需要替换任何代码。

  • 这非常有帮助,谢谢。不得不删除php-mcrypt扩展名,然后这就像一个魅力。 (2认同)

小智 5

如此处其他答案所详述,我发现的最佳解决方案是使用OpenSSL。它内置在PHP中,您不需要任何外部库。以下是简单的示例:

加密:

function encrypt($key, $payload) {
  $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
  $encrypted = openssl_encrypt($payload, 'aes-256-cbc', $key, 0, $iv);
  return base64_encode($encrypted . '::' . $iv);
}
Run Code Online (Sandbox Code Playgroud)

解密:

function decrypt($key, $garble) {
    list($encrypted_data, $iv) = explode('::', base64_decode($garble), 2);
    return openssl_decrypt($encrypted_data, 'aes-256-cbc', $key, 0, $iv);
}
Run Code Online (Sandbox Code Playgroud)

参考链接:https : //www.shift8web.ca/2017/04/how-to-encrypt-and-execute-your-php-code-with-mcrypt/