Java环境下用SM2或者RSA格式生成P10_在硬件中去生成p10文件的命令-程序员宅基地

技术标签: Java  RSA  java  SM2  

背景:
需求,生成P10时用的私钥不能暴露出来,为了安全起见,将需要用户自己用私钥进行签名后,将私钥签名当参数传入生成P10的接口中。
1.生成P10的工具类
①该方法是需要使用者传入用户公钥,签名算法,私钥签名,才能生成P10

   /**
     * 生成 P10
     * @param pubKey  用户公钥
     * @param signAlg   签名算法
     * @param signer   私钥签名 对象
     * @return  p10
     */
    public static String makeCertificate(String pubKey, String signAlg,ContentSigner signer) {
    
        try {
    
            byte[] publicKey = Base64.decodeBase64(pubKey);
          //  byte[] privateKey = Base64.decodeBase64(signedPriKey);
            PublicKey pubkey = null;
          //  PrivateKey prikey = null;
            if(signAlg.equalsIgnoreCase(SignAlg.SIGN_ALGO_SM3WITHSM2)){
    
                pubkey = BCECUtil.convertX509ToECPublicKey(publicKey);
              //  prikey = BCECUtil.convertPKCS8ToECPrivateKey(privateKey);
            }
            if(signAlg.equalsIgnoreCase(SignAlg.SIGN_ALGO_SHA1WITHRSA) || signAlg.equalsIgnoreCase(SignAlg.SIGN_ALGO_SHA256WITHRSA) || signAlg.equalsIgnoreCase(SignAlg.SIGN_ALGO_SHA384WITHRSA)|| signAlg.equalsIgnoreCase(SignAlg.SIGN_ALGO_SHA512WITHRSA)){
    
                KeyFactory keyFactory = KeyFactory.getInstance("RSA");
                X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKey);
                //转公钥
                pubkey = keyFactory.generatePublic(x509EncodedKeySpec);
                //转私钥
               // PKCS8EncodedKeySpec x509EncodedKeySpec1 = new PKCS8EncodedKeySpec(privateKey);
               // prikey = keyFactory.generatePrivate(x509EncodedKeySpec1);
            }
            X500NameBuilder localX500NameBuilder = new X500NameBuilder(BCStyle.INSTANCE);
            localX500NameBuilder.addRDN(BCStyle.CN, "userName or CompName"); //个人,企业用户名
            localX500NameBuilder.addRDN(BCStyle.C, "CN");  //国家
            localX500NameBuilder.addRDN(BCStyle.O, "39dian blog"); //机构名称
            localX500NameBuilder.addRDN(BCStyle.ST, "shanghai");  //省
            localX500NameBuilder.addRDN(BCStyle.L, "shanghai");  //市
            localX500NameBuilder.addRDN(BCStyle.E, "[email protected]"); //邮箱
            org.bouncycastle.asn1.x500.X500Name localX500Name = localX500NameBuilder.build();
            JcaPKCS10CertificationRequestBuilder p10Builder = new JcaPKCS10CertificationRequestBuilder(localX500Name, pubkey);
            JcaContentSignerBuilder csBuilder = new JcaContentSignerBuilder(signAlg);// 签名算法
          /*  ContentSigner signer = null;
            if(signAlg.equalsIgnoreCase(SignAlg.SIGN_ALGO_SM3WITHSM2)){
                signer = csBuilder.setProvider("BC").build(prikey);
            }*/
           // signer = csBuilder.build(prikey);    //  私钥签名    localKeyPair.getPrivate()
            PKCS10CertificationRequest csr = p10Builder.build(signer);// PKCS10的请求
            return Base64.encodeBase64String(csr.getEncoded());  //P10 Base64 CSR
        } catch (Exception ex) {
    
            ex.printStackTrace();
        }
        return null;
    }

②该方法需要使用者传入签名算法就可以生成P10,因为里面需要的公私钥都用随机数进行了计算生成,不需要再手动收入

