2FA 验证码生成器(TOTP)

输入 Base32 密钥或粘贴 otpauth:// URI,在线生成 2FA 动态验证码(RFC 6238 TOTP)。已用 RFC 测试向量核对;密钥只在当前页面内存里,不保存、不进网址。

  • 在浏览器中处理
  • 数据不离开你的设备
  • 免费 · 无需注册
粘贴 Base32 密钥或完整的 otpauth://totp/ URI。支持小写、空格、连字符、全角字符和末尾的 = 填充。导入 URI 会填好其中的设置,输入框只保留密钥。不支持 HOTP URI。
用 crypto.getRandomValues 生成新密钥:SHA-1 为 20 字节、SHA-256 为 32 字节、SHA-512 为 64 字节。新密钥会替换输入框内容,不会创建或更新服务账户。
验证码设置
验证码设置 算法、位数和周期需与服务方一致,默认为 SHA-1、6 位、30 秒。周期须为 1 到 86400 的整数秒。修改后会自动重新计算验证码。
Unix 时间留空时使用本机当前时间。输入非负整数秒可固定时刻,倒计时随之停止。T 显示 floor(Unix 时间 / 周期)。
验证器信息
验证器信息 发行方和账户用于命名验证器条目,均可留空;账户留空时使用 Account。两项都不能含冒号。这些名称改变 URI 和二维码,验证码由密钥与验证码设置决定。

当前验证码和验证器二维码会显示在这里。

阅读完整使用指南 TOTP 原理详解:用 RFC 6238 测试向量一步步算出动态验证码
示例、说明与常见问题 带实际输出的示例、与同类工具的差别,以及常见问题。

验证码的算法是 RFC 6238 的 TOTP:先算 T = floor(Unix 时间 / 周期),再对 T 做 RFC 4226 的 HOTP(HMAC 加动态截取)。

场景:阿里云虚拟 MFA 手动添加后验证码不对

阿里云帮助中心的RAM 用户自行绑定 MFA 设备写了两种添加方式:扫码添加,或者「手动添加」,即把绑定页面上的账号和密钥抄进阿里云 App 或 Google Authenticator。手动抄写时错一个字符,App 照样会显示 6 位数,但服务端永远不认。

这时把绑定页上的同一串密钥粘到本工具里:

  • 和 App 在同一个 30 秒里显示的数字不同:说明 App 里那份密钥抄错了。工具会直接指出非法字符,例如密钥里出现 1、0、8、9(Base32 字母表里没有这四个数字,多半是把 I、O、B 看错了)。
  • 数字相同,控制台还是提示安全码错误:看时钟。阿里云的 MFA 常见问题列出的原因包括手机时间「延迟或超前」、绑定页打开太久导致「二维码(密钥)已过期」。前者本工具会提示(本机时钟与服务器相差超过约 3 秒时);后者要刷新绑定页,拿到的是一串新密钥。

实测示例(RFC 测试向量)

以下都用 RFC 公布的测试密钥,任何实现都应该算出同样的结果。

密钥(Base32)算法 / 位数Unix 时间上一个当前下一个
GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQSHA-1 / 81234567890399803578900592438590587
同上SHA-1 / 61234567890980357005924590587
64 字节种子,末尾带 =SHA-512 / 82000000000199541933861890141841313

第一行的 89005924 与第三行的 38618901 分别是 RFC 6238 附录 B 表中对应行的值。第二行说明 6 位验证码就是 8 位值的后 6 位,开头的 0 会保留。第三行的种子是 GEZDGNBVGY3TQOJQ 重复 6 次再接 GEZDGNA=,即 64 个 ASCII 字符 1234567890…1234;RFC 正文只提到 20 字节种子,但附录 A 的参考代码对 SHA-256 / SHA-512 用的是 32 / 64 字节种子,表中数值也只对这两个种子成立。

填上发行方「测试环境」、账户 dev@example.com,生成的 URI 是:

otpauth://totp/%E6%B5%8B%E8%AF%95%E7%8E%AF%E5%A2%83:dev%40example.com?secret=GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ&issuer=%E6%B5%8B%E8%AF%95%E7%8E%AF%E5%A2%83

