6

HOTP, the HMAC-based One-Time Password algorithm from RFC 4226, uses a "dynamic truncation" function to turn the 20 byte HMAC-SHA-1 value into a 31 bit string. The dynamic truncation (from Section 5.3) works like this (and is probably useless):

 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

TOTP (RFC 6238) allows using SHA-256 and SHA-512 as the HMAC hash in HOTP, but doesn't seem to define a new dynamic truncation function for use with them:

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

Should I use low 4 bits of String[19] as offset, low 4 bits of String[length-1], or perhaps some other number of bits or a completely different truncation algorithm?

otus
  • 32,132
  • 5
  • 70
  • 165
  • If you wanted to replicate it, use String[length-1] and do the low 4 bits of SHA-256 or low 5 bits of SHA-512... however the truncation method is probably useless with a well engineered hash function, and fixed LSB or MSB truncation is acceptable. – Richie Frame Aug 14 '15 at 09:19
  • 1
    @RichieFrame, I agree that it's useless and I could do away with it if I didn't care about compatibility. However, I would like to be able to just say "uses TOTP" rather than having to justify the change. – otus Aug 14 '15 at 10:17

1 Answers1

8

I managed to find it out by reproducing the test vectors.

TL;DR: The standard assumes that you use the low 4 bits of the last byte of the hash, regardless of its length. So replace 19 in the original DT definition with 31 for SHA-256 or 63 for SHA-512 and you are good to go.


Finding this out wasn't completely straightforward, as the standard only has a single test secret listed:

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

If fact, to reproduce the test vector values for SHA-256 and SHA-512 you have to extend that secret to 32/64 characters. I.e. use the ASCII strings "12345678901234567890123456789012" and "1234567890123456789012345678901234567890123456789012345678901234" instead.

otus
  • 32,132
  • 5
  • 70
  • 165