C # Encryption to PHP Decryption

Я пытаюсь зашифровать некоторые (cookie) данные в C #, а затем расшифровать их в PHP. Я решил использовать шифрование Rijndael. Я почти заработал, но только часть текста расшифрована! Я начал работать в этом примере: расшифровать зашифрованную PHP строку в C #

Вот текст (JSON), который я шифрую (конфиденциальная информация удалена):

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

Поэтому я заходил в приложение C #, которое создает / кодирует файл cookie из сохраненного ключа и IV, а затем перенаправляет на приложение PHP, которое должно расшифровывать / читать cookie. Когда я дешифрую файл 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 + 

Вот код c #, который я использую для генерации случайного ключа и IV:

UPDATE : Я просто использую статический ключ / 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 < $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); 

Я немного не уверен в этой части, потому что весь код примера, который я видел, просто передается в кодировке base64 непосредственно в дешифратор, но в моем примере я должен использовать base64_decode перед тем, как передать его, иначе я получу ошибку что ключ и IV не являются правильной длиной.

UPDATE : Я использую ключи ASCII в формате, необходимом для PHP. Если я создаю ключи из класса RijndaelManaged, они не работают на стороне PHP, но я могу использовать ключи, которые, как известно, работают на стороне PHP и используют их на стороне RijndaelManaged C #.

Пожалуйста, дайте мне знать, если я оставил любую соответствующую информацию. ТИА!

Так как строка частично ОК, но в конце есть тарабарщина, она предложит проблему заполнения в рамках шифрования, которая ожидает точные блоки из 256 байтов. Я предлагаю установить дополнение как PKCS7 (PaddingMode.PKCS7) вместо Zeros на стороне C #, которое 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

 <?php function decryptRJ256($key,$iv,$encrypted) { //PHP strips "+" and replaces with " ", but we need "+" so add it back in... $encrypted = str_replace(' ', '+', $encrypted); //get all the bits $key = base64_decode($key); $iv = base64_decode($iv); $encrypted = base64_decode($encrypted); $rtn = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $encrypted, MCRYPT_MODE_CBC, $iv); $rtn = unpad($rtn); return($rtn); } //removes PKCS7 padding function unpad($value) { $blockSize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC); $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; } } } return substr($value, 0, strlen($value) - $packing); } ?> <pre> <?php $enc = $_COOKIE["MyCookie"]; $ky = ""; //INSERT THE KEY GENERATED BY THE C# CLASS HERE $iv = ""; //INSERT THE IV GENERATED BY THE C# CLASS HERE $json_user = json_decode(decryptRJ256($ky, $iv, $enc), true); var_dump($json_user); ?>