(前言:我是加密和安全的新手,认为这是一种有趣的学习方式)
我正在用C#构建一个程序,它与使用标准HTTP协议用PHP编写的服务器进行通信。我希望两个程序都能够发送和接收加密数据。但是,尽管它们都使用相同类型的函数,但似乎在处理加密方面存在不一致之处。
两个程序都在CBC模式下使用Rjindael 128位。
对于演示/测试,我创建了两个几乎完全相同的函数,每个函数使用相同的字符串,对其进行加密,并将结果吐出为base64字符串。
PHP函数:
public static function EncryptionTest () {
echo 'Testing Encryption to base64 string...<br/>';
$originalString = 'This is the original String! How cool is that?';
$key = "abcdefghijklmnopqrstuvwxyz012345";
$iv = "1234567890123456";
$encrypted = mcrypt_encrypt (MCRYPT_RIJNDAEL_128, $key, $originalString, MCRYPT_MODE_CBC, $iv);
echo base64_encode ($encrypted);
}
它是C#对应物:
public static void EncryptionTest ()
{
System.Console.WriteLine ("Testing Encryption to base64 string...");
string originalString = "This is the original String! How cool is that?";
byte [] encryptedData;
byte [] key = System.Text.ASCIIEncoding.UTF8.GetBytes ("abcdefghijklmnopqrstuvwxyz012345");
byte [] iv = System.Text.ASCIIEncoding.UTF8.GetBytes ("1234567890123456");
RijndaelManaged cryptor = new RijndaelManaged ();
cryptor.Key = key;
cryptor.IV = iv;
cryptor.BlockSize = 128;
cryptor.Mode = CipherMode.CBC;
ICryptoTransform encryptor = cryptor.CreateEncryptor (cryptor.Key, cryptor.IV);
using (MemoryStream msEncrypt = new MemoryStream ())
{
using (CryptoStream csEncrypt = new CryptoStream (msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter (csEncrypt) )
{
swEncrypt.Write (originalString);
}
encryptedData = msEncrypt.ToArray ();
}
}
System.Console.WriteLine (System.Convert.ToBase64String (encryptedData) );
}
现在,这是PHP结果:
测试加密到base64字符串... yzwIdowhLj + cMOFPMuHSA80pWQ6R8yfFQlEsLx5kIzUOJdFykLjsaKfK4VfaBGRv
C#结果:
测试加密到base64字符串... yzwIdowhLj + cMOFPMuHSA80pWQ6R8yfFQlEsLx5kIzUg74mGEQf9iW + OQ68m6cpp
正如你所看到的,这两个结果显然是加密的(好),是相同数量的字符(好),但是不同(可能不好)。
我编写了解密测试,它们接受这些字符串并对其进行处理。这是PHP函数:
public static function DecryptionTest () {
$phpBase64 = 'yzwIdowhLj+cMOFPMuHSA80pWQ6R8yfFQlEsLx5kIzUOJdFykLjsaKfK4VfaBGRv';
$csBase64 = 'yzwIdowhLj+cMOFPMuHSA80pWQ6R8yfFQlEsLx5kIzUg74mGEQf9iW+OQ68m6cpp';
$key = "abcdefghijklmnopqrstuvwxyz012345";
$iv = "1234567890123456";
$phpEncrypted = base64_decode ($phpBase64);
$phpDecrypted = mcrypt_decrypt (MCRYPT_RIJNDAEL_128, $key, $phpEncrypted, MCRYPT_MODE_CBC, $iv);
$csEncrypted = base64_decode ($csBase64);
$csDecrypted = mcrypt_decrypt (MCRYPT_RIJNDAEL_128, $key, $csEncrypted, MCRYPT_MODE_CBC, $iv);
echo 'Decrypted PHP string: "' . $phpDecrypted . '"<br/>' .
'Decrypted CS string: "' . $csDecrypted . '"';
}
和C#版本:
public static void DecryptionTest ()
{
System.Console.WriteLine ("Testing Decryption for PHP and CS generated base64 strings!");
string phpBase64 = "yzwIdowhLj+cMOFPMuHSA80pWQ6R8yfFQlEsLx5kIzUOJdFykLjsaKfK4VfaBGRv";
string csBase64 = "yzwIdowhLj+cMOFPMuHSA80pWQ6R8yfFQlEsLx5kIzUg74mGEQf9iW+OQ68m6cpp";
byte [] phpEncrypted = System.Convert.FromBase64String (phpBase64);
byte [] csEncrypted = System.Convert.FromBase64String (csBase64);
string phpDecrypted;
string csDecrypted;
byte [] encryptedData;
byte [] key = System.Text.ASCIIEncoding.UTF8.GetBytes ("abcdefghijklmnopqrstuvwxyz012345");
byte [] iv = System.Text.ASCIIEncoding.UTF8.GetBytes ("1234567890123456");
RijndaelManaged cryptor = new RijndaelManaged ();
cryptor.Key = key;
cryptor.IV = iv;
cryptor.BlockSize = 128;
cryptor.Mode = CipherMode.CBC;
ICryptoTransform decryptor = cryptor.CreateDecryptor (cryptor.Key, cryptor.IV);
using (MemoryStream msDecrypt = new MemoryStream (csEncrypted))
{
using (CryptoStream csDecrypt = new CryptoStream (msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader swDecrypt = new StreamReader (csDecrypt) )
{
csDecrypted = swDecrypt.ReadToEnd ();
}
}
}
System.Console.WriteLine ("Decrypted CS string: \"" + csDecrypted + "\"");
using (MemoryStream msDecrypt = new MemoryStream (phpEncrypted))
{
using (CryptoStream csDecrypt = new CryptoStream (msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader swDecrypt = new StreamReader (csDecrypt) )
{
phpDecrypted = swDecrypt.ReadToEnd ();
}
}
}
System.Console.WriteLine ("Decrypted PHP string: \"" + phpDecrypted + "\"");
}
PHP结果:
解密的PHP字符串:“这是原始字符串!这有多酷?”
解密的CS字符串:“这是原始字符串!这有多酷?”
C#结果:
解密的CS字符串:“这是原始字符串!这有多酷?”
CryptographicException:错误的PKCS7填充。长度0无效。 at Mono.Security.Cryptography.SymmetricTransform.ThrowBadPaddingException(PaddingMode padding,Int32 length,Int32 position)[0x0005c] in&gt; /Applications/buildAgent/work/84669f285f6a667f/mcs/class/corlib/Mono.Security.Cryptography/SymmetricTransform.cs:363
因此,基本上,PHP代码可以成功解密两个base64字符串,但C#代码只能解密由其自己的解密器创建的base64字符串。
很多这是我在互联网上找到的代码,并根据我的需要进行了修改。就像我说的那样,我是一个加密的新手,但我在这里已经相当远了。我可以整天进行理论和测试,但它开始影响我的日程安排,所以我正在寻找其他人的见解,为什么它不起作用。谢谢!
答案 0 :(得分:4)
您需要使用PHPSecLib,因为PHP
实施与C++/C#
不兼容。它有不同的填充大小(这里不是加密专家,但这是我经过几天测试后发现的)。因此,使用phpseclib
中的原生实现,它将起作用。
不久前我自己陷入了这个问题。但是C++
/ CryptoAPI
和PHP
。