/**
     * 生成证书请求和公私玥。
     * @param subject  基本信息
     * @param signAlg  签名算法
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws OperatorCreationException
     * @throws IOException
     * @throws NoSuchProviderException
     * @throws InvalidAlgorithmParameterException
     */
    public static byte[] genUserReq(CertSubject subject, String signAlg) throws NoSuchAlgorithmException, InvalidKeyException, OperatorCreationException, IOException, NoSuchProviderException, InvalidAlgorithmParameterException {
    
        //主题信息
        org.bouncycastle.asn1.x500.X500Name userDN = subject.buildDN();
        if (signAlg.equalsIgnoreCase(SignAlg.SIGN_ALGO_SM3WITHSM2)) {
    
            //公私钥对
            KeyPair userKP = SM2Util.generateKeyPair();
            SM2PublicKey userPub = new SM2PublicKey(userKP.getPublic().getAlgorithm(),
                    (BCECPublicKey) userKP.getPublic());

            //生成证书请求
            byte[] userCSR = CommonUtil.createCSR(userDN, userPub, userKP.getPrivate(),
                    signAlg).getEncoded();
            //保存
            byte[] x = ((BCECPublicKey) userKP.getPublic()).getQ().getAffineXCoord().getEncoded();
            byte[] y = ((BCECPublicKey) userKP.getPublic()).getQ().getAffineYCoord().getEncoded();
            byte[] sk = ((BCECPrivateKey) userKP.getPrivate()).getD().toByteArray();

            GenReqResult genReqResult = new GenReqResult(userCSR, x, y, sk);
            return userCSR;
        } else if (signAlg.equalsIgnoreCase(SignAlg.SIGN_ALGO_SHA256WITHRSA)) {
    
            CertAndKeyGen gen = new CertAndKeyGen("RSA", SignAlg.SIGN_ALGO_SHA256WITHRSA);

            gen.generate(1024);//生成1024位密钥

            //生成证书请求
            byte[] userCSR = CommonUtil.createCSR(userDN, gen.getPublicKey(), gen.getPrivateKey(),
                    signAlg).getEncoded();
            return userCSR;
        } else if (signAlg.equalsIgnoreCase(SignAlg.SIGN_ALGO_SHA384WITHRSA)) {
    
            CertAndKeyGen gen = new CertAndKeyGen("RSA", SignAlg.SIGN_ALGO_SHA384WITHRSA);

            gen.generate(1024);//生成1024位密钥

            //生成证书请求
            byte[] userCSR = CommonUtil.createCSR(userDN, gen.getPublicKey(), gen.getPrivateKey(),
                    signAlg).getEncoded();
            return userCSR;
        } else if (signAlg.equalsIgnoreCase(SignAlg.SIGN_ALGO_SHA512WITHRSA)) {
    
            CertAndKeyGen gen = new CertAndKeyGen("RSA", SignAlg.SIGN_ALGO_SHA512WITHRSA);
            gen.generate(1024);//生成1024位密钥
            //生成证书请求
            byte[] userCSR = CommonUtil.createCSR(userDN, gen.getPublicKey(), gen.getPrivateKey(),
                    signAlg).getEncoded();
            return userCSR;
        } else if (signAlg.equalsIgnoreCase(SignAlg.SIGN_ALGO_SHA1WITHRSA)) {
    
            CertAndKeyGen gen = new CertAndKeyGen("RSA", SignAlg.SIGN_ALGO_SHA1WITHRSA);

            gen.generate(1024);//生成1024位密钥

            //生成证书请求
            byte[] userCSR = CommonUtil.createCSR(userDN, gen.getPublicKey(), gen.getPrivateKey(),
                    signAlg).getEncoded();
            return userCSR;
        }
        return null;
    }

注:补充②中用到的CertSubject实体类

import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStyle;

public class CertSubject {
    

    public  String country;
    public  String province;
    public String locality;
    public String orgName;
    public String orgUnit;
    public String commonName;
    public String email;


    public X500Name buildDN( ){
    

        X500NameBuilder builder = new X500NameBuilder(BCStyle.INSTANCE);
        if (country !=null) {
    
            builder.addRDN(BCStyle.C, country);
        }
        if (province !=null) {
    
            builder.addRDN(BCStyle.ST, province);
        }
        if (locality !=null) {
    
            builder.addRDN(BCStyle.L, locality);
        }
        if (orgName !=null) {
    
            builder.addRDN(BCStyle.O, orgName);
        }
        if (orgUnit !=null) {
    
            builder.addRDN(BCStyle.OU, orgUnit);
        }
        if (commonName !=null) {
    
            builder.addRDN(BCStyle.CN, commonName);
        }
        if (email !=null) {
    
            builder.addRDN(BCStyle.E, email);
        }

        return builder.build();

    }

    public String getCountry() {
    
        return country;
    }

    public void setCountry(String country) {
    
        this.country = country;
    }

    public String getProvince() {
    
        return province;
    }

    public void setProvince(String province) {
    
        this.province = province;
    }

    public String getLocality() {
    
        return locality;
    }

    public void setLocality(String locality) {
    
        this.locality = locality;
    }

    public String getOrgName() {
    
        return orgName;
    }

    public void setOrgName(String orgName) {
    
        this.orgName = orgName;
    }

    public String getCommonName() {
    
        return commonName;
    }

    public void setCommonName(String commonName) {
    
        this.commonName = commonName;
    }

    public String getEmail() {
    
        return email;
    }

    public void setEmail(String email) {
    
        this.email = email;
    }

    public String getOrgUnit() {
    
        return orgUnit;
    }

    public void setOrgUnit(String orgUnit) {
    
        this.orgUnit = orgUnit;
    }


