PHP和c#兼容Rijndael管理CBC模式,256位加密/解密
本文关键字:256位 加密 解密 模式 CBC 兼容 Rijndael 管理 PHP | 更新日期: 2023-09-27 18:18:53
这是我第一次尝试加密,我在将加密从PHP移植到c#时遇到了麻烦。
我已经在互联网上搜索了一个工作的解决方案,我的问题,但我所尝试的一切都不起作用。我在两种语言之间得到不同的结果。
在PHP中,我有以下代码:
function encrypt($Key, $strToEncrypt){
$md5Key = md5(pack("H*", $Key));
$md5Iv = md5($Key);
$block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
$padding = $block - (strlen($strToEncrypt) % $block);
$strToEncrypt .= str_repeat(chr($padding), $padding);
$enc = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $md5Key, $strToEncrypt, MCRYPT_MODE_CBC, $md5Iv);
$enc2 = base64_encode($enc);
return $enc2;
}
和c#中的以下代码:
public string Encrypt(string strToEncrypt)
{
string ret;
var pKey = PackH(_appkey);
var md5Key = CalcMd5(pKey);
var iv = CalcMd5(_appkey);
var enc =Encoding.UTF8;
var eIv = enc.GetBytes(iv);
var eKey = enc.GetBytes(md5Key);
using (var rij = new RijndaelManaged { BlockSize = 256, KeySize = 256, IV = eIv, Key = eKey, Mode = CipherMode.CBC, Padding = PaddingMode.Zeros})
using (var memoryStream = new MemoryStream())
using (var cryptoStream = new CryptoStream(memoryStream, rij.CreateEncryptor(eKey, eIv), CryptoStreamMode.Write))
{
using (var sw = new StreamWriter(cryptoStream))
{
sw.Write(strToEncrypt);
}
ret = Convert.ToBase64String(memoryStream.ToArray());
}
return ret;
}
c# Pack函数:
protected byte[] PackH(string hex)
{
if ((hex.Length % 2) == 1) hex += '0';
var bytes = new byte[hex.Length / 2];
for (var i = 0; i < hex.Length; i += 2)
{
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
}
return bytes;
}
和c# CalcMd5函数:
protected string CalcMd5(string textToEnc)
{
var sB = new StringBuilder();
using (var mdHash = MD5.Create())
{
var cHash = mdHash.ComputeHash(Encoding.UTF8.GetBytes(textToEnc));
foreach (byte t in cHash)
{
sB.Append(t.ToString("x2"));
}
}
return sB.ToString();
}
我有另一个CalcMd5函数,它接受一个字节[](它就像上面的那个,但没有GetBytes部分)。
需要加密的密钥和字符串在PHP和c#中是相同的:
关键字:"24acd2fcc7b20b8bd33ff45176f03061a09b729487e10d2dd38ab917"和
我要编码的字符串:"110114135AB96637711100"
在c#中,函数的结果是:"LHTqpxCJrONmbDdUFHyUZZUVf94z1RmSXWo85/wyEew="而在PHP中是:" 5MkCjfs0vp2HSKdY5XPUAuV68YsrP31Q+ddZsd5p7Sc=".
我试过修改c#中的填充模式,也试过在stackoverflow网站上找到的不同方法,但都不起作用。
我已经检查过了,传递给mcrypt函数和RijndaelManaged函数的最终密钥和Iv是相同的,都有32字节的大小。
奇怪的是,解密函数工作得非常好(它可以用c#函数解密PHP加密字符串,而其他围绕c#加密字符串的战争是用PHP函数解密的)。
可能是编码有问题吗?或者是填充物?还是我还忽略了什么?
问题似乎是你的填充,在php端你手动做pkcs7填充:
$padding = $block - (strlen($strToEncrypt) % $block);
$strToEncrypt .= str_repeat(chr($padding), $padding);
在c#端你使用:
Padding = PaddingMode.Zeros
要解决这个问题,您可以修改php代码,删除上面提到的两行,因为mcrypt()
会自动为您执行ZeroBytePadding
。
或者你可以将c#中的padding改为:
Padding = PaddingMode.PKCS7