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