authenticator 中文文档 下载 App

验证码是怎么算出来的:时间窗口与 HMAC

从一张二维码说起

绑定时你扫的那张二维码,载荷是一把共享密钥(setup key)——从这一刻起,平台和你的验证器各持同一把钥匙(二维码里装了什么有拆解)。之后每次出码,都是这把钥匙和当前时间的一次联合运算。

三步算出一枚码

  1. 数格子:把当前时间除以 30 秒,取整数——得到当前处于第几个时间窗口。世界协调时下,每 30 秒这个数字加一;
  2. 做运算:以密钥为钥匙、窗口数为输入,做一次 HMAC-SHA1 运算,得到一串固定长度的乱数;
  3. 裁数字:按标准规则从乱数中截取并折算出 6 位十进制数字——这就是屏幕上的验证码。
T   = 当前时间 ÷ 30(取整数部分)
HMAC = HMAC-SHA1(共享密钥, T)
码   = 从 HMAC 中截取的 6 位数字

为什么手机和平台必然算出同一个数

两边输入完全相同:同一把密钥(绑定时共享的)、同一个时间(只要双方钟都准,见手机时间不准为什么影响出码)。确定性算法保证输出必然一致——所以「校验」不需要任何网络往返,平台收到你填的码后,本地按同样公式算一遍,对上了就放行。

三个由原理直接推出的特性

标准的出处

这套机制是公开标准:HOTP 定义于 RFC 4226(计数器驱动),TOTP 定义于 RFC 6238(时间驱动,30 秒窗口、6 位数字是主流参数)。验证器与各平台都是标准的实现者——这也是「任何标准验证器都能扫任何平台的码」的根本原因(两款主流验证器怎么选的通用性一节)。