Home 应用安全 [转]HOTP:一种基于HMAC的一次性口令算法

摘要

本文描述了一种基于HMAC的一次性口令生成算法。对该算法进行了安全性分析,并讨论了该算法安全使用的重要参数。该算法已广泛应用于VPN访问,Wi-Fi登录及面向交易的Web应用等多项网络服务。

本文由OATH组织成员合作完成,详细讨论了可在技术界自由传播的算法。作者相信一种通用且共享的算法可以通过商业或开放资源工具实现共享,从而为Interne上采用的二因子认证提供了便利。

1.概述

本文首先介绍了可以生成基于HMAC的一次性口令值的算法的背景,因而这种算法也称为基于HMAC的一次性口令算法。将在第4节列出这种算法的要求,在第5节说明HOTP算法,第67节主要对这种算法进行安全性分析,第8节对其进行扩充和完善,并在第10节对本文作出结论。在附录A,有兴趣的读者会发现对算法安全性的详细、全面分析:并对该算法的理想化版本进行了评价,之后对HOTP算法的安全性进行了分析。

2.引言

今天,双因子认证仍只是在极有限的范围和规模内得到应用。尽管威胁和攻击的水平在不断提高,大多数Internet应用薄弱的认证体系来监视用户访问。硬件和软件技术供应商之间缺少可操作性成为了双因子认证应用的制约因素。特别是由于缺乏统一规范,硬件和软件组件常常通过专有技术紧密的结合,从而导致高成本解决方案,不佳的采用和有限的创新。

在过去两年中,网络威胁的迅速增长暴露了Internet上认证主要手段静态口令的不足。同时,目前的方法要求一个终端用户携带一个昂贵的,只能用来进行网络认证的功能单一的装置。这显然也不是最好的方法。对于Internet上流传的双因子认证方法则必须在能够跨广泛应用范围的灵活性更高的装置中嵌入它。

这种既可以引入基础技术同时又保证广泛互操作性的能力要求其在广大硬件和软件开发者技术界中随时可得。只有一种开放系统方法可以保证基本的原始双因子认证方法可用于下一代用户装置,如USB大量存储器、IP电话以及个人数字助理。

一次性口令当然是最简单而流行的保护网络访问权的双因子认证方法之一。例如,在大企业中,虚拟专用网络的访问通常都需要使用一次性口令来进行远程用户认证。一次性口令通常更适用于强认证方式如公钥体制(PKI)或生物统计,这是因为空气隔离装置不需要在用户机上安装客户桌面软件,因此可使他们在包括家用电脑、自动售货机、个人数字助理多台机器上漫游。

本文提出了一种简单的一次性口令算法,可以通过任何硬件制造商或软件开发者实现,从而建立了可互操作认证装置和软件代理。算法是基于事件的,因此它可用于大容量装置如Java智能卡、USB 安全装置以及GSM SIM卡。

所介绍的算法在IETF知识产权[RFC3979]规定的条件下可以在开发界自由使用。

本文的作者都是OATH组织成员。该组织成立于2004年,其目的是促进强认证技术提供者之间的合作。

3.术语

这篇文章中的关键词“必须”、“必须不”、“要求”、“即将”、“将不”、“应该”、“应该不”、“建议”、“可以”、和“可选”都如[RFC2119]中所定义。

4.算法要求

这一节说明了进行算法设计的要求。着重强调了终端用户的可用性和算法由低成本硬件实现的能力,从而使用户界面能力最小化。特别是以算法能插入高容量SIMJava卡的为前提。

要求1算法必须是基于序列号或基于计数器的。这样的目的之一是可以将HOTP算法用于大容量装置如Java智能卡,USB安全装置和GSM SIM卡。

要求2算法应该是经济可实现的,硬件上对电池、按键、计算马力、LCD显示器尺寸的需要最小化。

要求3算法必须用在不支持任何数值型输入的令牌,但也可以用于更复杂的机器如安全PIN键盘。

要求4令牌上显示的HOTP值必须易于用户阅读和输入,这要求HOTP值必须有一个合理的长度。

HOTP只必须至少为6位,同时也希望它仅由数字构成,这样用户就很容易在电话这样的有限设备上输入。

要求5必须有用户——可利用的友好装置来实现计数器重同步,7.4节和附录E.4详细说明了本文提到的重同步装置。

要求6算法必须使用强共享的密钥,共享密钥的长度必须至少为128比特。本文建议共享密钥的长度为160比特。

5.HOTP算法

在这一节,我们介绍标记并描述HOTP算法的基本模块­——计算HMAC-SHA1值的基本函数,以及抽取HOTP值的截短方法。

