C#加密到PHP解密 [英] C# Encryption to PHP Decryption
问题描述
我正在加密C#中的一些(cookie)数据,然后用PHP解密它。我选择使用Rijndael加密。我几乎得到它的工作,除了文本的一部分被解密!我从这个例子开始工作:在C#中解密PHP加密字符串
以下是我正在加密的文本(JSON)(敏感信息已删除):
{DisplayName:xxx,用户名:yyy,EmailAddress:zzz}
所以我登录到从存储的Key和IV中创建/编码cookie的C#应用程序,然后重定向到应用于解密/读取cookie的PHP应用程序。当我解密cookie时,它出现如下:
{DisplayName:xxx ,F A; HP=D 4 z ť k #E R j 5 \ t。t D
更新:我有一点点进一步,这是现在的结果
string(96){DisplayName:xxx,用户名: yyy,EmailAddress ) J k/ VV-v 9 B`7^
正如你所看到的,它开始解密它,但是被弄乱了...
当解密字符串它出来正确(填充,我有一个功能来删除填充),但如果我将测试字符串更改为一个字符,我再次收到垃圾:
< +
这是我使用的c#代码生成随机密钥和IV:
更新:我现在只使用静态密钥/ IV, :
键: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代码:
函数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);
}
函数unpad($ value)
{
$ blockSize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_256,MCRYPT_MODE_CBC);
//应用pkcs7填充删除
$ packing = ord($ value [strlen($ value) - 1]);
if($ pack&& $ packing< $ blockSize){
for($ P = strlen($ value) - 1; $ P> = strlen($ value) ; $ P - ){
if(ord($ value {$ P})!= $ packing){
$ packing = 0;
} // end if
} // end for
} // end if
return substr($ value,0,strlen($ value) - $包装);
}
$ ky ='lkirwf897 + 22#bbtrm8814z5qq = 498j5'; // 32 * 8 = 256位键
$ iv ='741952hheeyy66#cs!9hjv887mxx7 @ 8y'; // 32 * 8 = 256位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);
I'm trying to encrypt some (cookie) data in C# and then decrypt it in PHP. I have chosen to use Rijndael encryption. I've almost got it working, except only part of the text is decrypted! I started working from this example: Decrypt PHP encrypted string in C#
Here's the text (JSON) that I am encrypting (sensitive information removed):
{"DisplayName":"xxx", "Username": "yyy", "EmailAddress":"zzz"}
So I login to the C# app which creates/encodes the cookie from stored Key and IV and then redirects to the PHP app which is supposed to decrypt/read the cookie. When I decrypt the cookie, it comes out like this:
{"DisplayName":"xxx","F�A ;��HP=D�������4��z����ť���k�#E���R�j�5�\�t. t�D��"
UPDATE: i've gotten a little bit further and this is now the result
string(96) "{"DisplayName":"xxx","Username":"yyy","EmailAddress"�)ق��-�J��k/VV-v� �9�B`7^"
As you can see, it starts decrypting it, but then gets messed up...
When Decrypt the string it comes out correct (with padding, which I have a function to remove padding), but if I change the test string by one character I get garbage again:
B�nHL�Ek �¿?�UΣlO����OЏ�M��NO/�f.M���Lƾ�CC�Y>F��~�qd�+
Here's the c# code I use to generate the random Key and IV:
UPDATE: I'm just using static key/IV for now, here they are:
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);
I then save the key and IV to a database to be retrieved later for encoding/decoding.
This is the full encryption class:
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);
}
}
Here's the PHP code I am using to decrypt the data:
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 < $blockSize){
for($P = strlen($value) - 1; $P >= 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);
I am a little unsure about this part, because all of the example code I've seen simply passes in the base64 encoded string directly to the decryptor, but in my example, I have to base64_decode it before I pass it otherwise I get the error that the key and IV are not the correct length.
UPDATE: I'm using ASCII keys in the format needed by PHP. If I generate keys from the RijndaelManaged class they dont work on the PHP side, but I can use keys that are known to work on PHP side and use them in the RijndaelManaged C# side.
Please let me know if I left out any pertinent information. TIA!
Since the string is partially OK, but there is gibberish at the end it would suggest a padding problem within the encryption which expects exact blocks of 256 bytes. I suggest setting the padding as PKCS7 (PaddingMode.PKCS7) instead of Zeros on the C# side which PHP will understand without issues (as it's the default mode on that parser).
Edit: Oops, I did not notice that you had the following in your PHP:
$enc = $_COOKIE["MyCookie"];
This is the caveat. PHP is likely not getting the encrypted data as-is and is running some urldecode sanitizing. You should print this variable to see that it really matches what is being sent from the C# code.
Edit2:
Convert the whitespaces to missing + characters from the cookie by adding this:
str_replace(' ', '+', $enc);
这篇关于C#加密到PHP解密的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!