口令雜湊生成與驗證器

完全在你的瀏覽器裡用 bcrypt、scrypt、Argon2id 和 PBKDF2 雜湊並驗證口令 —— 生成 PHC 格式字串、用候選口令核對已有雜湊、並檢查其中隱藏的引數。不會上傳任何資料。
僅限測試口令。真實使用者口令絕不應該貼上進任何網頁。本工具完全在瀏覽器中執行 —— 字串從不離開你的標籤頁 —— 但真實的資料洩露往往始於一次貼上。
bcrypt cost(2^cost 輪)
bcrypt 變體 變體只改變字首;雜湊本身完全一致
scrypt N(CPU 成本)
scrypt r / p r =   p = 塊大小為 128·r 位元組;記憶體 = 128·N·r 位元組(N=214、r=8 → 16 MiB)
Argon2id m(記憶體)
Argon2id t / p t =   p = t = 迭代次數;p = 並行度(lane 數)
PBKDF2 PRF
PBKDF2 迭代次數  OWASP 2023:HMAC-SHA-256 為 600,000(SHA-1 為 1,300,000,SHA-384/512 為 210,000)
輸出長度(位元組)  bcrypt 輸出固定為 23 位元組(31 個 bcrypt-base64 字元)
演算法引數記憶體輸出長度耗時(本瀏覽器)
bcryptcost 124 KiB23 位元組-
scryptN=214, r=8, p=116 MiB32 位元組-
Argon2idm=19 MiB,t=2,p=119 MiB32 位元組-
PBKDF2HMAC-SHA-256,600,000 次迭代~032 位元組-
引數速查表(OWASP 口令儲存速查表,2023 年最低值)
演算法最低要求備註
Argon2idm = 19 MiB(19,456 KiB),t = 2,p = 1首選;記憶體困難
scryptN = 214, r = 8, p = 1記憶體困難(最低即 16 MiB)
bcryptcost = 10只有工作因子;口令上限 72 位元組
PBKDF2-HMAC-SHA256600,000 次迭代僅迭代困難 —— 對 GPU 友好,最後的選擇
本頁的預設值都在每一條最低要求之上。生產環境請優先選 Argon2id,不可用時選 scrypt 或 bcrypt,只有出於 FIPS 合規原因才選 PBKDF2。
PHP 互操作 —— password_hash($pw, PASSWORD_BCRYPT) 輸出 $2y$10$...:把它和候選口令一起貼上到“驗證”裡,本頁給出的答案與 password_verify() 完全一致。PASSWORD_ARGON2ID 的輸出($argon2id$v=19$m=65536,t=4,p=1$...)同樣可以驗證。passlib、django-argon2 和 crypto.scrypt 包裝的 PHC 字串也都能解析。
自檢
用公開向量重新執行頁面引擎:bcrypt 的 crypt_blowfish 測試套件、node/OpenSSL 生成的 scrypt 與 Argon2id 字串、RFC 6070 的 PBKDF2 向量與公開 SHA-256 集合,外加每種演算法的“生成後再驗證”往返測試和負面用例(錯誤口令必須失敗、畸形字串必須被拒絕)。不會向任何地方傳送資料。
口令雜湊從零講起
一句話:口令雜湊被刻意做得很慢(而且最好還吃記憶體),這樣攻擊者偷走資料庫也無法每秒嘗試數十億次猜測 —— 與 SHA-256 這類為速度而生的快速雜湊目標恰好相反。
為什麼不直接對口令做 SHA-256?

SHA-256 在現代 GPU 上每秒能跑數十億次猜測。一個 8 字元口令的組合數遠低於 1013 —— 幾小時 GPU 時間,大規模礦架只要幾分鐘。口令雜湊函式(KDF)用成本引數來對抗這一點:bcrypt 把核心運算重複 2cost 次,PBKDF2 把 HMAC 迭代幾十萬次,scrypt 和 Argon2id 還要求每次猜測佔用數 MB 記憶體,讓速度快但每核記憶體少的 GPU 失去優勢。鹽 —— 隨機生成、以明文形式存放在雜湊字串裡 —— 阻止了預計算的彩虹表,並迫使每一次猜測都為每個使用者重新計算。

