2016-02-29 142 views
1


我嘗試將此代碼轉換爲PHP,但在C#和PHP 我不能總是我得到不同的結果,這裏是加密我的C#代碼和解密:轉換C#代碼到PHP的加密和解密

private static readonly byte[] initVectorBytes = Encoding.ASCII.GetBytes("1234567812345678"); 
private const int keysize = 256; 
private string pass = "sample"; 

public static string Encrypt(string plainText, string passPhrase) 
{ 
    byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText); 
    PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null); 
    byte[] keyBytes = password.GetBytes(keysize/8); 
    RijndaelManaged symmetricKey = new RijndaelManaged(); 
    symmetricKey.Mode = CipherMode.CBC; 
    ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes); 
    MemoryStream memoryStream = new MemoryStream(); 
    CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write); 
    cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length); 
    cryptoStream.FlushFinalBlock(); 
    byte[] cipherTextBytes = memoryStream.ToArray(); 
    return Convert.ToBase64String(cipherTextBytes); 
} 

public static string Decrypt(string cipherText, string passPhrase) 
{ 
    byte[] cipherTextBytes = Convert.FromBase64String(cipherText); 
    PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null); 
    byte[] keyBytes = password.GetBytes(keysize/8); 
    RijndaelManaged symmetricKey = new RijndaelManaged(); 
    symmetricKey.Mode = CipherMode.CBC; 
    ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes); 
    MemoryStream memoryStream = new MemoryStream(cipherTextBytes); 
    CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read); 
    byte[] plainTextBytes = new byte[cipherTextBytes.Length]; 
    int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length); 
    return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount); 
} 

,這是我的PHP代碼:

$iv = "1234567812345678"; 
$out = null; 
$key = "sample"; 
foreach ($iv as $i) { $out .= chr(ord(substr($i,0,1))); } 
$res = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $string, MCRYPT_MODE_CBC, implode($out)); 
+2

請注意,mcrypt是遺棄的軟件,它在幾年內沒有更新過,所以最好不要使用它。 – zaph

+1

請勿使用固定的IV。應該隨機選擇每種加密方式,以實現語義安全。它不必是保密的,所以你可以將它和密文一起發送。一種常用的方法是將其預先加密到密文中。 –

回答

0
  1. 鍵是不一樣的。 C#將密鑰擴展爲PasswordDeriveBytes,這是一個很好的方法。 PHP mcrypt正在擴展他們的關鍵與空值。您需要擴展(256位)的密鑰相同。

  2. 的填充是不一樣的。未加密的數據需要是塊大小的倍數(AES爲128位),並且不一定必須添加填充。 C#沒有指定任何填充,並希望數據是塊大小的倍數(128位)。 PHP將默認添加非標準的null填充,並且不適用於二進制數據。您需要添加通用填充,標準是PKCS#7(aka PKCS#5),請參閱PKCS#7 padding。 C#支持PKCS#5,但對於mcrypt,您必須在您的代碼中執行此操作(mcrypt開發人員是Bozos並且沒有提供標準填充)。

  3. Rijndael算法支持多種尺寸的博克,它是不明確的C#默認的塊大小是什麼。如果你想要的是AES(它應該是),塊大小需要128位。

  4. 鑑於MSDN文檔不指定默認值最好是明確地設置塊大小,密鑰大小,模式和填充。

+0

感謝您的信息和幫助,但是我的嘗試到現在我無法得到正確的結果,請你給我示例代碼?你有可能嗎? – Sara

+0

我沒有C#可用,但在SO上應該有很多例子。 – zaph

0

你的PHP代碼將無法在PHP 5.6運行爲關鍵的大小是錯誤的,它必須是32個字節。

表示在之前的版本中,PHP使用\ 0來填充密鑰以達到正確的密鑰長度,但在C#中,您正在創建派生字節(確實是正確的),以便爲您的密鑰獲取足夠的字節,在C#和PHP中使用不同的鍵。

作爲一個證明,創建32個字節(32個字符)的關鍵,直接使用這些32個字節的關鍵,無論是在PHP和C#中,這樣,它應該工作。

但最後你需要一個通用的方式來派生PHP和C#上的字節,最終得到一致的密鑰代碼,例如可以使用SHA-256哈希來生成密鑰。