Internet Engineering Task Force (IETF)                        D. M'Raihi
Request for Comments: 6238                                Verisign, Inc.
Category: Informational                                       S. Machani
ISSN: 2070-1721                                         Diversinet Corp.
                                                                  M. Pei
                                                                Symantec
                                                               J. Rydell
                                                          Portwise, Inc.
                                                                May 2011
        
Internet Engineering Task Force (IETF)                        D. M'Raihi
Request for Comments: 6238                                Verisign, Inc.
Category: Informational                                       S. Machani
ISSN: 2070-1721                                         Diversinet Corp.
                                                                  M. Pei
                                                                Symantec
                                                               J. Rydell
                                                          Portwise, Inc.
                                                                May 2011
        

TOTP: Time-Based One-Time Password Algorithm

TOTP:基于时间的一次性密码算法

Abstract

摘要

This document describes an extension of the One-Time Password (OTP) algorithm, namely the HMAC-based One-Time Password (HOTP) algorithm, as defined in RFC 4226, to support the time-based moving factor. The HOTP algorithm specifies an event-based OTP algorithm, where the moving factor is an event counter. The present work bases the moving factor on a time value. A time-based variant of the OTP algorithm provides short-lived OTP values, which are desirable for enhanced security.

本文档描述了一次性密码(OTP)算法的扩展,即RFC 4226中定义的基于HMAC的一次性密码(HOTP)算法,以支持基于时间的移动因子。HOTP算法指定基于事件的OTP算法,其中移动因子是事件计数器。目前的工作基于时间值的移动因子。OTP算法的一个基于时间的变体提供了短期OTP值,这对于增强安全性是必要的。

The proposed algorithm can be used across a wide range of network applications, from remote Virtual Private Network (VPN) access and Wi-Fi network logon to transaction-oriented Web applications. The authors believe that a common and shared algorithm will facilitate adoption of two-factor authentication on the Internet by enabling interoperability across commercial and open-source implementations.

该算法可用于多种网络应用,从远程虚拟专用网(VPN)访问和Wi-Fi网络登录到面向事务的Web应用。作者认为,一个通用和共享的算法将有助于通过跨商业和开源实现的互操作性在互联网上采用双因素认证。

Status of This Memo

关于下段备忘

This document is not an Internet Standards Track specification; it is published for informational purposes.

本文件不是互联网标准跟踪规范;它是为了提供信息而发布的。

This document is a product of the Internet Engineering Task Force (IETF). It represents the consensus of the IETF community. It has received public review and has been approved for publication by the Internet Engineering Steering Group (IESG). Not all documents approved by the IESG are a candidate for any level of Internet Standard; see Section 2 of RFC 5741.

本文件是互联网工程任务组(IETF)的产品。它代表了IETF社区的共识。它已经接受了公众审查,并已被互联网工程指导小组(IESG)批准出版。并非IESG批准的所有文件都适用于任何级别的互联网标准;见RFC 5741第2节。

Information about the current status of this document, any errata, and how to provide feedback on it may be obtained at http://www.rfc-editor.org/info/rfc6238.

有关本文件当前状态、任何勘误表以及如何提供反馈的信息,请访问http://www.rfc-editor.org/info/rfc6238.

Copyright Notice

版权公告

Copyright (c) 2011 IETF Trust and the persons identified as the document authors. All rights reserved.

版权所有(c)2011 IETF信托基金和确定为文件作者的人员。版权所有。

This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Simplified BSD License.