5.1标记和符号

一个数串通常为二进制数串,即01的序列。

如果s是一个数组,则|s|表示其长度。

如果n是一个数,则|n|表示其绝对值。

如果s是一个数组,则s[i]表示其第i比特。我们以0为开始对这些比特进行编号。因此s = s[0]s[1]…s[n-1],这里n = |s|s的长度。

StToNum表示二进制串输入转换为十进制数的函数。

下面是本文中用到的符号列表

—————————————————————

C        8-byte 计数器值,此计数器必须与HOTP生成器(客户端)HOTP认证器(服务器)保持同步。

K        客户端和服务器之间的共享密钥;每一个HOTP生成器都有互不相同且唯一的密钥K

T        阈值参数:用户尝试认证次数达到T次后,服务器将拒绝该用户接入。

S        重同步参数:服务器将通过依次的S个计数器值来验证接收到的认证码。

Digit    系统参数,HOTP值的位数。

5.2描述

HOTP算法是基于一个加法计数器和一个静态的对称密钥,该密钥仅有令牌和认证服务器知道。为得到HOTP值,我们使用HMAC-SHA-1算法,如RFC 2104 [BCK2]所定义。

由于HMAC-SHA-1计算输出为160比特,我们必须将其截短以便于用户输入。

HOTP(K,C) = Truncate(HMAC-SHA-1(K,C))

这里:

Truncate表示将HMAC-SHA-1值转换为HOTP值的函数,如5.3节所定义。

首先对密钥(K),计数器(C),和Data值执行高阶字节散列。

HOTP生成器产生的HOTP值可以作为大尾数处理。

5.3.生成HOTP

我们可以分为3个步骤来描述改过程

步骤1:生成一个HMAC-SHA-1值,令HS = HMAC-SHA-1(K,C)// HS是一个20字节的数组。

步骤2:生成一个4字节数组(动态截短)

Sbits = DT(HS)//DT稍后定义

                //返回31位的数串

步骤3:计算HOTP

Snum = StToNum(Sbits)//Sbits转换为10进制数,取值在02^{31}-1之间

返回D = Snum mod 10^Digit//D是一个十进制数,取值在010^{digit}-1之间

截短函数用于步骤2和步骤3中,即进行动态截短之后与10^{digit}进行模运算。动态截短函数的作用是从160比特(20字节)HMAC-SHA-1运算结果中抽取4字节的动态二进制码。

DT(String) // String = String[0]…String[19]

OffsetBits作为String[19]的低4

Offset = StToNum(OffsetBits) // 0 <= OffSet <= 15

P = String[OffSet]…String[OffSet+3]

返回P的后31

不取P的最高位的原因是为了防止混淆有符号与无符号的模运算。不同的处理器回进行不同的处理,不取符号位可以消除这种模糊。

Digit必须最少取6位,可能的话取78位码。根据保密需要,应该考虑使Digit = 7或更高以得到长HOTP值。

5.4 Digit =6HOTP值计算举例

下面的例子描述了抽取动态二进制码的过程,hmac_result是存放HMAC-SHA-1结果的一个字节数组

int offset   =  hmac_result[19] & 0xf ;

        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) ;

   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|

   ——————————-***********—————-++|

*最后的字节(19字节)16进制值0x5a

*4位值是0xa(offset)

*offset值是字节10(0xa)

*10字节开始4字节值为0x50ef7f19,即动态二进制码DBC1

*由于DBC1的最高字节是0x50,所以DBC2=DBC1=0x50ef7f19

*HOTP= DBC2 modulo 10^6 = 872921

我们将动态二进制码看作31比特的无符号大尾整数,最高字节通过与0x7f进行与运算而屏蔽掉最高位。

之后我们就可以将这个数与1,000,000 (10^6)模运算产生6位十进制HOTP872921

6.安全性分析

在附录中详细讨论的安全性分析的结论是:对于所有实用目的,对于不同的计数器输入,动态截短的输出是各不相同且相互独立的31比特数串。

安全性分析之后详细说明了将一个数串转换为整数最后与10^{digit}进行模运算的影响。这里DigitHOTP值的位数。

分析还证明最后的步骤引入了一个可忽略的误差,这并不影响HOTP算法的安全性,从这个意义上说,针对HOTP函数最可能的攻击就是蛮力攻击。

假设一个敌人可以观察到众多的协议交换并收集了一系列成功的认证值。则这个敌人会试图在他的观察基础上建立函数F来产生HOTP值,但他在随机猜测中并不会有明显的优势。

合乎逻辑的结论就是最好的策略仍然是蛮力攻击,用枚举发来尝试所有可能的值。

