2013-02-18 55 views
3

我有以下代碼使用AesCryptoServiceProvider進行加密和解密。所使用的ivkey對於加密和解密都是相同的。解密值仍然與源字符串不同。使用AesCryptoServiceProvider獲取不正確的解密值

  1. 什麼需要糾正以獲得解密後的原始值?
  2. 此代碼適用於inputValue = valid128BitString。但是當inputString = 「Test」我得到以下例外Padding is invalid and cannot be removed.。我們如何糾正它?

修訂問題

下面將基於@jbtule答案做的伎倆。

​​

從加密結果改變IV值。假設加密是在一個單獨的過程中完成的,我們如何知道解密的IV?有沒有辦法使其保持不變或已知?

答案:您的其他選項是通過IV加密並在開始加密轉換之前分配它,而不是讓aesProvider爲您生成一個隨機的加密轉換。 - @Scott Chamberlain

aesProvider.IV = Convert.FromBase64String("4uy34C9sqOC9rbV4GD8jrA=="); 

更新:請參閱How to apply padding for Base64。我們可以使用UTF8來編碼源輸入和結果輸出。鑰匙和IV可能保留在Base64

使用的Base64源輸入會導致問題的一些的值,例如,「MyTest的」,其中的字符串的長度不是4

相關點的整數倍:

要解密的數據使用SymmetricAlgorithm類之一進行加密,必須將Key屬性和IV屬性設置爲用於加密的相同值。

SymmetricAlgorithm.IV屬性:來自前一個塊的信息混合到加密下一個塊的過程中。因此,兩個相同的純文本塊的輸出是不同的。由於該技術使用前一個塊來加密下一個塊,所以需要一個初始化向量來加密第一個數據塊。(正如每SymmetricAlgorithm.IV Property MSDN文章)

