PHP 7.2 中 mcrypt_encrypt 的精确替代
Exact alternate to mcrypt_encrypt in PHP 7.2
由于 mcrypt_encrypt 在 PHP 7.2 中不再受支持,我正在尝试完全替代此功能。
阅读许多 SO 答案后,我发现了以下使用 PHPSECLIB 的代码,但它没有生成与 mcrypt 完全相同的加密文本。
function encryptRJ256($key,$iv,$string_to_encrypt)
{
// $rtn = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $string_to_encrypt, MCRYPT_MODE_CBC, $iv);
$rijndael = new Crypt_Rijndael(CRYPT_RIJNDAEL_MODE_CBC);
$rijndael->setKey($key);
$rijndael->setIV($iv);
$rijndael->setKeyLength(256);
$rijndael->disablePadding();
$rijndael->setBlockLength(256);
$rtn = $rijndael->encrypt($string_to_encrypt);
$rtn = base64_encode($rtn);
return($rtn);
}
我的密钥和 IV 是
$ky = 'lkirwf897+22#bbtrm8814z5qq=498j5';
$iv = '741952hheeyy66#cs!9hjv887mxx7@8y';
如您所见,前 42 个字符相等,但其余字符不同
要加密的文本:57F0-ECD3-1A3B-341E-BA39-F81B-F020-0DE0
mcrypt_encrypt output:
3uw7mVZthiIPPNosvppZHd1jEau3Ul+0BQ4AVS2t80skauq3Zv9z5uztvmiBpYqQcKGIDP5YHfdEBhPBfdVbxg==
phpseclib output:
3uw7mVZthiIPPNosvppZHd1jEau3Ul+0BQ4AVS2t80tKnjjxVhuAwh3E1S5OnH1up5AujvQu1Grgyv16tNIEDw==
我需要生成相同的加密文本,因为该文本已被我无法更改的另一个程序解密。
所以我的问题是,是否可以使用 phpseclib 或任何其他方式生成与 mcrypt_encrypt 相同的加密文本?
您可能需要 "pad all the things"
如果你读过这个 entry on leaseweb 它一遍又一遍地指出 mcrypt 会自动将东西填充到它可以咀嚼的正确块大小。由于所有空字节,这当然会导致不同的输出。
所以我建议您确保输入到 phpseclib 代码中的所有数据都填充了正确数量的空字节,以模拟输入 mcrypt 输入到密码中。
默认情况下,如果您查看 code of PHPSECLIB,它会根据要填充的字符数决定填充字符。
mcrypt 但是用字符 0 填充。
所以,让我们解决这个问题。
您需要更改的代码是:
$cipher->disablePadding();
$length = strlen($text);
$pad = 32 - ($length % 32);
$text = str_pad($text, $length + $pad, chr(0));
我使用的是最新版本的PHPSECLIB as avaialble on github,所以我的代码与您的示例代码不同。这是我机器上的完整工作示例。
<?php
include "vendor/autoload.php";
include "phpseclib/bootstrap.php";
set_include_path(get_include_path() . PATH_SEPARATOR . 'phpseclib');
include('Crypt/Rijndael.php');
include('Crypt/Random.php');
use phpseclib\Crypt\Rijndael as Crypt_Rijndael;
$text = '57F0-ECD3-1A3B-341E-BA39-F81B-F020-0DE0';
$secret = 'lkirwf897+22#bbtrm8814z5qq=498j5';
$iv = '741952hheeyy66#cs!9hjv887mxx7@8y';
function encrypt128($secret, $iv, $str)
{
return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $secret, $str, MCRYPT_MODE_CBC, $iv));
}
function encryptRJ256($key,$iv,$text)
{
$cipher = new Crypt_Rijndael('cbc');
$cipher->setBlockLength(256);
// keys are null-padded to the closest valid size
// longer than the longest key and it's truncated
$cipher->setKeyLength(256);
$cipher->setKey($key);
// the IV defaults to all-NULLs if not explicitly defined
$cipher->setIV($iv);
$cipher->disablePadding();
$length = strlen($text);
$pad = 32 - ($length % 32);
$text = str_pad($text, $length + $pad, chr(0));
return base64_encode($cipher->encrypt($text));
}
function decryptRJ256($key,$iv,$text)
{
$cipher = new Crypt_Rijndael('cbc'); // could use CRYPT_RIJNDAEL_MODE_CBC
$cipher->setBlockLength(256);
// keys are null-padded to the closest valid size
// longer than the longest key and it's truncated
$cipher->setKeyLength(256);
$cipher->setKey($key);
// the IV defaults to all-NULLs if not explicitly defined
$cipher->setIV($iv);
$cipher->disablePadding();
return $cipher->decrypt(base64_decode($text));
}
echo $text;
echo encrypt128($secret, $iv, $text);
echo "\n";
$text = encryptRJ256($secret, $iv, $text);
echo $text;
echo "\n";
echo decryptRJ256($secret, $iv, $text);
由于它在技术上可以使用此方法进行加密和解密,因此实际加密的字符串可能会因输入而异。
如果输入字符串恰好是 32 个字符长,加密后的字符串将比使用原始 mcrypt 方法长得多。
原因是$pad变量的计算。对于 32 个字符的输入,$pad 将是 32,这将导致一个 64 个字符的 $text 变量。如果你在解密方法中使用 rtrim 它实际上不是问题。
为了避免这种情况,我找到了另一种方法来填充来自 phpseclib 的 mcrypt_compat 包中的输入字符串:
$extra = strlen($data) % 32;
if ($extra) {
$data.= str_repeat("[=10=]", 32 - $extra);
}
有了这个,32 个字符的输入字符串将不会被填充。这会产生与直接使用 mcrypt 完全相同的加密字符串。
希望这对某人有所帮助 - 或者直接使用 mcrypt_compat 包。
由于 mcrypt_encrypt 在 PHP 7.2 中不再受支持,我正在尝试完全替代此功能。
阅读许多 SO 答案后,我发现了以下使用 PHPSECLIB 的代码,但它没有生成与 mcrypt 完全相同的加密文本。
function encryptRJ256($key,$iv,$string_to_encrypt)
{
// $rtn = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $string_to_encrypt, MCRYPT_MODE_CBC, $iv);
$rijndael = new Crypt_Rijndael(CRYPT_RIJNDAEL_MODE_CBC);
$rijndael->setKey($key);
$rijndael->setIV($iv);
$rijndael->setKeyLength(256);
$rijndael->disablePadding();
$rijndael->setBlockLength(256);
$rtn = $rijndael->encrypt($string_to_encrypt);
$rtn = base64_encode($rtn);
return($rtn);
}
我的密钥和 IV 是
$ky = 'lkirwf897+22#bbtrm8814z5qq=498j5';
$iv = '741952hheeyy66#cs!9hjv887mxx7@8y';
如您所见,前 42 个字符相等,但其余字符不同
要加密的文本:57F0-ECD3-1A3B-341E-BA39-F81B-F020-0DE0
mcrypt_encrypt output:
3uw7mVZthiIPPNosvppZHd1jEau3Ul+0BQ4AVS2t80skauq3Zv9z5uztvmiBpYqQcKGIDP5YHfdEBhPBfdVbxg==phpseclib output:
3uw7mVZthiIPPNosvppZHd1jEau3Ul+0BQ4AVS2t80tKnjjxVhuAwh3E1S5OnH1up5AujvQu1Grgyv16tNIEDw==
我需要生成相同的加密文本,因为该文本已被我无法更改的另一个程序解密。
所以我的问题是,是否可以使用 phpseclib 或任何其他方式生成与 mcrypt_encrypt 相同的加密文本?
您可能需要 "pad all the things"
如果你读过这个 entry on leaseweb 它一遍又一遍地指出 mcrypt 会自动将东西填充到它可以咀嚼的正确块大小。由于所有空字节,这当然会导致不同的输出。
所以我建议您确保输入到 phpseclib 代码中的所有数据都填充了正确数量的空字节,以模拟输入 mcrypt 输入到密码中。
默认情况下,如果您查看 code of PHPSECLIB,它会根据要填充的字符数决定填充字符。
mcrypt 但是用字符 0 填充。
所以,让我们解决这个问题。
您需要更改的代码是:
$cipher->disablePadding();
$length = strlen($text);
$pad = 32 - ($length % 32);
$text = str_pad($text, $length + $pad, chr(0));
我使用的是最新版本的PHPSECLIB as avaialble on github,所以我的代码与您的示例代码不同。这是我机器上的完整工作示例。
<?php
include "vendor/autoload.php";
include "phpseclib/bootstrap.php";
set_include_path(get_include_path() . PATH_SEPARATOR . 'phpseclib');
include('Crypt/Rijndael.php');
include('Crypt/Random.php');
use phpseclib\Crypt\Rijndael as Crypt_Rijndael;
$text = '57F0-ECD3-1A3B-341E-BA39-F81B-F020-0DE0';
$secret = 'lkirwf897+22#bbtrm8814z5qq=498j5';
$iv = '741952hheeyy66#cs!9hjv887mxx7@8y';
function encrypt128($secret, $iv, $str)
{
return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $secret, $str, MCRYPT_MODE_CBC, $iv));
}
function encryptRJ256($key,$iv,$text)
{
$cipher = new Crypt_Rijndael('cbc');
$cipher->setBlockLength(256);
// keys are null-padded to the closest valid size
// longer than the longest key and it's truncated
$cipher->setKeyLength(256);
$cipher->setKey($key);
// the IV defaults to all-NULLs if not explicitly defined
$cipher->setIV($iv);
$cipher->disablePadding();
$length = strlen($text);
$pad = 32 - ($length % 32);
$text = str_pad($text, $length + $pad, chr(0));
return base64_encode($cipher->encrypt($text));
}
function decryptRJ256($key,$iv,$text)
{
$cipher = new Crypt_Rijndael('cbc'); // could use CRYPT_RIJNDAEL_MODE_CBC
$cipher->setBlockLength(256);
// keys are null-padded to the closest valid size
// longer than the longest key and it's truncated
$cipher->setKeyLength(256);
$cipher->setKey($key);
// the IV defaults to all-NULLs if not explicitly defined
$cipher->setIV($iv);
$cipher->disablePadding();
return $cipher->decrypt(base64_decode($text));
}
echo $text;
echo encrypt128($secret, $iv, $text);
echo "\n";
$text = encryptRJ256($secret, $iv, $text);
echo $text;
echo "\n";
echo decryptRJ256($secret, $iv, $text);
由于它在技术上可以使用此方法进行加密和解密,因此实际加密的字符串可能会因输入而异。 如果输入字符串恰好是 32 个字符长,加密后的字符串将比使用原始 mcrypt 方法长得多。
原因是$pad变量的计算。对于 32 个字符的输入,$pad 将是 32,这将导致一个 64 个字符的 $text 变量。如果你在解密方法中使用 rtrim 它实际上不是问题。
为了避免这种情况,我找到了另一种方法来填充来自 phpseclib 的 mcrypt_compat 包中的输入字符串:
$extra = strlen($data) % 32;
if ($extra) {
$data.= str_repeat("[=10=]", 32 - $extra);
}
有了这个,32 个字符的输入字符串将不会被填充。这会产生与直接使用 mcrypt 完全相同的加密字符串。
希望这对某人有所帮助 - 或者直接使用 mcrypt_compat 包。