C#加密到PHP解密

我正在尝试在C#中加密一些(cookie)数据,然后在PHP中解密它。 我选择使用Rijndael加密。 我几乎让它工作,除了只有部分文本被解密! 我从这个例子开始工作: 在C#中解密PHP加密字符串

这是我正在加密的文本(JSON)(删除了敏感信息):

{"DisplayName":"xxx", "Username": "yyy", "EmailAddress":"zzz"} 

所以我登录到C#app,它从存储的Key和IV创建/编码cookie,然后重定向到应该解密/读取cookie的PHP应用程序。 当我解密cookie时,它出现如下:

 {"DisplayName":"xxx","F A ;  HP=D       4  z    ť   k #E   R j 5 \ t. t D  " 

更新 :我已经进一步了,这就是结果

 string(96) "{"DisplayName":"xxx","Username":"yyy","EmailAddress" )ق  - J  k/VV-v   9 B`7^" 

正如你所看到的,它开始解密它,但后来搞砸了……

当解密字符串时它出来是正确的(使用填充,我有一个删除填充的函数),但是如果我将测试字符串改为一个字符,我会再次得到垃圾:

 B nHL Ek  ¿? UΣlO    OЏ M  NO/ fM   Lƾ CC Y>F  ~ qd + 

这是我用来生成随机密钥和IV的c#代码:

更新 :我现在只使用静态键/ IV,它们是:

 Key: lkirwf897+22#bbtrm8814z5qq=498j5 IV: 741952hheeyy66#cs!9hjv887mxx7@8y 

 RijndaelManaged symmetricKey = new RijndaelManaged(); symmetricKey.BlockSize = 256; symmetricKey.KeySize = 256; symmetricKey.Padding = PaddingMode.Zeros; symmetricKey.Mode = CipherMode.CBC; string key = Convert.ToBase64String(symmetricKey.Key); string IV = Convert.ToBase64String(symmetricKey.IV); 

然后,我将密钥和IV保存到数据库中,以便稍后检索以进行编码/解码。

这是完整的加密类:

 public static class Encryption { public static string Encrypt(string prm_text_to_encrypt, string prm_key, string prm_iv) { var sToEncrypt = prm_text_to_encrypt; var rj = new RijndaelManaged() { Padding = PaddingMode.PKCS7, Mode = CipherMode.CBC, KeySize = 256, BlockSize = 256, //FeedbackSize = 256 }; var key = Encoding.ASCII.GetBytes(prm_key); var IV = Encoding.ASCII.GetBytes(prm_iv); //var key = Convert.FromBase64String(prm_key); //var IV = Convert.FromBase64String(prm_iv); var encryptor = rj.CreateEncryptor(key, IV); var msEncrypt = new MemoryStream(); var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write); var toEncrypt = Encoding.ASCII.GetBytes(sToEncrypt); csEncrypt.Write(toEncrypt, 0, toEncrypt.Length); csEncrypt.FlushFinalBlock(); var encrypted = msEncrypt.ToArray(); return (Convert.ToBase64String(encrypted)); } public static string Decrypt(string prm_text_to_decrypt, string prm_key, string prm_iv) { var sEncryptedString = prm_text_to_decrypt; var rj = new RijndaelManaged() { Padding = PaddingMode.PKCS7, Mode = CipherMode.CBC, KeySize = 256, BlockSize = 256, //FeedbackSize = 256 }; var key = Encoding.ASCII.GetBytes(prm_key); var IV = Encoding.ASCII.GetBytes(prm_iv); //var key = Convert.FromBase64String(prm_key); //var IV = Convert.FromBase64String(prm_iv); var decryptor = rj.CreateDecryptor(key, IV); var sEncrypted = Convert.FromBase64String(sEncryptedString); var fromEncrypt = new byte[sEncrypted.Length]; var msDecrypt = new MemoryStream(sEncrypted); var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read); csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length); return (Encoding.ASCII.GetString(fromEncrypt)); } public static void GenerateKeyIV(out string key, out string IV) { var rj = new RijndaelManaged() { Padding = PaddingMode.PKCS7, Mode = CipherMode.CBC, KeySize = 256, BlockSize = 256, //FeedbackSize = 256 }; rj.GenerateKey(); rj.GenerateIV(); key = Convert.ToBase64String(rj.Key); IV = Convert.ToBase64String(rj.IV); } } 

这是我用来解密数据的PHP代码:

  function decryptRJ256($key,$iv,$string_to_decrypt) { $string_to_decrypt = base64_decode($string_to_decrypt); $rtn = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $string_to_decrypt, MCRYPT_MODE_CBC, $iv); //$rtn = rtrim($rtn, "\0\4"); $rtn = unpad($rtn); return($rtn); } function unpad($value) { $blockSize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC); //apply pkcs7 padding removal $packing = ord($value[strlen($value) - 1]); if($packing && $packing = strlen($value) - $packing; $P--){ if(ord($value{$P}) != $packing){ $packing = 0; }//end if }//end for }//end if return substr($value, 0, strlen($value) - $packing); } $ky = 'lkirwf897+22#bbtrm8814z5qq=498j5'; // 32 * 8 = 256 bit key $iv = '741952hheeyy66#cs!9hjv887mxx7@8y'; // 32 * 8 = 256 bit iv $enc = $_COOKIE["MyCookie"]; $dtext = decryptRJ256($ky, $iv, $enc); var_dump($dtext); 

我对这一部分有点不确定,因为我看到的所有示例代码都只是将base64编码的字符串直接传递给解密器,但在我的示例中,我必须在传递它之前对其进行base64_decode,否则我会收到错误键和IV不是正确的长度。

更新 :我正在使用PHP所需格式的ASCII密钥。 如果我从RijndaelManaged类生成键,他们不能在PHP端工作,但我可以使用已知在PHP端工作的键并在RijndaelManaged C#端使用它们。

如果我遗漏任何相关信息,请告诉我。 TIA!

由于字符串部分正常,但最后会出现乱码,这表明加密中的填充问题需要256字节的精确块。 我建议在C#端将填充设置为PKCS7 (PaddingMode.PKCS7)而不是Zeros ,PHP将理解没有问题(因为它是该解析器的默认模式)。

编辑:哎呀,我没注意到你的PHP中有以下内容:

 $enc = $_COOKIE["MyCookie"]; 

这是警告。 PHP可能无法按原样获取加密数据,并且正在运行一些urldecode清理。 您应该打印此变量,以确保它与C#代码发送的内容完全匹配。

EDIT2:

通过添加以下内容将空格转换为cookie中的缺失+字符:

 str_replace(' ', '+', $enc); 

对于后人,我在这里放置完整的解决方案。

C#加密类

 public static class Encryption { public static string Encrypt(string prm_text_to_encrypt, string prm_key, string prm_iv) { var sToEncrypt = prm_text_to_encrypt; var rj = new RijndaelManaged() { Padding = PaddingMode.PKCS7, Mode = CipherMode.CBC, KeySize = 256, BlockSize = 256, }; var key = Convert.FromBase64String(prm_key); var IV = Convert.FromBase64String(prm_iv); var encryptor = rj.CreateEncryptor(key, IV); var msEncrypt = new MemoryStream(); var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write); var toEncrypt = Encoding.ASCII.GetBytes(sToEncrypt); csEncrypt.Write(toEncrypt, 0, toEncrypt.Length); csEncrypt.FlushFinalBlock(); var encrypted = msEncrypt.ToArray(); return (Convert.ToBase64String(encrypted)); } public static string Decrypt(string prm_text_to_decrypt, string prm_key, string prm_iv) { var sEncryptedString = prm_text_to_decrypt; var rj = new RijndaelManaged() { Padding = PaddingMode.PKCS7, Mode = CipherMode.CBC, KeySize = 256, BlockSize = 256, }; var key = Convert.FromBase64String(prm_key); var IV = Convert.FromBase64String(prm_iv); var decryptor = rj.CreateDecryptor(key, IV); var sEncrypted = Convert.FromBase64String(sEncryptedString); var fromEncrypt = new byte[sEncrypted.Length]; var msDecrypt = new MemoryStream(sEncrypted); var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read); csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length); return (Encoding.ASCII.GetString(fromEncrypt)); } public static void GenerateKeyIV(out string key, out string IV) { var rj = new RijndaelManaged() { Padding = PaddingMode.PKCS7, Mode = CipherMode.CBC, KeySize = 256, BlockSize = 256, }; rj.GenerateKey(); rj.GenerateIV(); key = Convert.ToBase64String(rj.Key); IV = Convert.ToBase64String(rj.IV); } } 

PHP解密片段

 = strlen($value) - $packing; $P--) { if(ord($value{$P}) != $packing) { $packing = 0; } } } return substr($value, 0, strlen($value) - $packing); } ?>