2011-08-16 25 views
14

我想從Linux端管理的數據庫表中讀取Base64編碼值。在那個 表中有一個名爲first_name的列。在Linux中,我可以通過在PHP中使用下面的命令很容易解密此:如何解密C#中已加密的MCRYPT_RIJNDAEL_256值,該值是由PHP中的mcrypt加密的?

$data = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, "patient_fn_salt", 
         base64_decode("H6XmkH+VWvdD88THCliKJjLisGZIBk3CTNvyQMLnhpo="), 
         MCRYPT_MODE_ECB); 

但是我試着盡我所能複製的C#側這樣的邏輯和我得到的是亂碼。

我的C#代碼如下,我希望你有一些建議,因爲我跑出去的想法:(

byte [] cipherText = 
     Convert.FromBase64String("H6XmkH+VWvdD88THCliKJjLisGZIBk3CTNvyQMLnhpo="); 
byte [] key = Encoding.UTF8.GetBytes("patient_fn_salt"); 
Array.Resize(ref key, 32); 
byte [] iv = new byte[32]; 

string fname = Utilities.Decrypt(cipherText, key, iv); 


public static string Decrypt(byte[] cipherText, byte[] Key, byte[] IV) 
    { 
    // Check arguments. 
    if (cipherText == null || cipherText.Length <= 0) 
    throw new ArgumentNullException("cipherText"); 
    if (Key == null || Key.Length <= 0) 
    throw new ArgumentNullException("Key"); 
    if (IV == null || IV.Length <= 0) 
    throw new ArgumentNullException("Key"); 

    // TDeclare the streams used 
    // to decrypt to an in memory 
    // array of bytes. 
    MemoryStream msDecrypt = null; 
    CryptoStream csDecrypt = null; 
    StreamReader srDecrypt = null; 

    // Declare the AesManaged object 
    // used to decrypt the data. 
    RijndaelManaged rj = new RijndaelManaged(); 

    // Declare the string used to hold 
    // the decrypted text. 
    string plaintext = null; 

    try 
    { 
    // Create an AesManaged object 
    // with the specified key and IV. 

    rj.Mode = CipherMode.ECB; 
    rj.BlockSize = 256; 
    rj.KeySize = 256; 
    rj.Padding = PaddingMode.Zeros; 

    rj.Key = Key; 
    rj.GenerateIV(); 
    //rj.IV = IV; 


    // Create a decrytor to perform the stream transform. 
    ICryptoTransform decryptor = rj.CreateDecryptor(rj.Key, rj.IV); 

    // Create the streams used for decryption. 
    msDecrypt = new MemoryStream(cipherText); 
    csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read); 
    srDecrypt = new StreamReader(csDecrypt); 

    // Read the decrypted bytes from the decrypting stream 
    // and place them in a string. 
    plaintext = srDecrypt.ReadToEnd(); 
    } 
    finally 
    { 
    // Clean things up. 

    // Close the streams. 
    if (srDecrypt != null) 
    srDecrypt.Close(); 
    if (csDecrypt != null) 
    csDecrypt.Close(); 
    if (msDecrypt != null) 
    msDecrypt.Close(); 

    // Clear the AesManaged object. 
    if (rj != null) 
    rj.Clear(); 
    } 
    return plaintext; 
    } 
} 
+0

這也許可以提供幫助。 http://stackoverflow.com/questions/202011/encrypt-decrypt-string-in-net –

+1

只需要注意一點:在您的方法中不使用'IV'參數...並且ECB模式沒有初始化向量。 (但我不認爲這涉及到你的問題。) –

回答

5

正如保羅說,ECB模式不使用IV。如果C#的一個堅持,然後使用全零字節。

的關鍵「patient_fn_salt」爲15個字符,120位。你解密函數需要關鍵的256位。你需要非常確保額外的比特在兩個系統中相同的,正在添加到兩個系統中的相同位置,即使是單個錯誤也會導致垃圾解密非常謹慎地確定「patient_fn_salt」是如何擴展到256位密鑰的。特別檢查實際密鑰是否爲SHA256("patient_fn_salt")

另外,ECB模式是不安全的。優先使用CTR模式或CBC模式。 CTR模式不需要填充,所以可能意味着更少的密碼文件存儲。

ETA:在另一個讀通過我注意到,C#端填充零。 PHP方面使用什麼填充?零填充不是一個好主意,因爲它無法識別錯誤的解密。 PKCS7填充有更好的識別錯誤輸出的機會。最好明確指定兩端的填充而不是依賴默認值。

+0

[文檔說](http://www.php.net/manual/en/function.mcrypt-decrypt.php):*如果它小於所需的密鑰大小,它用'\ 0'填充。* ...和Array.Resize看起來好像它一樣。但是可能顯式填充更安全。 –

+0

如果可能,直接檢查兩個字節數組的內容會很有用。否則,顯式填充肯定值得嘗試。 – rossum

3

郵政是舊的,但這可能有助於未來的某個人。此功能加密酷似與參數MCRYPT_RIJNDAEL_256 mcrypt_encrypt和MCRYPT_MODE_ECB

static byte[] EncryptStringToBytes(string plainText, byte[] key) 
    { 
     if (plainText == null || plainText.Length <= 0) 
      throw new ArgumentNullException("plainText"); 
     if (key == null || key.Length <= 0) 
      throw new ArgumentNullException("key"); 

     byte[] encrypted; 
     using (var rijAlg = new RijndaelManaged()) 
     { 
      rijAlg.BlockSize = 256; 
      rijAlg.Key = key; 
      rijAlg.Mode = CipherMode.ECB; 
      rijAlg.Padding = PaddingMode.Zeros; 
      rijAlg.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 

      ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV); 
      using (var msEncrypt = new MemoryStream()) 
       using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) 
       { 
        using (var swEncrypt = new StreamWriter(csEncrypt)) 
         swEncrypt.Write(plainText); 
        encrypted = msEncrypt.ToArray(); 
       } 
     } 
     return encrypted; 
    } 

這裏是函數對其進行解密

 static string DecryptStringFromBytes(byte[] cipherText, byte[] key) 
    { 
     if (cipherText == null || cipherText.Length <= 0) 
      throw new ArgumentNullException("cipherText"); 
     if (key == null || key.Length <= 0) 
      throw new ArgumentNullException("key"); 

     string plaintext; 
     using (var rijAlg = new RijndaelManaged()) 
     { 
      rijAlg.BlockSize = 256; 
      rijAlg.Key = key; 
      rijAlg.Mode = CipherMode.ECB; 
      rijAlg.Padding = PaddingMode.Zeros; 
      rijAlg.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 

      ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV); 
      using (var msDecrypt = new MemoryStream(cipherText)) 
       using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) 
        using (var srDecrypt = new StreamReader(csDecrypt)) 
         plaintext = srDecrypt.ReadToEnd(); 
     } 
     return plaintext; 
    } 
+1

我希望這不會對任何人有用,因爲如果是這樣,這意味着他們使用的是非常有問題的加密。 – CodesInChaos