本文件受BCP 78和IETF信托有关IETF文件的法律规定的约束(http://trustee.ietf.org/license-info)自本文件出版之日起生效。请仔细阅读这些文件,因为它们描述了您对本文件的权利和限制。从本文件中提取的代码组件必须包括信托法律条款第4.e节中所述的简化BSD许可证文本,并提供简化BSD许可证中所述的无担保。

Table of Contents

目录

   1. Introduction ....................................................2
      1.1. Scope ......................................................2
      1.2. Background .................................................3
   2. Notation and Terminology ........................................3
   3. Algorithm Requirements ..........................................3
   4. TOTP Algorithm ..................................................4
      4.1. Notations ..................................................4
      4.2. Description ................................................4
   5. Security Considerations .........................................5
      5.1. General ....................................................5
      5.2. Validation and Time-Step Size ..............................6
   6. Resynchronization ...............................................7
   7. Acknowledgements ................................................7
   8. References ......................................................8
      8.1. Normative References .......................................8
      8.2. Informative References .....................................8
   Appendix A. TOTP Algorithm: Reference Implementation ...............9
   Appendix B. Test Vectors ..........................................14
        
   1. Introduction ....................................................2
      1.1. Scope ......................................................2
      1.2. Background .................................................3
   2. Notation and Terminology ........................................3
   3. Algorithm Requirements ..........................................3
   4. TOTP Algorithm ..................................................4
      4.1. Notations ..................................................4
      4.2. Description ................................................4
   5. Security Considerations .........................................5
      5.1. General ....................................................5
      5.2. Validation and Time-Step Size ..............................6
   6. Resynchronization ...............................................7
   7. Acknowledgements ................................................7
   8. References ......................................................8
      8.1. Normative References .......................................8
      8.2. Informative References .....................................8
   Appendix A. TOTP Algorithm: Reference Implementation ...............9
   Appendix B. Test Vectors ..........................................14
        
1. Introduction
1. 介绍
1.1. Scope
1.1. 范围

This document describes an extension of the One-Time Password (OTP) algorithm, namely the HMAC-based One-Time Password (HOTP) algorithm, as defined in [RFC4226], to support the time-based moving factor.

本文件描述了一次性密码(OTP)算法的扩展,即[RFC4226]中定义的基于HMAC的一次性密码(HOTP)算法,以支持基于时间的移动因子。

1.2. Background
1.2. 出身背景

As defined in [RFC4226], the HOTP algorithm is based on the HMAC-SHA-1 algorithm (as specified in [RFC2104]) and applied to an increasing counter value representing the message in the HMAC computation.

如[RFC4226]中所定义,HOTP算法基于HMAC-SHA-1算法(如[RFC2104]中所规定),并应用于表示HMAC计算中消息的递增计数器值。

Basically, the output of the HMAC-SHA-1 calculation is truncated to obtain user-friendly values:

基本上,HMAC-SHA-1计算的输出被截断,以获得用户友好的值:

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

where Truncate represents the function that can convert an HMAC-SHA-1 value into an HOTP value. K and C represent the shared secret and counter value; see [RFC4226] for detailed definitions.

其中Truncate表示可以将HMAC-SHA-1值转换为HOTP值的函数。K和C表示共享秘密和计数器值;有关详细定义,请参见[RFC4226]。

TOTP is the time-based variant of this algorithm, where a value T, derived from a time reference and a time step, replaces the counter C in the HOTP computation.

TOTP是该算法的基于时间的变体,其中从时间参考和时间步长导出的值T替换HOTP计算中的计数器C。

TOTP implementations MAY use HMAC-SHA-256 or HMAC-SHA-512 functions, based on SHA-256 or SHA-512 [SHA2] hash functions, instead of the HMAC-SHA-1 function that has been specified for the HOTP computation in [RFC4226].

TOTP实现可以基于SHA-256或SHA-512[SHA2]哈希函数使用HMAC-SHA-256或HMAC-SHA-512函数,而不是[RFC4226]中为HOTP计算指定的HMAC-SHA-1函数。

2. Notation and Terminology
2. 符号和术语

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC2119].

本文件中的关键词“必须”、“不得”、“必需”、“应”、“不应”、“应”、“不应”、“建议”、“可”和“可选”应按照[RFC2119]中所述进行解释。

3. Algorithm Requirements
3. 算法要求

This section summarizes the requirements taken into account for designing the TOTP algorithm.

本节总结了设计TOTP算法时考虑的要求。

R1: The prover (e.g., token, soft token) and verifier (authentication or validation server) MUST know or be able to derive the current Unix time (i.e., the number of seconds elapsed since midnight UTC of January 1, 1970) for OTP generation. See [UT] for a more detailed definition of the commonly known "Unix time". The precision of the time used by the prover affects how often the clock synchronization should be done; see Section 6.

R1:验证程序(例如,令牌、软令牌)和验证程序(身份验证或验证服务器)必须知道或能够导出生成OTP的当前Unix时间(即自1970年1月1日UTC午夜以来经过的秒数)。请参阅[UT]以了解常见的“Unix时间”的更详细定义。校准仪使用的时间精度影响时钟同步的频率;见第6节。

R2: The prover and verifier MUST either share the same secret or the knowledge of a secret transformation to generate a shared secret.

R2:验证方和验证方必须共享相同的秘密或秘密转换的知识,以生成共享秘密。

R3: The algorithm MUST use HOTP [RFC4226] as a key building block.

R3:算法必须使用HOTP[RFC4226]作为关键构建块。

R4: The prover and verifier MUST use the same time-step value X.

R4:校准仪和验证器必须使用相同的时间步长值X。

R5: There MUST be a unique secret (key) for each prover.

R5:每个验证程序必须有一个唯一的秘密(密钥)。

R6: The keys SHOULD be randomly generated or derived using key derivation algorithms.

R6:应该使用密钥派生算法随机生成或派生密钥。

R7: The keys MAY be stored in a tamper-resistant device and SHOULD be protected against unauthorized access and usage.

R7:钥匙可能存储在防篡改设备中,应防止未经授权的访问和使用。

4. TOTP Algorithm
4. TOTP算法

This variant of the HOTP algorithm specifies the calculation of a one-time password value, based on a representation of the counter as a time factor.

HOTP算法的此变体指定根据计数器作为时间因子的表示来计算一次性密码值。

4.1. Notations
4.1. 符号

o X represents the time step in seconds (default value X = 30 seconds) and is a system parameter.

o X表示以秒为单位的时间步长(默认值X=30秒),是一个系统参数。

o T0 is the Unix time to start counting time steps (default value is 0, i.e., the Unix epoch) and is also a system parameter.

o T0是开始计算时间步长的Unix时间(默认值为0,即Unix历元),也是一个系统参数。

4.2. Description
4.2. 描述

Basically, we define TOTP as TOTP = HOTP(K, T), where T is an integer and represents the number of time steps between the initial counter time T0 and the current Unix time.

基本上,我们将TOTP定义为TOTP=HOTP(K,T),其中T是一个整数,表示初始计数器时间T0和当前Unix时间之间的时间步数。

   More specifically, T = (Current Unix time - T0) / X, where the
   default floor function is used in the computation.
        
   More specifically, T = (Current Unix time - T0) / X, where the
   default floor function is used in the computation.
        

