仿新浪微盾客户端项目简介二
这个新浪微盾客户端的核心算法,就是这个OTP算法。
这个otp算法是什么了?
1.1 HOTP(基于事件)
1.1.1 算法概述
HOTP算法是基于一个加法计数器和一个静态对称密钥的,该密钥仅有令牌和认证服务器知道,如下:
C: 一个递增的值,可以看作是一个计数器
K: 一个静态对称密钥
每次进行密码验证的时候,双方都利用下面的算法来生成一个动态的值:
HOTP(K,C) = Truncate(HMAC-SHA-1(K,C))
在这里HMAC-SHA-1指的是在RFC2104里定义的HASH算法。Truncate代表一个削减函数,以便把HMAC-SHA-1算法的结果变成一个便于用户输入的值(比如6位,8位)。
这里Truncate表示将HMAC-SHA-1值转换为HOTP值的函数,如2.1.2节所定义。
1.1.2 生成HOTP值
这里我们分三步来描述这个过程
第1步:
生成一个HMAC-SHA-1值,让 HS = HMAC-SHA-1(K,C) //HS为20位的String
第2步:
生成一个4位的String(Dynamic Truncation,动态削减)
Sbits = DT(HS) //DT运算的定义参照下面说明,返回31-bit string
第3步:
计算HOTP值
Snum = StToNum(Sbits) // 把S转化成一个0至2^{31}-1的数
Return D = Snum mod 10^Digit // D是一个位于0至10{Digit}-1的数
削减函数Truncate执行第2步和第3步处理。
DT运算的定义:
DT(String) //String = String[0]...String[19],HMAC-SHA-1运算的结果
让 OffsetBits等于String[19]的低位4字节
Offset = StToNum(OffsetBits) // 0 <= OffSet <= 15
让 P = String[OffSet]...String[OffSet+3]
返回P的最后31字节
1.1.3 计算6位HOTP的例子
下面的例子介绍怎样从HMAC-SHA-1运算结果抽取动态的二进制代码,hmac_result是存放HMAC-SHA-1结果的一个数组
//String[19]的低位4字节
int offset = hmac_result[19] & 0xf ;
//不使用最高位,利用 &0x7f
int bin_code = (hmac_result[offset] & 0x7f) << 24
| (hmac_result[offset+1] & 0xff) << 16
| (hmac_result[offset+2] & 0xff) << 8
| (hmac_result[offset+3] & 0xff) ;
HMAC-SHA-1运算的例子
SHA-1 HMAC Bytes (Example)
-------------------------------------------------------------
| Byte Number |
-------------------------------------------------------------
|00|01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|16|17|18|19|
-------------------------------------------------------------
| Byte Value |
-------------------------------------------------------------
|1f|86|98|69|0e|02|ca|16|61|85|50|ef|7f|19|da|8e|94|5b|55|5a|
-------------------------------***********----------------++|
l 最后的字节(第19字节)的十六进制值是0x5a。
l 低位四字节是0xa (offset 值)。
l offset 值为10 (0xa)。
l 从第十位开始的4位是 0x50ef7f19,这个就作为动态的二进制代码DBC1。
l 由于DBC1的最高位是 0x50,所以 DBC2 = DBC1 = 0x50ef7f19 = 135872921。
l HOTP = DBC2 除以 10^6 的余 = 872921。
这样用二进制代码 135872921 除以 1,000,000 (10^6) 的余就是一个 6 位十进制HOTP值 872921 。
1.1.4 HOTP值的验证
HOTP客户端(软件或硬件令牌)将其计数器值加1后计算出HOTP客户端的下一个HOTP值。
如果HOTP服务器收到的值和客户端计算的值一致,则该HOTP值通过认证。在这种情况下,服务器把计数器的值加1。
如果HOTP服务器收到的值和客户端计算出来的值不一致,服务器在要求用户提供下一个动态口令之前将启动同步协议。(look-ahead window,即接受一定范围内的超前的HOTP值,比如将计数器的值加1,加2,加3后的值)。
如果同步失败,服务器会要求用户提供下一个动态口令,直到达到最大认证尝试次数。
如果达到了最大认证尝试次数,服务器应当锁定该帐户并通知该用户。
1.1.5 计数器的同步
虽然在一次成功的HOTP认证后,服务器才会增加服务器计数器的值,但是令牌上的计数器的值是只要用户请求一个新的HOTP就会增加。因此,服务器上的计数器和令牌上的计数器的值就可能不同步。
为了解决这个问题,可在服务器上设置一个超前(look-ahead)变量s ,让它来定义look-ahead window的大小。简单的说,就是服务器能计算接下来的s个服务器端HOTP的值,然后用它们来检测接收到的HOTP客户端的值,也就是与收到的HOTP客户端值进行比较。
在这种情况下,计数器的同步就仅仅是让服务器计算接下来的s个HOTP值并确定是否有一个匹配的。系统可以要求用户发送连续的几个HOTP值(比如2个, 3个)以用来同步,因为猜测连续的几个HOTP值比猜测单独的一个HOTP值要困难的多。
变量s设置的上限保证服务器不会一直在检测HOTP值(避免导致拒绝服务攻击)并且限制攻击者可能的猜测范围。在确保影响可用性的同事,s应当尽可能的小。
1.1.6 共享密钥的管理
用于生成和验证OTP值的共享密钥的操作必须被安全地进行。
这里我们考虑两种不同的用于生成和存储共享密钥的方式:
l 确定性生成:在提供和认证阶段,密钥由一个主种子得出,在需要时都能即时产生
l 随机生成:在提供阶段密钥随机产生,而且要被及时存储,并在整个有效周期中保持安全
确定性生成:
------------------------
从主密钥中得出共享密钥,这个主密钥只存储在服务器中。必须使用一种防篡改的装置来存储该主密钥,并能从该主密钥和公共信息中得出共享密钥。
我们区别两种不同的情形:
l 使用一个主密钥 MK 来产生共享密钥。每一个HOTP设备都有一个不同的密钥,K_i = SHA-1 (MK,i) 这里 i 代表一个用来识别HOTP设备的公开信息,比如一个序列号,一个令牌ID等。
l 使用若干主密钥 MK_i ,每一个HOTP设备存储一个个从中得到的互不相同的密钥。 {K_i,j = SHA-1(MK_i,j)} 这里 j 代表一个用来识别HOTP设备的公开信息。这样,如果一个主密钥 MK_i 泄露了,就只需要换用另一个而不必更换所有的设备。
确定性生成的缺点就是,当主密钥泄露后,攻击者很容易在正确公开信息的基础上重建任何共享密钥。
随机生成:
-----------------
随机生成共享密钥。我们可以按照在[RFC4086]里的建议选择一个好而安全的随机信号源来产生密钥。一个随机生成器需要一个自然发生的随机数源。从实际来看,有两个可以考虑的用来生成共享密钥的办法:
l 基于硬件的生成器: 通过物理现象产生随机数。可以利用振荡器来实现并以主动攻击更难以执行的方式完成。
l 基于软件的生成器: 设计一个好的软件随机生成器不是一件容易的事。一个简单的,但有效的实现应该基于多种数据源并用像 SHA-1 这样的单方向函数。
另外可以使用更安全的方法存储密钥,例如可使用防篡改的硬件加密存储器对共享密钥加密,并且仅在需要的时候才将其取出。当需要验证一个HOTP值时,共享密钥将被解密,之后将被立即加密以减少其在 RAM 中暴露的时间。存储共享密钥的数据存储器必须处于一个安全的环境中,以尽量避免对认证系统和保密数据库的攻击。
1.1.7 演示数据
这里以 K 为 12345678901234567890 为例
下面是各个计数器的值对应的 HMAC-SHA-1(K,C) 的值
计数 十六进制 HMAC-SHA-1(K,C)
0 cc93cf18508d94934c64b65d8ba7667fb7cde4b0
1 75a48a19d4cbe100644e8ac1397eea747a2d33ab
2 0bacb7fa082fef30782211938bc1c5e70416ff44
3 66c28227d03a2d5529262ff016a1e6ef76557ece
4 a904c900a64b35909874b33e61c5938a8e15ed1c
5 a37e783d7b7233c083d4f62926c7a25f238d0316
6 bc9cd28561042c83f219324d3c607256c03272ae
7 a4fb960c0bc06e1eabb804e5b397cdc4b45596fa
8 1b3c89f65e6c9e883012052823443f048b4332db
9 1637409809a679dc698207310c8c7fc07290d9e5
下面是削减过的值(包含十六进制和十进制)和HOTP的值
Truncated
计数 十六进制 十进制 HOTP
0 4c93cf18 1284755224 755224
1 41397eea 1094287082 287082
2 82fef30 137359152 359152
3 66ef7655 1726969429 969429
4 61c5938a 1640338314 338314
5 33c083d4 868254676 254676
6 7256c032 1918287922 287922
7 4e5b397 82162583 162583
8 2823443f 673399871 399871
9 2679dc69 645520489 520489
1.2 TOTP(基于时间)
1.2.1 算法
TOTP 的算法与 HOTP 的不同在于, HOT P是基于事件的, TOTP 是基于时间的,也就是说用一个由时间和更新频率得出的 T 来代替HOTP中的计数器 C 。
如下:
X:表示更新频率,单位为秒,默认为60秒
T0:表示Unix时间,默认为0
T = (当前 Unix 时间 - T0) / X
TOTP = HOTP(K, T) = Truncate(HMAC-SHA-1(K, T))
例如:
T0 = 0
X = 60
当前 Unix 时间为119,那么 T = 1
如果当前 Unix 时间为120,那么 T = 2
其他算法可遵循HOTP的算法,具体生成 TOTP 值的方法也与之前介绍的 HOTP 相同,可进行参考。
1.2.2 演示数据
这里以 K 为 12345678901234567890 为例
更新频率 X = 30
T0 = 0
+-------------+--------------+------------------+----------+--------+
| Time (sec) | UTC Time | Value of T (hex) | TOTP | Mode |
+-------------+--------------+------------------+----------+--------+
| 59 | 1970-01-01 | 0000000000000001 | 94287082 | SHA1 |
| | 00:00:59 | | | |
| 59 | 1970-01-01 | 0000000000000001 | 46119246 | SHA256 |
| | 00:00:59 | | | |
| 59 | 1970-01-01 | 0000000000000001 | 90693936 | SHA512 |
| | 00:00:59 | | | |
| 1111111109 | 2005-03-18 | 00000000023523EC | 07081804 | SHA1 |
| | 01:58:29 | | | |
| 1111111109 | 2005-03-18 | 00000000023523EC | 68084774 | SHA256 |
| | 01:58:29 | | | |
| 1111111109 | 2005-03-18 | 00000000023523EC | 25091201 | SHA512 |
| | 01:58:29 | | | |
| 1111111111 | 2005-03-18 | 00000000023523ED | 14050471 | SHA1 |
| | 01:58:31 | | | |
| 1111111111 | 2005-03-18 | 00000000023523ED | 67062674 | SHA256 |
| | 01:58:31 | | | |
| 1111111111 | 2005-03-18 | 00000000023523ED | 99943326 | SHA512 |
| | 01:58:31 | | | |
| 1234567890 | 2009-02-13 | 000000000273EF07 | 89005924 | SHA1 |
| | 23:31:30 | | | |
| 1234567890 | 2009-02-13 | 000000000273EF07 | 91819424 | SHA256 |
| | 23:31:30 | | | |
| 1234567890 | 2009-02-13 | 000000000273EF07 | 93441116 | SHA512 |
| | 23:31:30 | | | |
| 2000000000 | 2033-05-18 | 0000000003F940AA | 69279037 | SHA1 |
| | 03:33:20 | | | |
| 2000000000 | 2033-05-18 | 0000000003F940AA | 90698825 | SHA256 |
| | 03:33:20 | | | |
| 2000000000 | 2033-05-18 | 0000000003F940AA | 38618901 | SHA512 |
| | 03:33:20 | | | |
| 20000000000 | 2603-10-11 | 0000000027BC86AA | 65353130 | SHA1 |
| | 11:33:20 | | | |
| 20000000000 | 2603-10-11 | 0000000027BC86AA | 77737706 | SHA256 |
| | 11:33:20 | | | |
| 20000000000 | 2603-10-11 | 0000000027BC86AA | 47863826 | SHA512 |
| | 11:33:20 | | | |
+-------------+--------------+------------------+----------+--------+
这种基于时间的otp算法,也是我们本次微盾所用的otp算法。
这节我们主要介绍了新浪微盾实战教程核心算法——otp算法.