考虑到本文附录中的安全性分析具有普遍性,我们可以通过下列方程近似模拟HOTP算法的安全性。

Sec = sv/10^Digit

这里:

Sec表示敌人成功的概率

s是前顾同步窗口大小

v是认证尝试次数

DigitHOTP值的位数。

很明显,我们可以设置sT(减少攻击者尝试次数的阈值)Digit的值,直到获得一定程度的安全性,并仍保持系统的可用性。

7.安全性要求

任何一次性口令算法的安全性都是由实现它的应用软件和认证协议所确定,因此,这一节将讨论我们所选择的算法对认证协议和认证软件所提出的临界安全性要求。

这一节讨论的参数Ts对安全性有重大影响,第6节中的更多细节将在这些参数和他们对系统安全性的影响的关系间详细阐述。

同样应当注意的是HOTP算法并不能代替加密,也不能提供数据传输的保密性。应当采用其他一些装置来抵抗目的为破坏交易保密性的攻击。

7.1认证协议要求

本节我们介绍对实现HOTP在示证者和验证者之间作为认证方法的协议P的一些要求。

要求1 P必须支持双因子认证,即通信并认证你所知(如口令、通行短语和PIN等一些秘密码)和所有(令牌)。仅有用户知道秘密码,并输入一次性口令值进行认证(双因子认证)

要求2P应该不易受蛮力攻击的伤害,这意味着在认证服务器端需要一个阈值或锁定机制。

要求3P应该在一个安全通道上实现以保护用户隐私和抵抗重放攻击。

7.2HOTP值的确认

HOTP客户端(软件或硬件令牌)将其计数器值加1后计算出HOTP客户端的下一个HOTP值。如果HOTP服务器接收到的值客户端计算的值一致,则该HOTP值通过认证。在这种情况下,服务器计数器的值加1.

如果HOTP服务器接收到的值客户端计算的值不一致,服务器在要求用户提供下一个通行码之前将启动重同步协议(前顾窗口)

若重同步失败,服务器会要求协议的下一个认证通行码,直到达到最大认证尝试次数。

如果达到最大认证尝试次数,服务器应当锁定该帐户并启动一个进程来通知该用户。

7.3服务器的阈值

HMAC-SHA-1值截短成一个较短的数值会增大蛮力攻击的成功率,因此认证服务器需要检测并阻止蛮力攻击。

我们建议设置一个阈值参数T,其定义为一次性口令认证的最大尝试次数。认证服务器管理每一个HOTP装置所有的单独计数器来记录每一次失败的尝试。我们建议T值不能过大,特别是服务器上使用的重同步方法是基于窗口的,而窗口尺寸较大。T应当越低越好,同时仍能保证可用性不受很大影响。

另一种可选择的方法是执行一种延迟机制来躲避蛮力攻击。在一次尝试A失败后,认证服务器将等待T*A秒,而这个值是不断增加的。例如令T=5,则一次尝试失败后,服务器等待5秒,两次失败后等待10秒等等。

延迟或锁定机制都必须是跨登录会话的,以阻止基于多平行猜测技术的攻击。

7.4计数器的重同步

尽管服务器计数器的值仅在成功的HOTP认证后增值,令牌计数器的值每当应用户要求产生一个新HOTP值后就会增值。由于这个原因,服务器计数器和令牌计数器就有可能不同步。

我们建议在服务器上设置一个前顾参数,其定义了前顾窗口的大小。简单地说,服务器计算下面sHOTP-sever值,并与收到的HOTP客户端值比较。

在这种情况下计数器同步只需要计数器仅需要服务器计算下一个HOTP值并确定是否相配。有时系统可能要求用户发送一系列HOTP(23)来进行重同步,因为伪造一系列连续的HOTP值要比猜测一个HOTP值更困难。

参数s的上限值保证了服务器不会不停检测HOTP值,同时也限制了试图制造HOTP值的攻击者的可能解空间。s的值应当越小越好,同时保证可用性不受很大影响。

7.5共享密钥的管理

对用于产生和认证OTP值的共享密钥进行处理的运算应当安全地运行,以降低敏感信息泄露的风险。本节我们将描述不同的运算和技术方式,以展示对数据安全领域里的不同运作模式。

现在我们考虑在认证系统中两种不同的产生和存储共享密钥的途径。

确定性生成:同时在提供和认证阶段都由主种子得出密钥,在需要时都能即时产生。

随机性生成:在提供阶段密钥随机产生,而且要被及时存储,并在整个有效周期中保持安全。

确定性生成