有效鍵尺寸爲:128,192,256位(根據How many characters to create a byte array for my AES method?

主程序

class Program 
{ 
    static void Main(string[] args) 
    { 
     string valid128BitString = "AAECAwQFBgcICQoLDA0ODw=="; 
     string inputValue = valid128BitString; 
     string keyValue = valid128BitString; 
     string iv = valid128BitString; 

     byte[] byteValForString = Convert.FromBase64String(inputValue); 
     EncryptResult result = Aes128Utility.EncryptData(byteValForString, keyValue); 
     EncryptResult encyptedValue = new EncryptResult(); 
     encyptedValue.IV = iv; 
     encyptedValue.EncryptedMsg = result.EncryptedMsg; 

     string finalResult = Convert.ToBase64String(Aes128Utility.DecryptData(encyptedValue, keyValue)); 
     Console.WriteLine(finalResult); 

     if (String.Equals(inputValue, finalResult)) 
     { 
      Console.WriteLine("Match"); 
     } 
     else 
     { 
      Console.WriteLine("Differ"); 
     } 

     Console.ReadLine(); 
    } 
} 

AES實用

public static class Aes128Utility 
{ 
    private static byte[] key; 

    public static EncryptResult EncryptData(byte[] rawData, string strKey) 
    { 
     EncryptResult result = null; 
     if (key == null) 
     { 
      if (!String.IsNullOrEmpty(strKey)) 
      { 
       key = Convert.FromBase64String((strKey)); 
       result = Encrypt(rawData); 
      } 
     } 
     else 
     { 
      result = Encrypt(rawData); 
     } 

     return result; 

    } 

    public static byte[] DecryptData(EncryptResult encryptResult, string strKey) 
    { 
     byte[] origData = null; 
     if (key == null) 
     { 
      if (!String.IsNullOrEmpty(strKey)) 
      { 
       key = Convert.FromBase64String(strKey); 
       origData = Decrypt(Convert.FromBase64String(encryptResult.EncryptedMsg), Convert.FromBase64String(encryptResult.IV)); 
      } 
     } 
     else 
     { 
      origData = Decrypt(Convert.FromBase64String(encryptResult.EncryptedMsg), Convert.FromBase64String(encryptResult.IV)); 
     } 

     return origData; 
    } 

    private static EncryptResult Encrypt(byte[] rawData) 
    { 
     using (AesCryptoServiceProvider aesProvider = new AesCryptoServiceProvider()) 
     { 
      aesProvider.Key = key; 
      aesProvider.Mode = CipherMode.CBC; 
      aesProvider.Padding = PaddingMode.PKCS7; 
      using (MemoryStream memStream = new MemoryStream()) 
      { 
       CryptoStream encStream = new CryptoStream(memStream, aesProvider.CreateEncryptor(), CryptoStreamMode.Write); 
       encStream.Write(rawData, 0, rawData.Length); 
       encStream.FlushFinalBlock(); 
       EncryptResult encResult = new EncryptResult(); 
       encResult.EncryptedMsg = Convert.ToBase64String(memStream.ToArray()); 
       encResult.IV = Convert.ToBase64String(aesProvider.IV); 
       return encResult; 
      } 
     } 
    } 

    private static byte[] Decrypt(byte[] encryptedMsg, byte[] iv) 
    { 
     using (AesCryptoServiceProvider aesProvider = new AesCryptoServiceProvider()) 
     { 
      aesProvider.Key = key; 
      aesProvider.IV = iv; 
      aesProvider.Mode = CipherMode.CBC; 
      aesProvider.Padding = PaddingMode.PKCS7; 
      using (MemoryStream memStream = new MemoryStream()) 
      { 
       CryptoStream decStream = new CryptoStream(memStream, aesProvider.CreateDecryptor(), CryptoStreamMode.Write); 
       decStream.Write(encryptedMsg, 0, encryptedMsg.Length); 
       decStream.FlushFinalBlock(); 
       return memStream.ToArray(); 
      } 
     } 
    } 

} 

DTO類

public class EncryptResult 
{ 
    public string EncryptedMsg { get; set; } 
    public string IV { get; set; } 
} 

參考

  1. How many characters to create a byte array for my AES method?
  2. Specified key is not a valid size for this algorithm
  3. Encryption with AES-256 and the Initialization Vector
  4. Invalid length for a Base-64 char array
  5. What's the difference between UTF8/UTF16 and Base64 in terms of encoding
+1

什麼是實際的異常類型,你得到解密或加密?想知道因爲'byte [] byteValForString = Convert.FromBase64String(「Test」);'對你的純文本無效。 – jbtule 2013-02-18 15:32:19

+0

你可以在Encrypt()和Decrypt()中使用'aesProvider.Padding = PaddingMode.None'嗎?不知道爲什麼它使用相同的填充時出錯? – Amitd 2013-02-18 15:51:47

+0

@jbtule我在Decrypt()方法中遇到異常 - decStream.FlushFinalBlock();聲明。填充無效,無法刪除。 – Lijo 2013-02-18 16:00:59

回答

3

很容易使密碼原語執行的錯誤,人們做這一切的時候,最好使用high level library如果你能。

我有一個snippet,我試圖保持審查和最新的,這非常接近你的工作。它還對密文進行驗證,如果無論如何對手可以將選擇的密文發送給解密實現,我會推薦進行驗證,還有很多與修改密文有關的旁道攻擊。

但是,如果你的密文不匹配你的密鑰和iv,並且你沒有驗證你的iv和密文,你會遇到的問題與填充沒有任何關係得到一個填充錯誤(如果這是冒泡客戶端,它被稱爲padding oracle)。您需要將您的主要聲明更改爲:

string valid128BitString = "AAECAwQFBgcICQoLDA0ODw=="; 
    string inputValue = "Test"; 
    string keyValue = valid128BitString; 


    byte[] byteValForString = Encoding.UTF8.GetBytes(inputValue); 
    EncryptResult result = Aes128Utility.EncryptData(byteValForString, keyValue); 
    EncryptResult encyptedValue = new EncryptResult(); 
    encyptedValue.IV = result.IV; //<--Very Important 
    encyptedValue.EncryptedMsg = result.EncryptedMsg; 

    string finalResult =Encoding.UTF8.GetString(Aes128Utility.DecryptData(encyptedValue, keyValue)); 

因此,您使用相同的IV進行解密,就像您進行加密一樣。

+0

任何線索爲什麼會導致異常? FlushFinalBlock被調用加密 – Amitd 2013-02-18 16:30:13

+1

@Amitd你是對的問題是解密時IV是錯誤的。 – jbtule 2013-02-18 19:41:06

+0

謝謝..來自加密結果的IV值發生變化。假設加密是在一個單獨的過程中完成的,我怎麼能知道IV解密?有沒有辦法使其保持不變或已知? – Lijo 2013-02-19 04:55:28

相關問題