    @Override
    public String toString() {
    
        return "CertSubject{" +
                "country='" + country + '\'' +
                ", province='" + province + '\'' +
                ", locality='" + locality + '\'' +
                ", orgName='" + orgName + '\'' +
                ", orgUnit='" + orgUnit + '\'' +
                ", commonName='" + commonName + '\'' +
                ", email='" + email + '\'' +
                '}';
    }

2.上面工具类已成,下面开始调用,以第一种为例
直接上干货:

public void testP10(){
      //生成P10
        String signAlg = "SHA256WithRSA";
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        KeyPairGenerator localKeyPairGenerator = null;
        String pubKey  = null;
        ContentSigner signer = null;
        PrivateKey prikey1 = null;
        KeyPair localKeyPair = null;
        try {
    
            if(signAlg.equalsIgnoreCase(SignAlg.SIGN_ALGO_SHA1WITHRSA) || signAlg.equalsIgnoreCase(SignAlg.SIGN_ALGO_SHA256WITHRSA) || signAlg.equalsIgnoreCase(SignAlg.SIGN_ALGO_SHA384WITHRSA)|| signAlg.equalsIgnoreCase(SignAlg.SIGN_ALGO_SHA512WITHRSA)){
    

                localKeyPairGenerator = KeyPairGenerator.getInstance("RSA",new BouncyCastleProvider());
                localKeyPairGenerator.initialize(1024);
                KeyFactory keyFactory = KeyFactory.getInstance("RSA");
                localKeyPair = localKeyPairGenerator.genKeyPair();
                // X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(localKeyPair.getPublic().getEncoded());
                //转公钥
                // pubkey1 = keyFactory.generatePublic(x509EncodedKeySpec);
                //转私钥
                PKCS8EncodedKeySpec x509EncodedKeySpec1 = new PKCS8EncodedKeySpec(localKeyPair.getPrivate().getEncoded());
                // prikey1 = keyFactory.generatePrivate(x509EncodedKeySpec1);
            } else if (signAlg.equalsIgnoreCase(SignAlg.SIGN_ALGO_SM3WITHSM2)) {
    
                localKeyPairGenerator = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider());
                localKeyPairGenerator.initialize(new ECGenParameterSpec("sm2p256v1"));
                localKeyPair = localKeyPairGenerator.genKeyPair();
                //   pubkey1 = BCECUtil.convertX509ToECPublicKey(localKeyPair.getPublic().getEncoded());
                //  prikey1 = BCECUtil.convertPKCS8ToECPrivateKey(localKeyPair.getPrivate().getEncoded());
            }
            pubKey = Base64.encodeBase64String(localKeyPair.getPublic().getEncoded()); //转Base64
            //为了私钥的安全性,私钥签名过程需要用户自己来完成
            JcaContentSignerBuilder csBuilder = new JcaContentSignerBuilder(signAlg);// 签名算法
            if(signAlg.equalsIgnoreCase(SignAlg.SIGN_ALGO_SM3WITHSM2)){
    
                signer = csBuilder.setProvider("BC").build(localKeyPair.getPrivate());
            }
            signer = csBuilder.build(localKeyPair.getPrivate());    //  私钥签名    localKeyPair.getPrivate()
        } catch (Exception ex) {
    
            ex.printStackTrace();
            Assert.fail();
        }
        String P10 = makeCertificate(pubKey,signAlg,signer);
        Log4jBean.logger.info("生成的P10为:"+P10);

    }

结果图示:
在这里插入图片描述
补上:BCECUtil .java

import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x9.X962Parameters;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.asn1.x9.X9ECPoint;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
import org.bouncycastle.crypto.params.ECKeyParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util;
import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECNamedCurveSpec;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.math.ec.FixedPointCombMultiplier;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import org.bouncycastle.util.io.pem.PemWriter;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * 这个工具类的方法,也适用于其他基于BC库的ECC算法
 */
public class BCECUtil {
    
    private static final String ALGO_NAME_EC = "EC";
    private static final String PEM_STRING_PUBLIC = "PUBLIC KEY";
    private static final String PEM_STRING_ECPRIVATEKEY = "EC PRIVATE KEY";

    /**
     * 生成ECC密钥对
     *
     * @return ECC密钥对
     */
    public static AsymmetricCipherKeyPair generateKeyPairParameter(
            ECDomainParameters domainParameters, SecureRandom random) {
    
        ECKeyGenerationParameters keyGenerationParams = new ECKeyGenerationParameters(domainParameters,
                random);
        ECKeyPairGenerator keyGen = new ECKeyPairGenerator();
        keyGen.init(keyGenerationParams);
        return keyGen.generateKeyPair();
    }

    public static KeyPair generateKeyPair(ECDomainParameters domainParameters, SecureRandom random)
            throws NoSuchProviderException, NoSuchAlgorithmException,
            InvalidAlgorithmParameterException {
    
        KeyPairGenerator kpg = KeyPairGenerator.getInstance(ALGO_NAME_EC, BouncyCastleProvider.PROVIDER_NAME);
        ECParameterSpec parameterSpec = new ECParameterSpec(domainParameters.getCurve(), domainParameters.getG(),
                domainParameters.getN(), domainParameters.getH());
        kpg.initialize(parameterSpec, random);
        return kpg.generateKeyPair();
    }

