SM2/RSA加密解密 & SM2/RSA证书信息读取

目录

相关依赖

SM2加密解密工具类

RSA加密解密工具类

读取SM2证书信息

读取RSA证书信息


相关依赖



    org.bouncycastle
    bcpkix-jdk15on
    1.68


    org.bouncycastle
    bcprov-jdk15on
    1.68

SM2加密解密工具类

package utils;

import java.io.InputStream;
import java.math.BigInteger;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithID;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.signers.SM2Signer;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;

@Slf4j
public class SM2Util {

    /**
     * 密钥对中公钥映射key
     */
    private static final String PUBLIC_KEY = "PublicKey";
    /**
     * 密钥对中私钥映射key
     */
    private static final String PRIVATE_KEY = "PrivateKey";

    /**
     * 签名类实例化入参
     */
    private static final String SIGNATURE_ALGORITHM = "SHA1PRNG";

    /**
     * 椭圆曲线参数规范名称
     */
    private static final String EC_PARAM_SPEC_NAME = "sm2p256v1";

    /**
     * 签名ID,默认为1234567812345678
     */
    private static final String PARAMETER_ID = "1234567812345678";

    /**
     * 公钥前缀,该前缀是固定的
     * 通过代码读取SM2证书中的公钥,在公钥前面会有该前缀
     * 在进行验签时应该用剔除掉该前缀的公钥进行验签
     */
    private static final String PUB_KEY_PREFIX = "3059301306072a8648ce3d020106082a811ccf5501822d034200";

    /**
     * 生成SM2公私钥对
     * @return
     */
    private static AsymmetricCipherKeyPair genKeyPair0() {
        //获取一条SM2曲线参数
        X9ECParameters sm2ECParameters = GMNamedCurves.getByName(EC_PARAM_SPEC_NAME);

        //构造domain参数
        ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
                sm2ECParameters.getG(), sm2ECParameters.getN());

        //1.创建密钥生成器
        ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();

        //2.初始化生成器,带上随机数
        try {
            keyPairGenerator.init(new ECKeyGenerationParameters(domainParameters, SecureRandom.getInstance(SIGNATURE_ALGORITHM)));
        } catch (NoSuchAlgorithmException e) {
            log.error("生成公私钥对时出现异常:", e);
        }

