Home » Java » Enterprise Java » Google Authenticator: Using It With Your Own Java Authentication Server

About Enrico Crisostomo

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 :

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you our best selling eBooks for FREE!

1. JPA Mini Book

2. JVM Troubleshooting Guide

3. JUnit Tutorial for Unit Testing

4. Java Annotations Tutorial

5. Java Interview Questions

6. Spring Interview Questions

7. Android UI Design

and many more ....

5 comments

  1. 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. :
    : ok

  3. 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

  5. First, Thank you for post.

    But I find out just one problem.

    String format = “https://www.google.com/chart?chs=200×200&chld=M%%7C0&cht=qr&chl=otpauth://totp/%s@%s%%3Fsecret%%3D%s”;

    Above code isn’t correct.

    You will need to be replaced by
    String format = “http://chart.apis.google.com/chart?cht=qr&chs=300×300&chl=otpauth://totp/%s@%s%%3Fsecret%%3D%s&chld=H|0″;

    Because, your url of format can’t get QR code image by link.

Leave a Reply

Your email address will not be published. Required fields are marked *

*


− 2 = zero

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Do you want to know how to develop your skillset and become a ...

Subscribe to our newsletter to start Rocking right now!

To get you started we give you our best selling eBooks for FREE!
Get ready to Rock!
To download the books, please verify your email address by following the instructions found on the email we just sent you.

THANK YOU!

Close