    public static int getCurveLength(ECKeyParameters ecKey) {
    
        return getCurveLength(ecKey.getParameters());
    }

    public static int getCurveLength(ECDomainParameters domainParams) {
    
        return (domainParams.getCurve().getFieldSize() + 7) / 8;
    }

    public static byte[] fixToCurveLengthBytes(int curveLength, byte[] src) {
    
        if (src.length == curveLength) {
    
            return src;
        }

        byte[] result = new byte[curveLength];
        if (src.length > curveLength) {
    
            System.arraycopy(src, src.length - result.length, result, 0, result.length);
        } else {
    
            System.arraycopy(src, 0, result, result.length - src.length, src.length);
        }
        return result;
    }

    /**
     * @param dHex             十六进制字符串形式的私钥d值,如果是SM2算法,Hex字符串长度应该是64(即32字节)
     * @param domainParameters EC Domain参数,一般是固定的,如果是SM2算法的可参考{@link SM2Util#DOMAIN_PARAMS}
     * @return
     */
    public static ECPrivateKeyParameters createECPrivateKeyParameters(
            String dHex, ECDomainParameters domainParameters) {
    
        return createECPrivateKeyParameters(ByteUtils.fromHexString(dHex), domainParameters);
    }

    /**
     * @param dBytes           字节数组形式的私钥d值,如果是SM2算法,应该是32字节
     * @param domainParameters EC Domain参数,一般是固定的,如果是SM2算法的可参考{@link SM2Util#DOMAIN_PARAMS}
     * @return
     */
    public static ECPrivateKeyParameters createECPrivateKeyParameters(
            byte[] dBytes, ECDomainParameters domainParameters) {
    
        return createECPrivateKeyParameters(new BigInteger(1, dBytes), domainParameters);
    }

    /**
     * @param d                大数形式的私钥d值
     * @param domainParameters EC Domain参数,一般是固定的,如果是SM2算法的可参考{@link SM2Util#DOMAIN_PARAMS}
     * @return
     */
    public static ECPrivateKeyParameters createECPrivateKeyParameters(
            BigInteger d, ECDomainParameters domainParameters) {
    
        return new ECPrivateKeyParameters(d, domainParameters);
    }

    /**
     * 根据EC私钥构造EC公钥
     *
     * @param priKey ECC私钥参数对象
     * @return
     */
    public static ECPublicKeyParameters buildECPublicKeyByPrivateKey(ECPrivateKeyParameters priKey) {
    
        ECDomainParameters domainParameters = priKey.getParameters();
        ECPoint q = new FixedPointCombMultiplier().multiply(domainParameters.getG(), priKey.getD());
        return new ECPublicKeyParameters(q, domainParameters);
    }

    /**
     * @param x                大数形式的公钥x分量
     * @param y                大数形式的公钥y分量
     * @param curve            EC曲线参数,一般是固定的,如果是SM2算法的可参考{@link SM2Util#CURVE}
     * @param domainParameters EC Domain参数,一般是固定的,如果是SM2算法的可参考{@link SM2Util#DOMAIN_PARAMS}
     * @return
     */
    public static ECPublicKeyParameters createECPublicKeyParameters(
            BigInteger x, BigInteger y, ECCurve curve, ECDomainParameters domainParameters) {
    
        return createECPublicKeyParameters(x.toByteArray(), y.toByteArray(), curve, domainParameters);
    }

    /**
     * @param xHex             十六进制形式的公钥x分量,如果是SM2算法,Hex字符串长度应该是64(即32字节)
     * @param yHex             十六进制形式的公钥y分量,如果是SM2算法,Hex字符串长度应该是64(即32字节)
     * @param curve            EC曲线参数,一般是固定的,如果是SM2算法的可参考{@link SM2Util#CURVE}
     * @param domainParameters EC Domain参数,一般是固定的,如果是SM2算法的可参考{@link SM2Util#DOMAIN_PARAMS}
     * @return
     */
    public static ECPublicKeyParameters createECPublicKeyParameters(
            String xHex, String yHex, ECCurve curve, ECDomainParameters domainParameters) {
    
        return createECPublicKeyParameters(ByteUtils.fromHexString(xHex), ByteUtils.fromHexString(yHex),
                curve, domainParameters);
    }

