跳到主内容
UniKit

OTP 验证码生成与校验

按 RFC 6238 / RFC 4226 生成 TOTP 与 HOTP 验证码(HMAC-SHA1/SHA256/SHA512),显示当前/上一个/下一个验证码与剩余秒数,并校验用户输入的验证码。

浏览器本地运行所有计算都在你的浏览器里完成,数据不会离开本机。

密钥格式
算法
位数
时间步长(秒)
当前验证码
······

剩余 30 秒

上一个······
下一个······

这个工具能做什么

  • 本地调试两步验证:把 2FA 的 Base32 密钥粘进来就能看到当前、上一个、下一个验证码和剩余秒数,不用等 App 刷新。
  • 服务端对不上时定位问题:同一个密钥分别选 SHA-1 / SHA-256 / SHA-512、6 位或 8 位、30 或 60 秒步长,逐个试出对方实际用的参数。
  • 校验用户输入的验证码:输入框里填 6 位数字就会和当前时间步比对,并且默认接受相邻时间步(±1)的验证码,能容忍轻微时钟漂移。
  • 离线场景:内网机器、容器或没有手机的地方,用它算 HOTP/TOTP,密钥只在浏览器里参与计算。

示例

输入

模式:HOTP(计数器)
密钥:GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ(Base32)
算法:SHA-1
位数:6
计数器:1

输出

验证码:287082

这个结果是 RFC 4226 附录 D 的标准测试向量(计数器 1 → 287082);TOTP 模式下同一密钥在时间步 1(时间 30–59 秒)会得到 412578,对应 RFC 6238 的 6 位输出。

常见问题

TOTP 和 HOTP 该选哪个?

多数两步验证 App(Google Authenticator、各类手机令牌)用 TOTP:验证码按时间步变化,不需要同步计数器。HOTP 用一个自增计数器,每验证成功一次计数器加一,银行硬件令牌和部分内部系统还在用,需要服务端告诉你当前计数器值。

密钥要不要带空格或等号?

Base32 密钥里的空格会被忽略,末尾的 = 填充可以省略,大小写不敏感。如果服务端给的是十六进制密钥,把「密钥格式」切成「十六进制」再粘即可。空密钥和非法字符都会分别报错。

为什么和服务端算出来的验证码不一样?

按可能性排序:算法不对(很多服务默认 SHA-1,也有用 SHA-256 的)、位数不对(6 或 8)、步长不对(30 或 60 秒)、以及设备时间不同步。TOTP 完全依赖时间,电脑时间偏几十秒结果就完全不同。

校验为什么允许 ±1 个时间步?

这是 RFC 6238 推荐的窗口做法,用来容忍客户端与服务端几十秒的时钟漂移,避免用户在边界时刻输入「上一格」的验证码被判错。窗口固定为 1,也就是同时接受上一个、当前和下一个时间步。

在这里输入真实密钥安全吗?

验证码完全在本机按 RFC 4226 / 6238 计算,页面不发网络请求,密钥不会离开浏览器。不过密钥本身是等同于第二因素的敏感信息,用完建议关闭页面,别在共享电脑上保存。

关键词:totphotpotp2fa双重验证动态口令验证码google authenticatorrfc 6238rfc 4226base32

同类工具