本頁的四種演算法
演算法年份困難性簽名格式注意事項
bcrypt1999CPU(2cost 次金鑰準備)$2b$12$ + 22 字元鹽 + 31 字元雜湊口令上限 72 位元組(超出部分被靜默忽略);在最初的 C 實現裡 NUL 位元組會終止口令
PBKDF22000(RFC 2898/8018)CPU(迭代次數)$pbkdf2-sha256$i=600000$ + 鹽 + 雜湊(passlib 風格)無記憶體成本 —— GPU 和 ASIC 的最愛;只有迭代次數可調
scrypt2009(RFC 7914)CPU + 記憶體(128·N·r 位元組)$scrypt$ln=14,r=8,p=1$ + 鹽 + 雜湊N 必須是 2 的冪;記憶體隨 r 線性增長
Argon2id2015(PHC 獲勝者,RFC 9106)CPU + 記憶體(m KiB,t 輪)$argon2id$v=19$m=19456,t=2,p=1$ + 鹽 + 雜湊Argon2i(資料無關)vs Argon2d(資料相關)vs Argon2id(混合)—— 除非你知道為什麼不用,永遠選 id
記憶體困難 vs 計算困難

GPU 有數千個核心,但每個核心能訪問的高速記憶體都很少。一個每次猜測需要 19 MiB 工作集的 KDF,會把攻擊者的並行猜測數限制在其 19 MiB 記憶體塊的數目上 —— 這就是為什麼 19 MiB 的 Argon2id 在實踐中可以強過 cost 15 的 bcrypt,儘管後者在你的筆記本上耗時更短。PBKDF2 對此毫無辦法:它唯一的旋鈕是迭代次數,而專用晶片能讓它線性加速。

讀懂一個 PHC 字串

modular-crypt / PHC 格式是自描述的:在 $argon2id$v=19$m=19456,t=2,p=1$ICEiIyQlJicoKSorLC0uLw$WTGpK4hf... 中,欄位依次是演算法、版本、引數(m = 記憶體 KiB,t = 迭代次數,p = lane 數)、base64 鹽、base64 雜湊。bcrypt 早於該標準,使用自己緊湊的形式:$2b$ 變體、12 cost,然後是用 bcrypt 自定義 base64 字母表(./A-Za-z0-9)編碼的鹽和雜湊。本頁的“驗證”接受以上全部格式並展示解析出的欄位 —— 隨便貼一個雜湊進來,看看它由什麼組成。

常見錯誤
  • 把快速雜湊用於口令。MD5/SHA-1/SHA-256 的口令列在消費級 GPU 面前每秒被猜數十億次。檔案和資料的雜湊請用 Hash Generator;口令請用本頁這些演算法。
  • 共用一個鹽。所有使用者共用一個鹽意味著相同口令得到相同雜湊,彩虹表捲土重來。本頁每個雜湊都用全新的 16 位元組隨機鹽。
  • 無視 bcrypt 的 72 位元組。"a"*100 和 "a"*72 的雜湊完全相同 —— 超出部分被丟棄。口令超過 72 位元組時本頁會在輸入框旁警告。Argon2 沒有這種限制。
  • 在自己的程式碼裡用 == 比較雜湊。驗證必須恆時進行;頁面引擎內部就是這樣做的(重新計算並按位元組比較),但如果你照搬這個思路,請使用恆時比較函式。
  • 在飛快的開發機上調引數。請以生產使用者的中位數硬體上 ~250–500 ms 的雜湊耗時為目標,而不是你的工作站。“跑基準”按鈕展示的才是這臺瀏覽器真實的體驗。
  • 每次登入校驗都重新雜湊。先驗證;只有在驗證成功之後才重新雜湊(比如提高 cost),並把新字串存回去。PHP 的 password_needs_rehash() 就是為這件事準備的。
常見問題

該選哪一個?Argon2id,至少取 OWASP 最低引數。如果執行時不提供:先 scrypt,再 bcrypt(cost 取到雜湊耗時 ≥250 ms)。只有認證要求時才用 PBKDF2。

為什麼輸出字串裡能看到隨機鹽?鹽不是秘密 —— 它刻意以明文存在 PHC 字串裡,這樣驗證時只需要字串和候選口令。它的職責是唯一性,而不是保密。

變體($2a$ / $2b$ / $2y$)有區別嗎?對 ASCII 口令,三者產生完全相同的雜湊;$2a$ 是 1990 年代的原始版本,$2b$ 修復了一個罕見的符號擴充套件 bug(2014),$2y$ 是 PHP 用來標記已含修復的記號。“驗證”三者都接受。

一次雜湊應該多久?伺服器硬體上大約每次登入 250–500 ms。低於 100 ms 離線破解就很便宜;超過 1 s 使用者會先於安全性提升而抱怨。

能驗證別處生成的雜湊嗎?能 —— 貼上雜湊並給出候選口令即可。已知相容的格式:PHP password_hash(bcrypt $2y$ 與 Argon2id)、Python passlib、django 的 argon2 hasher,以及 Tarsnap 的 scrypt 工具所用的 scrypt 字串格式。

“跑基準”按鈕做什麼?它用頁面預設引數對當前口令各做一次雜湊,並報告在本瀏覽器中的牆鍾時間 —— 用於感受成本差異,不是嚴格測量。