        //3.生成密钥对
        AsymmetricCipherKeyPair asymmetricCipherKeyPair = keyPairGenerator.generateKeyPair();
        return asymmetricCipherKeyPair;
    }

    /**
     * 生成公私钥对(默认压缩公钥)
     * @return
     */
    public static Map genKeyPair() {
        return genKeyPair(true);
    }

    /**
     * 生成公私钥对
     * @param compressedPubKey  是否压缩公钥
     * @return
     */
    public static Map genKeyPair(boolean compressedPubKey) {
        AsymmetricCipherKeyPair asymmetricCipherKeyPair = genKeyPair0();

        //提取公钥点
        ECPoint ecPoint = ((ECPublicKeyParameters) asymmetricCipherKeyPair.getPublic()).getQ();
        //公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥,04的时候,可以去掉前面的04
        String pubKey = Hex.toHexString(ecPoint.getEncoded(compressedPubKey));

        BigInteger privateKey = ((ECPrivateKeyParameters) asymmetricCipherKeyPair.getPrivate()).getD();
        String priKey = privateKey.toString(16);

        Map keyMap = new HashMap<>(2);
        keyMap.put(PUBLIC_KEY, pubKey);
        keyMap.put(PRIVATE_KEY, priKey);
        return keyMap;
    }

    /**
     * 私钥签名
     * @param privateKey    私钥
     * @param content       待签名内容
     * @return
     */
    public static String sign(String privateKey, String content) throws CryptoException {
        //待签名内容转为字节数组
        byte[] message = Hex.decode(content);

        //获取一条SM2曲线参数
        X9ECParameters sm2ECParameters = GMNamedCurves.getByName(EC_PARAM_SPEC_NAME);
        //构造domain参数
        ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
                sm2ECParameters.getG(), sm2ECParameters.getN());

        BigInteger privateKeyD = new BigInteger(privateKey, 16);
        ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(privateKeyD, domainParameters);

        //创建签名实例
        SM2Signer sm2Signer = new SM2Signer();

        //初始化签名实例,带上ID,国密的要求
        try {
            sm2Signer.init(true, new ParametersWithID(new ParametersWithRandom(privateKeyParameters, SecureRandom.getInstance(SIGNATURE_ALGORITHM)), Strings.toByteArray(PARAMETER_ID)));
        } catch (NoSuchAlgorithmException e) {
            log.error("签名时出现异常:", e);
        }
        sm2Signer.update(message, 0, message.length);
        //生成签名,签名分为两部分r和s,分别对应索引0和1的数组
        byte[] signBytes = sm2Signer.generateSignature();

        String sign = Hex.toHexString(signBytes);

        return sign;
    }

    /**
     * 将R或者S修正为固定字节数
     * @param rs
     * @return
     */
    private static byte[] modifyRSFixedBytes(byte[] rs) {
        int length = rs.length;
        int fixedLength = 32;
        byte[] result = new byte[fixedLength];
        if (length < 32) {
            System.arraycopy(rs, 0, result, fixedLength - length, length);
        } else {
            System.arraycopy(rs, length - fixedLength, result, 0, fixedLength);
        }
        return result;
    }

    /**
     * 验证签名
     * @param publicKey     公钥
     * @param content       待签名内容
     * @param sign          签名值
     * @return
     */
    public static boolean verify(String publicKey, String content, String sign) {
        //待签名内容
        byte[] message = Hex.decode(content);
        byte[] signData = Hex.decode(sign);

        // 获取一条SM2曲线参数
        X9ECParameters sm2ECParameters = GMNamedCurves.getByName(EC_PARAM_SPEC_NAME);
        // 构造domain参数
        ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
                sm2ECParameters.getG(),
                sm2ECParameters.getN());
        //提取公钥点
        ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(Hex.decode(publicKey));
        // 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04
        ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters);
        //创建签名实例
        SM2Signer sm2Signer = new SM2Signer();
        ParametersWithID parametersWithID = new ParametersWithID(publicKeyParameters, Strings.toByteArray(PARAMETER_ID));
        sm2Signer.init(false, parametersWithID);
        sm2Signer.update(message, 0, message.length);
        //验证签名结果
        boolean verify = sm2Signer.verifySignature(signData);
        return verify;
    }

    /**
     * SM2加密算法
     * @param publicKey     公钥
     * @param data          数据
     * @return
     */
    public static String encrypt(String publicKey, String data){
        // 获取一条SM2曲线参数
        X9ECParameters sm2ECParameters = GMNamedCurves.getByName(EC_PARAM_SPEC_NAME);
        // 构造domain参数
        ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
                sm2ECParameters.getG(),
                sm2ECParameters.getN());
        //提取公钥点
        ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(Hex.decode(publicKey));
        // 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04
        ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters);

        SM2Engine sm2Engine = new SM2Engine();
        sm2Engine.init(true, new ParametersWithRandom(publicKeyParameters, new SecureRandom()));

        byte[] arrayOfBytes = null;
        try {
            byte[] in = data.getBytes("utf-8");
            arrayOfBytes = sm2Engine.processBlock(in, 0, in.length);
        } catch (Exception e) {
            log.error("SM2加密时出现异常:", e);
        }
        return Hex.toHexString(arrayOfBytes);
    }

    /**
     * SM2加密算法
     * @param publicKey     公钥
     * @param data          明文数据
     * @return
     */
    public static String encrypt(PublicKey publicKey, String data) {

        ECPublicKeyParameters ecPublicKeyParameters = null;
        if (publicKey instanceof BCECPublicKey) {
            BCECPublicKey bcecPublicKey = (BCECPublicKey) publicKey;
            ECParameterSpec ecParameterSpec = bcecPublicKey.getParameters();
            ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(),
                    ecParameterSpec.getG(), ecParameterSpec.getN());
            ecPublicKeyParameters = new ECPublicKeyParameters(bcecPublicKey.getQ(), ecDomainParameters);
        }

        SM2Engine sm2Engine = new SM2Engine();
        sm2Engine.init(true, new ParametersWithRandom(ecPublicKeyParameters, new SecureRandom()));

        byte[] arrayOfBytes = null;
        try {
            byte[] in = data.getBytes("utf-8");
            arrayOfBytes = sm2Engine.processBlock(in,0, in.length);
        } catch (Exception e) {
            log.error("SM2加密时出现异常:", e);
        }
        return Hex.toHexString(arrayOfBytes);
    }

    /**
     * SM2解密算法
     * @param privateKey    私钥
     * @param cipherData    密文数据
     * @return
     */
    public static String decrypt(String privateKey, String cipherData) {
        byte[] cipherDataByte = Hex.decode(cipherData);

        //获取一条SM2曲线参数
        X9ECParameters sm2ECParameters = GMNamedCurves.getByName(EC_PARAM_SPEC_NAME);
        //构造domain参数
        ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
                sm2ECParameters.getG(), sm2ECParameters.getN());

        BigInteger privateKeyD = new BigInteger(privateKey, 16);
        ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(privateKeyD, domainParameters);

        SM2Engine sm2Engine = new SM2Engine();
        sm2Engine.init(false, privateKeyParameters);

        String result = null;
        try {
            byte[] arrayOfBytes = sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length);
            return new String(arrayOfBytes, "utf-8");
        } catch (Exception e) {
            log.error("SM2解密时出现异常:", e);
        }
        return result;

    }

    /**
     * SM2解密算法
     * @param privateKey        私钥
     * @param cipherData        密文数据
     * @return
     */
    public static String decrypt(PrivateKey privateKey, String cipherData) {
        byte[] cipherDataByte = Hex.decode(cipherData);

        BCECPrivateKey bcecPrivateKey = (BCECPrivateKey) privateKey;
        ECParameterSpec ecParameterSpec = bcecPrivateKey.getParameters();

        ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(),
                ecParameterSpec.getG(), ecParameterSpec.getN());

        ECPrivateKeyParameters ecPrivateKeyParameters = new ECPrivateKeyParameters(bcecPrivateKey.getD(),
                ecDomainParameters);

        SM2Engine sm2Engine = new SM2Engine();
        sm2Engine.init(false, ecPrivateKeyParameters);

        String result = null;
        try {
            byte[] arrayOfBytes = sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length);
            return new String(arrayOfBytes, "utf-8");
        } catch (Exception e) {
            log.error("SM2解密时出现异常:", e);
        }
        return result;
    }

    /**
     * 将未压缩公钥压缩成压缩公钥
     * 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04
     * @param pubKey    未压缩公钥(16进制,不要带头部04)
     * @return
     */
    public static String compressPubKey(String pubKey) {
        pubKey = "04" + pubKey;    //将未压缩公钥加上未压缩标识.
        // 获取一条SM2曲线参数
        X9ECParameters sm2ECParameters = GMNamedCurves.getByName(EC_PARAM_SPEC_NAME);
        //提取公钥点
        ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(Hex.decode(pubKey));
        String compressPubKey = Hex.toHexString(pukPoint.getEncoded(Boolean.TRUE));

        return compressPubKey;
    }

    /**
     * 将压缩的公钥解压为非压缩公钥
     * @param compressKey   压缩公钥
     * @return
     */
    public static String unCompressPubKey(String compressKey) {
        // 获取一条SM2曲线参数
        X9ECParameters sm2ECParameters = GMNamedCurves.getByName(EC_PARAM_SPEC_NAME);
        //提取公钥点
        ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(Hex.decode(compressKey));
        String pubKey = Hex.toHexString(pukPoint.getEncoded(Boolean.FALSE));
        //去掉前面的04   (04的时候,可以去掉前面的04)
        pubKey = pubKey.substring(2);
        return pubKey;
    }

    /**
     * 读取SM2证书公钥
     * @param inStream
     * @return
     */
    public static String readSM2(InputStream inStream){
        String pubKey = "";
        try {
            // 引入BC库  证书类型是SM2证书时使用
            Security.addProvider(new BouncyCastleProvider());
            // 创建X509工厂类
            CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");
            // 创建证书对象
            X509Certificate cert = (X509Certificate) cf.generateCertificate(inStream);
            pubKey = Hex.toHexString(cert.getPublicKey().getEncoded()).replace(PUB_KEY_PREFIX,"");
        }catch (Exception e){
            log.error("读取SM2证书信息失败:",e);
            return null;
        }
        return pubKey;
    }


    public static void main(String[] args) throws Exception {
        Map smKeyPair = genKeyPair(false);
        String priKey = (String) smKeyPair.get(PRIVATE_KEY);
        System.out.println("私钥:"+ priKey);
        String pubKey = (String) smKeyPair.get(PUBLIC_KEY);
        System.out.println("公钥:"+ pubKey);
        //公钥解压缩
        String substring = pubKey.substring(2, pubKey.length());
        String s = compressPubKey(substring);
        System.out.println("压缩后:" + s);
        String s1 = unCompressPubKey(s);
        System.out.println("解压后:" + s1);
        //明文
        String text = "12345678";
        System.out.println("测试明文文本:" + text);
        //签名验签测试
        String sign = "";
        try {
            sign = sign(priKey, Hex.toHexString(text.getBytes()));
        } catch (CryptoException e) {
            e.printStackTrace();
        }
        System.out.println("生成签名:" + sign);
        boolean verify = verify(pubKey, Hex.toHexString(text.getBytes()), sign);
        System.out.println("验签结果:" + verify);

        //加解密测试
        String encryptData = encrypt(pubKey, text);
        System.out.println("加密结果:" + encryptData);
        String decryptData = decrypt(priKey, encryptData);
        System.out.println("解密结果:" + decryptData);
        
    }

}

