<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.4.1</version>
</dependency>
/**
* Project Name:google-auth
* File Name:GoogleAuth.java
* Package Name:cn.easysw.google
* Date:2017年2月28日上午10:27:44
* Copyright (c) 2017, www.windo-soft.com All Rights Reserved.
*
*/
package cn.easysw.google;
import java.net.URLEncoder;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base32;
import org.apache.http.client.utils.URIBuilder;
/**
* ClassName:GoogleAuth <br/>
* Function: TODO ADD FUNCTION. <br/>
* Reason: TODO ADD REASON. <br/>
* Date: 2017年2月28日 上午10:27:44 <br/>
*
* @author xiaospace
* @version
* @since JDK 1.7
* @see
*/
public class GoogleAuth {
private static final String TOTP_URI_FORMAT = "https://chart.googleapis.com/chart?chs=200x200&chld=M%%7C0&cht=qr&chl=%s";
private static final String HMAC_HASH_FUNCTION = "HmacSHA1";
/**
* getPassword:验证二维码. <br/>
*
* @author xiaospace
* @param secret 密钥
* @param nowDate 时间
* @param correction
* 处理网络传输偏差时间
* @return 返回验证码
* @since JDK 1.7
*/
public static int getPassword(String secret, long nowDate, long correction) {
long tm = (nowDate - correction) / TimeUnit.SECONDS.toMillis(30);
try {
return getCode(new Base32().decode(secret.toUpperCase()), tm);
} catch (Exception e) {
return -99;
}
}
/**
* getCodeUrl:得到二维码url. <br/>
*
* @author xiaospace
* @param appName<放置app名称>
* 不能为空且不能有':'
* @param user <账户名称>
* 不能为空
* @param secret
* 密钥
* @return 返回二维码url
* @since JDK 1.7
*/
public static String getCodeUrl(String appName, String user, String secret) {
try {
return String.format(TOTP_URI_FORMAT, URLEncoder.encode(getUrl(appName, user, secret), "UTF-8"));
} catch (Exception e) {
return null;
}
}
private static String formatLabel(String issuer, String accountName) {
StringBuilder sb = new StringBuilder();
sb.append(issuer);
sb.append(":");
sb.append(accountName);
return sb.toString();
}
private static String getUrl(String appName, String user, String secret) {
URIBuilder uri = new URIBuilder().setScheme("otpauth").setHost("totp").setPath("/" + formatLabel(appName, user))
.setParameter("secret", secret);
uri.setParameter("issuer", appName);
return uri.toString();
}
/**
* getCode:google具体实现算法. <br/>
*
* @author xiaospace
* @param key
* @param tm
* @return
* @throws Exception
* @since JDK 1.7
*/
private static int getCode(byte[] key, long tm) throws Exception {
byte[] data = new byte[8];
long value = tm;
for (int i = 8; i-- > 0; value >>>= 8) {
data[i] = (byte) value;
}
SecretKeySpec signKey = new SecretKeySpec(key, HMAC_HASH_FUNCTION);
Mac mac = Mac.getInstance(HMAC_HASH_FUNCTION);
mac.init(signKey);
byte[] hash = mac.doFinal(data);
int offset = hash[hash.length - 1] & 0xF;
long truncatedHash = 0;
for (int i = 0; i < 4; ++i) {
truncatedHash <<= 8;
truncatedHash |= (hash[offset + i] & 0xFF);
}
truncatedHash &= 0x7FFFFFFF;
truncatedHash %= (int) Math.pow(10, 6);// 除以10^6
return (int) truncatedHash;
}
public static void main(String[] args) {
// ---------------url-----------
System.out.println(getCodeUrl("***APP***", "***账号***", "XXXX XXXX XXXX XXXXX"));
// ---------------得到密码--------
System.out.println(getPassword("XXXX XXXX XXXX XXXXX", System.currentTimeMillis(),0));
}
}
主要缘由是因为印象笔记和google二次验证都用到了google的身份验证器,就想看看相关代码。当然没有再深入看算法~只是一个签名的过程(较为知名)~
https://itunes.apple.com/us/app/google-authenticator/id388497605?mt=8
https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&hl=zh-CN