首頁 › 加密解密 › TOTP 動態口令產生
🔧

TOTP 動態口令產生

把 Base32 金鑰換成和手機驗證器一樣的 6 位口令,純 JS 離線計算 SHA-1 與 HMAC,支援多帳戶、HOTP 計數器、口令反查與時鐘漂移診斷

只在本地算,密钥不外传
本页 100% 离线:所有 SHA-1 / HMAC-SHA1 / Base32 计算都是页面内的纯 JS 代码, 不发任何网络请求(连字体和图片都不从 CDN 取),断网、内网 http 打开照样能用。
账户只存在这台浏览器的 localStorage(键名 u2-totp-accounts)里, 不上传、不进任何统计;换浏览器或清掉站点数据就没了,请自行在验证器里留一份。
当前时间因子
Unix 秒—
计数值 counter—
倒计时—
计时用 Date.now() 的绝对时间戳现算,不是每秒累加:切到别的标签页、电脑休眠再回来, 口令和进度条都会直接对齐真实时间,不会越计越偏。周期切换取上方表单里的「周期」。
我的账户
口令默认打码(只露最后 3 位),点大号口令那行临时显示完整口令 10 秒后自动遮回; 点卡片空白处直接复制当前口令。上面一排按钮分别是编辑、复制 otpauth 链接、看链接原文、上移、下移、删除(删除要连点两次确认)。
新增账户
固定 HMAC-SHA1(纯 JS 实现,不用 crypto.subtle,内网 http 打开也能算)。 主流验证器(Google Authenticator / 微软 Authenticator / 1Password / FreeOTP)默认都是 SHA-1, 所以绑定时看到 SHA-256、SHA-512 的选项请保持默认;真遇上非 SHA-1 的站点,本页导入时会提醒你口令可能对不上。
从验证器导入 / 导出 otpauth 链接
本页不生成二维码(不引任何第三方二维码库):手机验证器都有「输入一个设置密钥 / 粘贴 otpauth 链接」的入口, 把上面这条链接复制过去粘贴即可,比拍照扫码更不容易出错。手动录入时要填的是去掉空格的大写 Base32 密钥, 位数和周期如果改过也要一起在验证器里改,否则两边算出来的口令不一样。
与 RFC 6238 / RFC 4226 官方向量对照
类型输入RFC 期望值本页算出
测试密钥是 RFC 6238 附录 B 的 ASCII 串 12345678901234567890,Base32 写法 GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ(8 位口令、周期 30 秒)。 这个密钥是公开印在标准里的,不要拿去绑真实账号,只用来验证算法实现对不对。 想核对真实账号时,把「载入 RFC 6238 示例密钥」生成的那个示例账户删掉即可。

工具介紹

兩步驗證裡那六個數字不是隨機數,也不是伺服器送過來的,而是你手機裡存的那串金鑰和目前時間一起算出來的結果。任何持有同一份金鑰、同一套參數的裝置,在同一秒內都能算出同一個碼。這個工具就是把這條公式在瀏覽器裡完整跑一遍:填進金鑰,頁面上出現的口令就和手機驗證器顯示的一致。

口令是怎麼算出來的

  • 共享金鑰:綁定時那串 Base32 字元(形如 JBSWY3DPEHPK3PXP),網站和你的裝置各存一份,從此不再在網路上傳輸
  • 時間因子:把 Unix 秒除以週期(預設 30 秒)向下取整,得到一個整數 counter,每過 30 秒自增 1
  • HMAC-SHA1:用金鑰作 key,對這個 8 位元組大端 counter 做帶金鑰雜湊,得到 20 位元組摘要
  • 動態截斷:取摘要最後一個位元組的低 4 位作為偏移,從該位置起讀 4 位元組並清掉最高位,得到一個 30 位元整數
  • 取模定長:對 10^位數 取餘,6 位就是 mod 1000000,不足位補前導零
  • 驗證端同樣算:伺服器收到碼後按自己的時間再算一遍,通常還會接受前後各 1 期,用來容忍幾秒到幾十秒的時鐘差

