| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- package org.springblade.common.utils;
- import cn.hutool.core.lang.Assert;
- import org.springblade.common.enums.ResCode;
- import org.springblade.core.log.exception.ServiceException;
- import javax.crypto.Mac;
- import javax.crypto.spec.SecretKeySpec;
- import java.lang.reflect.UndeclaredThrowableException;
- import java.math.BigInteger;
- import java.security.GeneralSecurityException;
- import java.util.Date;
- /**
- * @author: lianghanqiang
- * @description: TOP 一次性加密口令
- * @since: 8/2/21 -- 10:48 AM
- */
- public class OtpUtils {
- // 649957
- public static void main(String[] args) {
- System.out.println(generateMyTOTP("1423159010830884865"));
- }
- /**
- * id变形常量
- * */
- private static final Long TRANSFORM_PARAMS = 95963L;
- /**
- * 共享密钥
- */
- private static final String SECRET_KEY = "";
- /**
- * 时间步长 单位:毫秒 作为口令变化的时间周期
- */
- private static final long STEP = 60000;
- /**
- * 转码位数 [1-8]
- */
- private static final int CODE_DIGITS = 6;
- /**
- * 初始化时间
- */
- private static final long INITIAL_TIME = 0;
- /**
- * 数子量级
- */
- private static final int[] DIGITS_POWER = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000};
- private OtpUtils() {
- }
- /**
- * 生成一次性密码
- *
- * @param id
- * @return String
- */
- public static String generateMyTOTP(String id) {
- Assert.notBlank(id,()-> new ServiceException(ResCode.ID_NOT_NULL));
- long now = new Date().getTime();
- String time = Long.toHexString(timeFactor(now)).toUpperCase();
- return generateTOTP(id + SECRET_KEY, time);
- }
- /**
- * 获取动态因子
- *
- * @param targetTime 指定时间
- * @return long
- */
- private static long timeFactor(long targetTime) {
- return (targetTime - INITIAL_TIME) / STEP;
- }
- /**
- * 哈希加密
- *
- * @param crypto 加密算法
- * @param keyBytes 密钥数组
- * @param text 加密内容
- * @return byte[]
- */
- private static byte[] hmac_sha(String crypto, byte[] keyBytes, byte[] text) {
- try {
- Mac hmac;
- hmac = Mac.getInstance(crypto);
- SecretKeySpec macKey = new SecretKeySpec(keyBytes, "AES");
- hmac.init(macKey);
- return hmac.doFinal(text);
- } catch (GeneralSecurityException gse) {
- throw new UndeclaredThrowableException(gse);
- }
- }
- private static byte[] hexStr2Bytes(String hex) {
- byte[] bArray = new BigInteger("10" + hex, 16).toByteArray();
- byte[] ret = new byte[bArray.length - 1];
- System.arraycopy(bArray, 1, ret, 0, ret.length);
- return ret;
- }
- private static String generateTOTP(String key, String time) {
- return generateTOTP(key, time, "HmacSHA1");
- }
- private static String generateTOTP(String key, String time, String crypto) {
- StringBuilder timeBuilder = new StringBuilder(time);
- while (timeBuilder.length() < 16)
- timeBuilder.insert(0, "0");
- time = timeBuilder.toString();
- byte[] msg = hexStr2Bytes(time);
- byte[] k = key.getBytes();
- // byte[] k = Base32.decode(key);
- byte[] hash = hmac_sha(crypto, k, msg);
- return truncate(hash);
- }
- /**
- * 截断函数
- *
- * @param target 20字节的字符串
- * @return String
- */
- private static String truncate(byte[] target) {
- StringBuilder result;
- int offset = target[target.length - 1] & 0xf;
- int binary = ((target[offset] & 0x7f) << 24)
- | ((target[offset + 1] & 0xff) << 16)
- | ((target[offset + 2] & 0xff) << 8) | (target[offset + 3] & 0xff);
- int otp = binary % DIGITS_POWER[CODE_DIGITS];
- result = new StringBuilder(Integer.toString(otp));
- while (result.length() < CODE_DIGITS) {
- result.insert(0, "0");
- }
- return result.toString();
- }
- /**
- * 校验口令
- * */
- public static boolean validate(String id,String code) {
- String s = generateMyTOTP(id);
- return code.equals((Long.valueOf(id))+s);
- }
- /**
- * 根据code获取用户Id
- * */
- public static String getIdFormCode(String code) {
- return Long.valueOf(code.substring(0,19))+"";
- }
- }
|