For example, with T0 = 0 and Time Step X = 30, T = 1 if the current Unix time is 59 seconds, and T = 2 if the current Unix time is 60 seconds.

例如,对于T0=0和时间步长X=30,如果当前Unix时间为59秒,则T=1;如果当前Unix时间为60秒,则T=2。

The implementation of this algorithm MUST support a time value T larger than a 32-bit integer when it is beyond the year 2038. The value of the system parameters X and T0 are pre-established during the provisioning process and communicated between a prover and verifier as part of the provisioning step. The provisioning flow is out of scope of this document; refer to [RFC6030] for such provisioning container specifications.

当时间值超过2038年时,此算法的实现必须支持大于32位整数的时间值T。系统参数X和T0的值在供应过程中预先确定,并作为供应步骤的一部分在验证方和验证方之间进行通信。供应流程超出了本文件的范围;请参阅[RFC6030]了解此类供应容器规范。

5. Security Considerations
5. 安全考虑
5.1. General
5.1. 全体的

The security and strength of this algorithm depend on the properties of the underlying building block HOTP, which is a construction based on HMAC [RFC2104] using SHA-1 as the hash function.

该算法的安全性和强度取决于底层构建块HOTP的属性,HOTP是基于HMAC[RFC2104]的构造,使用SHA-1作为散列函数。

The conclusion of the security analysis detailed in [RFC4226] is that, for all practical purposes, the outputs of the dynamic truncation on distinct inputs are uniformly and independently distributed strings.

[RFC4226]中详述的安全性分析的结论是,出于所有实际目的,不同输入上的动态截断输出是均匀和独立分布的字符串。

The analysis demonstrates that the best possible attack against the HOTP function is the brute force attack.

分析表明,针对HOTP函数的最佳可能攻击是蛮力攻击。

As indicated in the algorithm requirement section, keys SHOULD be chosen at random or using a cryptographically strong pseudorandom generator properly seeded with a random value.

如“算法要求”部分所述,密钥应随机选择,或使用加密强伪随机生成器(使用随机值正确播种)。

Keys SHOULD be of the length of the HMAC output to facilitate interoperability.

密钥的长度应与HMAC输出相同,以便于互操作性。

We RECOMMEND following the recommendations in [RFC4086] for all pseudorandom and random number generations. The pseudorandom numbers used for generating the keys SHOULD successfully pass the randomness test specified in [CN], or a similar well-recognized test.

对于所有伪随机数和随机数生成,我们建议遵循[RFC4086]中的建议。用于生成密钥的伪随机数应成功通过[CN]中规定的随机性测试或类似的公认测试。

All the communications SHOULD take place over a secure channel, e.g., Secure Socket Layer/Transport Layer Security (SSL/TLS) [RFC5246] or IPsec connections [RFC4301].

所有通信应在安全通道上进行,例如,安全套接字层/传输层安全(SSL/TLS)[RFC5246]或IPsec连接[RFC4301]。

We also RECOMMEND storing the keys securely in the validation system, and, more specifically, encrypting them using tamper-resistant hardware encryption and exposing them only when required: for example, the key is decrypted when needed to verify an OTP value, and re-encrypted immediately to limit exposure in the RAM to a short period of time.

我们还建议将密钥安全地存储在验证系统中,更具体地说,使用防篡改硬件加密对密钥进行加密,并仅在需要时公开密钥:例如,在需要验证OTP值时对密钥进行解密,并立即重新加密,以将RAM中的公开时间限制在较短的时间内。

The key store MUST be in a secure area, to avoid, as much as possible, direct attack on the validation system and secrets database. Particularly, access to the key material should be limited to programs and processes required by the validation system only.

密钥存储必须位于安全区域,以尽可能避免对验证系统和机密数据库的直接攻击。特别是,对关键材料的访问应仅限于验证系统所需的程序和过程。

5.2. Validation and Time-Step Size
5.2. 验证和时间步长

An OTP generated within the same time step will be the same. When an OTP is received at a validation system, it doesn't know a client's exact timestamp when an OTP was generated. The validation system may typically use the timestamp when an OTP is received for OTP comparison. Due to network latency, the gap (as measured by T, that is, the number of time steps since T0) between the time that the OTP was generated and the time that the OTP arrives at the receiving system may be large. The receiving time at the validation system and the actual OTP generation may not fall within the same time-step window that produced the same OTP. When an OTP is generated at the end of a time-step window, the receiving time most likely falls into the next time-step window. A validation system SHOULD typically set a policy for an acceptable OTP transmission delay window for validation. The validation system should compare OTPs not only with the receiving timestamp but also the past timestamps that are within the transmission delay. A larger acceptable delay window would expose a larger window for attacks. We RECOMMEND that at most one time step is allowed as the network delay.

在同一时间步长内生成的OTP将是相同的。当验证系统收到OTP时,它不知道生成OTP时客户端的确切时间戳。验证系统通常可在接收OTP以进行OTP比较时使用时间戳。由于网络延迟,OTP生成的时间与OTP到达接收系统的时间之间的间隔(由T测量,即,自T0以来的时间步数)可能较大。验证系统的接收时间和实际OTP生成时间可能不在生成相同OTP的同一时间步长窗口内。当在时间步长窗口结束时生成OTP时,接收时间最有可能落在下一个时间步长窗口中。验证系统通常应为可接受的OTP传输延迟窗口设置策略以进行验证。验证系统不仅应将OTP与接收时间戳进行比较,还应与传输延迟内的过去时间戳进行比较。较大的可接受延迟窗口将暴露较大的攻击窗口。我们建议最多允许一个时间步长作为网络延迟。

