2FA.mo.cn 认证工具在浏览器内运行

开发者指南

RFC 6238 TOTP 算法详解:Python 与 Node.js 示例

从时间计数器、HMAC 到动态截断,用公开测试密钥理解 TOTP,并核对 RFC 6238 测试向量。

TOTP 将当前时间换算成计数器,再以共享密钥计算 HMAC,最后通过动态截断与取模得到验证码。下面仅使用 RFC 6238 中的公开测试密钥,不涉及真实账户。

计算过程

  1. 将 Base32 密钥解码为字节,Base32 是编码而不是加密。
  2. 以 floor(timestamp / period) 取得时间步数,写成 8 字节大端整数。
  3. 计算 HMAC,按规范使用摘要末字节的低四位作为截断偏移。
  4. 读取 31 位正整数,对 10 ** digits 取模,左侧补零。

示例采用 T0 = 0、30 秒周期、SHA-1 和 8 位验证码。在 Unix 时间 59 秒时,标准结果为 94287082。8 位演示用于对应 RFC 测试向量;真实配置应与服务端完全一致。

Python 标准库示例

import base64
import hashlib
import hmac
import struct

secret = "GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ"  # 公开演示密钥
counter = 59 // 30
key = base64.b32decode(secret)
digest = hmac.new(key, struct.pack(">Q", counter), hashlib.sha1).digest()
offset = digest[-1] & 15
number = int.from_bytes(digest[offset:offset + 4], "big") & 0x7fffffff
print(str(number % 10**8).zfill(8))  # 94287082

Node.js 标准库示例

RFC 的此组测试密钥是下面的 ASCII 字节;不要把一般 Base32 密钥未经解码就当成 ASCII 字节使用。

import { createHmac } from 'node:crypto';

const key = Buffer.from('12345678901234567890', 'ascii'); // 公开演示密钥
const counter = Buffer.alloc(8);
counter.writeBigUInt64BE(BigInt(Math.floor(59 / 30)));
const digest = createHmac('sha1', key).update(counter).digest();
const offset = digest[digest.length - 1] & 15;
const number = digest.readUInt32BE(offset) & 0x7fffffff;
console.log(String(number % 10 ** 8).padStart(8, '0')); // 94287082

生成器不等于完整认证系统

生产验证端还需考虑尝试次数限制、重复使用、可接受的时间窗口、密钥生成与保护、恢复与撤销。不要仅复制示例就把它当作完整登录认证系统。本网站使用浏览器 Web Crypto,并用标准向量验证多种哈希算法。

参考资料

选择验证器与了解个人服务 →
# 打开验证器