無需訪問 PBKDF2 或 bcrypt 即可生成安全密碼雜湊
Given 是一個系統,它只提供快速雜湊算法(MD5、SHA1、SHA-256、SHA-512)的實現。沒有可用的PBKDF2、bcrypt或scrypt的實現。該系統確實提供了
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