The time-step size has an impact on both security and usability. A larger time-step size means a larger validity window for an OTP to be accepted by a validation system. There are implications for using a larger time-step size, as follows:

时间步长对安全性和可用性都有影响。较大的时间步长意味着验证系统接受OTP的有效窗口较大。使用较大的时间步长会产生以下影响:

First, a larger time-step size exposes a larger window to attack. When an OTP is generated and exposed to a third party before it is consumed, the third party can consume the OTP within the time-step window.

首先,时间步长越大,攻击窗口越大。当OTP在使用前生成并公开给第三方时,第三方可以在时间步长窗口内使用OTP。

We RECOMMEND a default time-step size of 30 seconds. This default value of 30 seconds is selected as a balance between security and usability.

我们建议默认时间步长为30秒。选择30秒的默认值作为安全性和可用性之间的平衡。

Second, the next different OTP must be generated in the next time-step window. A user must wait until the clock moves to the next time-step window from the last submission. The waiting time may not be exactly the length of the time step, depending on when the last OTP was generated. For example, if the last OTP was generated at the halfway point in a time-step window, the waiting time for the next OTP is half the length of the time step. In general, a larger time-step window means a longer waiting time for a user to get the next valid OTP after the last successful OTP validation. A too-large window (for example, 10 minutes) most probably won't be suitable for typical Internet login use cases; a user may not be able to get the next OTP within 10 minutes and therefore will have to re-login to the same site in 10 minutes.

其次,必须在下一个时间步长窗口中生成下一个不同的OTP。用户必须等待时钟从上次提交移动到下一个时间步窗口。等待时间可能不完全是时间步长的长度,这取决于最后一个OTP的生成时间。例如,如果最后一个OTP是在时间步长窗口的中点生成的,则下一个OTP的等待时间是时间步长长度的一半。一般来说,较大的时间步长窗口意味着在最后一次成功的OTP验证之后,用户获得下一个有效OTP的等待时间更长。太大的窗口(例如10分钟)很可能不适合典型的Internet登录用例;用户可能无法在10分钟内获得下一个OTP,因此必须在10分钟内重新登录到同一站点。

Note that a prover may send the same OTP inside a given time-step window multiple times to a verifier. The verifier MUST NOT accept the second attempt of the OTP after the successful validation has been issued for the first OTP, which ensures one-time only use of an OTP.

请注意,验证人可以在给定的时间步长窗口内多次向验证人发送相同的OTP。在第一个OTP成功验证后,验证者不得接受OTP的第二次尝试,这确保了一次性仅使用OTP。

6. Resynchronization
6. 再同步

Because of possible clock drifts between a client and a validation server, we RECOMMEND that the validator be set with a specific limit to the number of time steps a prover can be "out of synch" before being rejected.

由于客户端和验证服务器之间可能存在时钟漂移,我们建议在验证程序被拒绝之前,对验证程序可能“不同步”的时间步数设置特定限制。

This limit can be set both forward and backward from the calculated time step on receipt of the OTP value. If the time step is 30 seconds as recommended, and the validator is set to only accept two time steps backward, then the maximum elapsed time drift would be around 89 seconds, i.e., 29 seconds in the calculated time step and 60 seconds for two backward time steps.

该限制可从收到OTP值时计算的时间步长向前和向后设置。如果建议的时间步长为30秒,并且验证器设置为仅接受两个向后的时间步长,则最大经过的时间漂移约为89秒,即计算的时间步长为29秒,两个向后的时间步长为60秒。

This would mean the validator could perform a validation against the current time and then two further validations for each backward step (for a total of 3 validations). Upon successful validation, the validation server can record the detected clock drift for the token in terms of the number of time steps. When a new OTP is received after this step, the validator can validate the OTP with the current timestamp adjusted with the recorded number of time-step clock drifts for the token.

这意味着验证器可以对当前时间执行一次验证,然后对每个后退步骤执行两次进一步的验证(总共3次验证)。验证成功后,验证服务器可以根据时间步数记录令牌检测到的时钟漂移。当在此步骤之后接收到新的OTP时,验证器可以使用当前时间戳来验证OTP,该时间戳根据令牌的时间步长时钟漂移的记录数量进行调整。

Also, it is important to note that the longer a prover has not sent an OTP to a validation system, the longer (potentially) the accumulated clock drift between the prover and the verifier. In such cases, the automatic resynchronization described above may not work if the drift exceeds the allowed threshold. Additional authentication measures should be used to safely authenticate the prover and explicitly resynchronize the clock drift between the prover and the validator.

此外,需要注意的是,验证人未向验证系统发送OTP的时间越长,验证人和验证人之间累积的时钟漂移(可能)就越长。在这种情况下,如果漂移超过允许的阈值,则上述自动重新同步可能不起作用。应使用额外的身份验证措施来安全地验证验证程序,并明确地重新同步验证程序和验证器之间的时钟漂移。

7. Acknowledgements
7. 致谢

The authors of this document would like to thank the following people for their contributions and support to make this a better specification: Hannes Tschofenig, Jonathan Tuliani, David Dix, Siddharth Bajaj, Stu Veath, Shuh Chang, Oanh Hoang, John Huang, and Siddhartha Mohapatra.

