Intereting Posts

WP: AesManaged encryption vs. mcrypt_encrypt

Я пытаюсь синхронизировать свои методы шифрования и дешифрования между C # и PHP, но что-то кажется неправильным.

В Windows Phone 7 SDK вы можете использовать AESManaged для шифрования ваших данных

Я использую следующий метод:

public static string EncryptA(string dataToEncrypt, string password, string salt) { AesManaged aes = null; MemoryStream memoryStream = null; CryptoStream cryptoStream = null; try { //Generate a Key based on a Password, Salt and HMACSHA1 pseudo-random number generator Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(password, Encoding.UTF8.GetBytes(salt)); //Create AES algorithm with 256 bit key and 128-bit block size aes = new AesManaged(); aes.Key = rfc2898.GetBytes(aes.KeySize / 8); aes.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // rfc2898.GetBytes(aes.BlockSize / 8); // to check my results against those of PHP var blaat1 = Convert.ToBase64String(aes.Key); var blaat2 = Convert.ToBase64String(aes.IV); //Create Memory and Crypto Streams memoryStream = new MemoryStream(); cryptoStream = new CryptoStream(memoryStream, aes.CreateEncryptor(), CryptoStreamMode.Write); //Encrypt Data byte[] data = Encoding.Unicode.GetBytes(dataToEncrypt); cryptoStream.Write(data, 0, data.Length); cryptoStream.FlushFinalBlock(); //Return Base 64 String string result = Convert.ToBase64String(memoryStream.ToArray()); return result; } finally { if (cryptoStream != null) cryptoStream.Close(); if (memoryStream != null) memoryStream.Close(); if (aes != null) aes.Clear(); } } 

Я решил проблему генерации ключа. Ключ и IV подобны ключам на конце PHP. Но тогда последний шаг в шифровании идет не так.

вот мой PHP-код

 <?php function pbkdf2($p, $s, $c, $dk_len, $algo = 'sha1') { // experimentally determine h_len for the algorithm in question static $lengths; if (!isset($lengths[$algo])) { $lengths[$algo] = strlen(hash($algo, null, true)); } $h_len = $lengths[$algo]; if ($dk_len > (pow(2, 32) - 1) * $h_len) { return false; // derived key is too long } else { $l = ceil($dk_len / $h_len); // number of derived key blocks to compute $t = null; for ($i = 1; $i <= $l; $i++) { $f = $u = hash_hmac($algo, $s . pack('N', $i), $p, true); // first iterate for ($j = 1; $j < $c; $j++) { $f ^= ($u = hash_hmac($algo, $u, $p, true)); // xor each iterate } $t .= $f; // concatenate blocks of the derived key } return substr($t, 0, $dk_len); // return the derived key of correct length } } $password = 'test'; $salt = 'saltsalt'; $text = "texttoencrypt"; #$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC); #echo $iv_size . '<br/>'; #$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND); #print_r (mcrypt_list_algorithms()); $iv = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; $key = pbkdf2($password, $salt, 1000, 32); echo 'key: ' . base64_encode($key) . '<br/>'; echo 'iv: ' . base64_encode($iv) . '<br/>'; echo '<br/><br/>'; function addpadding($string, $blocksize = 32){ $len = strlen($string); $pad = $blocksize - ($len % $blocksize); $string .= str_repeat(chr($pad), $pad); return $string; } echo 'text: ' . $text . '<br/>'; echo 'text: ' . addpadding($text) . '<br/>'; // -- works till here $crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CBC, $iv); echo '1.' . $crypttext . '<br/>'; $crypttext = base64_encode($crypttext); echo '2.' . $crypttext . '<br/>'; $crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, addpadding($text), MCRYPT_MODE_CBC, $iv); echo '1.' . $crypttext . '<br/>'; $crypttext = base64_encode($crypttext); echo '2.' . $crypttext . '<br/>'; ?> 

Таким образом, Key и IV выглядят одинаково как на .NET, так и на PHP, но что-то кажется неправильным в последнем вызове при выполнении mcrypt_encrypt (). Конечный результат, зашифрованная строка, отличается от .NET.

Может кто-нибудь сказать мне, что я делаю неправильно. Насколько я вижу, все должно быть правильно.

Спасибо!

РЕДАКТИРОВАТЬ:

Дополнительная информация об объекте AESManaged в .NET.

Keysize = 256 Mode = CBC Padding = PKCS7

    MCRYPT_RIJNDAEL_256 – это версия алгоритма Rijndael с размером блока 256 бит, тогда как AES – это только версии с размером блока 128 бит. Они несовместимы.

    Используйте MCRYPT_RIJNDAEL_128 , чтобы получить алгоритм, эквивалентный AES. Он по-прежнему поддерживает все три ключевых размера, стандартизированные как AES, т.е. 128 бит (16 байт), 196 бит (24 байта) и 256 бит (32 байта). Просто передайте достаточно длинную строку в качестве ключа.

    Я решил проблемы. Вам нужно убедиться, что вы используете кодировку UTF8 в строках, и вы используете правильное дополнение (PKCS7)

    Вот код:

      public static string EncryptA(string dataToEncrypt, string password, string salt) { AesManaged aes = null; MemoryStream memoryStream = null; CryptoStream cryptoStream = null; try { //Generate a Key based on a Password, Salt and HMACSHA1 pseudo-random number generator Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(password, Encoding.UTF8.GetBytes(salt)); //Create AES algorithm with 256 bit key and 128-bit block size aes = new AesManaged(); aes.Key = rfc2898.GetBytes(aes.KeySize / 8); aes.IV = Encoding.UTF8.GetBytes("AAAAAAAAAAAAAAAA"); // new byte[] { 0x41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // rfc2898.GetBytes(aes.BlockSize / 8); //Create Memory and Crypto Streams memoryStream = new MemoryStream(); cryptoStream = new CryptoStream(memoryStream, aes.CreateEncryptor(aes.Key, aes.IV), CryptoStreamMode.Write); //Encrypt Data byte[] data = Encoding.UTF8.GetBytes(dataToEncrypt); cryptoStream.Write(data, 0, data.Length); cryptoStream.FlushFinalBlock(); //Return Base 64 String var temp = memoryStream.ToArray(); string result = Convert.ToBase64String(temp); return result; } finally { if (cryptoStream != null) cryptoStream.Close(); if (memoryStream != null) memoryStream.Close(); if (aes != null) aes.Clear(); } } 

    и в php:

     <?php function pbkdf2($p, $s, $c, $dk_len, $algo = 'sha1') { // experimentally determine h_len for the algorithm in question static $lengths; if (!isset($lengths[$algo])) { $lengths[$algo] = strlen(hash($algo, null, true)); } $h_len = $lengths[$algo]; if ($dk_len > (pow(2, 32) - 1) * $h_len) { return false; // derived key is too long } else { $l = ceil($dk_len / $h_len); // number of derived key blocks to compute $t = null; for ($i = 1; $i <= $l; $i++) { $f = $u = hash_hmac($algo, $s . pack('N', $i), $p, true); // first iterate for ($j = 1; $j < $c; $j++) { $f ^= ($u = hash_hmac($algo, $u, $p, true)); // xor each iterate } $t .= $f; // concatenate blocks of the derived key } return substr($t, 0, $dk_len); // return the derived key of correct length } } $text = "blaat"; $password = 'this is my secret passwordthis is my secret password'; $salt = 'thisismysalt'; #$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC); #$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND); $iv = 'AAAAAAAAAAAAAAAA'; $key = pbkdf2($password, $salt, 1000, 32); echo 'key size: ' . strlen($key) . '<br/>'; echo 'key: ' . base64_encode($key) . '<br/>'; echo 'iv size: ' . strlen($iv) . '<br/>'; #echo 'iv: ' . $iv . '<br/>'; echo 'iv: ' . base64_encode($iv) . '<br/>'; echo '<br/><br/>'; # $data = $this->paddingAlgorithm->padData($data, $blockSize); # return $iv . mcrypt_encrypt($this->MCRYPT_DES, $keyBytes, $data, MCRYPT_MODE_CBC, $iv); function addpadding($string) { $blocksize = 16; $len = strlen($string); $pad = $blocksize - ($len % $blocksize); $string .= str_repeat(chr($pad), $pad); return $string; } $crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, addpadding($text), MCRYPT_MODE_CBC, $iv); $crypttext = base64_encode($crypttext); echo '3. [' . $crypttext . ']<br/>'; echo '<br/>'; ?> 

    Надеюсь, это тоже поможет кому-то.

    Пауло благодарит за помощь!