Skip to content

Instantly share code, notes, and snippets.

@markscottwright
Created September 23, 2021 16:27
Show Gist options
  • Save markscottwright/06957001e4e772c8db0ff21834e23d8d to your computer and use it in GitHub Desktop.
Save markscottwright/06957001e4e772c8db0ff21834e23d8d to your computer and use it in GitHub Desktop.
How to do a totp in Java
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base32;
/**
* Needs:
* <pre> {@code
* <dependency>
* <groupId>commons-codec</groupId>
* <artifactId>commons-codec</artifactId>
* <version>1.15</version>
* </dependency>
* } </pre>
*/
public class Totp {
private int timeStepSizeSeconds = 30;
private int numberOfDigits = 6;
public String totp(String code) throws NoSuchAlgorithmException, InvalidKeyException {
return hotp(code, Math.floorDiv(Instant.now().getEpochSecond(), timeStepSizeSeconds), numberOfDigits);
}
public static String hotp(String keyString, long counter, int digits) throws NoSuchAlgorithmException, InvalidKeyException {
byte[] key = new Base32().decode(keyString);
byte[] counterBytes = ByteBuffer.allocate(8).order(ByteOrder.BIG_ENDIAN).putLong(counter).array();
SecretKeySpec keySpec = new SecretKeySpec(key, "HmacSHA1");
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(keySpec);
byte[] macValue = mac.doFinal(counterBytes);
int offset = macValue[macValue.length - 1] & 0x0f;
int binary = ByteBuffer.wrap(macValue, offset, 4).order(ByteOrder.BIG_ENDIAN).getInt() & 0x7fffffff;
String otp = Integer.toString(binary);
return otp.substring(otp.length() - digits);
}
public static void main(String[] args) throws InvalidKeyException, NoSuchAlgorithmException {
String base32Secret = args[0];
System.out.println(new Totp().totp(base32Secret));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment