javaalgorithmhmachmacsha1

Java - TOTP algorithm, from HMAC SHA1 to HMAC SHA256


Small question regarding a TOTP generation algorithm please.

I am building a TOTP generation algorithm. In order to do so, I am using HMAC SHA1. The result is correct, I used many time this HMAC SHA1 generated TOTP to authenticate myself to servers, I had confirmation the TOTP is correct, very happy.

Now, knowing HMAC SHA1 is a bit less secure, I would like to migrate from HMAC SHA1 to HMAC SHA256.

I thought I was as simple as changing the HMAC algorithm. Unfortunately, all TOTP generated with HMAC SHA256 were not accepted by the server.

Just to emphasize, this question is about how to make it work with HMAC SHA256.

This question is not about:

This technical question is really about a technical algorithm of TOTP generation with HAMC SHA256.

The code I use to generate HMAC SHA1 TOTP is:

String getTOTP() {
        try {
            long value = LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() / TimeUnit.SECONDS.toMillis(30);
            final byte[] key = new Base32().decode("the_password".toUpperCase(Locale.US));
            final var data = new byte[8];
            for (int i = 8; i-- > 0; value >>>= 8) {
                data[i] = (byte) value;
            }
            final var signKey = new SecretKeySpec(key, "HmacSHA1"); // would like to change here to "HmacSHA256"
            final var mac = Mac.getInstance("HmacSHA1"); // would like to change here to "HmacSHA256"
            mac.init(signKey);
            final String hashString = new String(new Hex().encode(mac.doFinal(data)));
            final var offset = Integer.parseInt(hashString.substring(hashString.length() - 1), 16);
            final var truncatedHash = hashString.substring(offset * 2, offset * 2 + 8);
            final var finalHash = String.valueOf(Integer.parseUnsignedInt(truncatedHash, 16) & 0x7FFFFFFF);
            final var finalHashCut = finalHash.substring(finalHash.length() - 6);
            System.out.println("THE TOTP generated with HmacSHA1 is  " + finalHashCut);
            System.out.println("THE TOTP generated with HmacSHA256 will not work though :'( ");
            return finalHashCut;
        } catch (NoSuchAlgorithmException | InvalidKeyException e) {
            LOGGER.warn("", e);
            return "";
        }
    }

Question: What element of the algorithm should I adjust in order to have the TOTP using HMAC SHA256, and still work please?

Thank you.


Solution

  • Thanks to Robert's comment, changing the hash will change the output.

    Unless the destination server accepts the other hash algorithm, changing hash on the client will yield a different TOTP, and will not be accepted by the server.