RSA加密解密工具类

package utils;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
import java.security.cert.Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.Cipher;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;


@Slf4j
public class RSAUtil {

    /**
     * 密钥类实例化入参
     */
    private static final String KEY_ALGORITHM = "RSA";
    /**
     * Cipher类实例化入参
     */
    private static final String CIPHER_ALGORITHM = "RSA/ECB/PKCS1Padding";
    /**
     * 密钥对中公钥映射key
     */
    private static final String PUBLIC_KEY = "PublicKey";
    /**
     * 密钥对中私钥映射key
     */
    private static final String PRIVATE_KEY = "PrivateKey";
    /**
     * 签名类实例化入参
     */
    private static final String SIGNATURE_ALGORITHM = "MD5withRSA";
    /**
     * RSA最大加密明文大小
     */
    private static final int MAX_ENCRYPT_BLOCK = 117;

    /**
     * 初始化密钥对生成器时,指定密钥大小的整数值(安全漏洞,长度至少为2048)
     */
    private static final int KEY_PAIR_INIT_SIZE = 2048;

    /**
     * RSA最大解密密文大小,
     * RSA 位数 如果采用1024 上面最大加密和最大解密则须填写: 117 128
     * RSA 位数 如果采用2048 上面最大加密和最大解密则须填写: 245 256
     */
    private static final int MAX_DECRYPT_BLOCK = 256;

