C#和PHP之间的对称加密
目前,我对PHP和C#之间的对称加密很感兴趣,无论我如何重写我的脚本,我总是会收到一条错误消息,或者加密的文本更加加密。3天来,我一直在尝试互联网上提供的所有建议,但都没有成功,我希望有人能帮助我完成加密和解密过程。您可以在下面找到我的脚本示例 这是我构建和发送包含密钥、IV和加密文本的消息的方式:C#和PHP之间的对称加密,c#,php,encryption,C#,Php,Encryption,目前,我对PHP和C#之间的对称加密很感兴趣,无论我如何重写我的脚本,我总是会收到一条错误消息,或者加密的文本更加加密。3天来,我一直在尝试互联网上提供的所有建议,但都没有成功,我希望有人能帮助我完成加密和解密过程。您可以在下面找到我的脚本示例 这是我构建和发送包含密钥、IV和加密文本的消息的方式: function alphaNumeric () : string { $number = rand(32, 127); return $number >= 48 &
function alphaNumeric () : string {
$number = rand(32, 127);
return $number >= 48 && $number <= 57
|| $number >= 65 && $number <= 90
|| $number >= 97 && $number <= 122
? chr($number)
: alphaNumeric();
}
function randomBytes (int $length, string $byteString = '') : string {
return $length > 0
? randomBytes($length - 1, $byteString.alphaNumeric())
: $byteString;
}
$key = randomBytes(16);
$iv = randomBytes(16);
$data = 'This text should be encrypted in PHP and decrypted in C#!';
$encrypted = openssl_encrypt($data, 'aes-128-cbc', $key, 1, $iv);
$message = $key.$iv.$encrypted;
file_put_contents('message.txt', $message);
echo $message;
die;
最后是c#代码,它应该解密消息:
public static void Main()
{
var client = new HttpClient();
var requestUri = "http://localhost/message.php";
while (Console.ReadLine() == string.Empty)
{
var response = client.GetAsync(requestUri).Result;
if (!response.IsSuccessStatusCode)
{
continue;
}
var content = response.Content.ReadAsStringAsync().Result;
if (string.IsNullOrWhiteSpace(content) || content.Length < 48)
{
continue;
}
File.WriteAllText("../../../message.txt", content);
var keyString = content.Substring(0, 16);
var keyBytes = Encoding.UTF8.GetBytes(keyString);
var ivString = content.Substring(16, 16);
var ivBytes = Encoding.UTF8.GetBytes(ivString);
var encString = content.Substring(32);
var encBytes = Encoding.UTF8.GetBytes(encString);
Console.WriteLine($"{keyBytes.Length}: {keyString}");
Console.WriteLine($"{ivBytes.Length}: {ivString}");
Console.WriteLine($"{encBytes.Length}: {encString}");
try
{
var plainText = Decrypt(encBytes, keyBytes, ivBytes);
Console.WriteLine(plainText);
}
catch (Exception e)
{
Console.WriteLine($"Error: {e.Message}");
}
}
}
static string Decrypt(byte[] encrypted, byte[] key, byte[] iv)
{
using var alg = AesCryptoServiceProvider.Create();
//alg.IV = iv;
//alg.Key = key;
//alg.KeySize = 128;
//alg.BlockSize = 256;
//alg.Mode = CipherMode.CBC;
alg.Padding = PaddingMode.PKCS7;
var decryptor = alg.CreateDecryptor(key, iv);
using var ms = new MemoryStream(encrypted);
using var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read);
using var sr = new StreamReader(cs);
return sr.ReadToEnd();
}
publicstaticvoidmain()
{
var client=新的HttpClient();
var requestUri=”http://localhost/message.php";
while(Console.ReadLine()==string.Empty)
{
var response=client.GetAsync(requestUri).Result;
如果(!response.issucessStatusCode)
{
继续;
}
var content=response.content.ReadAsStringAsync().Result;
if(string.IsNullOrWhiteSpace(content)| | content.Length<48)
{
继续;
}
File.writealText(“../../../message.txt”,content);
var-keyString=content.Substring(0,16);
var keyBytes=Encoding.UTF8.GetBytes(keyString);
var ivString=content.Substring(16,16);
var ivBytes=Encoding.UTF8.GetBytes(ivString);
var encString=content.Substring(32);
var encBytes=Encoding.UTF8.GetBytes(encString);
WriteLine($“{keyBytes.Length}:{keyString}”);
WriteLine($“{ivBytes.Length}:{ivString}”);
WriteLine($“{encBytes.Length}:{encString}”);
尝试
{
var plainText=解密(encBytes、keyBytes、ivBytes);
Console.WriteLine(纯文本);
}
捕获(例外e)
{
WriteLine($“错误:{e.Message}”);
}
}
}
静态字符串解密(字节[]加密,字节[]密钥,字节[]iv)
{
使用var alg=aescyptoserviceprovider.Create();
//alg.IV=IV;
//alg.Key=Key;
//alg.KeySize=128;
//alg.BlockSize=256;
//alg.Mode=CipherMode.CBC;
alg.Padding=PaddingMode.PKCS7;
var decryptor=alg.CreateDecryptor(密钥,iv);
使用var ms=新内存流(加密);
使用var cs=新的加密流(ms、解密器、CryptoStreamMode.Read);
使用var sr=新的StreamReader(cs);
返回sr.ReadToEnd();
}
这是我目前收到的信息:
提前感谢。C代码中有以下问题:
- 在PHP代码中会生成一个32字节的密钥,但由于指定了AES-128(
),因此只考虑前16个字节。因此,在C#代码中,只考虑密钥的前16个字节,而不是完整的32个字节(参见第一条注释)AES-128-cbc
- 在PHP代码中,openssl#u encrypt返回默认编码的密文Base64,因此这部分密文必须在C#代码中进行Base64解码,而不是UTF8编码(参见第二条注释)
默认情况下使用CBC模式和PKCS7填充,因此无需在C代码中明确指定这两种模式AESCryptServiceProvider
请考虑PHP代码,当为AES-128生成32字节密钥时,它是不一致的。相反,应该生成一个16字节的密钥。或者,您可以切换到AES-256(
AES-256-cbc
)。还要记住第一条注释中的提示:密钥通常不能与密文一起发送,因为任何攻击者都可以轻松解密数据。两个“快速截图”:在PHP端,您为加密函数“aes-128-cbc”提供一个32个字符长的密钥。当使用“128”键时,任何更长的键都会被截断16个字符,因此您应该在PHP和C#端截断该键[将子字符串参数缩短为16]。第二:PHP默认使用PKCS7Padding,所以在C端也需要它[不知道默认值]。顺便说一句:将密钥和iv与加密消息一起发送意味着发送明文,是不安全的。此外:openssl\u encrypt
默认使用Base64编码数据,即数据的第三部分(实际密文)必须是Base64解码:var encBytes=Convert.FromBase64String(encString)代码>AesCryptoServiceProvider
默认情况下使用PKCS7,即填充正常。我将两边的密钥长度减少到16字节,但得到的消息相同,当我使用Base64解码时,它抛出一个异常,表示:输入不是有效的Base-64字符串,因为它包含一个非Base 64字符,多于两个填充字符,或者是填充字符中的非法字符。我得到了它,所以我使用16字节作为密钥和向量,并对以base64编码的加密消息进行了编码,然后对base64消息进行了解码
string content = "UeWeXUAnu98RKTkMiBGLWpMNy4CRKJErOqTTUfJWrtXziFTELGG+647lw/XT846dj8tlNMITLVBg2cKS3dFINeKot4zlb+gVpfq4oIb/M3a8n3a9XWaeIOrHpNedZmMrYiZoCQ==";
var keyString = content.Substring(0, 16);
var keyBytes = Encoding.UTF8.GetBytes(keyString);
var ivString = content.Substring(32, 16);
var ivBytes = Encoding.UTF8.GetBytes(ivString);
var encString = content.Substring(48);
var encBytes = Convert.FromBase64String(encString);
using var alg = AesCryptoServiceProvider.Create();
alg.IV = ivBytes;
alg.Key = keyBytes;
var decryptor = alg.CreateDecryptor(keyBytes, ivBytes);
using var ms = new MemoryStream(encBytes);
using var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read);
using var sr = new StreamReader(cs);
string decrypted = sr.ReadToEnd();
Console.WriteLine(decrypted);