2015-01-02 26 views
1

我正在研究一個簡單的實用程序來加密文件作爲學習體驗。 一切似乎工作正常,但我想知道如果我已安全地設置密鑰/ IV /鹽數據。Rijndael加密功能 - 密鑰/ IV /鹽設置

我注意到,當涉及到密碼術時,大多數人似乎設想到一個工作環境,加載了一個惡意軟件,該惡意軟件由遠程嚮導遠程準備通過正在運行的應用程序/頁面文件的內存來獲取這些安全文件。

讓我們假裝你在一臺乾淨的機器上,然後加密一些文件並關閉計算機。 我想知道的是,某人是否可以拿走你的硬盤,並使用我提出的代碼檢索文件的內容。

我最關心的攻擊矢量是確保頁面文件/文件緩存不可訪問。 我也想確保使用的Key/IV系統不會使基於彩虹表/散列的攻擊變得可行。

輸入密碼:使用設置爲true的passwordchar值的文本框中輸入

的密碼。

只要在加密後正確刪除字符串,我並不關心字符串在內存中。我讀到使用SecureString在這一點上是毫無意義的,因爲如果您的計算機上已經存在惡意軟件,那麼您可以輕鬆地在其上放置一個鍵盤記錄器,這會導致其他一切無用。

private static string salt = "02341235XadfaDADFexA8932F7Dz3J3X"; 

我使用硬編碼的32個字符的字符串給密碼加鹽。 (上面的字符串只是一個例子)

爲了解決這個問題,它需要有人用十六進制編輯器反編譯/查看.exe文件本身(我知道的東西很容易做到,但是額外的步驟)。

我曾考慮過這種鹽是可編輯的,但我不知道如何安全地存儲它。我認爲加密你的鹽有點荒謬,因爲那樣你就會遇到同樣的問題,所以把它作爲一個硬編碼的字符串放在exe文件中看起來對我來說最有意義。

這種方式的工作方式是,如果你決定讓你的密碼「密碼」,它實際上保存爲「thepasswordfaDADFexA8932F7Dz3J3X」。

這裏的主要關鍵是你總是有一個32個字符的密碼,而不管你輸入什麼。

密鑰和IV:

密鑰和IV也鹽醃如下。 這是我希望得到一些意見,因爲說實話,我不是很確定它在做什麼:

UnicodeEncoding UE = new UnicodeEncoding(); 
byte[] keysalt = UE.GetBytes("Xjafe231x42X423XadXCadfkhjeAdS");  //Another string of random characters hard coded in the exe 
byte[] IVSodium = UE.GetBytes("83Xkda7l78Dkx85KdJazppoqq6SaxDs");  //Another string of random characters hard coded in the exe 
byte[] key = new Rfc2898DeriveBytes(password, keysalt).GetBytes(32); //Derive the key using the password and salt 
byte[] IV = new Rfc2898DeriveBytes(password, IVSodium).GetBytes(16); //Derive the IV using the password and salt 

我主要在這裏擔心的是,IV基於關鍵。再次,我不確定這是否會導致任何問題,我希望你們可以讓我知道是否有問題,它們是什麼。

此外,這是另一種情況下,硬編碼鹽是一種不好的做法?這應該存儲在加密文件中,如果是這樣,它是否真的使它更安全?我應該讓這個可編輯嗎?

的加密流是使用使用關鍵字的設置:

using (FileStream fsCrypt = new FileStream(cryptFile, FileMode.Create)) 
{ 
    using (RijndaelManaged RMCrypto = new RijndaelManaged()) 
    { 
     using (CryptoStream cs = new CryptoStream(fsCrypt, RMCrypto.CreateEncryptor(key, IV), CryptoStreamMode.Write)) 
     { 
      using (FileStream fsIn = new FileStream(inputFile, FileMode.Open)) 
      { 
       byte[] buffer = new byte[4096]; //4096 is kind of arbitrary - better idea? 
       int data; 
       long bytesRead = 0; 
       while((data = fsIn.Read(buffer, 0, buffer.Length)) > 0) 
       { 
        bytesRead += data; 
        ///////////////////////////////////////// 
        // Handle Aborts and Update Progress Bar 
        ///////////////////////////////////////// 
        if (!caller.isClosing) 
         caller.Invoke((MethodInvoker)delegate { 
          caller.fileProgressBar.Value = ((int)(((double)bytesRead/totalBytes) * 100)); 
         }); 
        else 
         return false; //Encryption Aborted 
        ///////////////////////////////////////// 
        cs.Write(buffer, 0, data); 
        fsIn.Close(); 
        cs.Close(); 
        fsCrypt.Close(); 
        return true; 
       } 
      } 
     } 
    } 
} 

感謝您的時間和請讓我知道,如果有設置鍵/ IV /鹽更好的辦法。 我認爲,只要沒有包含類似字符的IV和Key的數學問題,它就很可能足夠安全。如果是這樣,我是否也應該使用硬編碼的IV?這似乎很奇怪。

請注意,我沒有保存密碼或任何類似的散列。密碼不保存在任何地方。它只是用來生成密鑰和IV。

謝謝你的時間。

編輯:下面是對未來的任何人推薦的更改。

請注意,這不是用胡椒 - 只是一個隨機的鹽,雖然這將是很容易的添加

