TOTP 动态口令生成器
把两步验证的 Base32 密钥粘贴进来,即可看到当前验证码、剩余有效秒数与下一个验证码。算法与 Google Authenticator、Microsoft Authenticator 一致(RFC 6238),支持 SHA-1 / SHA-256、6 位 / 8 位、30 秒 / 60 秒。密钥只在浏览器本地参与计算,不经过服务器。
两步验证的动态口令(6 位数字、30 秒一换)就是 TOTP:验证器 App 与服务端共享同一把 Base32 密钥,各自用当前时间除以 30 秒算出同一个码,全程不经网络传输。本工具与 Google Authenticator 同算法(RFC 6238),粘贴密钥即可看到当前验证码、剩余秒数与下一个码,适合密钥在电脑上、手机不在手边的场景。
验证码总是不对的第一大原因是时钟:本机时间与服务器相差超过 30 秒必然算错,开启自动对时即可。其次确认参数——绝大多数服务用 SHA-1 加 6 位加 30 秒的默认组合,只有服务端明确写了 SHA256、8 位或 60 秒才需要改。密钥的保密等级等同密码,公共电脑上不要粘贴。
这个工具解决你的问题了吗?
提交后会把工具名、你的输入与当前结果发送到服务器;请勿填写身份证号、手机号等隐私信息。
AI 助手 会结合你当前的输入与结果回答
追问会再次把当前输入与结果发送到服务器;请勿填写隐私信息。
使用步骤
- 从服务端的显示密钥或二维码解析结果里完整复制 Base32 密钥。
- 粘进密钥框,验证码即时生成,进度条显示剩余有效秒数。
- 等进度条刚刷新(新时间片开始)再提交,避免边界失效。
- 对不上时按顺序排查:时钟、密钥完整性、算法与位数参数。
计算原理与示例
基本用法
在密钥框粘贴验证器里的那串 Base32 字母数字(从 A 到 Z 与 2 到 7,可带空格或连字符分组),验证码会随输入即时生成,并显示「还有多少秒更新」的进度条。页面下方给出两个辅助值:下一个时间片的验证码(用于掐点登录)、当前计数器。
验证码对不上怎么排查
对不上时先看时钟:TOTP 用「当前时间 ÷ 30 秒」作为输入,本机时间与服务端(或验证器)相差超过一个时间片就会算错,手机自动对时即可解决。再看密钥本身——密钥里若混入二维码扫描时带出的空格之外的特殊字符、或复制时漏掉几位,会直接提示「不是合法的 Base32」。最后确认算法与位数:少数服务用 SHA-256、8 位验证码或 60 秒周期,与默认设置不同。
参数怎么选
绝大多数服务用「SHA-1 + 6 位 + 30 秒」,这是 Google Authenticator 的默许约定,保持默认即可。只有服务端明确写了「SHA256」「8 位」「60 秒」时才需要改;改错不会报错,只会得到永远对不上的验证码。
计算口径:TOTP 按 RFC 6238、动态截断按 RFC 4226;密钥按 RFC 4648 Base32 解码(忽略空格、连字符与 = 填充,大小写不敏感),计数器 = ⌊浏览器本地时间 ÷ 周期⌋,HMAC 使用 SHA-1(默认)或 SHA-256;结果截断为 6 位或 8 位十进制数字并按位数左侧补零。时间取本机时钟,不做网络对时。
代码示例
JavaScript Node 用 otplib 生成
// npm install otplib
const { authenticator } = require("otplib");
authenticator.generate("JBSWY3DPEHPK3PXP"); // 当前 6 位验证码
authenticator.check(code, secret); // 服务端校验
// 默认即 SHA-1 + 6 位 + 30 秒,与主流验证器一致
Shell 命令行生成
# oathtool:brew install oathtool 或 apt install oathtool
oathtool --totp -b "JBSWY3DPEHPK3PXP" # -b 表示 Base32 密钥
# 指定 8 位、60 秒
oathtool --totp=SHA1 -b -d 8 -s 60 "JBSWY3DPEHPK3PXP"
常见问题
验证码多久变一次?为什么我和服务端差一两位?
默认 30 秒变一次。差一两位通常是时间边界效应:验证码在第 30 秒的瞬间切换,如果你在本机还剩 0.2 秒时提交、服务端收到时已进入下一时间片,就会出现「刚生成就失效」。稳妥做法是等进度条回满(新时间片刚开始)再提交;部分服务端也允许前后各一个时间片,容忍这种抖动。
提示「密钥不是合法 Base32」怎么办?
Base32 只允许 A~Z 与 2~7 这 32 个字符(另外允许空格、连字符与 = 填充,页面会自动忽略)。常见错因:把数字 0 与字母 O、数字 1 与字母 I 看错(Base32 里没有这两个数字,出现了就说明复制错位);复制时带上了「otpauth://」开头的整条链接的其余部分;少复制或多复制了几位。请从二维码解析结果或服务端的「显示密钥」处重新完整复制。
扫码得到的二维码里包含什么?
二维码里是一段 otpauth://totp/... 链接,参数包含密钥(secret)、发行方、位数与周期。本工具只需要其中的 secret 部分——把它单独粘进来即可,不要粘整条链接(斜杠与冒号不是合法 Base32 字符,会直接报错)。
手机时间不准会影响验证码吗?
会,而且这是「验证码总是不对」的第一大原因。TOTP 把「当前 Unix 时间 ÷ 周期」的结果当作计数器,时间差 30 秒以上必然算错。手机开启「自动设置时间」即可;服务器端同理,运维手册里通常要求 NTP 对时。
TOTP 和短信验证码有什么区别?
短信验证码由服务端随机生成后下发,依赖运营商通道,存在被拦截、被补卡的风险;TOTP 是「共享密钥 + 时间」在双方各自本地算出来的,全程不经网络传输,因此不能靠劫持短信拿到。代价是密钥一旦泄露(例如截图外发),任何人任何时候都能算出验证码,所以密钥的保密等级等同于密码。
SHA-1 已经不安全了,为什么验证码还在用?
SHA-1 的问题在碰撞——能造出两段内容不同但摘要相同的消息;而 HMAC-SHA1 依赖的是「不知道密钥就伪造不出」,碰撞攻击并不能直接用来伪造 HMAC。既然 TOTP 是既有协议,改算法需要客户端与服务端同步升级,所以 SHA-1 仍是默认。服务端若支持 SHA-256,本工具可以切换。
密钥会被上传或保存吗?
不会。计算在浏览器本地完成,密钥不发送到服务器、不写入浏览器存储,本工具没有「计算历史」区块,刷新页面即清空。请注意:即便如此,把两步验证的长期密钥粘贴到任何网页都存在风险,公共电脑上尤其不要这么做。
为什么本工具不提供 SHA-512 的选项?
RFC 6238 允许 SHA-512,但它需要 64 位整数运算,而主流验证器与服务端几乎都用默认的 SHA-1(少数用 SHA-256)。只提供实际会被用到的两种算法,可以把结果口径讲清楚,也避免给出一个「选了也用不上」的选项。
延伸阅读
来自本站原创文章,讲清这个工具背后的算法与口径。