本文件的作者要感谢以下人士的贡献和支持,使本规范更完善:Hannes Tschofenig、Jonathan Tuliani、David Dix、Siddharth Bajaj、Stu Veath、Shuh Chang、Oanh Hoang、John Huang和Siddharta Mohapatra。

8. References
8. 工具书类
8.1. Normative References
8.1. 规范性引用文件

[RFC2104] Krawczyk, H., Bellare, M., and R. Canetti, "HMAC: Keyed-Hashing for Message Authentication", RFC 2104, February 1997.

[RFC2104]Krawczyk,H.,Bellare,M.,和R.Canetti,“HMAC:用于消息认证的键控哈希”,RFC 2104,1997年2月。

[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.

[RFC2119]Bradner,S.,“RFC中用于表示需求水平的关键词”,BCP 14,RFC 2119,1997年3月。

[RFC4086] Eastlake 3rd, D., Schiller, J., and S. Crocker, "Randomness Recommendations for Security", BCP 106, RFC 4086, June 2005.

[RFC4086]Eastlake 3rd,D.,Schiller,J.,和S.Crocker,“安全性的随机性建议”,BCP 106,RFC 4086,2005年6月。

[RFC4226] M'Raihi, D., Bellare, M., Hoornaert, F., Naccache, D., and O. Ranen, "HOTP: An HMAC-Based One-Time Password Algorithm", RFC 4226, December 2005.

[RFC4226]M'Raihi,D.,Bellare,M.,Hoornaert,F.,Naccache,D.,和O.Ranen,“HOTP:基于HMAC的一次性密码算法”,RFC 42262005年12月。

[SHA2] NIST, "FIPS PUB 180-3: Secure Hash Standard (SHS)", October 2008, <http://csrc.nist.gov/publications/fips/ fips180-3/fips180-3_final.pdf>.

[SHA2]NIST,“FIPS发布180-3:安全哈希标准(SHS)”,2008年10月<http://csrc.nist.gov/publications/fips/ fips180-3/fips180-3_final.pdf>。

8.2. Informative References
8.2. 资料性引用

[CN] Coron, J. and D. Naccache, "An Accurate Evaluation of Maurer's Universal Test", LNCS 1556, February 1999, <http://www.gemplus.com/smart/rd/publications/pdf/ CN99maur.pdf>.

[CN]Coron,J.和D.Naccache,“对Maurer万能试验的准确评估”,LNCS 15561999年2月<http://www.gemplus.com/smart/rd/publications/pdf/ CN99maur.pdf>。

[RFC4301] Kent, S. and K. Seo, "Security Architecture for the Internet Protocol", RFC 4301, December 2005.

[RFC4301]Kent,S.和K.Seo,“互联网协议的安全架构”,RFC 43012005年12月。

[RFC5246] Dierks, T. and E. Rescorla, "The Transport Layer Security (TLS) Protocol Version 1.2", RFC 5246, August 2008.

[RFC5246]Dierks,T.和E.Rescorla,“传输层安全(TLS)协议版本1.2”,RFC 5246,2008年8月。

[RFC6030] Hoyer, P., Pei, M., and S. Machani, "Portable Symmetric Key Container (PSKC)", RFC 6030, October 2010.

[RFC6030]Hoyer,P.,Pei,M.和S.Machani,“便携式对称密钥容器(PSKC)”,RFC 603012010年10月。

[UT] Wikipedia, "Unix time", February 2011, <http://en.wikipedia.org/wiki/Unix_time>.

[UT]维基百科,“Unix时代”,2011年2月<http://en.wikipedia.org/wiki/Unix_time>.

Appendix A. TOTP Algorithm: Reference Implementation

附录A.TOTP算法:参考实施

<CODE BEGINS>

<代码开始>

 /**
 Copyright (c) 2011 IETF Trust and the persons identified as
 authors of the code. All rights reserved.
        
 /**
 Copyright (c) 2011 IETF Trust and the persons identified as
 authors of the code. All rights reserved.
        

Redistribution and use in source and binary forms, with or without modification, is permitted pursuant to, and subject to the license terms contained in, the Simplified BSD License set forth in Section 4.c of the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info). */

根据IETF信托有关IETF文件的法律规定第4.c节规定的简化BSD许可证中包含的许可条款,允许以源代码和二进制格式重新分发和使用,无论是否修改(http://trustee.ietf.org/license-info). */

 import java.lang.reflect.UndeclaredThrowableException;
 import java.security.GeneralSecurityException;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import javax.crypto.Mac;
 import javax.crypto.spec.SecretKeySpec;
 import java.math.BigInteger;
 import java.util.TimeZone;
        
 import java.lang.reflect.UndeclaredThrowableException;
 import java.security.GeneralSecurityException;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import javax.crypto.Mac;
 import javax.crypto.spec.SecretKeySpec;
 import java.math.BigInteger;
 import java.util.TimeZone;
        
 /**
  * This is an example implementation of the OATH
  * TOTP algorithm.
  * Visit www.openauthentication.org for more information.
  *
  * @author Johan Rydell, PortWise, Inc.
  */
        
 /**
  * This is an example implementation of the OATH
  * TOTP algorithm.
  * Visit www.openauthentication.org for more information.
  *
  * @author Johan Rydell, PortWise, Inc.
  */
        

public class TOTP {

公共类TOTP{

     private TOTP() {}
        
     private TOTP() {}
        
     /**
      * This method uses the JCE to provide the crypto algorithm.
      * HMAC computes a Hashed Message Authentication Code with the
      * crypto hash algorithm as a parameter.
      *
      * @param crypto: the crypto algorithm (HmacSHA1, HmacSHA256,
      *                             HmacSHA512)
      * @param keyBytes: the bytes to use for the HMAC key
      * @param text: the message or text to be authenticated
      */
        
     /**
      * This method uses the JCE to provide the crypto algorithm.
      * HMAC computes a Hashed Message Authentication Code with the
      * crypto hash algorithm as a parameter.
      *
      * @param crypto: the crypto algorithm (HmacSHA1, HmacSHA256,
      *                             HmacSHA512)
      * @param keyBytes: the bytes to use for the HMAC key
      * @param text: the message or text to be authenticated
      */
        
     private static byte[] hmac_sha(String crypto, byte[] keyBytes,
             byte[] text){
         try {
             Mac hmac;
             hmac = Mac.getInstance(crypto);
             SecretKeySpec macKey =
                 new SecretKeySpec(keyBytes, "RAW");
             hmac.init(macKey);
             return hmac.doFinal(text);
         } catch (GeneralSecurityException gse) {
             throw new UndeclaredThrowableException(gse);
         }
     }
        
     private static byte[] hmac_sha(String crypto, byte[] keyBytes,
             byte[] text){
         try {
             Mac hmac;
             hmac = Mac.getInstance(crypto);
             SecretKeySpec macKey =
                 new SecretKeySpec(keyBytes, "RAW");
             hmac.init(macKey);
             return hmac.doFinal(text);
         } catch (GeneralSecurityException gse) {
             throw new UndeclaredThrowableException(gse);
         }
     }
        
     /**
      * This method converts a HEX string to Byte[]
      *
      * @param hex: the HEX string
      *
      * @return: a byte array
      */
        
     /**
      * This method converts a HEX string to Byte[]
      *
      * @param hex: the HEX string
      *
      * @return: a byte array
      */
        
     private static byte[] hexStr2Bytes(String hex){
         // Adding one byte to get the right conversion
         // Values starting with "0" can be converted
         byte[] bArray = new BigInteger("10" + hex,16).toByteArray();
        
     private static byte[] hexStr2Bytes(String hex){
         // Adding one byte to get the right conversion
         // Values starting with "0" can be converted
         byte[] bArray = new BigInteger("10" + hex,16).toByteArray();
        
         // Copy all the REAL bytes, not the "first"
         byte[] ret = new byte[bArray.length - 1];
         for (int i = 0; i < ret.length; i++)
             ret[i] = bArray[i+1];
         return ret;
     }
        
         // Copy all the REAL bytes, not the "first"
         byte[] ret = new byte[bArray.length - 1];
         for (int i = 0; i < ret.length; i++)
             ret[i] = bArray[i+1];
         return ret;
     }
        
     private static final int[] DIGITS_POWER
     // 0 1  2   3    4     5      6       7        8
     = {1,10,100,1000,10000,100000,1000000,10000000,100000000 };
        
     private static final int[] DIGITS_POWER
     // 0 1  2   3    4     5      6       7        8
     = {1,10,100,1000,10000,100000,1000000,10000000,100000000 };
        
     /**
      * This method generates a TOTP value for the given
      * set of parameters.
      *
      * @param key: the shared secret, HEX encoded
      * @param time: a value that reflects a time
      * @param returnDigits: number of digits to return
      *
      * @return: a numeric String in base 10 that includes
      *              {@link truncationDigits} digits
      */
        
     /**
      * This method generates a TOTP value for the given
      * set of parameters.
      *
      * @param key: the shared secret, HEX encoded
      * @param time: a value that reflects a time
      * @param returnDigits: number of digits to return
      *
      * @return: a numeric String in base 10 that includes
      *              {@link truncationDigits} digits
      */
        
     public static String generateTOTP(String key,
             String time,
             String returnDigits){
         return generateTOTP(key, time, returnDigits, "HmacSHA1");
     }
        
     public static String generateTOTP(String key,
             String time,
             String returnDigits){
         return generateTOTP(key, time, returnDigits, "HmacSHA1");
     }
        
     /**
      * This method generates a TOTP value for the given
      * set of parameters.
      *
      * @param key: the shared secret, HEX encoded
      * @param time: a value that reflects a time
      * @param returnDigits: number of digits to return
      *
      * @return: a numeric String in base 10 that includes
      *              {@link truncationDigits} digits
      */
        
     /**
      * This method generates a TOTP value for the given
      * set of parameters.
      *
      * @param key: the shared secret, HEX encoded
      * @param time: a value that reflects a time
      * @param returnDigits: number of digits to return
      *
      * @return: a numeric String in base 10 that includes
      *              {@link truncationDigits} digits
      */
        
     public static String generateTOTP256(String key,
             String time,
             String returnDigits){
         return generateTOTP(key, time, returnDigits, "HmacSHA256");
     }
        
     public static String generateTOTP256(String key,
             String time,
             String returnDigits){
         return generateTOTP(key, time, returnDigits, "HmacSHA256");
     }
        
     /**
      * This method generates a TOTP value for the given
      * set of parameters.
      *
      * @param key: the shared secret, HEX encoded
      * @param time: a value that reflects a time
      * @param returnDigits: number of digits to return
      *
      * @return: a numeric String in base 10 that includes
      *              {@link truncationDigits} digits
      */
        
     /**
      * This method generates a TOTP value for the given
      * set of parameters.
      *
      * @param key: the shared secret, HEX encoded
      * @param time: a value that reflects a time
      * @param returnDigits: number of digits to return
      *
      * @return: a numeric String in base 10 that includes
      *              {@link truncationDigits} digits
      */
        
     public static String generateTOTP512(String key,
             String time,
             String returnDigits){
         return generateTOTP(key, time, returnDigits, "HmacSHA512");
     }
        
     public static String generateTOTP512(String key,
             String time,
             String returnDigits){
         return generateTOTP(key, time, returnDigits, "HmacSHA512");
     }
        
     /**
      * This method generates a TOTP value for the given
      * set of parameters.
      *
      * @param key: the shared secret, HEX encoded
      * @param time: a value that reflects a time
      * @param returnDigits: number of digits to return
      * @param crypto: the crypto function to use
      *
      * @return: a numeric String in base 10 that includes
      *              {@link truncationDigits} digits
      */
        
     /**
      * This method generates a TOTP value for the given
      * set of parameters.
      *
      * @param key: the shared secret, HEX encoded
      * @param time: a value that reflects a time
      * @param returnDigits: number of digits to return
      * @param crypto: the crypto function to use
      *
      * @return: a numeric String in base 10 that includes
      *              {@link truncationDigits} digits
      */
        
     public static String generateTOTP(String key,
             String time,
             String returnDigits,
             String crypto){
         int codeDigits = Integer.decode(returnDigits).intValue();
         String result = null;
        
     public static String generateTOTP(String key,
             String time,
             String returnDigits,
             String crypto){
         int codeDigits = Integer.decode(returnDigits).intValue();
         String result = null;
        
         // Using the counter
         // First 8 bytes are for the movingFactor
         // Compliant with base RFC 4226 (HOTP)
         while (time.length() < 16 )
             time = "0" + time;
        
         // Using the counter
         // First 8 bytes are for the movingFactor
         // Compliant with base RFC 4226 (HOTP)
         while (time.length() < 16 )
             time = "0" + time;
        
         // Get the HEX in a Byte[]
         byte[] msg = hexStr2Bytes(time);
         byte[] k = hexStr2Bytes(key);
        
         // Get the HEX in a Byte[]
         byte[] msg = hexStr2Bytes(time);
         byte[] k = hexStr2Bytes(key);
        
         byte[] hash = hmac_sha(crypto, k, msg);
        
         byte[] hash = hmac_sha(crypto, k, msg);
        
         // put selected bytes into result int
         int offset = hash[hash.length - 1] & 0xf;
        
         // put selected bytes into result int
         int offset = hash[hash.length - 1] & 0xf;
        
         int binary =
             ((hash[offset] & 0x7f) << 24) |
             ((hash[offset + 1] & 0xff) << 16) |
             ((hash[offset + 2] & 0xff) << 8) |
             (hash[offset + 3] & 0xff);
        
         int binary =
             ((hash[offset] & 0x7f) << 24) |
             ((hash[offset + 1] & 0xff) << 16) |
             ((hash[offset + 2] & 0xff) << 8) |
             (hash[offset + 3] & 0xff);
        

int otp = binary % DIGITS_POWER[codeDigits];

int otp=二进制%DIGITS_幂[码位];

         result = Integer.toString(otp);
         while (result.length() < codeDigits) {
             result = "0" + result;
         }
         return result;
     }
        
         result = Integer.toString(otp);
         while (result.length() < codeDigits) {
             result = "0" + result;
         }
         return result;
     }
        
     public static void main(String[] args) {
         // Seed for HMAC-SHA1 - 20 bytes
         String seed = "3132333435363738393031323334353637383930";
         // Seed for HMAC-SHA256 - 32 bytes
         String seed32 = "3132333435363738393031323334353637383930" +
         "313233343536373839303132";
         // Seed for HMAC-SHA512 - 64 bytes
         String seed64 = "3132333435363738393031323334353637383930" +
         "3132333435363738393031323334353637383930" +
         "3132333435363738393031323334353637383930" +
         "31323334";
         long T0 = 0;
         long X = 30;
         long testTime[] = {59L, 1111111109L, 1111111111L,
                 1234567890L, 2000000000L, 20000000000L};
        
     public static void main(String[] args) {
         // Seed for HMAC-SHA1 - 20 bytes
         String seed = "3132333435363738393031323334353637383930";
         // Seed for HMAC-SHA256 - 32 bytes
         String seed32 = "3132333435363738393031323334353637383930" +
         "313233343536373839303132";
         // Seed for HMAC-SHA512 - 64 bytes
         String seed64 = "3132333435363738393031323334353637383930" +
         "3132333435363738393031323334353637383930" +
         "3132333435363738393031323334353637383930" +
         "31323334";
         long T0 = 0;
         long X = 30;
         long testTime[] = {59L, 1111111109L, 1111111111L,
                 1234567890L, 2000000000L, 20000000000L};
        
         String steps = "0";
         DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
         df.setTimeZone(TimeZone.getTimeZone("UTC"));
        
         String steps = "0";
         DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
         df.setTimeZone(TimeZone.getTimeZone("UTC"));
        
         try {
             System.out.println(
                     "+---------------+-----------------------+" +
             "------------------+--------+--------+");
             System.out.println(
                     "|  Time(sec)    |   Time (UTC format)   " +
             "| Value of T(Hex)  |  TOTP  | Mode   |");
             System.out.println(
                     "+---------------+-----------------------+" +
             "------------------+--------+--------+");
        
         try {
             System.out.println(
                     "+---------------+-----------------------+" +
             "------------------+--------+--------+");
             System.out.println(
                     "|  Time(sec)    |   Time (UTC format)   " +
             "| Value of T(Hex)  |  TOTP  | Mode   |");
             System.out.println(
                     "+---------------+-----------------------+" +
             "------------------+--------+--------+");
        
             for (int i=0; i<testTime.length; i++) {
                 long T = (testTime[i] - T0)/X;
                 steps = Long.toHexString(T).toUpperCase();
                 while (steps.length() < 16) steps = "0" + steps;
                 String fmtTime = String.format("%1$-11s", testTime[i]);
                 String utcTime = df.format(new Date(testTime[i]*1000));
                 System.out.print("|  " + fmtTime + "  |  " + utcTime +
                         "  | " + steps + " |");
                 System.out.println(generateTOTP(seed, steps, "8",
                 "HmacSHA1") + "| SHA1   |");
                 System.out.print("|  " + fmtTime + "  |  " + utcTime +
                         "  | " + steps + " |");
                 System.out.println(generateTOTP(seed32, steps, "8",
                 "HmacSHA256") + "| SHA256 |");
                 System.out.print("|  " + fmtTime + "  |  " + utcTime +
                         "  | " + steps + " |");
                 System.out.println(generateTOTP(seed64, steps, "8",
                 "HmacSHA512") + "| SHA512 |");
        
             for (int i=0; i<testTime.length; i++) {
                 long T = (testTime[i] - T0)/X;
                 steps = Long.toHexString(T).toUpperCase();
                 while (steps.length() < 16) steps = "0" + steps;
                 String fmtTime = String.format("%1$-11s", testTime[i]);
                 String utcTime = df.format(new Date(testTime[i]*1000));
                 System.out.print("|  " + fmtTime + "  |  " + utcTime +
                         "  | " + steps + " |");
                 System.out.println(generateTOTP(seed, steps, "8",
                 "HmacSHA1") + "| SHA1   |");
                 System.out.print("|  " + fmtTime + "  |  " + utcTime +
                         "  | " + steps + " |");
                 System.out.println(generateTOTP(seed32, steps, "8",
                 "HmacSHA256") + "| SHA256 |");
                 System.out.print("|  " + fmtTime + "  |  " + utcTime +
                         "  | " + steps + " |");
                 System.out.println(generateTOTP(seed64, steps, "8",
                 "HmacSHA512") + "| SHA512 |");
        
                 System.out.println(
                         "+---------------+-----------------------+" +
                 "------------------+--------+--------+");
             }
         }catch (final Exception e){
             System.out.println("Error : " + e);
         }
     }
 }
        
                 System.out.println(
                         "+---------------+-----------------------+" +
                 "------------------+--------+--------+");
             }
         }catch (final Exception e){
             System.out.println("Error : " + e);
         }
     }
 }
        

<CODE ENDS>

<代码结束>

Appendix B. Test Vectors
附录B.测试向量

This section provides test values that can be used for the HOTP time-based variant algorithm interoperability test.

本节提供可用于HOTP基于时间的变量算法互操作性测试的测试值。

The test token shared secret uses the ASCII string value "12345678901234567890". With Time Step X = 30, and the Unix epoch as the initial value to count time steps, where T0 = 0, the TOTP algorithm will display the following values for specified modes and timestamps.

测试令牌共享密钥使用ASCII字符串值“123456789001234567890”。时间步长X=30,Unix历元作为计算时间步长的初始值,其中T0=0,TOTP算法将显示指定模式和时间戳的以下值。

  +-------------+--------------+------------------+----------+--------+
  |  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   |                  |          |        |
  +-------------+--------------+------------------+----------+--------+
        
  +-------------+--------------+------------------+----------+--------+
  |  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   |                  |          |        |
  +-------------+--------------+------------------+----------+--------+
        

Table 1: TOTP Table

表1:TOTP表

Authors' Addresses

作者地址

David M'Raihi Verisign, Inc. 685 E. Middlefield Road Mountain View, CA 94043 USA

David M'Raihi Verisign,Inc.美国加利福尼亚州米德尔菲尔德路山景大道东685号,邮编94043

   EMail: davidietf@gmail.com
        
   EMail: davidietf@gmail.com
        

Salah Machani Diversinet Corp. 2225 Sheppard Avenue East, Suite 1801 Toronto, Ontario M2J 5C2 Canada

Salah Machani Diversinet Corp.加拿大安大略省多伦多Sheppard大道东2225号1801室M2J 5C2

   EMail: smachani@diversinet.com
        
   EMail: smachani@diversinet.com
        

Mingliang Pei Symantec 510 E. Middlefield Road Mountain View, CA 94043 USA

贝聿铭赛门铁克510美国加利福尼亚州米德尔菲尔德路东山景城94043号

   EMail: Mingliang_Pei@symantec.com
        
   EMail: Mingliang_Pei@symantec.com
        

Johan Rydell Portwise, Inc. 275 Hawthorne Ave., Suite 119 Palo Alto, CA 94301 USA

美国加利福尼亚州帕洛阿尔托市霍桑大道275号119室约翰·赖德尔·波特威斯公司,邮编94301

   EMail: johanietf@gmail.com
        
   EMail: johanietf@gmail.com