package com.skr.mdm.util;

import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.checkerframework.checker.units.qual.s;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

/**
 * @Author tty
 * @Date 2022/9/21 14:42
 * @Description hmac算法 口令动态加密
 */
@NoArgsConstructor
public class HmacShaUtils {
    // 加密算法名称
    private static final String MAC_NAME = "HmacSHA1";
    // 密钥使用的字符编码
    private static final String ENCODING = "UTF-8";
    // 口令长度
    private static final int CODE_LENGTH = 6;
    // 口令刷新时间 默认三十分钟
    private static final int CODE_FLESH_TIME = 30 * (1000 * 60);

    /**
     * 使用 HMAC-SHA1 签名方法对encryptText进行签名
     *
     * @param encryptText 被签名的字符串
     * @param encryptKey  密钥
     * @return
     */
    private static byte[] HmacSHA1Encrypt(String encryptText, String encryptKey) {
        // 生成一个指定 Mac 算法 的 Mac 对象
        Mac mac;
        byte[] text = null;
        try {
            byte[] data = encryptKey.getBytes(ENCODING);
            // 根据给定的字节数组构造一个密钥,第二参数指定一个密钥算法的名称
            SecretKey secretKey = new SecretKeySpec(data, MAC_NAME);
            mac = Mac.getInstance(MAC_NAME);
            // 用给定密钥初始化 Mac 对象
            mac.init(secretKey);
            text = encryptText.getBytes(ENCODING);
            // 完成 Mac 操作
            return mac.doFinal(text);
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 截取加密字节数组的后四个字节，并拼接成一个32位整数
     *
     * @param k 被签名的字符串
     * @param t 密钥
     * @return 经计算获得的加密数字
     */
    private static int truncate(String k, String t) {
        byte[] a = HmacSHA1Encrypt(k, t);
        int s = 0;
        for (int i = 0; i < 4; i++) {// 取4个字节
            // 将数组后四个字节拼接成一个32位数字
            s += a[a.length - 1 - i] << 8 * (3 - i);
        }
        return s;
    }

    /**
     * 获取动态码
     *
     * @param key 密文(需要加密的信息)
     * @return
     */
    public static String getCode(String key) {
        String code = "";
        if (StringUtils.isNotBlank(key)) {
            // 当前时间毫秒数
            long scends = System.currentTimeMillis();
            // 获取刷新时间整数倍
            scends = scends / CODE_FLESH_TIME;
            // 根据整数和时间进行加密计算
            String s = String.valueOf(truncate(key, "" + scends));
            // 截取的位置
            int subIndex = s.length() - CODE_LENGTH;
            if (subIndex < 0) {
                throw new ArrayIndexOutOfBoundsException("口令长度大于原始字符串长度");
            }
            code = s.substring(subIndex);
        }
        // 取后CODE_LENGTH数字
        return code;
    }

}