Google Authenticator: Using It With Your Own Java Authentication Server

The Google Authenticator application for mobile devices is a very handy application that implements the TOTP algorithm (specified in RFC 6238). Using Google Authenticator you can generate time passwords that can be used to authorize users in an authentication server that shares the secret key of the requesting users.

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;
}

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!

Reference: Google Authenticator: Using It With Your Own Java Authentication Server from our JCG partner Enrico Crisostomo at the The Grey Blog.

 Related Articles :

Related Whitepaper:

Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions

Get ready to program in a whole new way!

Functional Programming in Java will help you quickly get on top of the new, essential Java 8 language features and the functional style that will change and improve your code. This short, targeted book will help you make the paradigm shift from the old imperative way to a less error-prone, more elegant, and concise coding style that’s also a breeze to parallelize. You’ll explore the syntax and semantics of lambda expressions, method and constructor references, and functional interfaces. You’ll design and write applications better using the new standards in Java 8 and the JDK.

Get it Now!  

4 Responses to "Google Authenticator: Using It With Your Own Java Authentication Server"

  1. Ben Reeves says:

    Thank you for posting this. Just a quick note to any developers that might be confused by this. You have to divide the current time in milliseconds by 30000 before calling check_code e.g.

    if (check_code(shared_secret, user_code, new Date().getTime()  / 30000)) { //OK!}https://blockchain.info/wallet/google-authenticator

  2. mohammed idrissi says:

    :
    : ok

  3. manish says:

    hI
    Thanks for the valuable code .
    But when i used these code . validity always showing false .
    Please help me in checking validity ..
    Thanks…

  4. hey!

    The example was good. But how does it verify a user ? Anyone with the app installed, can generate the passwd ? How does it relate to a particular user ?

    To be very specific here I’ve explained in detail :

    http://stackoverflow.com/questions/22699329/how-to-use-googleauthenticator-for-tfa-two-factor-authentication-in-a-custom-n

    Regards
    Nitin

Leave a Reply


eight − 5 =



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.

Sign up for our Newsletter

15,153 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books
Get tutored by the Geeks! JCG Academy is a fact... Join Now
Hello. Add your message here.