    private static final char[] HEX_CHAR = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

    /**
     * 获取公钥字符串
     *
     * @param keyMap 密钥对
     * @return 公钥字符串
     * @throws Exception 异常
     */
    public static String getPublicKeyStr(Map keyMap) throws Exception {
        //获得map中的公钥对象 转为key对象
        Key key = (Key) keyMap.get(PUBLIC_KEY);
        //编码返回字符串
        return encryptBASE64(key.getEncoded());
    }

    /**
     * 获取私钥字符串
     *
     * @param keyMap 密钥对
     * @return 私钥字符串
     * @throws Exception 异常
     */
    public static String getPrivateKeyStr(Map keyMap) throws Exception {
        //获得map中的私钥对象 转为key对象
        Key key = (Key) keyMap.get(PRIVATE_KEY);
        //编码返回字符串
        return encryptBASE64(key.getEncoded());
    }


    /**
     * 获取公钥
     *
     * @param key 公钥字符串
     * @return 公钥
     * @throws Exception 异常
     */
    public static PublicKey getPublicKey(String key) throws Exception {
        byte[] keyBytes;
        keyBytes = decryptBASE64(key);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PublicKey publicKey = keyFactory.generatePublic(keySpec);
        return publicKey;
    }

    /**
     * 获取私钥
     *
     * @param key 私钥字符串
     * @return 私钥
     * @throws Exception 异常
     */
    public static PrivateKey getPrivateKey(String key) throws Exception {
        byte[] keyBytes;
        keyBytes = decryptBASE64(key);
        // 修复异常:java.security.InvalidKeyException: IOException : algid parse error, not a sequence
        Security.addProvider(new BouncyCastleProvider());
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
        return privateKey;
    }

