How does the HOTP dynamic truncation function generalize to longer hashes? 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 &lt;= OffSet &lt;= 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?
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.