Rewrite Rijndael 256 C # Код шифрования в PHP

У меня есть алгоритм шифрования / дешифрования, написанный на C # – мне нужно иметь возможность производить такое же шифрование в PHP, чтобы я мог отправлять зашифрованный текст через HTTP, чтобы быть расшифрованным на стороне C #. Вот код C # для шифрования.

this.m_plainText = string.Empty; this.m_passPhrase = "passpharse"; this.m_saltValue = "saltvalue"; this.m_hashAlgorithm = "SHA1"; this.m_passwordIterations = 2; this.m_initVector = "1a2b3c4d5e6f7g8h"; this.m_keySize = 256; public string Encrypt() { string plainText = this.m_plainText; string passPhrase = this.m_passPhrase; string saltValue = this.m_saltValue; string hashAlgorithm = this.m_hashAlgorithm; int passwordIterations = this.m_passwordIterations; string initVector = this.m_initVector; int keySize = this.m_keySize; // Convert strings into byte arrays. // Let us assume that strings only contain ASCII codes. // If strings include Unicode characters, use Unicode, UTF7, or UTF8 // encoding. byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector); byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue); // Convert our plaintext into a byte array. // Let us assume that plaintext contains UTF8-encoded characters. byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText); // First, we must create a password, from which the key will be derived. // This password will be generated from the specified passphrase and // salt value. The password will be created using the specified hash // algorithm. Password creation can be done in several iterations. PasswordDeriveBytes password = new PasswordDeriveBytes( passPhrase, saltValueBytes, hashAlgorithm, passwordIterations); // Use the password to generate pseudo-random bytes for the encryption // key. Specify the size of the key in bytes (instead of bits). byte[] keyBytes = password.GetBytes(keySize / 8); // Create uninitialized Rijndael encryption object. RijndaelManaged symmetricKey = new RijndaelManaged(); // It is reasonable to set encryption mode to Cipher Block Chaining // (CBC). Use default options for other symmetric key parameters. symmetricKey.Mode = CipherMode.CBC; // Generate encryptor from the existing key bytes and initialization // vector. Key size will be defined based on the number of the key // bytes. ICryptoTransform encryptor = symmetricKey.CreateEncryptor( keyBytes, initVectorBytes); // Define memory stream which will be used to hold encrypted data. MemoryStream memoryStream = new MemoryStream(); // Define cryptographic stream (always use Write mode for encryption). CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write); // Start encrypting. cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length); // Finish encrypting. cryptoStream.FlushFinalBlock(); // Convert our encrypted data from a memory stream into a byte array. byte[] cipherTextBytes = memoryStream.ToArray(); // Close both streams. memoryStream.Close(); cryptoStream.Close(); // Convert encrypted data into a base64-encoded string. string cipherText = Convert.ToBase64String(cipherTextBytes); // Return encrypted string. return cipherText; } 

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

 <?php /* * DEFINE CONSTANTS */ $HashPassPhrase = "passpharse"; $HashSalt = "saltvalue"; $HashAlgorithm = "SHA1"; $HashIterations = "2"; $InitVector = "1a2b3c4d5e6f7g8h"; // Must be 16 bytes $keySize = "256"; class Cipher { private $securekey, $iv; function __construct($textkey) { $this->securekey = hash($HashAlgorithm,$textkey,TRUE); $this->iv = $InitVector; } function encrypt($input) { return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $this->securekey, $input, MCRYPT_MODE_CBC, $this->iv)); } function decrypt($input) { return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $this->securekey, base64_decode($input), MCRYPT_MODE_CBC, $this->iv)); } } $cipher = new Cipher($HashPassPhrase); $encryptedtext = $cipher->encrypt("Text To Encrypt"); echo "->encrypt = $encryptedtext<br />"; $decryptedtext = $cipher->decrypt($encryptedtext); echo "->decrypt = $decryptedtext<br />"; var_dump($cipher); 

?>

Solutions Collecting From Web of "Rewrite Rijndael 256 C # Код шифрования в PHP"

Вам необходимо вывести ключ из фразы прохода так же, как код C # в PasswordDeriveBytes . Это задокументировано, чтобы сделать вывод ключа PBKDF1, согласно RFC2898 :

Этот класс использует расширение алгоритма PBKDF1, определенное в стандарте PKCS # 5 v2.0, для получения байтов, подходящих для использования в качестве ключевого материала из пароля. Стандарт документирован в IETF RRC 2898.

есть библиотеки PHP, которые реализуют PBKDF1 там, но на самом деле просто написать один с нуля на основе RFC:

PBKDF1 (P, S, c, dkLen)

Опции: Хэш
основная хеш-функция

Вход: P
пароль, октетная строка S соль, восьмеричный октет с номером итерации строки, положительное целое dkLen предполагаемая длина в октетах производного ключа, положительное целое число, максимум 16 для MD2 или MD5 и 20 для SHA-1

Вывод: ключ, созданный DK, строка dkLen-октет

шаги:

  1. If dkLen > 16 for MD2 and MD5, or dkLen > 20 for SHA-1, output "derived key too long" and stop. 2. Apply the underlying hash function Hash for c iterations to the concatenation of the password P and the salt S, then extract the first dkLen octets to produce a derived key DK: T_1 = Hash (P || S) , T_2 = Hash (T_1) , ... T_c = Hash (T_{c-1}) , DK = Tc<0..dkLen-1> 3. Output the derived key DK. 

обновленный

Когда вы находите себя в этой ситуации, вы обычно ищете пример реализации, который показывает значения на каждом шаге. например, на http://www.di-mgt.com.au/cryptoKDFs.html#examplespbkdf :

 Password = "password" = (0x)70617373776F7264 Salt = (0x)78578E5A5D63CB06 Count = 1000 kLen = 16 Key = PBKDF1(Password, Salt, Count, kLen) = (0x)DC19847E05C64D2FAF10EBFB4A3D2A20 P || S = 70617373776F726478578E5A5D63CB06 T_1= D1F94C4D447039B034494400F2E7DF9DCB67C308 T_2= 2BB479C1D369EA74BB976BBA2629744E8259C6F5 ... T_999= 6663F4611D61571068B5DA168974C6FF2C9775AC T_1000= DC19847E05C64D2FAF10EBFB4A3D2A20B4E35EFE Key= DC19847E05C64D2FAF10EBFB4A3D2A20 

Итак, теперь давайте напишем функцию PHP, которая делает это:

 function PBKDF1($pass,$salt,$count,$dklen) { $t = $pass.$salt; //echo 'S||P: '.bin2hex($t).'<br/>'; $t = sha1($t, true); //echo 'T1:' . bin2hex($t) . '<br/>'; for($i=2; $i <= $count; $i++) { $t = sha1($t, true); //echo 'T'.$i.':' . bin2hex($t) . '<br/>'; } $t = substr($t,0,$dklen); return $t; } 

Теперь вы можете увидеть ошибки своих способов: вы не указали все важные параметры raw=true для sha1 . Давайте посмотрим, что такое выход нашей функции:

 $HashPassPhrase = pack("H*","70617373776F7264"); $HashSalt = pack("H*","78578E5A5D63CB06"); $HashIterations = 1000; $devkeylength = 16; $devkey = PBKDF1($HashPassPhrase,$HashSalt,$HashIterations,$devkeylength); echo 'Key:' . bin2hex(substr($devkey, 0, 8)) . '<br/>'; echo 'IV:' . bin2hex(substr($devkey, 8, 8)) .'<br/>'; echo 'Expected: DC19847E05C64D2FAF10EBFB4A3D2A20<br/>'; 

это выводит точно ожидаемый результат:

 Key:dc19847e05c64d2f IV:af10ebfb4a3d2a20 Expected: DC19847E05C64D2FAF10EBFB4A3D2A20 

Затем мы можем подтвердить, что функция C # делает то же самое:

  byte[] password = Encoding.ASCII.GetBytes("password"); byte[] salt = new byte[] { 0x78, 0x57, 0x8e, 0x5a, 0x5d, 0x63, 0xcb, 0x06}; PasswordDeriveBytes pdb = new PasswordDeriveBytes( password, salt, "SHA1", 1000); byte[] key = pdb.GetBytes(8); byte[] iv = pdb.GetBytes(8); Console.Out.Write("Key: "); foreach (byte b in key) { Console.Out.Write("{0:x} ", b); } Console.Out.WriteLine(); Console.Out.Write("IV: "); foreach (byte b in iv) { Console.Out.Write("{0:x} ", b); } Console.Out.WriteLine(); 

это дает тот же результат:

 Key: dc 19 84 7e 5 c6 4d 2f IV: af 10 eb fb 4a 3d 2a 20 

QED

описание бонуса

Пожалуйста, не делайте крипто, если вы точно не знаете , что делаете. Даже после того, как вы правильно исправите PHP-реализацию, ваш опубликованный код C # имеет серьезные проблемы. Вы смешиваете байт-массивы с помехами, представляющими шестнадцатеричные дампы, вы используете жестко закодированный IV вместо того, чтобы выводить его из кодовой фразы и соли, просто неправильно. Пожалуйста, используйте схему шифрования вне поля, например SSL или S-MIME, и не заново создавайте свои собственные. Вы ошибетесь .

Похоже, ваша основная проблема заключается в том, что вы используете hash() PHP hash() вместо шага PasswordDeriveBytes() на стороне C #. Эти два метода не эквивалентны. Последний реализует алгоритм дешифрования пароля PBKDF1 , а hash() – только хэш. Похоже, что PEAR может иметь реализацию PBKDF1 , но в противном случае вам, возможно, придется написать его самостоятельно.

Вам также необходимо убедиться, что кодировка текста согласована с обеих сторон, если вы еще этого не сделали.

Наконец, вы должны не делать то, что делаете, потому что криптография сложнее, чем кажется . Поскольку вы используете HTTP, вы можете использовать протокол SSL вместо написания собственного. Это обеспечит вам гораздо лучшую безопасность и меньше хлопот на низкоуровневых деталях, таких как сохранение инкрементных IVs в синхронизации и еще много чего.

Есть ли веская причина, по которой вы не можете просто использовать http://php.net/manual/en/function.mcrypt-module-open.php и использовать rijndael-256 в качестве алгоритма ????

Проверяйте подпрограммы OpenSSL на PHP, они должны уметь обрабатывать то, что вам нужно делать.