TOTP / HOTP 动态口令
编码所有处理都在浏览器本地完成,数据不上传服务器
⚠️ 请不要输入你正在使用的账号密钥。 这里确实全在本机计算、不发任何请求,但页面是从网上加载来的 —— 而 TOTP 的密钥就是第二个因素的全部秘密,拿到它的人可以一直生成有效的动态口令。这个工具是用来核对某个服务给的密钥能不能用、以及在写自动化测试时生成期望值的。 算法两步,都是定死的:先算计数器(TOTP 用「当前 Unix 时间 ÷ 步长」,HOTP 用你给的整数),再做 HMAC 与动态截断 —— 从 HMAC 结果里按最后一个字节选起点、取 4 个字节、取 31 位、再取模成 6 位数字。所以密钥一样、时间一样,结果就一样,你在手机 App 上看到的应当与此处逐位相同。 ⚠️ 这里只算「此刻这个密钥对应的口令是什么」,不做验证 —— 验证要拿候选口令去撞服务端,那是在线行为。另外:服务端接受前后几个窗口由服务端自己定,列出来的相邻口令只是它能容忍的范围。
功能
- 按 RFC 6238 / RFC 4226 计算 TOTP 与 HOTP,实现通过 RFC 官方的全部测试向量
- ⚠️ 页面第一行就是「不要输入正在使用的密钥」的提醒 —— 动态口令的密钥就是第二个因素的全部秘密
- 算法可选 SHA-1 / SHA-256 / SHA-512(SHA-1 是绝大多数服务的默认)
- 步长、位数可调(默认 30 秒 / 6 位,与常见 App 一致)
- 显示本窗口还剩多少秒,以及当前的计数器值
- 可列出前后若干窗口的口令,用来核对设备时钟偏了多少
- HOTP 模式可直接指定计数器,便于对照 RFC 的测试向量
- 密钥容忍小写、空格、连字符与末尾填充;含 0/1/8/9 时明确报错,而不是猜一个出来
使用方法
- ⚠️ 用一个测试账号的密钥,不要用你真在用的
- 把 Base32 密钥粘进去
- 对准算法、步长与位数(大多数服务是 SHA-1 / 30 秒 / 6 位)
- 结果里的 6 位数字应当与你的验证器 App 完全一致
常见问题
- 为什么算出来的和我的验证器 App 不一样?
- 按可能性排:一是时钟偏差 —— TOTP 完全依赖双方时钟,设备差 30 秒以上就会落到相邻窗口,勾上「前后窗口」看看相邻的那几个里有没有你 App 上显示的;二是参数不一致 —— 算法(SHA-1 / 256 / 512)、步长(30 或 60 秒)、位数(6 或 8)三者任一不同结果都不同;三是密钥抄错了 —— 密钥只含 A–Z 与 2–7,手抄时最容易把 `0` 写成 `O`、`1` 写成 `I`,而本工具会因为出现 0/1 直接报错。
- TOTP 和 HOTP 有什么区别?
- 区别只在计数器从哪来。HOTP 用一个双方各自递增的计数器,每用一次加一 —— 问题是客户端与服务端的计数一旦不同步就再也对不上,而且用户在没登录成功时按出的次数也会消耗计数器。TOTP 用时间当计数器(当前时间 ÷ 步长),双方只要时钟大致一致就不用同步状态。代价是窗口只有 30 秒,且严重依赖时钟准确。
- 密钥和验证码,哪个更不能泄露?
- 密钥。 验证码 30 秒就过期,而且必须与你的用户名、密码一起用才有效;而密钥是可以无限生成有效验证码的东西 —— 拿到它的人什么时候都能登录,而且你这边看不出任何异常。所以密钥泄露等同于第二个因素整个失效,而验证码泄露只影响那 30 秒。
- 这个工具能帮我验证一个验证码对不对吗?
- 不能,而且不应该。验证要拿候选口令去撞服务端,那是在线行为,这个站没有服务端也不做请求。这里回答的是「此刻这个密钥算出来的数字是什么」—— 对照你自己的验证器 App 就够了,两者一致说明密钥与参数都对。
相关工具
Base64 编解码
编码把文本转成 Base64,或把 Base64 还原成文本,中文与 emoji 都按 UTF-8 正确处理。全部在浏览器本地完成,内容不上传。
URL 编解码
编码把中文、空格与符号转义成 %XX,或把 %XX 还原成文本;整条 URL 与单独的参数值要选对方式,选错不会报错,但链接会打不开。全部在浏览器本地完成。
HTML 实体编解码
编码把 < > & 与引号转成 HTML 实体,也能把实体还原成字符,而且只解一遍:&lt; 得到的是 < 而不是尖括号。全部在浏览器本地完成。
JWT 解析与验签
编码把 JWT 拆成 header、payload、signature,支持用密钥验证 HS256/384/512 签名,并把 exp、nbf 换算成可读时间。全部在浏览器本地完成。
Unicode 转义
编码把中文、emoji 这类非 ASCII 字符转成 \uXXXX、\xXX 或 &#xXXXX; 的转义写法,也能还原回来。全部在浏览器本地完成,不上传。
文件转 Base64
编码拖入任意文件即可得到 Base64 与可直接粘进 src / url() 的 data URL,并列出 MIME、体积与编码后的长度。文件不上传。