1. wiki
动态密码,也叫一次性密码 (OTP, One-Time Password)
,本身最大优点是防止重放攻击(replay attack),常见的动态密码有 HOTP
和 TOPT
两种。
1. HOTP
HOTP(HMAC-based One-Time Password)
:表示基于基于事件计数的一次性密码生成算法,通过某一特定的事件次序及相同的种子值作为输入,通过 HASH 算法运算出一致的密码。详见 RFC 4226。
算法本身可以用两条简短的表达式描述:
HOTP(K,C) = Truncate(HMAC-SHA-1(K,C))
PWD(K,C,digit) = HOTP(K,C) mod 10^Digit
其中:
K
表示共享密钥,一般与设备绑定,使相同设备才能生成有效的HOTP
值C
表示事件计数的值,在每次验证成功后加一,因此在一次性密码被使用后C
就会变化,从而下一个HOTP
的值也会发生改变。使用 8 字节的整数,称为移动因子(moving factor)。HMAC-SHA-1
表示对共享密钥和移动因子进行 HMAC 的 SHA1 算法加密,得到 160 位长度(20字节)的加密结果Truncate
表示截断函数,取加密后串的哪些字段组成一个数字Digit
表示产生的验证码的长度,常见的是 6 位长度的动态密码
1. 知识点补充
1. MAC
MAC(Message Authentication Code)
,消息认证码,它兼容了 MD 和 SHA 的特性,并且在它们的基础上加入了密钥,因此也叫含密钥散列函数算法,即 HMAC(keyed-Hash Message Authentication Code)
,是通信实体双方使用的一种验证机制。
使用时,双方约定好散列函数并共享密钥,发送方使用该散列函数计算数据的摘要值,并用密钥加密,和数据一起发送。接收方收到报文后,会用密钥解密摘要值,同时用同一散列函数在本地计算所收到数据的摘要值,并比对两个摘要是否相同,从而确认报文是否被篡改。
2. 实战
计算步骤为:
- SHA-1 算法加密得到的 20 字节长度的 key;
- 取最后一个字节的低字节位的 4 位,作为偏移量;
- 以上述偏移量连续截取 4 个字节(32 位),最后返回 32 位中的后面 31 位;
- 根据验证码长度 digit ,并对 10digit 取模,不足的补零。
其中,利用 JDK8 自带的 MAC 算法以及事件计数,来生成新的密文:
1 | // 获取实例 |
使用 ByteBuffer
来操作字节数组:
1 | // 按照 Mac 长度(一般20字节)分配空间 |
详见 一次性密码算法
2. TOTP
TOTP(Time-based One-Time Password)
:表示基于基于时间戳的一次性密码生成算法,其也是基于 HOTP 算法实现,但将移动因子从事件计数改为时间差,基于客户端的动态口令和动态口令验证服务器的时间比对,两者的时钟一致时,计算的动态口令才能一致。详见 RFC 6238。
1. 实战
可以直接调用 HOTP 的实现,将 count 值替换成相应时间变量。