Skip to main content

Time-based One-Time Passwords (TOTP)

The Time-Based One-Time Password algorithm is defined in RFC 6238.

T = Floor ( (Current Unix time - T0) / X)

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

T0 = Initial counter time (default 0 seconds) X = time step in seconds (recommended default 30 seconds)

HMAC-SHA-256 and HMAC-SHA-512 are also allowed

HMAC-Based One-Time Password (HOTP)

policy for an acceptable OTP transmission delay window for validation

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

OTP is received time

multiple successive logins should use a different OTP, and therefore the time step should not be too long.

resynchronisation to allow for clock drift

client, prover / authenticatee

validation server, authenticator, validation system

[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.

HOTP says: shared secret. The length of the shared secret MUST be at least 128 bits. This document RECOMMENDs a shared secret length of 160 bits

Step 1: Generate an HMAC-SHA-1 value Let HS = HMAC-SHA-1(K,C) // HS is a 20-byte string

Step 2: Generate a 4-byte string (Dynamic Truncation) Let Sbits = DT(HS) // DT, defined below, // returns a 31-bit string

Step 3: Compute an HOTP value Let Snum = StToNum(Sbits) // Convert S to a number in 0…2^{31}-1 Return D = Snum mod 10^Digit // D is a number in the range 0…10^{Digit}-1

DT(String) // String = String[0]…String[19] Let OffsetBits be the low-order 4 bits of String[19] Offset = StToNum(OffsetBits) // 0 <= OffSet <= 15 Let P = String[OffSet]…String[OffSet+3] Return the Last 31 bits of P

 throttling
 resynchronisation parameter
 number of digits
 
 
 
    HMAC is not a hash function.  It is a message authentication code

(MAC) that uses a hash function internally. A MAC depends on a secret key, while hash functions don’t. What one needs to worry about with a MAC is forgery, not collisions. HMAC was designed so that collisions in the hash function (here SHA-1) do not yield forgeries for HMAC.

Alphanumeric (appendix E2, 32 characters

Definition of HMAC

The definition of HMAC requires a cryptographic hash function, which we denote by H, and a secret key K. We assume H to be a cryptographic hash function where data is hashed by iterating a basic compression function on blocks of data. We denote by B the byte-length of such blocks (B=64 for all the above mentioned examples of hash functions), and by L the byte-length of hash outputs (L=16 for MD5, L=20 for SHA-1). The authentication key K can be of any length up to B, the block length of the hash function. Applications that use keys longer than B bytes will first hash the key using H and then use the resultant L byte string as the actual key to HMAC. In any case the minimal recommended length for K is L bytes (as the hash output length). See section 3 for more information on keys.

We define two fixed and different strings ipad and opad as follows (the ‘i’ and ‘o’ are mnemonics for inner and outer):

               ipad = the byte 0x36 repeated B times
              opad = the byte 0x5C repeated B times.

To compute HMAC over the data `text' we perform

                H(K XOR opad, H(K XOR ipad, text))

Namely,

(1) append zeros to the end of K to create a B byte string
    (e.g., if K is of length 20 bytes and B=64, then K will be
     appended with 44 zero bytes 0x00)
(2) XOR (bitwise exclusive-OR) the B byte string computed in step
    (1) with ipad
(3) append the stream of data 'text' to the B byte string resulting
    from step (2)
(4) apply H to the stream generated in step (3)
(5) XOR (bitwise exclusive-OR) the B byte string computed in
    step (1) with opad
(6) append the H result from step (4) to the B byte string
    resulting from step (5)
(7) apply H to the stream generated in step (6) and output
    the result

The key for HMAC can be of any length (keys longer than B bytes are first hashed using H). However, less than L bytes is strongly discouraged as it would decrease the security strength of the function. Keys longer than L bytes are acceptable but the extra length would not significantly increase the function strength. (A longer key may be advisable if the randomness of the key is considered weak.)

key = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b key_len = 16 bytes data = “Hi There” data_len = 8 bytes digest = 0x9294727a3638bb1c13f48ef8158bfc9d

key = “Jefe” data = “what do ya want for nothing?” data_len = 28 bytes digest = 0x750c783e6ab0b503eaa86e310a5db738

key = 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Krawczyk, et. al. Informational [Page 9]

RFC 2104 HMAC February 1997

key_len 16 bytes data = 0xDDDDDDDDDDDDDDDDDDDD… ..DDDDDDDDDDDDDDDDDDDD… ..DDDDDDDDDDDDDDDDDDDD… ..DDDDDDDDDDDDDDDDDDDD… ..DDDDDDDDDDDDDDDDDDDD data_len = 50 bytes digest = 0x56be34521d144c88dbb8c733f0e8b3f6

Google

https://garbagecollected.org/2014/09/14/how-google-authenticator-works/

From https://security.stackexchange.com/questions/35157/how-does-google-authenticator-work

original_secret = xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx

secret = BASE32_DECODE(TO_UPPERCASE(REMOVE_SPACES(original_secret)))

input = CURRENT_UNIX_TIME() / 30 // sets a constant value for 30 seconds

hmac = SHA1(secret + SHA1(secret + input)) //apply hashing

offset = hmac[len(hmac)-1] & 0x0F //Last nibble

four_bytes = hmac[offset : offset+4] //takes a subset of 4 bytes from 20 bytes

large_integer = INT(four_bytes) //Covert four bytes to integer

small_integer = large_integer % 1,000,00 //gives 6 digit code

Google Authenticator

Secret

Secrets for the Google Authenticator are always exactly 160-bits in length.

For manually typing in the secret into the Google Authenticator app, the secret is represented using the “base32” encoding defined in RFC 4648. This is a base-32 encoding that uses the symbols [A-Z], [2-7] (the numbers 0 and 1 are not used, since they look similar to the letters O and I).

If the user chooses “Enter a setup key” on the app, they are prompted for their “account” and “key”, and given the option for it to be a “time-based” or “counter-based” one time password. The account is just a label, so the user can identify which one-time-password is for which account or service. The key

The more common method of entering the secret into the Google Authenticator app is to scan a QR-code.

The QR-code is a “URL” type QR-code, representing a URL in this form:

If exporting a secret from the Google Authenticator app, the QR code URL is:

otpauth-migration://offline?data=CiUKFABEMhTHQlS2Nc%2BEZTpW18Z1vnffEgdUZXN0aW5nIAEoATACEAEYASAA

Raw bytes in the QR code:

45 f6 f7 47 06 17 57 46   82 d6 d6 96 77 26 17 46
96 f6 e3 a2 f2 f6 f6 66   66 c6 96 e6 53 f6 46 17
46 13 d4 36 95 54 b4 64   14 24 54 d6 85 44 85 16
c5 33 24 e6 32 53 24 24   55 a5 47 05 73 13 85 a3
17 66 e6 66 64 56 76 45   55 a5 84 e3 06 15 73 56
e4 94 14 56 f4 15 44 14   34 54 14 55 94 15 34 14
10 ec 11 ec 11 ec 11 ec   11 ec 11 ec 
otpauth://{type}/{label}?secret={secret}&issuer={issuer}


otpauth://totp/Google%3ATEST2%40GMAIL.com?secret=abcdefghijklmnopqrstuvwxyz234567&issuer=Google

Where:

The part after “totp/” is the url-encoded value of “Google:username@gmail.com”, which the authenticator uses to display the label of “Issuer (username@gmail.com)”.

The entry in the Google Authenticator app has a label for the account. If the identity is the same as the issuer, the label is “issuer (identity)”. If they are different, the label is “issuer (source:identity)”.

For example,

otpauth://totp/A-Z%2C%202-7?secret=ABCdefghijklmnopqrstuvwxyz234567&issuer=Test

This will show up with the label of “Test (A-Z, 2-7)”.

Is displayed with a label that says “Test (foo:bar)”

If there is no colon in the account, “Issuer (account)”

If there is no issuer query parameter (or its value is the empty string), “Account”.

If there is no account (otpauth://totp?secret=… or otpauth://totp/?secret=…) “Issuer (Untitled)”

If there is no account and no issuer “Untitled”.

Google’s “2-step verification” can be enabled/disabled at: https://myaccount.google.com/security

When setting it up, instead of choosing to receive codes by “text message” or “phone call”, choose “Show more options” and choose “Security key”


k3aw 7xic yz2x 62z3 67kw dnfk svnw 7ijz - real one for testing

otpauth://totp/Google%3Atest.qcif%40gmail.com?secret=igrjawtyzoqhrcu763gnfiamllzw5ojl&issuer=Google

Security

The human readable representation of the secret

Base-32 encoding

The Google Authenticator uses the “base32” encoding defined by RFC 4648. This is a base-32 encoding that uses the symbols [A-Z] and [2-7]. The numbers zero and one are not used, because they look very similar to the letters O and I (which are used).

Please be aware that RFC 4648 defines another base-32 encoding, as well as other encodings using other bases. So it is not precise enough to simply refer to RFC 4648.

There are also several other base-32 encodings.

See also

https://stackoverflow.com/questions/63222629/what-is-the-difference-between-google-authenticator-totp-and-regular-totp