TOTP 算法校验一则
TOTP算法(Time-based One-time Password algorithm)是一种从共享密钥和当前时间计算一次性密码的算法; 它已被采纳为Internet工程任务组标准RFC 6238, 是Initiative for Open Authentication(OATH)的基石, 并被用于许多双因素身份验证系统;
pom.xml
<dependency>
<groupId>de.taimos</groupId>
<artifactId>totp</artifactId>
<version>1.0</version>
</dependency>java
public static void main(String[] args) {
//1. 随机key
byte[] keybt = "QDWSM3OYBDGHLAJJJHGJVDM3CSNCWHVK".getBytes();
String encode = Base32.encode(keybt);
//2. 编码为base32 (给客户端, 例Google Authenticator作为key的)
System.out.println(encode );
byte[] keybt32 = Base32.decode(encode);
//3. 需编码为十六进制字符串
String secretKey = HexUtil.encodeHexStr(keybt32 );
String lastCode = null;
while (true) {
//4. 获取代码(每隔30s刷新一次)
String code = TOTP.getOTP(secretKey);
if (!code.equals(lastCode)) {
System.out.println(code);
}
lastCode = code;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {break;};
}
}生成Google Authenticator 二维码
public static String getGoogleAuthenticatorBarCode(String secretKey,
String account, String issuer) {
try {
return "otpauth://totp/"
+ URLEncoder.encode(issuer + ":" + account, "UTF-8").replace("+", "%20")
+ "?secret=" + URLEncoder.encode(secretKey, "UTF-8").replace("+", "%20")
+ "&issuer=" + URLEncoder.encode(issuer, "UTF-8").replace("+", "%20");
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException(e);
}
}otpauth://totp/[客户端显示的账户信息]?secret=[secretBase32]
PBKDF2 算法校验一则
/**
*
* @param password 密码
* @param salt 盐
* @param iterations 迭代次数
* @return
* @auth yangfh
*/
public static String generateStorngPasswordHash(String password, long salt, int iterations) {
try {
char[] chars = password.toCharArray();
byte[] salt_ = longToBytes(salt);
PBEKeySpec spec = new PBEKeySpec(chars, salt_, iterations, 64 * 8);
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] hash = skf.generateSecret(spec).getEncoded();
return iterations + ":" + toHex(salt_) + ":" + toHex(hash);
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
/**
* 校验
* originalPassword 密码
* storedPassword PasswordHash
*/
public static boolean validatePassword(String originalPassword, String storedPassword) {
try {
String[] parts = storedPassword.split(":");
int iterations = Integer.parseInt(parts[0]);
byte[] salt = fromHex(parts[1]);
byte[] hash = fromHex(parts[2]);
PBEKeySpec spec = new PBEKeySpec(originalPassword.toCharArray(), salt, iterations, hash.length * 8);
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] testHash = skf.generateSecret(spec).getEncoded();
int diff = hash.length ^ testHash.length;
for (int i = 0; i < hash.length && i < testHash.length; i++) {
diff |= hash[i] ^ testHash[i];
}
return diff == 0;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
public static byte[] longToBytes(long value) {
byte[] src = new byte[8];
src[0] = (byte) (value & 0xFF);
src[1] = (byte) ((value >> 8) & 0xFF);
src[2] = (byte) ((value >> 16) & 0xFF);
src[3] = (byte) ((value >> 24) & 0xFF);
src[4] = (byte) ((value >> 32) & 0xFF);
src[5] = (byte) ((value >> 40) & 0xFF);
src[6] = (byte) ((value >> 48) & 0xFF);
src[7] = (byte) ((value >> 56) & 0xFF);
return src;
}
public static byte[] fromHex(String hex) throws NoSuchAlgorithmException {
byte[] bytes = new byte[hex.length() / 2];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) Integer.parseInt(hex.substring(2 * i, 2 * i + 2), 16);
}
return bytes;
}
public static String toHex(byte[] array) throws NoSuchAlgorithmException {
BigInteger bi = new BigInteger(1, array);
String hex = bi.toString(16);
int paddingLength = (array.length * 2) - hex.length();
if (paddingLength > 0) {
return String.format("%0" + paddingLength + "d", 0) + hex;
} else {
return hex;
}
}String enpwd = EncryptionUtils.generateStorngPasswordHash(dto.getSystemUserPwd(), System.currentTimeMillis(),1000);