hotp案例-Java
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
public class OTPGenerator {
public static void main(String[] args) {
// 设置共享的密钥,此密钥应该与客户端共享
String sharedSecret = "mySharedSecretKey";
// 生成 TOTP 验证码
String totp = generateTOTP(sharedSecret);
System.out.println("生成的TOTP验证码: " + totp);
// 模拟客户端验证过程
boolean isVerified = verifyTOTP(sharedSecret, totp);
if (isVerified) {
System.out.println("TOTP验证通过");
} else {
System.out.println("TOTP验证失败");
}
}
public static String generateTOTP(String sharedSecret) {
long timeStep = 30; // 时间步长,通常为30秒
long currentTime = Instant.now().getEpochSecond();
long timeWindow = currentTime / timeStep;
try {
// 将密钥转换为字节数组
byte[] keyBytes = sharedSecret.getBytes();
// 创建一个HMAC算法的实例
Mac hmac = Mac.getInstance("HmacSHA1");
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "RAW");
hmac.init(keySpec);
// 将时间窗口转换为字节数组
byte[] timeWindowBytes = longToBytes(timeWindow);
// 计算HMAC
byte[] hmacResult = hmac.doFinal(timeWindowBytes);
// 获取HMAC的后10位并计算验证码
int offset = hmacResult[hmacResult.length - 1] & 0xF;
int binary =
((hmacResult[offset] & 0x7F) << 24) |
((hmacResult[offset + 1] & 0xFF) << 16) |
((hmacResult[offset + 2] & 0xFF) << 8) |
(hmacResult[offset + 3] & 0xFF);
int otp = binary % 1000000; // 生成六位验证码
return String.format("%06d", otp);
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
e.printStackTrace();
return null;
}
}
public static boolean verifyTOTP(String sharedSecret, String userEnteredOTP) {
// 获取当前时间戳
long currentTime = Instant.now().getEpochSecond();
long timeStep = 30; // 时间步长,与生成时保持一致
for (int i = -1; i <= 1; i++) {
long timeWindow = (currentTime / timeStep) + i;
String otp = generateTOTP(sharedSecret, timeWindow);
if (otp.equals(userEnteredOTP)) {
return true;
}
}
return false;
}
public static String generateTOTP(String sharedSecret, long timeWindow) {
try {
// 将密钥转换为字节数组
byte[] keyBytes = sharedSecret.getBytes();
// 创建一个HMAC算法的实例
Mac hmac = Mac.getInstance("HmacSHA1");
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "RAW");
hmac.init(keySpec);
// 将时间窗口转换为字节数组
byte[] timeWindowBytes = longToBytes(timeWindow);
// 计算HMAC
byte[] hmacResult = hmac.doFinal(timeWindowBytes);
// 获取HMAC的后10位并计算验证码
int offset = hmacResult[hmacResult.length - 1] & 0xF;
int binary =
((hmacResult[offset] & 0x7F) << 24) |
((hmacResult[offset + 1] & 0xFF) << 16) |
((hmacResult[offset + 2] & 0xFF) << 8) |
(hmacResult[offset + 3] & 0xFF);
int otp = binary % 1000000; // 生成六位验证码
return String.format("%06d", otp);
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
e.printStackTrace();
return null;
}
}
public static byte[] longToBytes(long value) {
byte[] result = new byte[8];
for (int i = 7; i >= 0; i--) {
result[i] = (byte) (value & 0xFF);
value >>= 8;
}
return result;
}
}