2012-12-16 55 views
20

我想了解如何使用對稱加密算法(在本例中爲AES)對數據進行加密和解密時如何處理和管理初始化矢量和鹽(適用時)。對稱加密(AES):是否將安全和正確的加密數據與IV和Salt一起保存?

我從不同的SO線程和各種其他網站推斷出IV或鹽不需要是保密的,只有唯一的才能抵禦密碼分析攻擊,如暴力攻擊。考慮到這一點,我想到將我的僞隨機IV與加密數據一起存儲是可行的。我在問,我使用的方法是否正確,而且,我是否應該以同樣的方式對待我目前使用的硬編碼鹽?這是它的旁邊寫入內存流IV

我的代碼:

private const ushort ITERATIONS = 300; 
private static readonly byte[] SALT = new byte[] { 0x26, 0xdc, 0xff, 0x00, 0xad, 0xed, 0x7a, 0xee, 0xc5, 0xfe, 0x07, 0xaf, 0x4d, 0x08, 0x22, 0x3c }; 

private static byte[] CreateKey(string password, int keySize) 
{ 
    DeriveBytes derivedKey = new Rfc2898DeriveBytes(password, SALT, ITERATIONS); 
    return derivedKey.GetBytes(keySize >> 3); 
} 

public static byte[] Encrypt(byte[] data, string password) 
{ 
    byte[] encryptedData = null; 
    using (AesCryptoServiceProvider provider = new AesCryptoServiceProvider()) 
    { 
     provider.GenerateIV(); 
     provider.Key = CreateKey(password, provider.KeySize); 
     provider.Mode = CipherMode.CBC; 
     provider.Padding = PaddingMode.PKCS7; 

     using (MemoryStream memStream = new MemoryStream(data.Length)) 
     { 
      memStream.Write(provider.IV, 0, 16); 
      using (ICryptoTransform encryptor = provider.CreateEncryptor(provider.Key, provider.IV)) 
      { 
       using (CryptoStream cryptoStream = new CryptoStream(memStream, encryptor, CryptoStreamMode.Write)) 
       { 
        cryptoStream.Write(data, 0, data.Length); 
        cryptoStream.FlushFinalBlock(); 
       } 
      } 
      encryptedData = memStream.ToArray(); 
     } 
    } 
    return encryptedData; 
} 

public static byte[] Decrypt(byte[] data, string password) 
{ 
    byte[] decryptedData = new byte[data.Length]; 
    using (AesCryptoServiceProvider provider = new AesCryptoServiceProvider()) 
    { 
     provider.Key = CreateKey(password, provider.KeySize); 
     provider.Mode = CipherMode.CBC; 
     provider.Padding = PaddingMode.PKCS7; 
     using (MemoryStream memStream = new MemoryStream(data)) 
     { 
      byte[] iv = new byte[16]; 
      memStream.Read(iv, 0, 16); 
      using (ICryptoTransform decryptor = provider.CreateDecryptor(provider.Key, iv)) 
      { 
       using (CryptoStream cryptoStream = new CryptoStream(memStream, decryptor, CryptoStreamMode.Read)) 
       { 
        cryptoStream.Read(decryptedData, 0, decryptedData.Length); 
       } 
      } 
     } 
    } 
    return decryptedData; 
} 

我也開到約至於正確的做法對稱加密的任何其他信息。

+0

如果您沒有將它們與您的加密數據一起存儲,則需要將它們存儲在某個地方 - 如YMMV。 – larsw

+4

在CBC模式下,每個加密塊作爲下一個塊的IV,所以作爲公共值的IV不能與安全相關 - 否則CBC操作模式將不安全。 :) – vhallac

+0

@vhallac好了,更多的V(矢量)作爲IV(初始化向量)顯然只能是第一個。 –

回答

23

用密碼文本存儲IV和Salt很合適,也是一種最佳實踐。對鹽進行硬編碼是沒有用的,隨機性很重要,對迭代進行硬編碼是完全可以的,但通常遠遠高於300(實際上至少爲1000),如果您的機器/使用情況可以像10s一樣處理它,數千)。因爲我已經看到了很多來自堆棧溢出的壞的(或舊的)加密示例,並將其粘貼到開源代碼中,我寫了一小段剪切和粘貼加密代碼Modern Examples of Symmetric Authenticated Encryption of a string.,我試圖跟上日期和審查。它將iv和salt與密文一起存儲,還驗證包含在密文中的密文和值。

理想情況下,儘管更好的做法是使用高級加密庫來處理像iv這樣的最佳實踐,但是這些加密庫對於csharp通常不存在。我一直在研究Google的keyczar庫的原生csharp version。雖然它在功能上已經可以使用,但在第一次官方穩定發佈之前,我一直希望能夠更多地關注代碼。

13

是的,IV和鹽都是公共價值。更重要的是確保這些是每個加密操作的隨機值。

舉一個例子,在野外看看rncryptor data format。這裏salt和IV被打包成數據格式,以及密文和MAC值。 (注意:這是一個客觀的例子)。