编码加密 · JWT / Token

TOTP/OTP

RFC 6238 二步验证码 + 二维码

本地处理 · 不上传 免费 · 无需登录 无次数限制 累计 58 次使用
模式 RFC 6238 / RFC 4226 · 兼容 Google Authenticator / 1Password / Authy
密钥 SecretBase32(A–Z 2–7)· 不入 URL
算法 ALGORITHM
位数 DIGITS
周期 PERIOD(秒)
账户 / 发行方 LABEL
发行方 ISSUER
当前口令实时 · 每秒刷新
30seconds
------
下一个口令 next window ------
扫码导入otpauth://
用 Google Authenticator / Authy 等扫码添加
第一节

关于本工具

About

两步验证恢复或迁移时,最怕服务商给的密钥格式混乱——Base32、十六进制、甚至带空格。输入密钥或扫描二维码,它按 RFC 6238 实时生成 TOTP 验证码,不依赖任何后端,密钥全程留在浏览器内存里,刷新即消失。适合运维批量重置 MFA、或用户跨设备转移账号时临时校验。

使用场景

服务器密钥轮换

运维小周接到通知,公司核心数据库的 SSH 密钥必须在 4 小时内完成轮换,同时所有运维人员的 TOTP 双因子密钥也要同步更新。他需要为 12 位同事生成新的 32 位 Base32 密钥,并导出为二维码分发给每个人。本工具直接在浏览器内生成密钥和二维码,不经过任何网络传输,避免密钥在轮换窗口期被中间人截获。

网盘二次验证恢复

老张换了新手机,发现之前绑定的网盘 TOTP 验证器没迁移过来,登录时卡在 6 位数验证码上。他翻出 3 年前备份的密钥字符串(一串 16 位字母数字),本工具支持手动输入密钥即时生成当前有效的验证码,不用下载任何 App,浏览器打开就能完成一次性的登录恢复。

团队共享服务密码

开发组长需要让 5 个新实习生访问公司 GitLab 仓库,但管理员出差在外无法即时下发 TOTP 种子。组长用本工具生成一个临时 TOTP 密钥,将二维码截图发到团队群,实习生各自扫码添加。密钥在 24 小时后失效,本工具不保存任何种子,群聊记录里也不会留下明文密钥。

离线环境初始化

某涉密机房的服务器不连外网,安全员需要为 3 台堡垒机配置 TOTP 双因子认证。他带着 U 盘里的本工具 HTML 文件进入机房,在离线浏览器中打开,为每台设备生成不同的 20 位密钥和二维码。所有计算在本地完成,密钥不经过任何网络接口,符合等保三级对双因子密钥的离线生成要求。

应急演练验证码

安全演习中,蓝队模拟攻击方劫持了某员工的手机验证器。红队需要快速生成一个与真实密钥同步的 TOTP 验证码来验证漏洞修复效果。本工具支持自定义时间步长(30 秒/60 秒)和算法(SHA1/SHA256),红队成员输入已知的种子后,能在浏览器里看到与真实验证器完全同步的 6 位数字,用于对比验证。

第二节

使用指南

Getting Started

使用步骤

  1. 1在「密钥」输入框粘贴或键入 Base32 密钥(如 JBSWY3DPEHPK3PXP),下方实时显示当前 6 位验证码
  2. 2点击「生成二维码」按钮,右侧区域渲染出对应 TOTP 的 QR 码图案,供手机 Authenticator 扫描
  3. 3切换「时间步长」下拉框(30 秒/60 秒),验证码自动按新步长重新计算并更新显示
  4. 4点击验证码数字右侧的复制图标,码值即写入剪贴板,粘贴到登录页即可完成二步验证

输入输出示例

输入输出说明
secret=JBSWY3DPEHPK3PXP&issuer=Example&account=user@example.comotpauth://totp/Example:user@example.com?secret=JBSWY3DPEHPK3PXP&issuer=Example&algorithm=SHA1&digits=6&period=30常规:标准 RFC 6238 URI 格式,包含 issuer 和 account,验证基础 TOTP 链接生成
secret=GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ&issuer=Test&account=testotpauth://totp/Test:test?secret=GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ&issuer=Test&algorithm=SHA1&digits=6&period=30常规:32 字符 Base32 密钥(RFC 4648 标准长度),验证长密钥正确编码
secret=AAAAAAAAAAAAAAAA&issuer=&account=roototpauth://totp/:root?secret=AAAAAAAAAAAAAAAA&issuer=&algorithm=SHA1&digits=6&period=30边界:issuer 为空字符串,输出中 issuer 段留空但冒号保留,验证 URI 解析容错
secret=12345678901234567890123456789012&issuer=Long&account=aotpauth://totp/Long:a?secret=12345678901234567890123456789012&issuer=Long&algorithm=SHA1&digits=6&period=30边界:密钥含数字字符(非标准 Base32),工具应拒绝或警告,此处展示未校验时的输出
secret=JBSWY3DPEHPK3PXP&issuer=GitHub&account=user@github.com&algorithm=SHA256&digits=8&period=60otpauth://totp/GitHub:user@github.com?secret=JBSWY3DPEHPK3PXP&issuer=GitHub&algorithm=SHA256&digits=8&period=60易错:自定义参数(SHA256、8 位码、60 秒周期),验证工具是否正确解析并保留非默认参数
secret=JBSWY3DPEHPK3PXP&issuer=Example&account=user@example.com&algorithm=MD5otpauth://totp/Example:user@example.com?secret=JBSWY3DPEHPK3PXP&issuer=Example&algorithm=MD5&digits=6&period=30易错:algorithm=MD5 非 RFC 6238 支持的算法,工具应拒绝或降级,此处展示未校验时的输出

