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

智能推荐

达梦数据库的导出(备份)、导入_达梦数据库导入导出-程序员宅基地

文章浏览阅读2.9k次,点赞3次,收藏10次。偶尔会用到,记录、分享。1. 数据库导出1.1 切换到dmdba用户su - dmdba1.2 进入达梦数据库安装路径的bin目录,执行导库操作  导出语句:./dexp cwy_init/[email protected]:5236 file=cwy_init.dmp log=cwy_init_exp.log 注释:   cwy_init/init_123..._达梦数据库导入导出

js引入kindeditor富文本编辑器的使用_kindeditor.js-程序员宅基地

文章浏览阅读1.9k次。1. 在官网上下载KindEditor文件,可以删掉不需要要到的jsp,asp,asp.net和php文件夹。接着把文件夹放到项目文件目录下。2. 修改html文件,在页面引入js文件:<script type="text/javascript" src="./kindeditor/kindeditor-all.js"></script><script type="text/javascript" src="./kindeditor/lang/zh-CN.js"_kindeditor.js

STM32学习过程记录11——基于STM32G431CBU6硬件SPI+DMA的高效WS2812B控制方法-程序员宅基地

文章浏览阅读2.3k次,点赞6次,收藏14次。SPI的详情简介不必赘述。假设我们通过SPI发送0xAA,我们的数据线就会变为10101010,通过修改不同的内容,即可修改SPI中0和1的持续时间。比如0xF0即为前半周期为高电平,后半周期为低电平的状态。在SPI的通信模式中,CPHA配置会影响该实验,下图展示了不同采样位置的SPI时序图[1]。CPOL = 0,CPHA = 1:CLK空闲状态 = 低电平,数据在下降沿采样,并在上升沿移出CPOL = 0,CPHA = 0:CLK空闲状态 = 低电平,数据在上升沿采样,并在下降沿移出。_stm32g431cbu6

计算机网络-数据链路层_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输-程序员宅基地

文章浏览阅读1.2k次,点赞2次,收藏8次。数据链路层习题自测问题1.数据链路(即逻辑链路)与链路(即物理链路)有何区别?“电路接通了”与”数据链路接通了”的区别何在?2.数据链路层中的链路控制包括哪些功能?试讨论数据链路层做成可靠的链路层有哪些优点和缺点。3.网络适配器的作用是什么?网络适配器工作在哪一层?4.数据链路层的三个基本问题(帧定界、透明传输和差错检测)为什么都必须加以解决?5.如果在数据链路层不进行帧定界,会发生什么问题?6.PPP协议的主要特点是什么?为什么PPP不使用帧的编号?PPP适用于什么情况?为什么PPP协议不_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输

软件测试工程师移民加拿大_无证移民,未受过软件工程师的教育(第1部分)-程序员宅基地

文章浏览阅读587次。软件测试工程师移民加拿大 无证移民,未受过软件工程师的教育(第1部分) (Undocumented Immigrant With No Education to Software Engineer(Part 1))Before I start, I want you to please bear with me on the way I write, I have very little gen...

深度神经网络在训练初期的“梯度消失”或“梯度爆炸”的问题解决:数据标准化(Data Standardization),权重初始化(Weight Initialization),Dropout正则化等_在人工神经网络研究的初始阶段,辛顿针对训练过程中常出现的梯度消失现象, 提供相-程序员宅基地

文章浏览阅读101次。1986年,深度学习(Deep Learning)火爆,它提出了一个名为“深层神经网络”(Deep Neural Networks)的新型机器学习模型。随后几年,神经网络在图像、文本等领域取得了惊艳成果。但是,随着深度学习的应用范围越来越广泛,神经网络在遇到新的任务时出现性能下降或退化的问题。这主要是由于深度神经网络在训练初期面临着“梯度消失”或“梯度爆炸”的问题。_在人工神经网络研究的初始阶段,辛顿针对训练过程中常出现的梯度消失现象, 提供相

随便推点

C++如何做字符串分割(5种方法)_c++ 字符串分割-程序员宅基地

文章浏览阅读10w+次,点赞93次,收藏352次。1、用strtok函数进行字符串分割原型: char *strtok(char *str, const char *delim);功能:分解字符串为一组字符串。参数说明:str为要分解的字符串,delim为分隔符字符串。返回值:从str开头开始的一个个被分割的串。当没有被分割的串时则返回NULL。其它:strtok函数线程不安全,可以使用strtok_r替代。示例://借助strtok实现split#include <string.h>#include <stdio.h&_c++ 字符串分割

2013第四届蓝桥杯 C/C++本科A组 真题答案解析_2013年第四届c a组蓝桥杯省赛真题解答-程序员宅基地

文章浏览阅读2.3k次。1 .高斯日记 大数学家高斯有个好习惯:无论如何都要记日记。他的日记有个与众不同的地方,他从不注明年月日,而是用一个整数代替,比如:4210后来人们知道,那个整数就是日期,它表示那一天是高斯出生后的第几天。这或许也是个好习惯,它时时刻刻提醒着主人:日子又过去一天,还有多少时光可以用于浪费呢?高斯出生于:1777年4月30日。在高斯发现的一个重要定理的日记_2013年第四届c a组蓝桥杯省赛真题解答

基于供需算法优化的核极限学习机(KELM)分类算法-程序员宅基地

文章浏览阅读851次,点赞17次,收藏22次。摘要:本文利用供需算法对核极限学习机(KELM)进行优化,并用于分类。

metasploitable2渗透测试_metasploitable2怎么进入-程序员宅基地

文章浏览阅读1.1k次。一、系统弱密码登录1、在kali上执行命令行telnet 192.168.26.1292、Login和password都输入msfadmin3、登录成功,进入系统4、测试如下:二、MySQL弱密码登录:1、在kali上执行mysql –h 192.168.26.129 –u root2、登录成功,进入MySQL系统3、测试效果:三、PostgreSQL弱密码登录1、在Kali上执行psql -h 192.168.26.129 –U post..._metasploitable2怎么进入

Python学习之路:从入门到精通的指南_python人工智能开发从入门到精通pdf-程序员宅基地

文章浏览阅读257次。本文将为初学者提供Python学习的详细指南,从Python的历史、基础语法和数据类型到面向对象编程、模块和库的使用。通过本文,您将能够掌握Python编程的核心概念,为今后的编程学习和实践打下坚实基础。_python人工智能开发从入门到精通pdf

vscode打开markdown文件 不显示图片 预览markdown文件_vscodemarkdown图片无法显示-程序员宅基地

文章浏览阅读3.2k次,点赞3次,收藏4次。vscode打开markdown文件 不显示图片 预览markdown文件_vscodemarkdown图片无法显示

推荐文章

热门文章

相关标签