一种可行的方法是从主密钥中得出共享密钥,该主密钥只能存储在服务器中。必须使用一种防篡改的装置来存储该主密钥,并能从该主密钥和公共信息中得出共享密钥。这样做的主要优点是可以在任何时候都不会暴露该共享密钥,避免了对存储的特殊要求,因为共享密钥在提供和认证阶段都可以根据需要随时产生。

考虑两种不同情况

使用一个主密钥MK产生共享密钥,每一个HOTP装置都有一个不同的密钥。K_i = SHA-1 (MK,i),这里i表示用以唯一标志一个HOTP装置的公共信息,可以是序列号、一个令牌标识符等等。很明显,存在着一个应用或服务的背景——不同的应用或服务应当提供不同的密钥和设置。

使用若干主密钥MK_i,每一个HOTP装置存储个从中得到的互不相同的密钥。{K_i,j = SHA-1(MK_i,j)},这里j表示标识装置的公共信息。其思想是只需在认证服务器和硬件安全模块中存储有效主密钥,采用密钥分享法例如[Shamir]将其放置在一个安全的地方。在这种情况下,如果一个主密钥MK_i被泄露,只需要换用另一个而不必替换所有的装置。

确定性方法的缺点是当主密钥被泄露后,攻击者很容易在正确公共信息的基础上重建任何共享密钥。因此必须废除所有的密钥,或在多主密钥系统中换用另一组密钥。

在另一方面,用于存储主密钥和产生共享密钥的装置必须可以防止篡改,而且,HSM不能暴露于认证系统的安全范围之外以减少泄漏的风险。

随机性生成

随机生成共享密钥。我们建议依据[RFC4086]中的规定并选择好而安全的随机信号发生器来产生密钥。一个随机信号发生器要有随机性的自然发生源。实际中,可以考虑用两种方法来产生共享密钥。

*基于硬件的发生器:通过物理现象产生随机数。可以利用振荡器来实现并

并以主动攻击更难以执行的方式构建。

*基于软件的发生器:设计一个好的软件发生器并非易事。一种简单而又有

效的方法是使用多种信号源并将单向函数例如SHA-1应用于抽样序列。

我们推荐使用已经过证明的产品,可以是硬件或软件发生器来计算共享密钥。

我们同样建议使用安全方法存储密钥。更特别地,可使用防篡改的硬件加密存储器对共享密钥加密,并且仅在需要的时候才将其取出。

例如,当需要认证一个HOTP值时,共享密钥将被解密,之后将被立即加密以减少其在RAM中暴露的时间。存储共享密钥的数据存储器必须处于一个安全的环境中,以尽量避免对认证系统和保密数据库的攻击。

特别地,对共享密钥的使用权应当限制在认证系统的程序和进程中。我们不再详细说明所用的各种安全装置。但很明显,对共享密钥的保护是最重要的事。

8.合成共享密钥

在共享密钥K中也许会需要附加一些认证因素,组成这些附加的数据可以是由令牌知道而不易被其他人获得的任何数据。这些数据可以包括:

* 用户输入令牌的PIN或口令

* 电话号码

* 任何令牌能以编程方式得到的任何唯一的识别码

在这种方案下,在提供阶段共享密钥K由一个随机种子值联合一或多个附加认证值复合而成。服务器可以根据需要产生或存储密钥——不论哪种情况都依赖于执行选择。令牌仅存储种子值。当令牌执行HOTP运算,它从种子值和其他局部导出或输入的认证因子值计算出K

使用合成共享密钥可以通过引入令牌中的附加认证因子加强基于HOTP的认证系统。

在某种程度上,令牌是一个可信的设备。而且这种方法可以避免将认证因子(如用户输入PIN)暴露给其他设备。

9.双向认证

有趣的是,HOTP服务端也可以用来认证服务器,宣称其为知道共享密钥的真实实体。

由于HOTP服务器和客户端是同步的并共享同一密钥(或用某种方法重算),可以使用一种简单的3通过协议。

终端用户输入令牌口令和第一个OTPOTP1

服务器检查OTP1,如果正确,返回OTP2

终端用户使用他的HOTP装置检查OTP2,如果正确就进入为网站。

很明显,正如前文所述,所有的OTP通信都应在安全信道上进行。例如SSL/TLS, Ipsec链路。

10.结论

本文描述了HOTP, 基于HMAC的一次性口令生成算法。同时也推荐了较好的执行工具和实现该算法的相关方法。

本文同时展示了安全因素并证明了HOTP算法是实用且合理的。最可能的攻击即蛮力攻击可以通过认证服务器中计数器的仔细运行而阻止。

最后,为了改善安全性以满足某些特定应用的需要提出了一些增强方法。

打赏
0 comment

You may also like

Leave a Comment

*

code