常见错误对照

1.密钥 Base32 编码错误,导致验证码始终不对

✗ 错误直接复制网站提供的密钥字符串(如 JBSWY3DPEHPK3PXP)时,混入连字符或空格
✓ 修复JBSWY3DPEHPK3PXP

RFC 6238 规定密钥必须使用 Base32 编码,且不含分隔符。连字符、空格、换行符会被当作密钥的一部分,导致 HMAC-SHA1 计算结果与服务器不一致。

2.时间步长偏移,验证码提前/延迟失效

✗ 错误手机与服务器时间差超过 30 秒,但未校准系统时间
✓ 修复在工具内手动输入时间偏移量(如 -1 步)以对齐服务器时间

TOTP 基于当前时间戳整除 30 秒窗口生成。客户端与服务器时间偏差超过 ±30 秒会导致验证码不匹配。RFC 6238 允许窗口调整,但需用户主动设置偏移。

3.二维码内容包含非标准参数,工具无法解析

✗ 错误扫描的二维码 URI 中包含 otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example&algorithm=SHA256
✓ 修复otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example

部分服务商在 URI 中附加 algorithm、digits、period 等参数。本工具默认使用 SHA1、6 位数字、30 秒周期,非标准参数会被忽略或导致解析失败。

4.密钥长度不符合 Base32 要求,生成码位数错误

✗ 错误使用 8 字符的密钥(如 12345678)
✓ 修复使用 16 字符的 Base32 密钥(如 JBSWY3DPEHPK3PXP)

Base32 编码每 5 位一组,16 字符对应 80 位密钥。HMAC-SHA1 需要至少 20 字节密钥,过短密钥会降低熵值,且部分实现会拒绝执行。

5.验证码输入时忽略大小写,但工具要求严格匹配

✗ 错误工具生成的验证码输出为 6 位数字,但用户误以为支持字母,输入 'A1B2C3'
✓ 修复输入纯数字:123456

RFC 6238 标准 TOTP 输出为 6 位十进制数字(0-9),不包含字母。若工具界面显示字母,说明使用了非标准扩展(如 Steam 令牌),本工具不兼容。

6.重复使用同一密钥生成多个账号,导致冲突

✗ 错误为两个不同网站设置相同的 Base32 密钥
✓ 修复每个账号使用独立随机生成的密钥

TOTP 安全性依赖密钥唯一性。相同密钥下,同一时间窗口生成的验证码完全相同,攻击者可利用一个账号的验证码登录另一个账号。

7.忽略二维码中的 issuer 参数,导致多账号混淆

✗ 错误扫描多个网站二维码后,工具只显示密钥,不区分来源
✓ 修复在工具输入框中保留 URI 中的 issuer 参数(如 &issuer=GitHub)

issuer 参数用于标识账号归属,缺失时所有条目显示为 'Unknown'。用户无法区分验证码对应哪个服务,容易输错。

第三节

工作原理

How It Works

核心公式

TOTP = Truncate(HMAC-SHA1(K, T)) mod 10^D

变量说明

  • K共享密钥,Base32 编码
  • T时间步长计数,floor(Unix时间/30)
  • D验证码位数,通常为 6
  • HMAC-SHA1基于 SHA1 的密钥哈希算法
  • Truncate动态截断函数,取 31 位动态偏移

示例

密钥 K = JBSWY3DPEHPK3PXP(Base32),当前 Unix 时间 1712345678,T = floor(1712345678/30) = 57078189。计算 HMAC-SHA1(K, T) 得 20 字节哈希值,取末字节低 4 位作为偏移量 0x0F,从该偏移截取 4 字节并取模 10^6,得到 6 位验证码 872394。

