Passwords

無需訪問 PBKDF2 或 bcrypt 即可生成安全密碼雜湊

  • April 11, 2015

Given 是一個系統,它只提供快速雜湊算法(MD5、SHA1、SHA-256、SHA-512)的實現。沒有可用的PBKDF2bcryptscrypt的實現。該系統確實提供了generateDigest(algo, input)generateMac(algo, salt, input)功能。該系統還能夠安全地儲存 MAC 功能的私鑰。由於某些語言限制,不希望實現密鑰派生函式之一。

儘管它缺乏足夠的密鑰派生功能,但該系統應該用於為給定的密碼生成散列並儲存它們。

我想知道是否可以通過使用 HMAC_SHA512 算法重複呼叫 generateMac() 來進行一些簡單的密鑰拉伸:

algo = 'HMAC_SHA512'

for (i = 0; i++; i < ROUNDS) {
   input = generateMac(algo, salt, input)
}

從幼稚的角度來看,這看起來確實是減緩對雜湊的攻擊的可行解決方案。但我確實缺乏經驗和知識,如果這是一種正確的密碼方式。

實際上,您已經非常接近實現 PBKDF2。這是一種迭代的 HMAC 執行。所以看看這裡,只需實現缺失的部分:PBKDF2

正如 Thor 已經指出的,您的程式碼已經非常接近 PBKDF2,並且將其轉換為正確的 PBKDF2 實現並不難。

具體來說,這裡有一些(模糊的 C / C++ / C# / Java / JavaScript 之類的)虛擬碼來實現 PBKDF2-HMAC-SHA512,給定一個函式HMAC_SHA512(key, message)

function PBKDF2_HMAC_SHA512 (password, salt) {
   const blockId = "\x00\x00\x00\x01";  // = INT_32_BE(1)
   var message = salt + blockId;
   var output = "\x00" x (512 / 8);

   for (var j = 0; j < iterationCount; j++) {
       message = HMAC_SHA512(password, message);
       output ^= message;
   }
   return output;
}

注意:此程式碼假定您只需要一個雜湊輸出塊的輸出值(即 SHA-512 的 512 / 8 = 64 字節)。如果您需要更少,只需截斷輸出。

如果您需要更多輸出,PBKDF2 規範說您應該增加blockId並再次執行上面的程式碼以生成更多輸出塊,但這是一種相當低效的方法,我個人建議不要這樣做——相反,我建議採用上面的程式碼並使用 HKDF-Expand (來自RFC 5869)將其拉伸到所需的大小。HKDF 也很容易使用 HMAC-SHA512 實現:

function HKDF_Expand_HMAC_SHA512 (key, info, bytes) {
   var output = "", temp = "";

   if ((512 / 8) * 255 < bytes) {
       fail("Requested key length too large.");
   }

   for (var j = 0; (512 / 8) * j < bytes; j++) {
       temp = HMAC_SHA512(key, temp + info + chr(j + 1));
       output += temp;
   }
   return output.substr(0, bytes);
}

HKDF-Expand的key參數是輸入偽隨機密鑰,即 PBKDF2 的輸出。該info參數是一個任意字元串(類似於 PBKDF2 的 salt),它允許您從同一個輸入密鑰派生多個準獨立的輸出密鑰,並且bytes顯然是請求的輸出長度(以字節為單位)。

請注意,上面的兩個函式都HMAC_SHA512以原始字節字元串的形式返回(並期望返回)它們的輸出。如果需要,將最終輸出編碼為某種可列印的格式(例如 hex 或 base64)取決於呼叫者。

另請注意,這些作為虛擬碼的函式顯然都沒有經過測試。請使用已發布的測試向量和/或通過將輸出與已知的良好實現進行比較來驗證您自己的實現。

符號:在這兩個常式中,當應用於字元串變數時,運算符+表示字元串連接,x表示重複,^表示按位異或;速記符號和分別a += b與 和a ^= b含義相同。雙引號字元串內的符號表示空字節,表示數值為 1 的字節;在 HKDF-Expand 程式碼中,取一個介於 0 和 255 之間的數字(包括 0 和 255),並返回一個單字節字元串,其中包含一個帶有數值的字節。對於字元串變數,返回 的第一個字節。a = a + b``a = a ^ b``\x00``\x01``chr(n)``n``n``s``s.substr(0, n)``n``s

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