Google Authenticator is mainly used to access Google services using two-factor authentication. However, you can take advantage of Google Authenticator to generate time based password to be authenticated by a server of yours. The implementation of such a server is pretty simple in Java and you can get some inspiration getting the source code of the Google Authenticator PAM module. In this blog post, we will go through a simple implementation of the TOTP algorithm in a Java class.
Generating the Secret Key.
To generate the secret key we will use a random number generator to fill up a byte array of the required size. In this case, we want:- A 16 characters Base32 encoded secret key: since Base32 encoding of x bytes generate 8x/5 characters, we will use 10 bytes for the secret key.
- Some scratch codes (using Google's jargon).
// Allocating the buffer
byte[] buffer =
new byte[secretSize + numOfScratchCodes * scratchCodeSie];
// Filling the buffer with random numbers.
// Notice: you want to reuse the same random generator
// while generating larger random number sequences.
new Random().nextBytes(buffer);
Now we want to extract the bytes corresponding to the secret key and encode it using the Base32 encoding. I'm using the Apache Common Codec library to get a codec implementation:
// Getting the key and converting it to Base32
Base32 codec = new Base32();
byte[] secretKey = Arrays.copyOf(buffer, secretSize);
byte[] bEncodedKey = codec.encode(secretKey);
String encodedKey = new String(bEncodedKey);
Loading the Key Into Google Authenticator
You can manually load the key into Google Authenticator, or generate a QR barcode to have the application loading it from it. If you want to generate a QR barcode using Google services, you can generate the corresponding URL with a code such as this:public static String getQRBarcodeURL(
String user,
String host,
String secret) {
String format = "https://www.google.com/chart?chs=200x200&chld=M%%7C0&cht=qr&chl=otpauth://totp/%s@%s%%3Fsecret%%3D%s";
return String.format(format, user, host, secret);
}
Verifying a Code
Now that we've generated the key and our users can load them into their Google Authenticator application, we need the code required to verify the generated verification codes. Here's a Java implementation of the algorithm specified in the RFC 6238:private static boolean check_code(
String secret,
long code,
long t)
throws NoSuchAlgorithmException,
InvalidKeyException {
Base32 codec = new Base32();
byte[] decodedKey = codec.decode(secret);
// Window is used to check codes generated in the near past.
// You can use this value to tune how far you're willing to go.
int window = 3;
for (int i = -window; i <= window; ++i) {
long hash = verify_code(decodedKey, t + i);
if (hash == code) {
return true;
}
}
// The validation code is invalid.
return false;
}
private static int verify_code(
byte[] key,
long t)
throws NoSuchAlgorithmException,
InvalidKeyException {
byte[] data = new byte[8];
long value = t;
for (int i = 8; i-- > 0; value >>>= 8) {
data[i] = (byte) value;
}
SecretKeySpec signKey = new SecretKeySpec(key, "HmacSHA1");
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(signKey);
byte[] hash = mac.doFinal(data);
int offset = hash[20 - 1] & 0xF;
// We're using a long because Java hasn't got unsigned int.
long truncatedHash = 0;
for (int i = 0; i < 4; ++i) {
truncatedHash <<= 8;
// We are dealing with signed bytes:
// we just keep the first byte.
truncatedHash |= (hash[offset + i] & 0xFF);
}
truncatedHash &= 0x7FFFFFFF;
truncatedHash %= 1000000;
return (int) truncatedHash;
}
The t parameter of the check_code method and verify_code methods "is an integer and represents the number of time steps between the initial counter time t0 and the current Unix time." (RFC 6238, p. 3) The default size of a time step is 30 seconds, and it's the value that Google Authenticator uses too. Therefore, t can be calculated in Java as
t = new Date().getTime() / TimeUnit.SECONDS.toMillis(30);
Download the Library
A ready to use library can be downloaded from GitHub, where Mr. Warren Strange kindly started a repository with the code from this post and packaged it in a Maven project. The library contains a complete implementation of the server-side code, better documentation and some example code in the test cases.Conclusion
You can now use the Google Authenticator applications and use it to generate time based passwords for your users, authenticated against your own authentication server.As you can see, the required code is pretty simple and all of the required cryptographic functions are provided by the runtime itself. The only nuisance is dealing with signed types in Java.
Enjoy!