密钥 + 时间戳(Base32 解码)HMAC-SHA1 运算(RFC 4226)截断 + 取模(动态截取 6-8 位)TOTP验证码
用户输入 本地处理 输出结果
第五节

常见问题

Q & A
这个工具生成的验证码和我手机上的 Google Authenticator 对不上,怎么回事?

最常见的原因是手机和电脑的系统时间不一致。TOTP 算法依赖时间窗口(默认 30 秒),只要设备时间偏差超过几十秒,生成的码就会错位。先检查电脑系统时间是否自动同步(Windows 右键右下角时间→调整日期/时间→自动设置时间;macOS 系统偏好设置→日期与时间→自动设置)。如果手机是主力验证器,建议以手机时间为准,手动校正电脑时间后刷新页面再试。本工具纯前端运算,不涉及服务器时间,完全依赖浏览器所在系统的时钟。

输入密钥的时候要不要空格?大小写有影响吗?

密钥通常是一串 Base32 编码的字符(类似 JBSWY3DPEHPK3PXP),本工具会自动去除输入框中的空格和换行,所以粘贴时带空格没关系。大小写方面,Base32 编码不区分大小写,工具内部统一转为大写处理,因此你输入小写字母同样能正确生成验证码。唯一需要注意的是不要混入多余的特殊符号或中文,那会导致密钥解析失败。

为什么有时候验证码刚生成就过期了?

TOTP 的标准时间步长是 30 秒,但部分服务端(如某些银行的动态口令)会配置更短步长(15 秒)或更严格的时间窗口校验。本工具严格遵循 RFC 6238,默认 30 秒步长。如果你发现码的有效期明显短于 30 秒,可能是你使用的服务端启用了「前一个窗口/后一个窗口」的宽松校验,而你的设备时间恰好处于窗口边界。建议打开系统自动时间同步,并在倒计时还剩 5 秒以上时提交验证码,避免卡边界。

这个工具需要把密钥上传到你们的服务器吗?

完全不需要。本工具是纯前端实现(FE),所有运算——包括密钥解析、HMAC-SHA1 哈希计算、时间窗口切片——都在你的浏览器本地完成。没有任何数据被发送到任何服务器。你可以打开浏览器开发者工具的网络面板(F12 → Network)刷新页面,确认没有任何网络请求。关闭页面后所有输入数据自动消失,不留痕迹。这一点对于处理银行、邮箱等敏感服务的二步验证密钥尤其重要。

能不能离线使用?没网的时候还能生成验证码吗?

可以。本工具的核心逻辑(SHA1 + TOTP 算法)打包在单个 JavaScript 文件中,首次加载后浏览器会缓存。只要你在有网时打开过一次本页面(让缓存生效),之后断网刷新页面依然能正常工作。建议在有网时打开页面后不要关闭标签页,或者将页面添加到浏览器书签,断网时直接打开即可。如果浏览器设置了「退出时清除缓存」,则需要重新联网加载。

生成的二维码别人扫了也能看到我的密钥吗?

本工具生成的二维码内容是一个标准的 otpauth:// URI,其中包含密钥(secret)参数。如果你在生成二维码后截图或分享给他人,对方扫描该二维码确实能拿到你的密钥,从而生成相同的动态验证码。因此二维码的隐私级别等同于密钥本身:不要在公共屏幕展示、不要发给不可信的人。本工具不会记录或存储你生成的任何二维码图片,生成后请自行妥善保管。

和手机上的 1Password / Bitwarden 自带的 TOTP 有什么区别?

核心算法完全一样(RFC 6238),生成的验证码理论上一致。区别在于使用场景:手机密码管理器通常把 TOTP 密钥和密码存在一起,方便自动填充但存在单点风险(手机丢了可能同时泄露密码和验证码)。本工具是独立的纯浏览器工具,适合在电脑上临时生成验证码(比如在网页登录时手机不在身边),密钥不会与任何密码管理器绑定。另外本工具不依赖任何账号系统,打开即用,隐私性更强。

密钥输入后提示「无效的 Base32」,但我确定密钥是对的,怎么办?

首先检查密钥长度:Base32 编码的密钥长度通常是 16、26 或 32 位(不含填充符),部分服务商提供的密钥末尾可能带有等号(=)填充符,本工具支持自动去除。其次确认密钥中没有混入数字 0 和字母 O、数字 1 和字母 I/L 等易混淆字符——有些服务商生成密钥时故意避开了这些字符,但如果你手动抄写时弄混,会导致解码失败。最后,如果你是从网页直接复制密钥,注意不要复制到前后的空格或隐藏字符,建议粘贴到纯文本编辑器里看一眼再复制。

隐私保证所有计算与处理均在你的浏览器本地完成,输入数据不会上传服务器,也不会保存或共享。

选择 打开 +新窗口 esc关闭