master
otp-cj
仓颉(Cangjie)一次性密码(OTP)库,实现 HOTP(RFC 4226)与 TOTP(RFC 6238),提供 Base32 密钥编解码(RFC 4648)与 otpauth:// URI 生成,可直接与 Google Authenticator / Microsoft Authenticator 等常见 OTP App 互通。
组织:simcu | 包名:otp | 版本:1.0.0
特性
- TOTP:基于时间步长的动态码,默认 6 位 / 30 秒步长,支持自定义位数、步长与时钟偏移窗口
- HOTP:基于计数器的一次性密码,默认 6 位
- Base32:RFC 4648 无填充变体编解码,解码时忽略大小写、空格、短横线与
= - otpauth:// URI:生成可用于二维码的认证链接,并附带随机密钥生成工具
- 零三方依赖:仅依赖仓颉标准库
stdx.crypto.digest.SHA1 - 密钥支持 Base32 字符串(Google Authenticator 惯例)与原始字节两种传入方式
安装
在 cjpm.toml 中声明依赖(可改用中央仓版本号):
[dependencies]
"simcu::otp" = { path = "../../cangjie/otp-cj" }
# 或发布到中央仓后:"simcu::otp" = "1.0.0"
代码中引用:
import simcu::otp.*
快速开始
1. 生成密钥并绑定 OTP
// 生成随机 Base32 密钥(默认 20 字节 = 160 bit)
let secret = OtpUri.generateSecret() // 例如 "N6C5HNT2F633..."
// 生成 otpauth:// 链接,前端渲染成二维码供用户绑定
let uri = OtpUri.build(issuer: "GamePlatform", account: "18600127718", secretBase32: secret)
// otpauth://totp/GamePlatform%3A18600127718?secret=N6C5HNT2F633...&issuer=GamePlatform&algorithm=SHA1&digits=6&period=30
2. 生成动态码
// TOTP:默认 6 位 / 30s 步长,基于当前时间
let code = Totp.generate(secret) // "351047"
// 自定义位数与步长
let code2 = Totp.generate(secret, digits: 8, period: 60)
// 原始字节密钥
let raw = Base32.decode(secret)
let code3 = Totp.generateBytes(raw)
// HOTP:基于计数器(第 N 次动态码)
let hotp = Hotp.generate(raw, counter: 0) // 默认 6 位
let hotp2 = Hotp.generate(raw, counter: 0, digits: 8)
3. 校验动态码
// TOTP 校验:默认允许前后各 1 个时间步的时钟偏移
let ok = Totp.verify(secret, code) // Bool
// 放宽/收紧偏移窗口
let ok2 = Totp.verify(secret, code, digits: 6, period: 30, window: 2)
// 字节密钥版本
let ok3 = Totp.verifyBytes(raw, code)
4. Base32 编解码
let raw = Base32.decode("N6C5HNT2F633") // 忽略空格/短横线/大小写
let encoded = Base32.encode(raw) // 往返后还原 "N6C5HNT2F633"
API 参考
包结构:全部类型位于根包 simcu::otp(单一命名空间,无子包)
| 类型 | 说明 |
|---|---|
Base32 |
RFC 4648 无填充 Base32 编解码;encode(data) / decode(input),非法字符抛 IllegalArgumentException |
HmacSha1 |
RFC 2104 / 4226 HMAC-SHA1(blockSize=64);init(key) / compute(data) |
Hotp |
RFC 4226;generate(secret, counter[, digits]) |
Totp |
RFC 6238;generate/generateAt/generateBytes(..., digits, period) 与 verify/verifyBytes(..., digits, period, window) 多种重载;默认 period=30、window=1 |
OtpUri |
generateSecret([bytes]) 随机密钥;build(issuer, account, secret[, digits, period]) 生成 otpauth:// 链接 |
常用常量:
Totp.DEFAULT_PERIOD = 30Totp.DEFAULT_T0 = 0
说明
- HMAC-SHA1 为何自实现:仓颉标准库
std.crypto.digest的 HMAC 目前仅支持 SHA512,而 HOTP/TOTP 标准基于 HMAC-SHA1,因此本库基于stdx.crypto.digest.SHA1实现了 RFC 2104 的 HMAC-SHA1。 - 兼容性:
Totp.generate/Totp.verify的结果与 Google Authenticator 完全一致,可交叉验证。 - 服务端校验建议:绑定阶段将 Base32 secret 持久化到账号表(
otp_secret字段);校验时用Totp.verify(secret, code)。
运行测试
cjpm test
测试覆盖:Base32 编解码往返、HOTP/TOTP 与 RFC 官方测试向量的对拍、时钟偏移窗口、otpauth:// URI 生成等。
配合 SimApi 使用
在 simapi 后端中作为账号二次验证通道:
// AuthCodeService 示例:绑定 OTP 的账号优先接受 TOTP 动态码
let otpOk = Totp.verify(acc.otpSecret, code)
Languages
Cangjie
100%