中文按 UTF-8 百分号编码;按 Google 的 Key Uri Format,默认值(SHA1、6 位、30 秒)不写进 URI,发行方或账户里带 : 会被拒绝,因为冒号是两者的分隔符。

与其他在线 2FA 工具的区别

2026-09-30 我们用同样的输入测了中文搜索「2FA 在线」「2FA 验证码」结果里常见的几个工具:

  • 密钥去了哪里。 2fa.cn 提交后,浏览器请求的是 https://2fa.cn/codes/<你的密钥>,验证码由服务器算好返回(开发者工具的网络记录可见)。BrowserScan 把密钥写进地址栏的 # 后面,会留在浏览历史里,页面还介绍了把密钥直接接在网址路径后的用法。本工具的密钥只在页面内存里,唯一的请求是读取服务器时间的 HEAD,不含密钥。
  • 非法字符。 输入 GEZDGNBV1Y3TQOJQ(含 1),2fa.cn 返回了 000449,BrowserScan 也显示了验证码(它的红字「密钥字符不合法,请检查密钥」在输入正确的 RFC 密钥时同样显示)。本工具直接报错并指出是哪个字符。
  • otpauth:// 链接。 BrowserScan 粘贴 URI 后不出验证码;2fa.cn 支持批量输入。本工具会把 URI 里的全部参数填好。
  • 参数。 本工具支持 SHA-1 / SHA-256 / SHA-512、6 / 8 位、1–86400 秒任意周期,以及固定 Unix 时间,方便对照测试向量。

限制

  • 只生成 TOTP。otpauth://hotp/ 会被拒绝,没有计数器模式。
  • 位数只有 6 和 8(Key Uri Format 规定的取值);周期是 1 到 86400 的整数秒,从 Unix 纪元起算(T0 = 0)。
  • Key Uri Format 文档写明 Google Authenticator 忽略 algorithm 与 period,Android 版还忽略 digits。改动这些参数时,二维码下方会出现提示。
  • 不能直接读二维码图片。先用二维码解码器取出 otpauth:// 文本,再粘贴到这里;要把其他文字做成二维码,用二维码生成器。
  • 什么都不保存,刷新即清空,这是有意的设计。
  • 时钟检查依赖服务器 Date 头,精度 1 秒,约 3 秒以内的偏差不提示;请求失败时不显示任何提示。

想单独看 HMAC 这一步,可以用 HMAC 生成器;账号密码用密码生成器。

FAQ

密钥会上传或保存吗?

不会。验证码用浏览器的 Web Crypto API 在本机计算。密钥不写入 localStorage、sessionStorage、Cookie,也不进网址;本页不加载统计与广告脚本。刷新页面密钥就没了。工具唯一发出的请求是对本页的一次 HEAD 请求,用来读取服务器的 Date 时间做时钟检查,不带查询参数,也不带请求体。

这里的验证码和手机 App 或服务端对不上,怎么排查?

按顺序查三样:本机时钟(偏差超过约 3 秒时工具会提示)、密钥(抄错一个字符,或重新打开绑定页后密钥已换)、参数(算法、位数、周期两边必须一致)。当前验证码下方的上一个 / 下一个验证码,可用来判断对方是不是差了一个时间步。

能直接粘贴二维码里的 otpauth:// 链接吗?

能。把整条 otpauth://totp/ URI 粘进密钥框,工具会填好密钥、发行方、账户、算法、位数和周期,输入框里只留下密钥。otpauth://hotp/(计数器型)会被拒绝,本工具只生成基于时间的验证码。要从二维码图片里取出 URI,先用二维码解码工具。

随机生成的密钥多长?

SHA-1 为 20 字节(160 位),SHA-256 为 32 字节,SHA-512 为 64 字节,即 RFC 6238 第 5.1 节建议的与 HMAC 输出等长。RFC 4226 要求至少 128 位;更短的密钥也能算,工具会给出提示。

可以把这个页面当日常用的验证器吗?

不建议。页面什么都不保存,关掉标签页验证码就没了;而且谁拿到密钥,谁就能算出你的验证码。正式账号的密钥请放在验证器 App 或密码管理器里。这个页面适合测试 2FA 功能、核对手动抄写的密钥,或查看某个密钥在某个时刻的验证码。