    /**
     * Base64解码,返回byte[]
     *
     * @param key 待解码字符串
     * @return 解码后的byte[]
     */
    public static byte[] decryptBASE64(String key) {
        return Base64.getMimeDecoder().decode(key);
    }

    /**
     * 将byte[]进行Base64编码
     *
     * @param key 待编码的byte[]
     * @return 编码后的字符串
     */
    public static String encryptBASE64(byte[] key) {
        return Base64.getMimeEncoder().encodeToString(key);
    }

    /**
     * 生成签名
     *
     * @param data          待生成签名内容
     * @param privateKeyStr 私钥
     * @return 签名信息
     * @throws Exception 异常
     */
    public static String sign(byte[] data, String privateKeyStr) throws Exception {
        PrivateKey priK = getPrivateKey(new String(hexToBytes(privateKeyStr)));
        Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM);
        sig.initSign(priK);
        sig.update(data);
        return bytesToHex(sig.sign());
    }

    /**
     * 验证签名
     *
     * @param data         待验证原文
     * @param sign         待验证签名
     * @param publicKeyStr 公钥
     * @return 是否验证成功
     * @throws Exception 异常
     */
    public static boolean verify(byte[] data, String sign, String publicKeyStr) throws Exception {
        PublicKey pubK = getPublicKey(new String(hexToBytes(publicKeyStr)));
        Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM);
        sig.initVerify(pubK);
        sig.update(data);
        return sig.verify(hexToBytes(sign));
    }

    /**
     * RSA加密
     * @param plainText 待加密内容
     * @param publicKeyStr 公钥字符串
     * @return 加密后内容
     * @throws Exception 异常
     */
    public static String encrypt(byte[] plainText, String publicKeyStr) throws Exception {
        PublicKey publicKey = getPublicKey(publicKeyStr);
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        int inputLen = plainText.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        int i = 0;
        byte[] cache;
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(plainText, offSet, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(plainText, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptText = out.toByteArray();
        out.close();
        return bytesToHex(encryptText);
    }

    /**
     * RSA解密
     * @param encryptTextHex 已加密内容
     * @param privateKeyStr 私钥字符串
     * @return 解密后内容
     * @throws Exception 异常
     */
    public static String decrypt(String encryptTextHex, String privateKeyStr) throws Exception {
        byte[] encryptText = hexToBytes(encryptTextHex);
        PrivateKey privateKey = getPrivateKey(privateKeyStr);
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        int inputLen = encryptText.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段解密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                cache = cipher.doFinal(encryptText, offSet, MAX_DECRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(encryptText, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_DECRYPT_BLOCK;
        }
        byte[] plainText = out.toByteArray();
        out.close();
        return new String(plainText);
    }

    public static Map initKey() throws Exception {
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        keyPairGen.initialize(KEY_PAIR_INIT_SIZE);
        KeyPair keyPair = keyPairGen.generateKeyPair();
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        Map keyMap = new HashMap<>(2);
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }

    /**
     * 将byte[]转换为16进制字符串
     *
     * @param bytes 待转换byte[]
     * @return 转换后的字符串
     */
    public static String bytesToHex(byte[] bytes) {
        //一个byte为8位,可用两个十六进制位标识
        char[] buf = new char[bytes.length * 2];
        int a = 0;
        int index = 0;
        for (byte b : bytes) { // 使用除与取余进行转换
            if (b < 0) {
                a = 256 + b;
            } else {
                a = b;
            }

            buf[index++] = HEX_CHAR[a / 16];
            buf[index++] = HEX_CHAR[a % 16];
        }
        return new String(buf);
    }

    /**
     * 将16进制字符串转换为byte[]
     *
     * @param str 待转换字符串
     * @return 转换后的byte[]
     */
    public static byte[] hexToBytes(String str) {
        if (str == null || "".equals(str.trim())) {
            return new byte[0];
        }

        byte[] bytes = new byte[str.length() / 2];
        for (int i = 0; i < str.length() / 2; i++) {
            String subStr = str.substring(i * 2, i * 2 + 2);
            bytes[i] = (byte) Integer.parseInt(subStr, 16);
        }

        return bytes;
    }

    /**
     * 读取RSA加密的pfx证书
     * @param stream    待读取证书
     * @param password  RSA密码
     * @return          公钥 && 私钥
     */
    public static Map readPFX(InputStream stream,String password){
        try {
            // 加载PFX证书
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            keyStore.load(stream, password.toCharArray());

            // 获取证书及私钥
            PrivateKey privateKey = (PrivateKey)keyStore.getKey(keyStore.aliases().nextElement(), password.toCharArray());
            Certificate certificate = keyStore.getCertificate(keyStore.aliases().nextElement());
            String pubKey = Base64.getMimeEncoder().encodeToString(certificate.getPublicKey().getEncoded());
            String priKey = Base64.getMimeEncoder().encodeToString(privateKey.getEncoded());
            Map resMap = new HashMap<>();
            resMap.put(PRIVATE_KEY, Hex.toHexString(priKey.getBytes()));
            resMap.put(PUBLIC_KEY,Hex.toHexString(pubKey.getBytes()));
            return resMap;
        }catch (Exception e){
            log.error("读取pfx证书失败:",e.getMessage());
            e.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) throws Exception {
        // 初始化密钥对
        Map keyMap = initKey();
        // 获取公钥字符串
        String publicKey = getPublicKeyStr(keyMap);
        // 获取私钥字符串
        String privateKey = getPrivateKeyStr(keyMap);

        // 打印公钥、私钥
        System.out.println("公钥:(填充方式:PKCS1_PADDING,输出类型:base64,字符集:utf8编码)");
        System.out.println("-----BEGIN PUBLIC KEY-----");
        System.out.println(publicKey);
        System.out.println("-----END PUBLIC KEY-----");
        System.out.println("\n");

        System.out.println("私钥:(填充方式:PKCS1_PADDING,输出类型:base64,字符集:utf8编码)");
        System.out.println("-----BEGIN RSA PRIVATE KEY-----");
        System.out.println(privateKey);
        System.out.println("-----END RSA PRIVATE KEY-----");
        System.out.println("\n");

        // 待加密内容,例:123
        String s = "123";
        // 进行RSA加密
        String encrypt = encrypt(s.getBytes(), publicKey);
        // 打印加密后内容
        System.out.println("密文:(填充方式:PKCS1_PADDING,输出类型:hex,字符集:utf8编码)");
        System.out.println(encrypt);
        System.out.println("\n");

        // 进行RSA解密
        String decrypt = decrypt(encrypt, privateKey);
        // 打印解密后内容
        System.out.println("解密后明文: ");
        System.out.println(decrypt);
    }
}


读取SM2证书信息

package utils;

import cn.hutool.core.date.DateUtil;
import java.util.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.PublicKey;
import java.security.Security;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

public class CertManagerBC {
    public static void showCertInfo() {
        try {
            // 读取证书文件
            String filePath = "E:\\测试SM2证书.cer";
            File file = new File(filePath);
            InputStream inStream = new FileInputStream(file);
            // 引入BC库  证书类型是SM2证书时使用
            Security.addProvider(new BouncyCastleProvider());
            // 创建X509工厂类
            CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");
            // 创建证书对象
            X509Certificate cert = (X509Certificate) cf.generateCertificate(inStream);
            PublicKey pk = cert.getPublicKey();
            System.out.println(pk);
            System.out.println("Base64公钥信息:\n" + Base64.getMimeEncoder().encodeToString(pk.getEncoded()));
            System.out.println("16进制公钥信息:\n" + Hex.toHexString(pk.getEncoded()));
            System.out.println("----------------------------");
            System.out.println("证书版本:" + cert.getVersion());
            System.out.println("证书序列号:" + cert.getSerialNumber().toString(16));
            System.out.println("证书生效日期:" + DateUtil.formatDate(cert.getNotBefore()));
            System.out.println("证书失效日期:" + DateUtil.formatDate(cert.getNotAfter()));
            System.out.println("证书拥有者:" + cert.getSubjectDN().getName());
            System.out.println("证书颁发者:" + cert.getIssuerDN().getName());
            System.out.println("证书签名算法:" + cert.getSigAlgName());
            inStream.close();
        } catch (Exception e) {
            System.out.println("解析证书出错!");
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        CertManagerBC certManager = new CertManagerBC();
        certManager.showCertInfo();
    }
}

读取RSA证书信息

package utils;

import cn.hutool.core.date.DateUtil;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;

public class ReadRSA {


    /**
     * 读取PFX格式的证书
     * @param pfxFile   证书文件地址
     * @param password  证书私钥
     */
    public static void readPFX(String pfxFile,String password){
        try {
            // 加载PFX证书
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            FileInputStream fis = new FileInputStream(pfxFile);
            keyStore.load(fis, password.toCharArray());

            // 获取证书及私钥
            PrivateKey privateKey = (PrivateKey)keyStore.getKey(keyStore.aliases().nextElement(), password.toCharArray());
            Certificate certificate = keyStore.getCertificate(keyStore.aliases().nextElement());
            // 输出证书的详细信息
            if (certificate instanceof X509Certificate) {
                X509Certificate x509Certificate = (X509Certificate)certificate;
                System.out.println("证书颁发机构: " + x509Certificate.getIssuerDN());
                System.out.println("证书拥有者: " + x509Certificate.getSubjectDN());
                System.out.println("证书序列号: " + x509Certificate.getSerialNumber());
                System.out.println("证书生效日期: " + DateUtil.formatDate(x509Certificate.getNotBefore()));
                System.out.println("证书失效日期:" + DateUtil.formatDate(x509Certificate.getNotAfter()));
            }
            //输出证书公钥私钥
            String pubKey = Base64.getMimeEncoder().encodeToString(certificate.getPublicKey().getEncoded());
            String priKey = Base64.getMimeEncoder().encodeToString(privateKey.getEncoded());
            System.out.println("证书公钥: \n" + Hex.toHexString(pubKey.getBytes()));
            System.out.println("证书私钥:\n" + Hex.toHexString(priKey.getBytes()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 读取CER格式的证书
     * @param cerFile   证书文件地址
     */
    public static void readCER(String cerFile){
        try {
            // 引入BC库  证书类型是SM2证书时使用
            Security.addProvider(new BouncyCastleProvider());

            // 创建X509工厂类
            CertificateFactory cf = CertificateFactory.getInstance("X.509");

            InputStream stream = new FileInputStream(cerFile);
            // 创建证书对象
            X509Certificate cert = (X509Certificate) cf.generateCertificate(stream);
            System.out.println("证书公钥:" + Hex.toHexString(cert.getPublicKey().getEncoded()));
            System.out.println("证书版本:" + cert.getVersion());
            System.out.println("证书序列号:" + cert.getSerialNumber().toString(16));
            System.out.println("证书生效日期:" + DateUtil.formatDate(cert.getNotBefore()));
            System.out.println("证书失效日期:" + DateUtil.formatDate(cert.getNotAfter()));
            System.out.println("证书拥有者:" + cert.getSubjectDN().getName());
            System.out.println("证书颁发者:" + cert.getIssuerDN().getName());
            System.out.println("证书签名算法:" + cert.getSigAlgName());
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {

        String pfxFile = "E:\\测试RSA证书.pfx";
        String password = "1234567890";
        String cerFile = "E:\\测试RSA证书.cer";
        readCER(cerFile);
        System.out.println("\n");
        readPFX(pfxFile,password);
    }
}

 校验证书加密方式

    /**
     * 验证证书加密类型
     * 
     * @param certData 证书文件
     * @return
     */
    public static String checkCertEncType(byte[] certData) {
        try {
            InputStream stream = new ByteArrayInputStream(certData);
            X509Certificate certificate = (X509Certificate) loadCert(stream);
            String signName = certificate.getPublicKey().getAlgorithm().toUpperCase();
            if ("RSA".equals(signName)) {
                return "RSA";
            } else if ("EC".equals(signName)) {
                return "SM2";
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

在线生成SM2/RSA秘钥&证书

在线PEM转cer/pfx

你可能感兴趣的:(java)