Encryption

如何正確導出密鑰和 IV?

  • January 31, 2012

主要是我想了解如何正確創建密鑰和 IV 以用於 AES 的 .NET 實現(AesManaged 類)。

此加密程式碼將與數據庫中的現有客戶記錄一起使用。

這是我想出的過程。首先,從加密的 web.config 中獲取密鑰,並使用 Rfc2898DeriveBytes 類獲取字節數組。鹽是一個常數。

public static byte[] GetKey(string key)
{
   var deriveBytes = new Rfc2898DeriveBytes(key, _salt);

   return deriveBytes.GetBytes(32);
}

接下來,給定使用者 ID 和上面的相同鹽,為 IV 生成另一個字節數組。此方法本質上是相同的,但返回一個 16 字節而不是 32 字節的數組(輸入是使用者 ID,而不是鍵)。

public static byte[] GetKey(string text)
{
   var deriveBytes = new Rfc2898DeriveBytes(text, _salt);

   return deriveBytes.GetBytes(16);
}

給定密鑰和 IV,我使用 CryptoStream 加密數據:

var aesAlg = new AesManaged();

// Create an encryptor to perform the stream transform.
var encryptor = aesAlg.CreateEncryptor(key, iv);

// ... Code that uses the Crypto Stream

主要問題:

  • 我應該使用更好/不同的課程來代替Rfc2898DeriveBytes嗎?類名引用 RFC 似乎很有趣。
  • 使用恆定鹽不好嗎?我這樣做是為了不需要在使用者記錄上儲存任何其他資訊。我見過的其他範例使用恆定的 IV,但使用隨機的 Salt。這兩種情況本質上是一樣的嗎?

從密碼學上講,AesManaged在 CBC 模式下使用 AES。為確保安全執行,您需要隨機選擇 IV,即不可能在迭代之間預測 IV。這個問題討論了非隨機 IV:Using a Non-Random IV with mode than CBC和這個 SO question:Why is using a Non-Random IV with CBC Mode a漏洞?討論了使用非隨機 IV 選擇的明文漏洞。

根據文件,Rfc2898DeriveBytesimplements PBKDF2,一個關鍵的拉伸功能。DeriveBytes是一個有趣的名稱選擇,但這本質上就是它要做的——從PBKDF2算法中輸出一些字節。PBKDF2 的核心是 SHA1 的重複應用;如果您輸入相同的密碼和 IV,您最終會得到相同的加密密鑰。

與雜湊不同,您不會將其儲存在任何地方,因為它是對稱操作的密鑰,因此攻擊者試圖找到原像(恢復密碼)的風險較小,主要是因為他們只是不需要。因此,唯一性要求看起來沒有必要——但是,假設您的所有使用者都使用相同的密碼片語“我喜歡在 SE 上詢問加密問題”。如果他們這樣做並且您使用的是恆定鹽,那麼他們將擁有相同的密鑰。我們的 CBC 模式的非重複 IV 會稍微緩解這個問題,但如果一開始的密鑰不完全相同,情況會好很多。

所以,總結一下:

  • 恆鹽:不好。選擇一個大鹽,每個使用者唯一。隨機挑選鹽將幫助您實現這一點 - 如果您生成一個 64 位鹽,它為您提供了一個總可能的輸出空間 $ 2^{64} = 18446744073709551616 $ ,或大約 $ 2635249153 $ 現在每個人都有獨特的鹽。所以你不太可能用完,並保證你所有使用者的密鑰都是唯一的,假設在 PBKDF2 中沒有衝突。

感謝fgrieu進行編輯- salt 大小必須為 8-bytes (64-bits)或更大。如果你能容納更大的鹽,你應該避免生日攻擊。有關更多資訊,請參閱評論。

  • 常數IV:不好。你肯定想要一個隨機 IV 用於 CBC 模式。

引用自:https://crypto.stackexchange.com/questions/1780