将C#TripleDESCryptoServiceProvider加密移植到PHP
本文关键字:PHP C#TripleDESCryptoServiceProvider 加密 | 更新日期: 2024-09-22 12:14:22
有一个用C#编写的项目,它使用以下代码加密/解密数据库中的数据:
public string EncryptString(string Text)
{
byte[] IV = new byte[8] { 1, 2, 3, 4, 5, 6, 7, 8 };
string Key = "abcdef";
byte[] buffer = Encoding.UTF8.GetBytes(Text);
TripleDESCryptoServiceProvider triple = new TripleDESCryptoServiceProvider();
MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
triple.IV = IV;
triple.Key = md5.ComputeHash(ASCIIEncoding.UTF8.GetBytes(Key));
byte[] encodeText = triple.CreateEncryptor().TransformFinalBlock(buffer, 0, buffer.Length);
string user = Convert.ToBase64String(encodeText);
return user;
}
public static string DecryptString(string EncryptText)
{
byte[] IV = new byte[8] { 1, 2, 3, 4, 5, 6, 7, 8 };
string Key = "abcdef";
byte[] decodeText = null;
byte[] buffer = Convert.FromBase64String(EncryptText);
TripleDESCryptoServiceProvider triple = new TripleDESCryptoServiceProvider();
MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
triple.IV = IV;
triple.Key = md5.ComputeHash(ASCIIEncoding.UTF8.GetBytes(Key));
decodeText = triple.CreateDecryptor().TransformFinalBlock(buffer, 0, buffer.Length);
return Encoding.UTF8.GetString(decodeText);
}
现在我应该在PHP中也这样做。到目前为止,我已经接近以下代码:
define('CIPHER', 'tripledes');
define('MODE', 'cbc');
function Encrypt($data)
{
$iv = chr(1) . chr(2) . chr(3) . chr(4) . chr(5) . chr(6) . chr(7) . chr(8);
$key = 'abcdef';
$tripleKey = substr(md5($key), 0, mcrypt_get_key_size(CIPHER, MODE));
$encodedText = mcrypt_encrypt(CIPHER, $tripleKey, $data, MODE, $iv);
return base64_encode($encodedText);
}
function Decrypt($data)
{
$iv = chr(1) . chr(2) . chr(3) . chr(4) . chr(5) . chr(6) . chr(7) . chr(8);
$key = 'abcdef';
$tripleKey = substr(md5($key), 0, mcrypt_get_key_size(CIPHER, MODE));
$decodedText = mcrypt_decrypt(CIPHER, $tripleKey, base64_decode($data), MODE, $iv);
return $decodedText;
}
但是我无法解密由C#代码加密的字符串!我不是加密专家,有人能告诉我应该使用哪种加密算法和哪种模式吗?
您的主要问题在于密钥的处理。有一个问题很琐碎:在PHP中,md5
函数默认返回十六进制的散列转储,而您需要原始二进制值来匹配C#的MD5CryptoServiceProvider.ComputeHash()
。为此,只需在PHP调用(md5(key, true)
)中添加一个true
参数。
另一个问题稍微复杂一点:MD5返回128位的散列,而3DES使用192位的密钥(实际上是168位的密钥,其余的是奇偶校验位,但我们在这里忽略它)。当您为PHP实现提供一个太短的密钥时,它会使用零字节填充密钥;然而,3DES的.NET/CSP实现似乎从一开始就重复密钥字节(将密钥包裹起来)。因此,为了匹配PHP中的.NET行为,需要手动包装密钥($key . $key
)。
最后一个问题是填充:PHP使用零填充数据,而.NET默认使用PKCS#7填充。如果需要正确处理填充,则需要在加密时添加它,在解密时删除它。
define('CIPHER', 'tripledes');
define('MODE', 'cbc');
function Encrypt($data)
{
$iv = chr(1) . chr(2) . chr(3) . chr(4) . chr(5) . chr(6) . chr(7) . chr(8);
$key = 'abcdef';
// determine key bytes from the key text, using MD5 and wrapping around
$key = md5($key, true);
$key = $key . $key;
$tripleKey = substr($key, 0, mcrypt_get_key_size(CIPHER, MODE));
// add PKCS#7 padding
$blocksize = mcrypt_get_block_size(CIPHER, MODE);
$paddingSize = $blocksize - (strlen($data) % $blocksize);
$data .= str_repeat(chr($paddingSize), $paddingSize);
$encodedText = mcrypt_encrypt(CIPHER, $tripleKey, $data, MODE, $iv);
return base64_encode($encodedText);
}
function Decrypt($data)
{
$iv = chr(1) . chr(2) . chr(3) . chr(4) . chr(5) . chr(6) . chr(7) . chr(8);
// determine key bytes from the key text, using MD5 and wrapping around
$key = 'abcdef';
$key = md5($key, true);
$key = $key . $key;
$tripleKey = substr($key, 0, mcrypt_get_key_size(CIPHER, MODE));
$decodedText = mcrypt_decrypt(CIPHER, $tripleKey, base64_decode($data), MODE, $iv);
// check and remove PKCS#7 padding
if (!$decodedText) return $decodedText;
$lastByte = ord($decodedText[strlen($decodedText) - 1]);
if ($lastByte == 0 || $lastByte > mcrypt_get_block_size(CIPHER, MODE)) return FALSE;
$paddingText = substr($decodedText, -$lastByte, $lastByte);
$decodedText = substr($decodedText, 0, -$lastByte);
if ($paddingText != str_repeat(chr($lastByte), $lastByte)) return FALSE;
return $decodedText;
}
但是,正如上面的一位评论员已经说过的那样,由于多种原因,这并不是一个真正好的加密实现。(我对调整的实现也没有真正强化。)