package com.bootdo.util.safe;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

public class SignatureTools {

    private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;

    /**
     * sha256WithRsa 加签
     *
     * @param content      待签名的字符串
     * @param priKeyBase64 base64编码的私钥
     * @return base64编码的签名
     */
    public static String rsa256Sign(String content, String priKeyBase64) {
        byte[] signed = sign(SignAlgorithm.SHA256withRSA, content.getBytes(DEFAULT_CHARSET), Base64Tools.decodeFromString(priKeyBase64));
        return Base64Tools.encodeToString(signed);
    }

    /**
     * sha256WithRsa 验签
     *
     * @param content      待验签的字符串
     * @param pubKeyBase64 base64编码的公钥
     * @param signBase64   base64编码签名
     * @return 签名是否正确
     */
    public static boolean rsa256Verify(String content, String pubKeyBase64, String signBase64) {
        return verify(SignAlgorithm.SHA256withRSA, content.getBytes(DEFAULT_CHARSET), Base64Tools.decodeFromString(signBase64),
                Base64Tools.decodeFromString(pubKeyBase64));
    }

    public static byte[] sign(SignAlgorithm algorithm, byte[] content, byte[] key) {
        try {
            PrivateKey priKey = generatePrivateKey(algorithm, key);
            java.security.Signature signature = java.security.Signature.getInstance(algorithm.getValue());
            signature.initSign(priKey);
            signature.update(content);
            byte[] signed = signature.sign();
            return signed;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static boolean verify(SignAlgorithm algorithm, byte[] content, byte[] sign, byte[] key) {
        try {
            java.security.Signature signature = java.security.Signature.getInstance(algorithm.getValue());
            PublicKey publicKey = generatePublicKey(algorithm, key);
            signature.initVerify(publicKey);
            signature.update(content);
            return signature.verify(sign);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    public static PrivateKey generatePrivateKey(SignAlgorithm algorithmType, byte[] key)
            throws InvalidKeySpecException, NoSuchAlgorithmException {
        return generatePrivateKey(algorithmType, new PKCS8EncodedKeySpec(key));
    }

    public static PrivateKey generatePrivateKey(SignAlgorithm algorithmType, KeySpec keySpec)
            throws InvalidKeySpecException, NoSuchAlgorithmException {
        return KeyFactory.getInstance(algorithmType.getType()).generatePrivate(keySpec);
    }

    public static PublicKey generatePublicKey(SignAlgorithm algorithm, byte[] key)
            throws InvalidKeySpecException, NoSuchAlgorithmException {
        return generatePublicKey(algorithm, new X509EncodedKeySpec(key));
    }

    public static PublicKey generatePublicKey(SignAlgorithm algorithm, KeySpec keySpec)
            throws InvalidKeySpecException, NoSuchAlgorithmException {
        return KeyFactory.getInstance(algorithm.getType()).generatePublic(keySpec);
    }

}
