Google Authenticator:将其与您自己的Java身份验证服务器配合使用

用于移动设备的Google Authenticator应用程序是一个非常方便的应用程序,它实现了TOTP算法(在RFC 6238中指定)。 使用Google Authenticator,您可以生成时间密码,该密码可用于在共享请求用户密钥的身份验证服务器中授权用户。

Google Authenticator主要用于通过两因素身份验证访问Google服务。 但是,您可以利用Google Authenticator生成基于时间的密码,以供您的服务器进行认证。 这样的服务器的实现在Java中非常简单,您可以从Google Authenticator PAM模块的源代码中获得启发。 在这篇博客文章中,我们将在Java类中简单介绍一下TOTP算法。

生成密钥

  • 为了生成密钥,我们将使用随机数生成器填充所需大小的字节数组。 在这种情况下,我们想要:
  • 16个字符的Base32编码密钥:由于x字节的Base32编码生成8x / 5个字符,因此我们将10个字节用作密钥。

一些临时代码(使用Google的行话)。

// 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);

现在我们要提取对应于密钥的字节,并使用Base32编码对其进行编码。 我正在使用Apache Common Codec库来获取编解码器实现:

// 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);

将密钥加载到Google Authenticator中

您可以手动将密钥加载到Google Authenticator中,或生成QR条码以使应用程序从中加载密钥。 如果要使用Google服务生成QR条码,则可以使用以下代码生成相应的URL:

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

验证码

现在,我们已经生成了密钥,并且我们的用户可以将其加载到他们的Google Authenticator应用程序中,我们需要验证生成的验证码所需的代码。 这是RFC 6238中指定的算法的Java实现:

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

结论

现在,您可以使用Google Authenticator应用程序,并使用它为您的用户生成基于时间的密码,并根据您自己的身份验证服务器进行身份验证。

如您所见,所需的代码非常简单,并且所有必需的加密功能均由运行时本身提供。 唯一的麻烦是处理Java中的签名类型。 请享用!

参考: Google身份验证器:The Gray Blog上与我们的JCG合作伙伴 Enrico Crisostomo一起在您自己的Java身份验证服务器上使用

相关文章 :


翻译自: https://www.javacodegeeks.com/2011/12/google-authenticator-using-it-with-your.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值