頁面上能做的事

  • TOTP 動態口令:多帳戶卡片,口令預設打碼只露後 3 位,點口令列臨時顯示完整 10 秒後自動遮回,點卡片空白處直接複製
  • 時間因子面板:即時顯示 Unix 秒、目前 counter、剩餘秒數,環形進度與時間條在每個週期歸零。計時基於絕對時間戳現算而不是逐秒累加,切到別的標籤頁、電腦休眠再回來都能立刻對齊真實時間
  • HOTP 計數器:手填計數器值產生命令,「計數器 +1 並記住」模擬事件型權杖,還能一次列出連續 10 個口令,用來對齊 RFC 4226 附錄 D
  • 口令反查:把手機上正在顯示的 6 位填進來,在所有帳戶的前後 1 期或前後 2 期裡尋找。命中上一期說明你電腦時鐘快了,命中下一期是慢了,都沒命中基本就是金鑰不是同一份
  • otpauth 連結:貼上 otpauth://totp/... 一鍵加入帳戶,也能反向匯出某個帳戶的連結複製到手機;解析時會自動 URL 解碼、容忍前後多餘文字,遇到非 SHA-1 參數會提醒口令可能對不上
  • 隨機金鑰:16/20/32 字元三檔(80/128/160 bit),走 crypto.getRandomValues,給自己架的站台產生初始金鑰很方便
  • 官方向量自測:內建 RFC 6238 附錄 B 與 RFC 4226 的對照表,點一下就能把本頁算出的值和標準期望值逐行比對,任何一格不一致都會標紅
  • 帳戶本地儲存:寫在瀏覽器 localStorage,支援編輯、上移下移、兩次點擊確認刪除和一鍵清空全部

參數含義速查

參數常見取值改錯會怎樣
金鑰 secretBase32,A 到 Z 與 2 到 7哪怕只差一個字元,口令就和對方完全不同
位數 digits6(少數 8)位數不同取模結果不同,兩邊看著就不一樣
週期 period30 秒(有站台用 60)換算是第幾期,口令永遠錯開一檔
演算法SHA-1(標準還允許 SHA-256/512)主流驗證器預設都是 SHA-1,選別的就會對不上
裝置時間與 UTC 相差 30 秒內漂移超過一個週期就開始報驗證碼錯誤

常見問題

  • 為什麼我算出來的碼和手機不一樣?依序排查四件事:金鑰是否漏抄或多抄字元(Base32 裡沒有 0、1、8、9,把 O 看成 0 極常見)、位數與週期是否兩邊一致、電腦時鐘是否漂了、站台是否用了非 SHA-1 演算法。本頁的口令反查能直接把前三條區分出來
  • 為什麼用 Base32 而不是 Base64?金鑰要讓人手抄或在電話裡念,Base32 只用 32 個不易混淆的大寫字母與數字,去掉了 0O1IL 這類視覺歧義字元,也避開了 Base64 裡 + / = 需要轉義的問題。貼上時帶空格、連字號、換行和 = 填充,工具會先規範化再解碼,非法字元會連位置一起報出來
  • 能替代手機驗證器嗎?能算出口令,但沒有系統級通知、加密儲存和多裝置同步,瀏覽器資料被清掉就沒了。穩妥用法是把它當除錯與應急備用:主驗證器照常綁,金鑰自己再留一份離線備份
  • 金鑰會上傳嗎?不會。本頁的 SHA-1、HMAC-SHA1、Base32 全是頁面裡的純 JS 實作,不呼叫 crypto.subtle、不發任何請求,連字型和圖片都不從 CDN 取,斷網或內網 http 開啟照樣能算。帳戶只存在你這台瀏覽器的本機儲存裡
  • 帳戶資料怎麼備份?逐個複製 otpauth 連結存進密碼管理器的備註,或用「複製 otpauth 連結」匯出後集中保管;金鑰是明文,保管方式按密碼級別對待。需要給別人看參數時,用連結原文比截圖安全
  • TOTP 和簡訊驗證碼哪個更穩?口令產生在本機完成,不依賴電信通道,也就不受 SIM 互換、簡訊攔截和訊號影響;缺點是金鑰丟了沒法像手機號那樣透過身分覆核找回,所以復原碼一定要留
  • 連續兩次輸錯會不會鎖?限制在伺服器側,與本頁無關。真出現越往後越錯的情況,先對一下電腦時間,再檢查是不是把 HOTP 帳戶當成 TOTP 用了
  • HOTP 現在還有人用嗎?硬體權杖和少數老系統還在用。它每用一次計數器加一,兩邊必須保持同步,一旦不同步就得重新配對,所以基於時間的新系統基本都是 TOTP
  • RFC 6238 那個範例金鑰能綁真實帳號嗎?不能。測試金鑰 12345678901234567890(Base32 GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ)是公開印在標準文件裡的,任何人都能算出它的口令,只用來驗證演算法實作是否正確

所有計算在瀏覽器本地完成,金鑰不會上傳伺服器。