import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;

/**
 * RSA 签名与解密。
 */
public class SignUtil {

    private static final String RSA_KEY_ALGORITHM = "RSA";
    private static final String RSA2_SIGNATURE_ALGORITHM = "SHA256withRSA";

    /**
     * 私钥解密业务数据。
     *
     * @param data          待解密的业务数据
     * @param secret        RSA 加密后的 AES 密钥
     * @param privateKeyStr 私钥
     * @return 解密后的业务 JSON
     */
    public static String decryptByPrivateKey(String data, String secret, String privateKeyStr) throws Exception {
        byte[] priKey = Base64.getDecoder().decode(privateKeyStr);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(priKey);
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM);
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] decrypt = cipher.doFinal(Base64.getDecoder().decode(secret));
        SecretKey originalKey = new SecretKeySpec(decrypt, 0, decrypt.length, "AES");
        Cipher aesCipher = Cipher.getInstance("AES");
        aesCipher.init(Cipher.DECRYPT_MODE, originalKey);
        byte[] bytePlainText = aesCipher.doFinal(Base64.getDecoder().decode(data));
        return new String(bytePlainText, StandardCharsets.UTF_8);
    }

    /**
     * RSA 签名。
     *
     * @param data   待签名数据
     * @param priKey 私钥
     * @return Base64 签名
     */
    public static String sign(String data, String priKey) throws Exception {
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(priKey));
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM);
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
        Signature signature = Signature.getInstance(RSA2_SIGNATURE_ALGORITHM);
        signature.initSign(privateKey);
        signature.update(data.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(signature.sign());
    }
}