    /**
     * @param xBytes           十六进制形式的公钥x分量,如果是SM2算法,应该是32字节
     * @param yBytes           十六进制形式的公钥y分量,如果是SM2算法,应该是32字节
     * @param curve            EC曲线参数,一般是固定的,如果是SM2算法的可参考{@link SM2Util#CURVE}
     * @param domainParameters EC Domain参数,一般是固定的,如果是SM2算法的可参考{@link SM2Util#DOMAIN_PARAMS}
     * @return
     */
    public static ECPublicKeyParameters createECPublicKeyParameters(
            byte[] xBytes, byte[] yBytes, ECCurve curve, ECDomainParameters domainParameters) {
    
        final byte uncompressedFlag = 0x04;
        int curveLength = getCurveLength(domainParameters);
        xBytes = fixToCurveLengthBytes(curveLength, xBytes);
        yBytes = fixToCurveLengthBytes(curveLength, yBytes);
        byte[] encodedPubKey = new byte[1 + xBytes.length + yBytes.length];
        encodedPubKey[0] = uncompressedFlag;
        System.arraycopy(xBytes, 0, encodedPubKey, 1, xBytes.length);
        System.arraycopy(yBytes, 0, encodedPubKey, 1 + xBytes.length, yBytes.length);
        return new ECPublicKeyParameters(curve.decodePoint(encodedPubKey), domainParameters);
    }

    public static ECPrivateKeyParameters convertPrivateKeyToParameters(BCECPrivateKey ecPriKey) {
    
        ECParameterSpec parameterSpec = ecPriKey.getParameters();
        ECDomainParameters domainParameters = new ECDomainParameters(parameterSpec.getCurve(), parameterSpec.getG(),
                parameterSpec.getN(), parameterSpec.getH());
        return new ECPrivateKeyParameters(ecPriKey.getD(), domainParameters);
    }

    public static ECPublicKeyParameters convertPublicKeyToParameters(BCECPublicKey ecPubKey) {
    
        ECParameterSpec parameterSpec = ecPubKey.getParameters();
        ECDomainParameters domainParameters = new ECDomainParameters(parameterSpec.getCurve(), parameterSpec.getG(),
                parameterSpec.getN(), parameterSpec.getH());
        return new ECPublicKeyParameters(ecPubKey.getQ(), domainParameters);
    }

    public static BCECPublicKey createPublicKeyFromSubjectPublicKeyInfo(SubjectPublicKeyInfo subPubInfo)
            throws NoSuchProviderException,
            NoSuchAlgorithmException, InvalidKeySpecException, IOException {
    
        return BCECUtil.convertX509ToECPublicKey(subPubInfo.toASN1Primitive().getEncoded(ASN1Encoding.DER));
    }

    /**
     * 将ECC私钥转换为PKCS8标准的字节流
     *
     * @param priKey
     * @param pubKey 可以为空,但是如果为空的话得到的结果OpenSSL可能解析不了
     * @return
     */
    public static byte[] convertECPrivateKeyToPKCS8(
            ECPrivateKeyParameters priKey, ECPublicKeyParameters pubKey) {
    
        ECDomainParameters domainParams = priKey.getParameters();
        ECParameterSpec spec = new ECParameterSpec(domainParams.getCurve(), domainParams.getG(),
                domainParams.getN(), domainParams.getH());
        BCECPublicKey publicKey = null;
        if (pubKey != null) {
    
            publicKey = new BCECPublicKey(ALGO_NAME_EC, pubKey, spec,
                    BouncyCastleProvider.CONFIGURATION);
        }
        BCECPrivateKey privateKey = new BCECPrivateKey(ALGO_NAME_EC, priKey, publicKey,
                spec, BouncyCastleProvider.CONFIGURATION);
        return privateKey.getEncoded();
    }

    /**
     * 将PKCS8标准的私钥字节流转换为私钥对象
     *
     * @param pkcs8Key
     * @return
     * @throws NoSuchAlgorithmException
     * @throws NoSuchProviderException
     * @throws InvalidKeySpecException
     */
    public static BCECPrivateKey convertPKCS8ToECPrivateKey(byte[] pkcs8Key)
            throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException {
    
        PKCS8EncodedKeySpec peks = new PKCS8EncodedKeySpec(pkcs8Key);
        KeyFactory kf = KeyFactory.getInstance(ALGO_NAME_EC, BouncyCastleProvider.PROVIDER_NAME);
        return (BCECPrivateKey) kf.generatePrivate(peks);
    }

    /**
     * 将PKCS8标准的私钥字节流转换为PEM
     *
     * @param encodedKey
     * @return
     * @throws IOException
     */
    public static String convertECPrivateKeyPKCS8ToPEM(byte[] encodedKey) throws IOException {
    
        return convertEncodedDataToPEM(PEM_STRING_ECPRIVATEKEY, encodedKey);
    }

    /**
     * 将PEM格式的私钥转换为PKCS8标准字节流
     *
     * @param pemString
     * @return
     * @throws IOException
     */
    public static byte[] convertECPrivateKeyPEMToPKCS8(String pemString) throws IOException {
    
        return convertPEMToEncodedData(pemString);
    }

