| < draft-mraihi-totp-timebased-07.txt | draft-mraihi-totp-timebased-08.txt > | |||
|---|---|---|---|---|
| Internet Engineering Task Force D. M'Raihi | Internet Engineering Task Force D. M'Raihi | |||
| Internet-Draft Verisign, Inc. | Internet-Draft Verisign, Inc. | |||
| Intended status: Informational S. Machani | Intended status: Informational S. Machani | |||
| Expires: July 8, 2011 Diversinet Corp. | Expires: August 28, 2011 Diversinet Corp. | |||
| M. Pei | M. Pei | |||
| Symantec | Symantec | |||
| J. Rydell | J. Rydell | |||
| Portwise, Inc. | Portwise, Inc. | |||
| January 4, 2011 | February 24, 2011 | |||
| TOTP: Time-based One-time Password Algorithm | TOTP: Time-based One-time Password Algorithm | |||
| draft-mraihi-totp-timebased-07.txt | draft-mraihi-totp-timebased-08.txt | |||
| Abstract | Abstract | |||
| This document describes an extension of one-time password (OTP) | This document describes an extension of one-time password (OTP) | |||
| algorithm, namely the HAMC-Based One-Time Password (HOTP) Algorithm | algorithm, namely the HMAC-Based One-Time Password (HOTP) Algorithm | |||
| as defined in RFC 4226, to support time-based moving factor. The | as defined in RFC 4226, to support time-based moving factor. The | |||
| HOTP algorithm specifies an event based OTP algorithm where the | HOTP algorithm specifies an event based OTP algorithm where the | |||
| moving factor is an event counter. The present work bases the moving | 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 | factor on a time value. A time-based variant of the OTP algorithm | |||
| provides short-lived OTP values, which are desirable for enhanced | provides short-lived OTP values, which are desirable for enhanced | |||
| security. | security. | |||
| The proposed algorithm can be used across a wide range of network | The proposed algorithm can be used across a wide range of network | |||
| applications ranging from remote Virtual Private Network (VPN) | applications ranging from remote Virtual Private Network (VPN) | |||
| access, Wi-Fi network logon to transaction-oriented Web applications. | access, Wi-Fi network logon to transaction-oriented Web applications. | |||
| skipping to change at page 2, line 4 ¶ | skipping to change at page 2, line 4 ¶ | |||
| Internet-Drafts are working documents of the Internet Engineering | Internet-Drafts are working documents of the Internet Engineering | |||
| Task Force (IETF). Note that other groups may also distribute | Task Force (IETF). Note that other groups may also distribute | |||
| working documents as Internet-Drafts. The list of current Internet- | working documents as Internet-Drafts. The list of current Internet- | |||
| Drafts is at http://datatracker.ietf.org/drafts/current/. | Drafts is at http://datatracker.ietf.org/drafts/current/. | |||
| Internet-Drafts are draft documents valid for a maximum of six months | Internet-Drafts are draft documents valid for a maximum of six months | |||
| and may be updated, replaced, or obsoleted by other documents at any | and may be updated, replaced, or obsoleted by other documents at any | |||
| time. It is inappropriate to use Internet-Drafts as reference | time. It is inappropriate to use Internet-Drafts as reference | |||
| material or to cite them other than as "work in progress." | material or to cite them other than as "work in progress." | |||
| This Internet-Draft will expire on July 8, 2011. | This Internet-Draft will expire on August 28, 2011. | |||
| Copyright Notice | Copyright Notice | |||
| Copyright (c) 2011 IETF Trust and the persons identified as the | Copyright (c) 2011 IETF Trust and the persons identified as the | |||
| document authors. All rights reserved. | document authors. All rights reserved. | |||
| This document is subject to BCP 78 and the IETF Trust's Legal | This document is subject to BCP 78 and the IETF Trust's Legal | |||
| Provisions Relating to IETF Documents | Provisions Relating to IETF Documents | |||
| (http://trustee.ietf.org/license-info) in effect on the date of | (http://trustee.ietf.org/license-info) in effect on the date of | |||
| publication of this document. Please review these documents | publication of this document. Please review these documents | |||
| skipping to change at page 3, line 19 ¶ | skipping to change at page 3, line 19 ¶ | |||
| 1.2. Background . . . . . . . . . . . . . . . . . . . . . . . . 4 | 1.2. Background . . . . . . . . . . . . . . . . . . . . . . . . 4 | |||
| 2. Notation and Terminology . . . . . . . . . . . . . . . . . . . 4 | 2. Notation and Terminology . . . . . . . . . . . . . . . . . . . 4 | |||
| 3. Algorithm Requirements . . . . . . . . . . . . . . . . . . . . 4 | 3. Algorithm Requirements . . . . . . . . . . . . . . . . . . . . 4 | |||
| 4. TOTP Algorithm . . . . . . . . . . . . . . . . . . . . . . . . 5 | 4. TOTP Algorithm . . . . . . . . . . . . . . . . . . . . . . . . 5 | |||
| 4.1. Notations . . . . . . . . . . . . . . . . . . . . . . . . 5 | 4.1. Notations . . . . . . . . . . . . . . . . . . . . . . . . 5 | |||
| 4.2. Description . . . . . . . . . . . . . . . . . . . . . . . 5 | 4.2. Description . . . . . . . . . . . . . . . . . . . . . . . 5 | |||
| 5. Security Considerations . . . . . . . . . . . . . . . . . . . 6 | 5. Security Considerations . . . . . . . . . . . . . . . . . . . 6 | |||
| 5.1. General . . . . . . . . . . . . . . . . . . . . . . . . . 6 | 5.1. General . . . . . . . . . . . . . . . . . . . . . . . . . 6 | |||
| 5.2. Validation and Time-step Size . . . . . . . . . . . . . . 7 | 5.2. Validation and Time-step Size . . . . . . . . . . . . . . 7 | |||
| 6. Resynchronization . . . . . . . . . . . . . . . . . . . . . . 8 | 6. Resynchronization . . . . . . . . . . . . . . . . . . . . . . 8 | |||
| 7. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 8 | 7. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 9 | |||
| 8. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 8 | 8. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 9 | |||
| 9. References . . . . . . . . . . . . . . . . . . . . . . . . . . 9 | 9. References . . . . . . . . . . . . . . . . . . . . . . . . . . 9 | |||
| 9.1. Normative references . . . . . . . . . . . . . . . . . . . 9 | 9.1. Normative references . . . . . . . . . . . . . . . . . . . 9 | |||
| 9.2. Informative References . . . . . . . . . . . . . . . . . . 9 | 9.2. Informative References . . . . . . . . . . . . . . . . . . 9 | |||
| Appendix A. TOTP Algorithm: Reference Implementation . . . . . . 9 | Appendix A. TOTP Algorithm: Reference Implementation . . . . . . 10 | |||
| Appendix B. Test Vectors . . . . . . . . . . . . . . . . . . . . 14 | Appendix B. Test Vectors . . . . . . . . . . . . . . . . . . . . 15 | |||
| Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 15 | Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 16 | |||
| 1. Introduction | 1. Introduction | |||
| 1.1. Scope | 1.1. Scope | |||
| This document describes an extension of one-time password (OTP) | This document describes an extension of one-time password (OTP) | |||
| algorithm HOTP as defined in [RFC4226] to support time based moving | algorithm HMAC-Based One-Time Password (HOTP) as defined in [RFC4226] | |||
| factor. | to support time based moving factor. | |||
| 1.2. Background | 1.2. Background | |||
| As defined in [RFC4226] the HOTP algorithm is based on the HMAC-SHA-1 | As defined in [RFC4226] the HOTP algorithm is based on the HMAC-SHA-1 | |||
| algorithm, as specified in [RFC2104] applied to an increasing counter | algorithm, as specified in [RFC2104] applied to an increasing counter | |||
| value representing the message in the HMAC computation. | value representing the message in the HMAC computation. | |||
| Basically, the output of the HMAC-SHA-1 calculation is truncated to | Basically, the output of the HMAC-SHA-1 calculation is truncated to | |||
| obtain user-friendly values: | obtain user-friendly values: | |||
| 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 | where Truncate represents the function that can convert an HMAC-SHA-1 | |||
| value into an HOTP value. | value into an HOTP value. K and C reprensent the shared secret and | |||
| counter value, see [RFC4226] for their detail definition. | ||||
| TOTP is the time-based variant of this algorithm where a value T | 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 | derived from a time reference and a time step replaces the counter C | |||
| in the HOTP computation. | in the HOTP computation. | |||
| The default HMAC-SHA-1 function could be replaced by HMAC-SHA-256 or | TOTP implementations MAY use HMAC-SHA-256 or HMAC-SHA-512 functions, | |||
| HMAC-SHA-512 to leverage HMAC implementations based on SHA-256 or | based on SHA-256 or SHA-512 [SHA2] hash functions, instead of HMAC- | |||
| SHA-512 hash functions. | SHA-1 function that has been specified for HOTP computation in | |||
| [RFC4226]. | ||||
| 2. Notation and Terminology | 2. Notation and Terminology | |||
| The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", | The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", | |||
| "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this | "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this | |||
| document are to be interpreted as described in [RFC2119] | document are to be interpreted as described in [RFC2119] | |||
| 3. Algorithm Requirements | 3. Algorithm Requirements | |||
| This section summarizes the requirements taken into account for | This section summarizes the requirements taken into account for | |||
| designing the TOTP algorithm. | designing the TOTP algorithm. | |||
| R1 - The prover (e.g. token, soft token) and verifier (authentication | R1 - The prover (e.g. token, soft token) and verifier (authentication | |||
| or validation server) MUST have access to the Unix Time | 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 more detail | ||||
| 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. | ||||
| R2 - The prover and verifier MUST either share a same secret or the | R2 - The prover and verifier MUST either share a same secret or the | |||
| knowledge of a secret transformation to generate a shared secret | knowledge of a secret transformation to generate a shared secret | |||
| R3 - The algorithm MUST use HOTP [RFC4226] as a key building block. | R3 - The algorithm MUST use HOTP [RFC4226] as a key building block. | |||
| R4 - The prover and verifier MUST use the same time step value X. | R4 - The prover and verifier MUST use the same time step value X. | |||
| R5 - There MUST be a unique secret (key) for each prover. | R5 - There MUST be a unique secret (key) for each prover. | |||
| R6 - The keys SHOULD be randomly generated or derived using a key | R6 - The keys SHOULD be randomly generated or derived using a key | |||
| derivation algorithms. | derivation algorithms. | |||
| R7 - The keys MAY be stored in a tamper-resistant device and SHOULD | R7 - The keys MAY be stored in a tamper-resistant device and SHOULD | |||
| be protected against unauthorized access and usage. | be protected against unauthorized access and usage. | |||
| R8 - The TOTP algorithm SHOULD be used for online application. | ||||
| 4. TOTP Algorithm | 4. TOTP Algorithm | |||
| This variant of the HOTP algorithm specifies the calculation of a | This variant of the HOTP algorithm specifies the calculation of a | |||
| one-time password value, based on a representation of the counter as | one-time password value, based on a representation of the counter as | |||
| a time factor. | a time factor. | |||
| 4.1. Notations | 4.1. Notations | |||
| - X represents the time step in seconds (default value X = 30 | - X represents the time step in seconds (default value X = 30 | |||
| seconds) and is a system parameter; | seconds) and is a system parameter; | |||
| - T0 is the Unix time to start counting time steps (default value is | - T0 is the Unix time to start counting time steps (default value is | |||
| 0, Unix epoch) and is also a system parameter. | 0, Unix epoch) and is also a system parameter. | |||
| 4.2. Description | 4.2. Description | |||
| Basically, we define TOTP as TOTP = HOTP(K, T) where T is an integer | 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 | and represents the number of time steps between the initial counter | |||
| time T0 and the current Unix time (i.e. the number of seconds elapsed | time T0 and the current Unix time. | |||
| since midnight UTC of January 1, 1970). | ||||
| More specifically T = (Current Unix time - T0) / X where: | More specifically T = (Current Unix time - T0) / X where: | |||
| - X represents the time step in seconds (default value X = 30 | - X represents the time step in seconds (default value X = 30 | |||
| seconds) and is a system parameter; | seconds) and is a system parameter. | |||
| - T0 is the Unix time to start counting time steps (default value is | - T0 is the Unix time to start counting time steps (default value is | |||
| 0, Unix epoch) and is also a system parameter; | 0, Unix epoch) and is also a system parameter; | |||
| - The default floor function is used in the computation. For | - 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 | 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. | time is 59 seconds and T = 2 if the current Unix time is 60 seconds. | |||
| The implementation of this algorithm MUST support the time value T | ||||
| larger than 32-bit integer when it is beyond 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 specification. | ||||
| 5. Security Considerations | 5. Security Considerations | |||
| 5.1. General | 5.1. General | |||
| The security and strength of this algorithm depends on the properties | The security and strength of this algorithm depends on the properties | |||
| of the underlying building block HOTP, which is a construction based | of the underlying building block HOTP, which is a construction based | |||
| on HMAC [RFC2104] using SHA-1 as the hash function. | on HMAC [RFC2104] using SHA-1 as the hash function. | |||
| The conclusion of the security analysis detailed in [RFC4226] is | The conclusion of the security analysis detailed in [RFC4226] is | |||
| that, for all practical purposes, the outputs of the dynamic | that, for all practical purposes, the outputs of the dynamic | |||
| skipping to change at page 6, line 35 ¶ | skipping to change at page 6, line 47 ¶ | |||
| Keys SHOULD be of the length of the HMAC output to facilitate | Keys SHOULD be of the length of the HMAC output to facilitate | |||
| interoperability. | interoperability. | |||
| We RECOMMEND following the recommendations in [RFC4086] for all | We RECOMMEND following the recommendations in [RFC4086] for all | |||
| pseudo-random and random generations. The pseudo-random numbers used | pseudo-random and random generations. The pseudo-random numbers used | |||
| for generating the keys SHOULD successfully pass the randomness test | for generating the keys SHOULD successfully pass the randomness test | |||
| specified in [CN] or a similar well-recognized test. | specified in [CN] or a similar well-recognized test. | |||
| All the communications SHOULD take place over a secure channel e.g. | All the communications SHOULD take place over a secure channel e.g. | |||
| SSL/TLS, IPsec connections. | SSL/TLS [RFC5246], IPsec connections [RFC4301]. | |||
| We also RECOMMEND storing the keys securely in the validation system, | We also RECOMMEND storing the keys securely in the validation system, | |||
| and more specifically encrypting them using tamper-resistant hardware | and more specifically encrypting them using tamper-resistant hardware | |||
| encryption and exposing them only when required: for example, the key | encryption and exposing them only when required: for example, the key | |||
| is decrypted when needed to verify an OTP value, and re-encrypted | is decrypted when needed to verify an OTP value, and re-encrypted | |||
| immediately to limit exposure in the RAM for a short period of time. | immediately to limit exposure in the RAM for a short period of time. | |||
| The key store MUST be in a secure area, to avoid as much as possible | The key store MUST be in a secure area, to avoid as much as possible | |||
| direct attack on the validation system and secrets database. | direct attack on the validation system and secrets database. | |||
| Particularly, access to the key material should be limited to | Particularly, access to the key material should be limited to | |||
| skipping to change at page 7, line 37 ¶ | skipping to change at page 7, line 45 ¶ | |||
| The Time-step size has impact on both security and usability. A | The Time-step size has impact on both security and usability. A | |||
| larger Time-step size means larger validity window for an OTP to be | larger Time-step size means larger validity window for an OTP to be | |||
| accepted by a validation system. There are the following | accepted by a validation system. There are the following | |||
| implications with a larger Time-step size. | implications with a larger Time-step size. | |||
| At first, a larger Time-step size exposes larger window for attack. | At first, a larger Time-step size exposes larger window for attack. | |||
| When an OTP is generated and exposed to a third party before it is | 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 | consumed, the third party can consume the OTP within the Time-step | |||
| window. | window. | |||
| We RECOMMEND default Time-step size for 30 seconds. | We RECOMMEND default Time-step size for 30 seconds. This default | |||
| value of 30 seconds is selected to balance between security and | ||||
| usability. | ||||
| Secondly, the next different OTP must be generated in the next Time- | Secondly, the next different OTP must be generated in the next Time- | |||
| step window. A user must wait till the clock moves to the next Time- | step window. A user must wait till the clock moves to the next Time- | |||
| step window from the last submission. The waiting time may not be | step window from the last submission. The waiting time may not be | |||
| exactly the length of Time-step depending on when the last OTP was | exactly the length of Time-step depending on when the last OTP was | |||
| generated. For example, if the last OTP was generated at the half | generated. For example, if the last OTP was generated at the half | |||
| way in a Time-step window, the waiting time for the next OTP is half | way in a Time-step window, the waiting time for the next OTP is half | |||
| of length of Time-step. In general, a larger Time-step window means | of length of Time-step. In general, a larger Time-step window means | |||
| larger waiting time for a user to get the next valid OTP after the | larger waiting time for a user to get the next valid OTP after the | |||
| last successfully OTP validation. A too large window, for example 10 | last successfully OTP validation. A too large window, for example 10 | |||
| minutes, most probably won't be suitable for typical internet login | 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 | use cases; a user may not be able to get the next OTP within 10 | |||
| minutes and therefore re-login back to the same site in 10 minutes. | minutes and therefore re-login back to the same site in 10 minutes. | |||
| The default Time-step size 30 seconds is recommended. | ||||
| Note that a prover may send the same OTP inside a given time 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. | ||||
| 6. Resynchronization | 6. Resynchronization | |||
| Because of possible clock drifts between a client and a validation | Because of possible clock drifts between a client and a validation | |||
| server, we RECOMMEND that the validator be set with a specific limit | 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 | to the number of time steps a prover can be 'out of synch' before | |||
| being not validated/rejected. | being rejected. | |||
| This limit can be set both forward and backwards from the calculated | This limit can be set both forward and backwards from the calculated | |||
| time step on receipt of the OTP value. If the time step is 30 | 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 2 | seconds as recommended, and the validator is set to only accept 2 | |||
| time step backwards then the maximum elapsed time drift would be | time step backwards then the maximum elapsed time drift would be | |||
| around 89 seconds, i.e. 29 seconds in the calculated time step and 60 | around 89 seconds, i.e. 29 seconds in the calculated time step and 60 | |||
| for two backward time steps. | for two backward time steps. | |||
| This would mean the validator could perform a validation against the | This would mean the validator could perform a validation against the | |||
| current time and then further two validations for each backward step | current time and then further two validations for each backward step | |||
| (for a total of 3 validations). Upon successful validation, the | (for a total of 3 validations). Upon successful validation, the | |||
| validation server can record the detected clock drift for the token | validation server can record the detected clock drift for the token | |||
| in terms of number of Time-step. When a new OTP is received after | in terms of number of Time-step. When a new OTP is received after | |||
| this step, the validator can validate the OTP with current timestamp | this step, the validator can validate the OTP with current timestamp | |||
| adjusted with recorded number of Time-step clock drifts for the | adjusted with recorded number of Time-step clock drifts for the | |||
| token. | token. | |||
| Also, it is important to note that the longer a prover has not sent | Also, it is important to note that the longer a prover has not sent | |||
| an OTP to a validation system, the longer (potentially) the | an OTP to a validation system, the longer (potentially) the | |||
| accumulated clock drift between the prover and the verifier. In such | accumulated clock drift between the prover and the verifier. In such | |||
| cases, the default synchronization may not be proper when the drift | cases, the automatic resynchronization described above may not work | |||
| exceeds beyond allowed threshold. Additional authentication measures | if the drift exceeds the allowed threshold. Additional | |||
| SHOULD be used for the validation system to safely authenticate the | authentication measures should be used to safely authenticate the | |||
| prover. | prover and explicitly resynchronize the clock drift between the | |||
| prover and the validator. | ||||
| 7. IANA Considerations | 7. IANA Considerations | |||
| The OTP algorithm defined in this document can be referred by a URI | This document has no actions for IANA. | |||
| defined in a separate document. [ALGP] is such an attempt that | ||||
| defines various OTP related algorithm URIs. There is no registration | ||||
| needed in this document. | ||||
| 8. Acknowledgements | 8. Acknowledgements | |||
| The authors of this draft would like to thank the following people | The authors of this draft would like to thank the following people | |||
| for their contributions and support to make this a better | for their contributions and support to make this a better | |||
| specification: Hannes Tschofenig, Jonathan Tuliani, David Dix, | specification: Hannes Tschofenig, Jonathan Tuliani, David Dix, | |||
| Siddharth Bajaj, Stu Veath, Shuh Chang, Oanh Hoang, John Huang, and | Siddharth Bajaj, Stu Veath, Shuh Chang, Oanh Hoang, John Huang, and | |||
| Siddhartha Mohapatra. | Siddhartha Mohapatra. | |||
| 9. References | 9. References | |||
| skipping to change at page 9, line 26 ¶ | skipping to change at page 9, line 38 ¶ | |||
| [RFC4086] Eastlake, D., Schiller, J., and S. Crocker, "Randomness | [RFC4086] Eastlake, D., Schiller, J., and S. Crocker, "Randomness | |||
| Recommendations for Security", RFC 4086, June 2005, | Recommendations for Security", RFC 4086, June 2005, | |||
| <http://www.ietf.org/rfc/rfc4086.txt>. | <http://www.ietf.org/rfc/rfc4086.txt>. | |||
| [RFC4226] M'Raihi, D., Bellare, M., Hoornaert, F., Naccache, D., and | [RFC4226] M'Raihi, D., Bellare, M., Hoornaert, F., Naccache, D., and | |||
| O. Ranen, "HOTP: An HMAC-Based One-Time Password | O. Ranen, "HOTP: An HMAC-Based One-Time Password | |||
| Algorithm", RFC 4226, December 2005, | Algorithm", RFC 4226, December 2005, | |||
| <http://www.ietf.org/rfc/rfc4226.txt>. | <http://www.ietf.org/rfc/rfc4226.txt>. | |||
| 9.2. Informative References | [SHA2] NIST, "FIPS PUB 180-3: Secure Hash Standard (SHS)", | |||
| October 2008, <http://csrc.nist.gov/publications/fips/ | ||||
| fips180-3/fips180-3_final.pdf>. | ||||
| [ALGP] Hoyer, P., Pei, M., Machani, S., and A. Doherty, | 9.2. Informative References | |||
| "Additional Portable Symmetric Key Container (PSKC) | ||||
| Algorithm Profiles", December 2008, <http:// | ||||
| tools.ietf.org/id/ | ||||
| draft-hoyer-keyprov-pskc-algorithm-profiles-01.txt>. | ||||
| [CN] Coron, J. and D. Naccache, "An accurate evaluation of | [CN] Coron, J. and D. Naccache, "An accurate evaluation of | |||
| Maurer's universal test", LNCS 1556, February 1999, <http: | Maurer's universal test", LNCS 1556, February 1999, <http: | |||
| //www.gemplus.com/smart/rd/publications/pdf/CN99maur.pdf>. | //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, | ||||
| <http://www.ietf.org/rfc/rfc4301.txt>. | ||||
| [RFC5246] Dierks, T. and E. Rescorla, "The Transport Layer Security | ||||
| (TLS) Protocol Version 1.2", RFC 5246, August 2008, | ||||
| <http://www.ietf.org/rfc/rfc5246.txt>. | ||||
| [RFC6030] Hoyer, P., Pei, M., and S. Machani, "Portable Symmetric | ||||
| Key Container (PSKC)", RFC 6030, October 2010, | ||||
| <http://www.ietf.org/rfc/rfc6030.txt>. | ||||
| [UT] Wikipedia, "Unix time", February 2011, | ||||
| <http://en.wikipedia.org/wiki/Unix_time>. | ||||
| Appendix A. TOTP Algorithm: Reference Implementation | Appendix A. TOTP Algorithm: Reference Implementation | |||
| import java.lang.reflect.UndeclaredThrowableException; | <CODE BEGINS> | |||
| 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 an example implementation of the OATH TOTP algorithm. | Copyright (c) 2011 IETF Trust and the persons identified as authors of | |||
| * Visit www.openauthentication.org for more information. | the code. All rights reserved. | |||
| * | ||||
| * @author Johan Rydell, PortWise, Inc. | ||||
| */ | ||||
| public class TOTP { | ||||
| private TOTP() {} | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||||
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||||
| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
| */ | ||||
| /** | import java.lang.reflect.UndeclaredThrowableException; | |||
| * This method uses the JCE to provide the crypto | import java.security.GeneralSecurityException; | |||
| * algorithm. | import java.text.DateFormat; | |||
| * HMAC computes a Hashed Message Authentication Code with the | import java.text.SimpleDateFormat; | |||
| * crypto hash algorithm as a parameter. | import java.util.Date; | |||
| * | import javax.crypto.Mac; | |||
| * @param crypto the crypto algorithm (HmacSHA1, HmacSHA256, | import javax.crypto.spec.SecretKeySpec; | |||
| * HmacSHA512) | import java.math.BigInteger; | |||
| * @param keyBytes the bytes to use for the HMAC key | import java.util.TimeZone; | |||
| * @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); | ||||
| } | ||||
| } | ||||
| /** | /** | |||
| * This method converts HEX string to Byte[] | * This an example implementation of the OATH TOTP algorithm. | |||
| * | * Visit www.openauthentication.org for more information. | |||
| * @param hex the HEX string | * | |||
| * | * @author Johan Rydell, PortWise, Inc. | |||
| * @return A byte array | */ | |||
| */ | public class TOTP { | |||
| 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; | ||||
| } | ||||
| private static final int[] DIGITS_POWER | private TOTP() {} | |||
| // 0 1 2 3 4 5 6 7 8 | ||||
| = {1,10,100,1000,10000,100000,1000000,10000000,100000000 }; | ||||
| /** | /** | |||
| * This method generates an TOTP value for the given | * This method uses the JCE to provide the crypto | |||
| * set of parameters. | * algorithm. | |||
| * | * HMAC computes a Hashed Message Authentication Code with the | |||
| * @param key the shared secret, HEX encoded | * crypto hash algorithm as a parameter. | |||
| * @param time a value that reflects a time | * | |||
| * @param returnDigits number of digits to return | * @param crypto the crypto algorithm (HmacSHA1, HmacSHA256, | |||
| * | * HmacSHA512) | |||
| * @return A numeric String in base 10 that includes | * @param keyBytes the bytes to use for the HMAC key | |||
| * {@link truncationDigits} digits | * @param text the message or text to be authenticated. | |||
| */ | */ | |||
| public static String generateTOTP(String key, | private static byte[] hmac_sha(String crypto, byte[] keyBytes, | |||
| String time, | byte[] text){ | |||
| String returnDigits){ | try { | |||
| return generateTOTP(key, time, returnDigits, "HmacSHA1"); | 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 generates an TOTP value for the given | * This method converts HEX string to Byte[] | |||
| * set of parameters. | * | |||
| * | * @param hex the HEX string | |||
| * @param key the shared secret, HEX encoded | * | |||
| * @param time a value that reflects a time | * @return A byte array | |||
| * @param returnDigits number of digits to return | */ | |||
| * | private static byte[] hexStr2Bytes(String hex){ | |||
| * @return A numeric String in base 10 that includes | // Adding one byte to get the right conversion | |||
| * {@link truncationDigits} digits | // values starting with "0" can be converted | |||
| */ | byte[] bArray = new BigInteger("10" + hex,16).toByteArray(); | |||
| public static String generateTOTP256(String key, | ||||
| String time, | ||||
| String returnDigits){ | ||||
| return generateTOTP(key, time, returnDigits, "HmacSHA256"); | ||||
| } | ||||
| /** | ||||
| * This method generates an 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"); | ||||
| } | ||||
| /** | // Copy all the REAL bytes, not the "first" | |||
| * This method generates an TOTP value for the given | byte[] ret = new byte[bArray.length - 1]; | |||
| * set of parameters. | for (int i = 0; i < ret.length ; i++) | |||
| * | ret[i] = bArray[i+1]; | |||
| * @param key the shared secret, HEX encoded | return ret; | |||
| * @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; | ||||
| // Using the counter | } | |||
| // First 8 bytes are for the movingFactor | ||||
| // Complaint with base RFC 4226 (HOTP) | ||||
| while(time.length() < 16 ) | ||||
| time = "0" + time; | ||||
| // Get the HEX in a Byte[] | private static final int[] DIGITS_POWER | |||
| byte[] msg = hexStr2Bytes(time); | // 0 1 2 3 4 5 6 7 8 | |||
| byte[] k = hexStr2Bytes(key); | = {1,10,100,1000,10000,100000,1000000,10000000,100000000 }; | |||
| byte[] hash = hmac_sha(crypto, k, msg); | /** | |||
| // put selected bytes into result int | * This method generates an TOTP value for the given | |||
| int offset = hash[hash.length - 1] & 0xf; | * 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"); | ||||
| } | ||||
| int binary = | /** | |||
| ((hash[offset] & 0x7f) << 24) | | * This method generates an TOTP value for the given | |||
| ((hash[offset + 1] & 0xff) << 16) | | * set of parameters. | |||
| ((hash[offset + 2] & 0xff) << 8) | | * | |||
| (hash[offset + 3] & 0xff); | * @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"); | ||||
| } | ||||
| int otp = binary % DIGITS_POWER[codeDigits]; | /** | |||
| * This method generates an 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"); | ||||
| } | ||||
| result = Integer.toString(otp); | /** | |||
| while (result.length() < codeDigits) { | * This method generates an TOTP value for the given | |||
| result = "0" + result; | * set of parameters. | |||
| } | * | |||
| return result; | * @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 void main(String[] args) { | // Using the counter | |||
| // Seed for HMAC-SHA1 - 20 bytes | // First 8 bytes are for the movingFactor | |||
| String seed = "3132333435363738393031323334353637383930"; | // Complaint with base RFC 4226 (HOTP) | |||
| // Seed for HMAC-SHA256 - 32 bytes | while(time.length() < 16 ) | |||
| String seed32 = "3132333435363738393031323334353637383930" + | time = "0" + time; | |||
| "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"; | // Get the HEX in a Byte[] | |||
| DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); | byte[] msg = hexStr2Bytes(time); | |||
| df.setTimeZone(TimeZone.getTimeZone("UTC")); | byte[] k = hexStr2Bytes(key); | |||
| try{ | byte[] hash = hmac_sha(crypto, k, msg); | |||
| System.out.println( | ||||
| "+---------------+-----------------------+" + | ||||
| "------------------+--------+--------+"); | ||||
| System.out.println( | ||||
| "| Time(sec) | Time (UTC format) " + | ||||
| "| Value of T(Hex) | TOTP | Mode |"); | ||||
| System.out.println( | ||||
| "+---------------+-----------------------+" + | ||||
| "------------------+--------+--------+"); | // 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); | ||||
| for(int i=0; i<testTime.length; i++) { | int otp = binary % DIGITS_POWER[codeDigits]; | |||
| 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( | result = Integer.toString(otp); | |||
| "+---------------+-----------------------+" + | while (result.length() < codeDigits) { | |||
| "------------------+--------+--------+"); | result = "0" + result; | |||
| } | } | |||
| }catch (final Exception e){ | return result; | |||
| System.out.println("Error : " + e); | } | |||
| } | ||||
| } | 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")); | ||||
| 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 |"); | ||||
| System.out.println( | ||||
| "+---------------+-----------------------+" + | ||||
| "------------------+--------+--------+"); | ||||
| } | ||||
| }catch (final Exception e){ | ||||
| System.out.println("Error : " + e); | ||||
| } | ||||
| } | ||||
| } | ||||
| <CODE ENDS> | ||||
| Appendix B. Test Vectors | Appendix B. Test Vectors | |||
| This section provides test values that can be used for HOTP time- | This section provides test values that can be used for HOTP time- | |||
| based variant algorithm interoperability test. | based variant algorithm interoperability test. | |||
| The test token shared secret uses the ASCII string value | The test token shared secret uses the ASCII string value | |||
| "12345678901234567890". With Time Step X = 30, and Unix epoch as | "12345678901234567890". With Time Step X = 30, and Unix epoch as | |||
| initial value to count time steps where T0 = 0, the TOTP algorithm | initial value to count time steps where T0 = 0, the TOTP algorithm | |||
| will display the following values for specified modes and timestamps. | will display the following values for specified modes and timestamps. | |||
| End of changes. 45 change blocks. | ||||
| 245 lines changed or deleted | 297 lines changed or added | |||
This html diff was produced by rfcdiff 1.48. The latest version is available from http://tools.ietf.org/tools/rfcdiff/ | ||||