如何在 JavaScript 中完成密鑰派生?
我需要獲取一個可能很弱的使用者密碼,並為 JavaScript 中的 AES 加密派生一個強密鑰。我怎樣才能做到這一點?
我預計最難的問題是生成一個好的隨機鹽——也許可以使用 SSL 請求來要求伺服器提供一半的鹽。這會起作用,但如果可能的話,我寧願保持簡單。
我應該使用 bcrypt 嗎?也許需要多次迭代才能在慢速硬體(目前型號的智能手機)上達到大約 1 秒。
我只需要支持現代瀏覽器,我的使用者群很小,每個人都是極客。
派生的密鑰將用於使用 AES 加密明文密碼,類似於 LastPass 的工作方式。
好的,對於瀏覽器中的密鑰派生,您將使用第三方庫。
如果您想成為絕對的佼佼者,那麼 scrypt(要考慮的潛在庫)是您的最佳選擇,根據您的使用者將要使用什麼,它具有中等到高的工作係數。Bcrypt 可以工作,但不是很難記憶,所以要考慮到這一點。(即使是 5MB 的記憶體使用也可能嚴重阻礙使用自定義硬體來攻擊您的密鑰)
鹽可以從 crypto.getRandomValues 派生,它接受一個類型化的數組並返回填充了可信賴的隨機數據。
你不能。您可以做的最好的事情是 PBKDF2 或 scrypt 或 bcrypt。但它們不會生成強加密密鑰。如果你從一個弱密碼或弱密碼開始,並從中派生出一個加密密鑰,那麼結果將不可避免地不是很強大。像 PBKDF2 或 scrypt 或 bcrypt 這樣的函式並不是靈丹妙藥。他們讓事情變得比原本不那麼糟糕,但最終,它仍然很糟糕;它沒有那麼糟糕。這當然不好,也不會產生我稱之為強的鍵。
您可以做的第一件事是:不要那樣做。不要從密碼或密碼片語生成加密密鑰。人類不太擅長選擇或記住高熵密碼/密碼片語。因此,鑑於我們對人類行為的了解,如果您從密碼/密碼片語中獲取加密密鑰,您的數據將比人們希望的安全性低得多。
相反,如果您想要強大的安全性,請選擇一個真正隨機的加密密鑰(不是從密碼/密碼片語派生的)。使用適當的密鑰管理。是的,這是更多的工作。實現強大的安全性確實需要更多的工作。根據您的要求,您甚至可能無法在瀏覽器環境中實現您的安全目標。這就是生活。如果你需要強大的安全性,你能做的最糟糕的事情就是給使用者一種虛假的安全感:讓他們認為他們是安全的,而實際上他們只有有限的保護。