    /**
     * 将ECC私钥转换为SEC1标准的字节流
     * openssl d2i_ECPrivateKey函数要求的DER编码的私钥也是SEC1标准的,
     * 这个工具函数的主要目的就是为了能生成一个openssl可以直接“识别”的ECC私钥.
     * 相对new NetworkConnPub().getProtocolHostPort()私钥的PKCS1标准,ECC私钥的标准为SEC1
     *
     * @param priKey
     * @param pubKey
     * @return
     * @throws IOException
     */
    public static byte[] convertECPrivateKeyToSEC1(
            ECPrivateKeyParameters priKey, ECPublicKeyParameters pubKey) throws IOException {
    
        byte[] pkcs8Bytes = convertECPrivateKeyToPKCS8(priKey, pubKey);
        PrivateKeyInfo pki = PrivateKeyInfo.getInstance(pkcs8Bytes);
        ASN1Encodable encodable = pki.parsePrivateKey();
        ASN1Primitive primitive = encodable.toASN1Primitive();
        byte[] sec1Bytes = primitive.getEncoded();
        return sec1Bytes;
    }

    /**
     * 将SEC1标准的私钥字节流恢复为PKCS8标准的字节流
     *
     * @param sec1Key
     * @return
     * @throws IOException
     */
    public static byte[] convertECPrivateKeySEC1ToPKCS8(byte[] sec1Key) throws IOException {
    
        /**
         * 参考org.bouncycastle.asn1.pkcs.PrivateKeyInfo和
         * org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey,逆向拼装
         */
        X962Parameters params = getDomainParametersFromName(SM2Util.JDK_EC_SPEC, false);
        ASN1OctetString privKey = new DEROctetString(sec1Key);
        ASN1EncodableVector v = new ASN1EncodableVector();
        v.add(new ASN1Integer(0)); //版本号
        v.add(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params)); //算法标识
        v.add(privKey);
        DERSequence ds = new DERSequence(v);
        return ds.getEncoded(ASN1Encoding.DER);
    }

    /**
     * 将SEC1标准的私钥字节流转为BCECPrivateKey对象
     *
     * @param sec1Key
     * @return
     * @throws NoSuchAlgorithmException
     * @throws NoSuchProviderException
     * @throws InvalidKeySpecException
     * @throws IOException
     */
    public static BCECPrivateKey convertSEC1ToBCECPrivateKey(byte[] sec1Key)
            throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, IOException {
    
        PKCS8EncodedKeySpec peks = new PKCS8EncodedKeySpec(convertECPrivateKeySEC1ToPKCS8(sec1Key));
        KeyFactory kf = KeyFactory.getInstance(ALGO_NAME_EC, BouncyCastleProvider.PROVIDER_NAME);
        return (BCECPrivateKey) kf.generatePrivate(peks);
    }

    /**
     * 将SEC1标准的私钥字节流转为ECPrivateKeyParameters对象
     * openssl i2d_ECPrivateKey函数生成的DER编码的ecc私钥是:SEC1标准的、带有EC_GROUP、带有公钥的,
     * 这个工具函数的主要目的就是为了使Java程序能够“识别”openssl生成的ECC私钥
     *
     * @param sec1Key
     * @return
     * @throws NoSuchAlgorithmException
     * @throws NoSuchProviderException
     * @throws InvalidKeySpecException
     */
    public static ECPrivateKeyParameters convertSEC1ToECPrivateKey(byte[] sec1Key)
            throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, IOException {
    
        BCECPrivateKey privateKey = convertSEC1ToBCECPrivateKey(sec1Key);
        return convertPrivateKeyToParameters(privateKey);
    }

    /**
     * 将ECC公钥对象转换为X509标准的字节流
     *
     * @param pubKey
     * @return
     */
    public static byte[] convertECPublicKeyToX509(ECPublicKeyParameters pubKey) {
    
        ECDomainParameters domainParams = pubKey.getParameters();
        ECParameterSpec spec = new ECParameterSpec(domainParams.getCurve(), domainParams.getG(),
                domainParams.getN(), domainParams.getH());
        BCECPublicKey publicKey = new BCECPublicKey(ALGO_NAME_EC, pubKey, spec,
                BouncyCastleProvider.CONFIGURATION);
        return publicKey.getEncoded();
    }

    /**
     * 将X509标准的公钥字节流转为公钥对象
     *
     * @param x509Bytes
     * @return
     * @throws NoSuchProviderException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */
    public static BCECPublicKey convertX509ToECPublicKey(byte[] x509Bytes) throws NoSuchProviderException,
            NoSuchAlgorithmException, InvalidKeySpecException {
    
        X509EncodedKeySpec eks = new X509EncodedKeySpec(x509Bytes);
        KeyFactory kf = KeyFactory.getInstance("EC", BouncyCastleProvider.PROVIDER_NAME);
        return (BCECPublicKey) kf.generatePublic(eks);
    }

    /**
     * 将X509标准的公钥字节流转为PEM
     *
     * @param encodedKey
     * @return
     * @throws IOException
     */
    public static String convertECPublicKeyX509ToPEM(byte[] encodedKey) throws IOException {
    
        return convertEncodedDataToPEM(PEM_STRING_PUBLIC, encodedKey);
    }

    /**
     * 将PEM格式的公钥转为X509标准的字节流
     *
     * @param pemString
     * @return
     * @throws IOException
     */
    public static byte[] convertECPublicKeyPEMToX509(String pemString) throws IOException {
    
        return convertPEMToEncodedData(pemString);
    }

    /**
     * copy from BC
     *
     * @param genSpec
     * @return
     */
    public static X9ECParameters getDomainParametersFromGenSpec(ECGenParameterSpec genSpec) {
    
        return getDomainParametersFromName(genSpec.getName());
    }

    /**
     * copy from BC
     *
     * @param curveName
     * @return
     */
    public static X9ECParameters getDomainParametersFromName(String curveName) {
    
        X9ECParameters domainParameters;
        try {
    
            if (curveName.charAt(0) >= '0' && curveName.charAt(0) <= '2') {
    
                ASN1ObjectIdentifier oidID = new ASN1ObjectIdentifier(curveName);
                domainParameters = ECUtil.getNamedCurveByOid(oidID);
            } else {
    
                if (curveName.indexOf(' ') > 0) {
    
                    curveName = curveName.substring(curveName.indexOf(' ') + 1);
                    domainParameters = ECUtil.getNamedCurveByName(curveName);
                } else {
    
                    domainParameters = ECUtil.getNamedCurveByName(curveName);
                }
            }
        } catch (IllegalArgumentException ex) {
    
            domainParameters = ECUtil.getNamedCurveByName(curveName);
        }
        return domainParameters;
    }

    /**
     * copy from BC
     *
     * @param ecSpec
     * @param withCompression
     * @return
     */
    public static X962Parameters getDomainParametersFromName(
            java.security.spec.ECParameterSpec ecSpec, boolean withCompression) {
    
        X962Parameters params;

        if (ecSpec instanceof ECNamedCurveSpec) {
    
            ASN1ObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec) ecSpec).getName());
            if (curveOid == null) {
    
                curveOid = new ASN1ObjectIdentifier(((ECNamedCurveSpec) ecSpec).getName());
            }
            params = new X962Parameters(curveOid);
        } else if (ecSpec == null) {
    
            params = new X962Parameters(DERNull.INSTANCE);
        } else {
    
            ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());

            X9ECParameters ecP = new X9ECParameters(
                    curve,
                    new X9ECPoint(EC5Util.convertPoint(curve, ecSpec.getGenerator()), withCompression),
                    ecSpec.getOrder(),
                    BigInteger.valueOf(ecSpec.getCofactor()),
                    ecSpec.getCurve().getSeed());

             如果是1.62或更低版本的bcprov-jdk15on应该使用以下这段代码,因为高版本的EC5Util.convertPoint没有向下兼容
            /*
            X9ECParameters ecP = new X9ECParameters(
                curve,
                EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression),
                ecSpec.getOrder(),
                BigInteger.valueOf(ecSpec.getCofactor()),
                ecSpec.getCurve().getSeed());
            */

            params = new X962Parameters(ecP);
        }

        return params;
    }

    private static String convertEncodedDataToPEM(String type, byte[] encodedData) throws IOException {
    
        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
        PemWriter pWrt = new PemWriter(new OutputStreamWriter(bOut));
        try {
    
            PemObject pemObj = new PemObject(type, encodedData);
            pWrt.writeObject(pemObj);
        } finally {
    
            pWrt.close();
        }
        return new String(bOut.toByteArray());
    }

    private static byte[] convertPEMToEncodedData(String pemString) throws IOException {
    
        ByteArrayInputStream bIn = new ByteArrayInputStream(pemString.getBytes());
        PemReader pRdr = new PemReader(new InputStreamReader(bIn));
        try {
    
            PemObject pemObject = pRdr.readPemObject();
            return pemObject.getContent();
        } finally {
    
            pRdr.close();
        }
    }
}
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_39921821/article/details/121424343

