PHP-эквивалент .net AES-шифрование

Я работаю над интеграцией обмена данными с моим клиентом, и данные, которые они отправляют мне, зашифровываются с использованием их метода encrypt C # (ниже).

В моем приложении работает PHP 5.3, и мне нужен эквивалентный код для дешифрования отправляемых данных. У меня есть PHP-код, но он не будет дешифровать данные клиента правильно для меня.

Понятно, что я ошибаюсь в своих методах шифрования / дешифрования, ключ IV или что-то в этом роде. Кто-нибудь может заметить ошибку?

Благодарю.

Код C # (от моего клиента):

 using System; using System.Security.Cryptography; using System.Text; using System.IO; public class Program { public static void Main() { var text = "this is a plain string"; var enc = Program.Encrypt(text); Console.WriteLine(enc); Console.WriteLine(Program.Decrypt(enc)); } public static string Encrypt(string clearText) { var EncryptionKey = "1234567890123456"; byte[] clearBytes = Encoding.Unicode.GetBytes(clearText); using (Aes encryptor = Aes.Create()) { byte[] IV = new byte[15]; var rand = new Random(); rand.NextBytes(IV); Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, IV); encryptor.Key = pdb.GetBytes(32); encryptor.IV = pdb.GetBytes(16); using (MemoryStream ms = new MemoryStream()) { using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write)) { cs.Write(clearBytes, 0, clearBytes.Length); cs.Close(); } clearText = Convert.ToBase64String(IV) + Convert.ToBase64String(ms.ToArray()); } } return clearText; } public static string Decrypt(string cipherText) { var EncryptionKey = "1234567890123456"; byte[] IV = Convert.FromBase64String(cipherText.Substring(0, 20)); cipherText = cipherText.Substring(20).Replace(" ", "+"); byte[] cipherBytes = Convert.FromBase64String(cipherText); using (Aes encryptor = Aes.Create()) { Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, IV); encryptor.Key = pdb.GetBytes(32); encryptor.IV = pdb.GetBytes(16); using (MemoryStream ms = new MemoryStream()) { using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write)) { cs.Write(cipherBytes, 0, cipherBytes.Length); cs.Close(); } cipherText = Encoding.Unicode.GetString(ms.ToArray()); } } return cipherText; } } 

Код PHP У меня есть:

 public function encrypt($plainText) { $secretKey = '1234567890123456'; return rtrim( base64_encode( mcrypt_encrypt( MCRYPT_RIJNDAEL_256, $secretKey, $plainText, MCRYPT_MODE_ECB, mcrypt_create_iv( mcrypt_get_iv_size( MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB ), MCRYPT_RAND) ) ), "\0" ); } public function decrypt($encodedData) { $secretKey = '1234567890123456'; return rtrim( mcrypt_decrypt( MCRYPT_RIJNDAEL_256, $secretKey, base64_decode($encodedData), MCRYPT_MODE_ECB, mcrypt_create_iv( mcrypt_get_iv_size( MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB ), MCRYPT_RAND ) ), "\0" ); } 

Кто-нибудь может заметить ошибку?

Да, и большой – это не ваша вина: запутанный API mcrypt снова наносит удар .

Тем не менее, здесь есть несколько ошибок.

 return rtrim( // unnecessary base64_encode( mcrypt_encrypt( MCRYPT_RIJNDAEL_256, // Not AES $secretKey, $plainText, MCRYPT_MODE_ECB, // BAD, use MCRYPT_MODE_CBC or 'ctr' instead mcrypt_create_iv( mcrypt_get_iv_size( // unless you're going make this MCRYPT_RIJNDAEL_256, // configurable, you should just MCRYPT_MODE_ECB // hard-code this as an integer ), MCRYPT_RAND) // BAD, use MCRYPT_DEV_URANDOM ) ), "\0" ); 

Если вы собираетесь генерировать IV, он должен быть передан, чтобы ваш получатель мог успешно расшифровать один и тот же первый блок. C # код делает это, PHP не делает.

С точки зрения криптографии вы должны рассмотреть как на C # land, так и на PHP, развертывая протокол Encrypt, а затем Authenticate. См. Это сообщение в блоге по шифрованию и аутентификации . Кроме того, весь криптокод, который вы когда-либо писали, вероятно, сломан .

Похоже, скрипт PHP использует неправильный режим:
https://msdn.microsoft.com/en-us/library/system.security.cryptography.symmetricalgorithm.mode%28v=vs.110%29.aspx
Функции C # не устанавливают какой-либо режим, поэтому по умолчанию используется CBC.
Вместо этого часть PHP использует ECB, что не только неправильно, но и небезопасно.