2011-11-14 33 views
2

我想在C#和PHP之間同步我的加密和解密方法,但似乎出了問題。WP:AesManaged加密與mcrypt_encrypt

在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(); 
     } 
    } 

我解決產生的關鍵問題。 Key和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/>'; 

?> 

因此指出,密鑰和IV看在.NET和PHP類似的事,但似乎執行mcrypt_encrypt時是想錯在最後調用() 。最終的結果,加密的字符串與.NET不同。

有人可以告訴我我做錯了什麼。據我所知,一切都應該是正確的。

謝謝!

編輯:在.NET的AESManaged對象上

附加信息

密鑰大小= 256 模式= CBC 填充= PKCS7

+0

*看起來出錯*是什麼意思?你會收到錯誤消息嗎?你有不同的結果嗎? (如果IV是隨機的,這是正常的。)你不能再解密嗎?還要別的嗎? –

+0

嗨保羅,最終結果,加密的字符串,PHP和.NET不同,但我幾乎肯定我輸入正確的密鑰和IV(和文本加密)。希望能多解釋一下。 – invalidusername

回答

1

我解決了這個問題。你需要確保你的字符串使用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/>'; 

?> 

希望這也會幫助某人。

Paulo謝謝你的幫助!

+0

+1爲addpadding函數和塊大小...... –

+0

當我使用這個函數集成加密我g0t從c#和php的兩個不同的值。我環顧所有的領域,如關鍵,鹽等,都是一樣的。如果有任何東西從C#代碼上面丟失。如果你能幫助我,請幫助我。 –

+0

嗨Deepu,這個代碼是完整的,並已被用於一個程序。如果您希望有人幫助您解決問題,您需要提供源代碼和數據示例。 – invalidusername

1

MCRYPT_RIJNDAEL_256是與塊大小256的版本的Rijndael算法的位,而AES只是塊大小爲128位的版本。這些不兼容。

使用MCRYPT_RIJNDAEL_128,得到相當於AES的算法。它仍支持標準化爲AES的所有三種密鑰尺寸,即128位(16字節),196位(24字節)和256位(32字節)。只需傳遞足夠長的字符串作爲鍵。

+0

我切換到MCRYPT_RIJNDAEL_128,我的密鑰大小是32位。 .NET和PHP之間的鍵匹配相同,但mcrypt_encrypt的最終結果仍然不符合.NET上加密的最終結果。我使用以下輸入: $ text =「這是我的文本」; $ password ='這是我的祕密密碼,這是我的祕密密碼'; $ salt ='thisismysalt'; 在兩個系統上,IV和KEY的base64_encode字符串看起來相似。任何其他想法可能會出錯? 謝謝你的時間! – invalidusername

+0

「看起來相似」還是「相同」? –

+0

你確定你在.NET端使用256位版本嗎?我沒有看到代碼中設置密鑰大小的任何內容(和[文檔](http://msdn.microsoft.com/en-us/library/system.security.cryptography.aesmanaged.aspx)默認值)。 –