智能推荐

oracle 12c 集群安装后的检查_12c查看crs状态-程序员宅基地

文章浏览阅读1.6k次。安装配置gi、安装数据库软件、dbca建库见下:http://blog.csdn.net/kadwf123/article/details/784299611、检查集群节点及状态:[root@rac2 ~]# olsnodes -srac1 Activerac2 Activerac3 Activerac4 Active[root@rac2 ~]_12c查看crs状态

解决jupyter notebook无法找到虚拟环境的问题_jupyter没有pytorch环境-程序员宅基地

文章浏览阅读1.3w次,点赞45次,收藏99次。我个人用的是anaconda3的一个python集成环境,自带jupyter notebook,但在我打开jupyter notebook界面后,却找不到对应的虚拟环境,原来是jupyter notebook只是通用于下载anaconda时自带的环境,其他环境要想使用必须手动下载一些库:1.首先进入到自己创建的虚拟环境(pytorch是虚拟环境的名字)activate pytorch2.在该环境下下载这个库conda install ipykernelconda install nb__jupyter没有pytorch环境

国内安装scoop的保姆教程_scoop-cn-程序员宅基地

文章浏览阅读5.2k次,点赞19次,收藏28次。选择scoop纯属意外,也是无奈,因为电脑用户被锁了管理员权限,所有exe安装程序都无法安装,只可以用绿色软件,最后被我发现scoop,省去了到处下载XXX绿色版的烦恼,当然scoop里需要管理员权限的软件也跟我无缘了(譬如everything)。推荐添加dorado这个bucket镜像,里面很多中文软件,但是部分国外的软件下载地址在github,可能无法下载。以上两个是官方bucket的国内镜像,所有软件建议优先从这里下载。上面可以看到很多bucket以及软件数。如果官网登陆不了可以试一下以下方式。_scoop-cn