byte[] salt = new byte[32];          //Create a 32 byte salt 
rand.NextBytes(salt);            //Fill it with random values (use RandomNumberGenerator rand = new RNGCryptoServiceProvider(); to be safe 
byte[] IV = new byte[16];           //Create a 16 byte IV 
rand.NextBytes(IV);            //Fill it with random numbers 
byte[] key = new Rfc2898DeriveBytes(password, salt).GetBytes(32); //Derive our Key by mixing our password with the salt 

using (FileStream fsCrypt = new FileStream(cryptFile, FileMode.Create)) 
{ 
    using (RijndaelManaged RMCrypto = new RijndaelManaged()) 
    { 
     using (CryptoStream cs = new CryptoStream(fsCrypt, RMCrypto.CreateEncryptor(key, IV), CryptoStreamMode.Write)) 
     { 
      using (FileStream fsIn = new FileStream(inputFile, FileMode.Open)) 
      { 
       fsCrypt.Write(salt, 0, salt.Length); //Write our salt to the file 
       fsCrypt.Write(IV, 0, IV.Length);  //Write our IV to the file 
       fsIn.CopyTo(cs);      //Encrypt and Write 
      } 
     } 
    } 
} 
+1

不要使用固定鹽,鹽的一點是如果密碼重用,你不能說它被重用。鹽不需要保密,只需將其附加到正在加密的文件的前面。 –

+0

好的,那麼直接把鹽寫入被加密文件的開始處?此外,鹽在這裏真的有必要嗎?我沒有散列任何東西。沒有存儲的密碼。我想確保密碼可以是任意長度,並且仍然可以使用算法,所以我知道它需要一定數量的字符長度。缺少硬編碼或將隨機字符附加到文件的開頭(基本上是同一個東西,不是?)會影響任何內容嗎?基本上,我可能會錯誤地將它稱爲鹽來解釋它。 – user1274820

回答

3

該鹽被用於兩個目的:

  1. 防止彩虹表攻擊(如果施加其正確確實);
  2. 防止相同的密碼生成相同的密碼散列。

爲此鹽需要是隨機數據的8至16個字節(未字符),存儲有密碼哈希。如果使用靜態散列,則會破壞散列的兩個用途。

如果您需要字符串,請使用base 64編碼鹽和密碼哈希。如果你想要,你可以在調用密碼哈希函數之前向鹽中添加靜態數據(有時稱爲「胡椒」)。如果程序數據不容易被攻擊者讀取,這可能會增加一些安全性。

你不應該直接自己混合鹽和密碼; Rfc2898DeriveBytes(這是PBKDF2的一個實現)已經混合了這兩個。您也不應該存儲密碼,也不應該向其中添加任何數據。 PBKDF2可以處理任何大小的輸入,所以它不會添加任何功能。

現在可以從PBKDF2功能中使用IV(使用GetBytes)。然而,存在一個問題,這很可能會使PBKDF2函數的迭代次數增加一倍,這會消耗CPU時間並降低攻擊者的優勢。生成一個隨機IV並將其加密到密文可能更好。

所以最後你應該存儲salt | IV | ciphertext,然後使用salt | pepper作爲鹽並計算你的密鑰,然後使用計算出的密鑰和IV進行加密/解密。

+0

非常感謝您的跟進。你回答了幾個問題,但我沒有問。所以基本上,我不需要加入IV - 我可以隨機生成一個並將其寫入文件。將密鑰與鹽結合使用時,我可以使用密碼並撥打一個Rfc2898的電話。我將寫入salt(16字節),IV(16字節),然後在解密期間將相同數量的字節讀入這些值。我喜歡胡椒的想法,所以在這種情況下,我可以使用一個8字節的靜態胡椒粉和一個8字節的隨機鹽,使用rfc2898 – user1274820

+1

來混合是的,聽起來像你有想法。鹽和胡椒各16個字節是比較保守的,它不會增加很多處理。 –

+0

密鑰也不會被添加到它嗎?我只應該打電話給rfc2898,聽起來就像是你說的那樣。 DeriveBytes(key,salt + pepper).GetBytes(32);對? rand.NextBytes(新字節[16])= IV – user1274820

0

據我所知,

  1. IV /鹽不需要是私人的。它可以以純文本形式存儲在硬盤上。事實上,鹽必須是純文本的,否則你不能用它產生相同的輸出。
  2. 這不是一個好主意,因爲它可能會泄漏您的關鍵信息,因此使用您的關鍵信息來生成IV。
  3. 你無法防止像彩虹一樣的攻擊。但隨着鹽,彩虹的攻擊變得昂貴,因爲只有這個鹽的價值。
  4. 有一個可能對你有用的密鑰推導函數的標準(http://en.wikipedia.org/wiki/PBKDF2)。
+0

非常感謝您的回覆。因此,對於IV和Key使用相同的鹽,或者您認爲我應該生成兩種隨機鹽,將它們寫入文件,使用鹽生成IV,然後使用鹽生成最終密鑰?此外,我可以將一個靜態字符串追加到密鑰的末尾,以便它總是32個字符?這會對消費產生負面影響嗎?很明顯,我永遠不會寫文件的關鍵部分,所以我假設我必須使它靜態?再次感謝你的回覆。 – user1274820

+0

我認爲最好分別使用兩個鹽值和密鑰。可以將一個靜態字符串附加到密鑰的末尾,但它不會使您的原始密鑰比不添加該字符串更安全。 – monkeyo

+0

非常感謝您回答我的問題。我很感激! – user1274820