Google两步验证

  1. HOTP:计数器验证
  2. TOTP:时间戳验证

算法公式

HS = HMAC-SHA-1(K,C)
DT(HS)//相当于算法分析2-5步
K:秘钥,客户端和服务端都知道,其他第三方不知道
C:在HOTP里面属于计数器
在TOTP里面属于时间戳

算法分析

  1. 通过K和C生成一个容量为20的byte数组,byte[] a;
  2. 取最后数组a的最后一位,和0xF相余,也就是取最后一位的低四位,作为偏移量
  3. 取偏移量开始的第一个整形字节
  4. 将第三部取得的整形自己与0x7FFFFFFF相&,&完就相当于取后31位
  5. 将第四部的值模除10^6,就会得到6位验证码
//第一步
byte[] hash = signer.sign(challenge);
//第二步
int offset = hash[hash.length - 1] & 0xF;//取数组最后一个字节的低四位作为偏移量
//第三步,第四步
int truncatedHash = hashToInt(hash, offset) & 0x7FFFFFFF;//取后31位
//第五步
int pinValue = truncatedHash % DIGITS_POWER[codeLength];//最后验证码要求六位就%10^6
return padOutput(pinValue);//不够6位补0

TOTP

  1. 客户端和服务端都有统一约定的K,用客户端生成验证码前,需要和服务端校准时间。通常是发送一个网络请求,在响应头中得到服务器的时间。将偏差的时间与System.currentTimeMillis()函数相加,就可以和服务端时间同步。
  2. 客户端和服务端还要约定一个有效时间周期,用于在某个时间周期更换验证码,一般为30s。
  3. 但是由于网络原因,客户端生成密码时间和服务器接受密码的时间还可能存在延迟,服务器会需要有一个延迟策略,可以允许验证前一个有效时间周期的验证码。
    这里写图片描述
    图片来自参考二
    这里写图片描述
    图片来自参考二

HOTP

客户端和服务端都有一个计数器C,并且事先将计数器同步,保持一致。
客户端,使用当前C进行算法计算
HS = HMAC-SHA-1(K,0);DT(HS)
计算成功后,C + 1。
将计算的验证码提交给服务器之后,服务端的C也用上面的公式计算,与客户端提交的验证码进行比对,如果一致,服务端的C + 1
这里写图片描述
图片来自参考一
参考链接
HOTP和TOTP算法图解
基于时间的一次性密码 TOTP

相关文章
相关标签/搜索