Element ui colorpicker在Vue中的使用_vue el-color-picker-程序员宅基地

文章浏览阅读4.5k次,点赞2次,收藏3次。首先要有一个color-picker组件 <el-color-picker v-model="headcolor"></el-color-picker>在data里面data() { return {headcolor: ’ #278add ’ //这里可以选择一个默认的颜色} }然后在你想要改变颜色的地方用v-bind绑定就好了,例如:这里的:sty..._vue el-color-picker

迅为iTOP-4412精英版之烧写内核移植后的镜像_exynos 4412 刷机-程序员宅基地

文章浏览阅读640次。基于芯片日益增长的问题,所以内核开发者们引入了新的方法,就是在内核中只保留函数,而数据则不包含,由用户(应用程序员)自己把数据按照规定的格式编写,并放在约定的地方,为了不占用过多的内存,还要求数据以根精简的方式编写。boot启动时,传参给内核,告诉内核设备树文件和kernel的位置,内核启动时根据地址去找到设备树文件,再利用专用的编译器去反编译dtb文件,将dtb还原成数据结构,以供驱动的函数去调用。firmware是三星的一个固件的设备信息,因为找不到固件,所以内核启动不成功。_exynos 4412 刷机

Linux系统配置jdk_linux配置jdk-程序员宅基地

文章浏览阅读2w次,点赞24次,收藏42次。Linux系统配置jdkLinux学习教程,Linux入门教程(超详细)_linux配置jdk

随便推点

matlab(4):特殊符号的输入_matlab微米怎么输入-程序员宅基地

文章浏览阅读3.3k次,点赞5次,收藏19次。xlabel('\delta');ylabel('AUC');具体符号的对照表参照下图:_matlab微米怎么输入

C语言程序设计-文件(打开与关闭、顺序、二进制读写)-程序员宅基地

文章浏览阅读119次。顺序读写指的是按照文件中数据的顺序进行读取或写入。对于文本文件,可以使用fgets、fputs、fscanf、fprintf等函数进行顺序读写。在C语言中,对文件的操作通常涉及文件的打开、读写以及关闭。文件的打开使用fopen函数,而关闭则使用fclose函数。在C语言中,可以使用fread和fwrite函数进行二进制读写。‍ Biaoge 于2024-03-09 23:51发布 阅读量:7 ️文章类型:【 C语言程序设计 】在C语言中,用于打开文件的函数是____,用于关闭文件的函数是____。

Touchdesigner自学笔记之三_touchdesigner怎么让一个模型跟着鼠标移动-程序员宅基地

文章浏览阅读3.4k次,点赞2次,收藏13次。跟随鼠标移动的粒子以grid(SOP)为partical(SOP)的资源模板,调整后连接【Geo组合+point spirit(MAT)】,在连接【feedback组合】适当调整。影响粒子动态的节点【metaball(SOP)+force(SOP)】添加mouse in(CHOP)鼠标位置到metaball的坐标,实现鼠标影响。..._touchdesigner怎么让一个模型跟着鼠标移动

【附源码】基于java的校园停车场管理系统的设计与实现61m0e9计算机毕设SSM_基于java技术的停车场管理系统实现与设计-程序员宅基地

文章浏览阅读178次。项目运行环境配置:Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot + mybatis + Maven +mysql5.7或8.0+html+css+js等等组成,B/S模式 + Maven管理等等。环境需要1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。_基于java技术的停车场管理系统实现与设计

Android系统播放器MediaPlayer源码分析_android多媒体播放源码分析 时序图-程序员宅基地

文章浏览阅读3.5k次。前言对于MediaPlayer播放器的源码分析内容相对来说比较多,会从Java-&amp;amp;gt;Jni-&amp;amp;gt;C/C++慢慢分析,后面会慢慢更新。另外,博客只作为自己学习记录的一种方式,对于其他的不过多的评论。MediaPlayerDemopublic class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal..._android多媒体播放源码分析 时序图

java 数据结构与算法 ——快速排序法-程序员宅基地

文章浏览阅读2.4k次,点赞41次,收藏13次。java 数据结构与算法 ——快速排序法_快速排序法