将 mcrypt AESencrypt 函数转换为 openssl 但不起作用

Posted

技术标签:

【中文标题】将 mcrypt AESencrypt 函数转换为 openssl 但不起作用【英文标题】:Convert mcrypt AESencrypt function to openssl but not working 【发布时间】:2021-10-28 04:05:15 【问题描述】:

这是我在 php 5.6 中完美运行的旧代码

function AESencrypt($decrypted, $password, $salt) 
 
  $block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
  $padding = $block - (strlen($decrypted) % $block);
  $decrypted .= str_repeat(chr($padding), $padding);
  $encrypted = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $password, $decrypted , MCRYPT_MODE_CBC, $password));
  $encrypted = hash('SHA256', $encrypted.'|'.$salt, true);
  return strToHex($encrypted);


$hashkey= AESencrypt("input","password", "salt");

然后我切换到 PHP 7.4,但该功能无法正常工作,因此我尝试将其转换为 OpenSSL,但它不会产生 有效的哈希键

新代码在这里

function AESencrypt($decrypted, $password, $salt) 
 
  $padding = 16 - (strlen($salt) % 16);
  $salt .= str_repeat("\0", $padding);
  
  $block = 16;
  $padding = $block - (strlen($decrypted) % $block);
  $decrypted .= str_repeat(chr($padding), $padding);

  $cipher = (mb_strlen($password, '8bit') <= 8) ? 'aes-128-cbc' : 'aes-256-cbc';

  $encrypted = base64_encode(
    openssl_encrypt($decrypted, $cipher, $password, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING, $password)
  );

  $encrypted = hash('SHA256', $encrypted.'|'.$salt, true);
  return strToHex($encrypted);


$hashkey = AESencrypt("input","password", "salt");

strToHex()在这里

function strToHex($string)
  $hex = '';
  for ($i=0; $i<strlen($string); $i++)
    $ord = ord($string[$i]);
    $hexCode = dechex($ord);
    $hex .= substr('0'.$hexCode, -2);
  
  return strToUpper($hex);

我已经尝试了上一个问题中给出的解决方案,但它仍然显示 invalid hash key

【问题讨论】:

您的填充不同。这也是一个非常奇怪的哈希函数。 【参考方案1】:

在旧代码中,salt 没有被填充,并且设计用于 AES-128,即 16 字节密钥。如果在新代码中删除了盐的填充,则没有 AES-256 用于大于 8 (?!) 字节的密钥并应用 16 字节的密钥,结果是相同的。

另外,新代码可以写得更紧凑:

使用隐式 PKCS#7 填充而不是显式填充(删除 OPENSSL_NO_PADDING) 使用隐式 Base64 编码而不是显式编码(删除 OPENSSL_RAW_DATA) 使用内置函数bin2hex(),而不是自定义函数strToHex()。但即使这样也可以避免,因为hash() 默认返回十六进制编码的结果:
function AESencrypt($decrypted, $password, $salt)  
 
  $encrypted = openssl_encrypt($decrypted, 'aes-128-cbc', $password, 0, $password);
  $hash = hash('SHA256', $encrypted . '|' . $salt);
  return strToUpper($hash);


$result = AESencrypt("The quick brown fox jumps over the lazy dog", "0123456789abcdef", "01234567");
print($result . PHP_EOL); // 7A8D13F38E4A63F821A75FAA8C7B879C7BCC99B34102BAA731015735F5F5EAD3

该方法的目的不明确。最终的散列使处理不可逆,即无法解密。也许用这个来实现一个密钥推导。但是,有更多经过验证的方法,例如Argon2(基于密码)或 HKDF(基于密钥)。

【讨论】:

以上是关于将 mcrypt AESencrypt 函数转换为 openssl 但不起作用的主要内容,如果未能解决你的问题,请参考以下文章

PHP 将 mcrypt 转换为 openssl

将此php加密函数转换为python

CryptoJS 中 CFB 模式中的 mcrypt_encrypt 函数

PHP:OpenSSL 等价于 mcrypt:MCRYPT_3DES?

在 PHP 中将 mcrypt_encrypt 转换为 openssl_encrypt

将 OSX 更新为“El Capitan”后未定义的函数 mcrypt