從給定密碼導出整數的函式
我需要獲取一個由給定密碼派生的 int,以將其作為種子提供給確定性 PRNG。派生的 int 不應洩露有關密碼的任何線索。
如何在不發生太多碰撞的情況下實現這一目標?(因為整數是從一個更大的字元串派生的,我懷疑會有很多可能的衝突,但我想盡量減少它們發生的機會。)
我嘗試了一些解決方案,但我目前的功能讓我覺得太笨拙了。
這是我現在正在做的虛擬碼:
password := getPasswordFromUser() salt_len := 16 salt := getRandomBytes(salt_len) // the password and salt is then put through a Key Derivation // function. The key will be used for encryption. // Here comes the part I have trouble with; to "randomize" the // order in which the data will be stored, I am using a deterministic // PRNG, which is seeded as follows: // Create a long string that contains the password: orderPasswd := password + "abcdefghijklmnopqrstuvwxyz" + "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ.,;:#+!§$%&/()=?" // Create a sha256 sum of this string, feed it to the // deterministic PRNG as seed and shuffle the string: orderPwHash := sha256sum(orderPasswd) // derive an int from the hash by converting it orderPwSeed := int64(binary.BigEndian.Uint64(orderPwHash)) // shuffle orderPasswd using the Fisher-Yates shuffle algorithm orderPasswd = shuffle(orderPasswd, orderPwSeed) // Put orderPasswd through the KDF, hash the key and shuffle // the order with an integer derived from the hash: orderKey := getKey(string(orderPasswd[salt_len:]), orderPasswd[:salt_len]) orderKeyHash := sha256sum(orderKey) // convert that hash to an integer to finally get the seed // that will be used to determine the order orderSeed := int64(binary.BigEndian.Uint64(orderKeyHash)) // seed the PRNG with orderSeed... shuffle the order...
編輯:
我已經接受了 Ilmari Karonen 的回答,因為他付出了很多努力,並且它包含了任何嘗試實施密碼學的人的重要資訊。
我已經駁回了改組消息的想法,因為它會不必要地使我的程式碼複雜化並增加錯誤的可能性而不會增加安全性,這在這種情況下尤其糟糕。
因為消息,一旦使用 AES256 加密並使用 scrypt 派生的密鑰設置為 N=65536 和 p=2,看起來就像隨機雜訊,這應該足夠了。
根據您的程式碼,您從密碼派生的種子值似乎是 64 位長。這意味著:
- 由於生日悖論,您可能會在大約 2 33 個密碼後看到種子衝突,並且
- 使用現代硬體,有合理動機的攻擊者可以列舉整個 64 位種子空間,從而破壞您的加密,無論您的密碼和密鑰派生過程有多安全。
您確實應該考慮使種子更長:至少 128 位,但是如果您想更加安全,則使用 256 位不會有任何壞處。當然,您還需要確保您的 PRNG 確實使用了整個種子。
此外,您沒有說明您使用的是什麼 PRNG,但除非它是專門為加密使用而設計的,否則攻擊者很可能可以相對輕鬆地根據少量輸出計算種子。
在評論中,您還提到您正在使用scrypt作為密鑰派生過程的一部分。這很好,但根據您的其餘設計,這似乎有點像在脆弱的木製外屋上放置鋼拱門。修復系統的所有其他部分,使其與 scrypt 一樣安全,您最終可能會得到一個安全的密碼系統。
在任何情況下,鑑於您使用的是 scrypt,您的密鑰派生程式碼中絕對不需要所有臨時改組和其他 klugy 內容。Scrypt 無論如何都會更徹底、更有效地洗牌你的密碼,並且會產生盡可能接近理論理想的衝突率。
只需記住將參數設置為適當的 scrypt(即,將並行係數設置為接近現代 CPU 上的典型核心數量,並且在保持密鑰派生時間合理的情況下盡可能高的成本參數)。而且,再次記住,scrypt 幾乎肯定不是系統中最薄弱的環節。