package com.ynfy.common.utils;
import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.security.Security;
import java.util.Arrays;

/**
 * "国标SM3消息摘要算法和SM4加解密算法"工具类,选用了[Bouncy Castle]开源的API,参考自 </br>
 * <a href=
 * "https://github.com/ZZMarquis/gmhelper/blob/master/src/main/java/org/zz/gmhelper/SM4Util.java">github
 * : org.zz.gmhelper.SM4Util.java</a></br>
 * <a href=
 * "https://github.com/ZZMarquis/gmhelper/blob/master/src/main/java/org/zz/gmhelper/SM3Util.java">github
 * : org.zz.gmhelper.SM3Util.java</a></br>
 * <a href="http://www.bouncycastle.org/java.html">Bouncy Castle Crypto APIs</a>
 * </p>
 * SM3是一个强度类似于SHA256的消息摘要算法 </br>
 * SM4是一个与AES近似的对称加密算法,需要双方持有相同的密钥
 *
 * @author wd
 * @since 2023-02-06
 */
public class SM3Utils {
    static {
        // 需要将BC的Provider加入到当前Java虚拟机的识别范围内
        Security.addProvider(new BouncyCastleProvider());
    }
    /**
     * 计算SM3摘要值
     *
     * @param srcData 原文
     * @return 摘要值，对于SM3算法来说是32字节
     */
    public static byte[] hash(byte[] srcData) {
        SM3Digest digest = new SM3Digest();
        digest.update(srcData, 0, srcData.length);
        byte[] hash = new byte[digest.getDigestSize()];
        digest.doFinal(hash, 0);
        return hash;
    }

    /**
     * 验证摘要
     *
     * @param srcData 原文
     * @param sm3Hash 摘要值
     * @return 返回true标识验证成功，false标识验证失败
     */
    public static boolean verify(byte[] srcData, byte[] sm3Hash) {
        byte[] newHash = hash(srcData);
        if (Arrays.equals(newHash, sm3Hash)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 计算SM3 Mac值
     *
     * @param key     key值，可以是任意长度的字节数组
     * @param srcData 原文
     * @return Mac值，对于HMac-SM3来说是32字节
     */
    public static byte[] hmac(byte[] key, byte[] srcData) {
        KeyParameter keyParameter = new KeyParameter(key);
        SM3Digest digest = new SM3Digest();
        HMac mac = new HMac(digest);
        mac.init(keyParameter);
        mac.update(srcData, 0, srcData.length);
        byte[] result = new byte[mac.getMacSize()];
        mac.doFinal(result, 0);
        return result;
    }
}
