Java环境下用SM2或者RSA格式生成P10

news/2024/10/19 2:25:00/

背景:
需求,生成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, "admin@39dian.com"); //邮箱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;}@Overridepublic String toString() {return "CertSubject{" +"country='" + country + '\'' +", province='" + province + '\'' +", locality='" + locality + '\'' +", orgName='" + orgName + '\'' +", orgUnit='" + orgUnit + '\'' +", commonName='" + commonName + '\'' +", email='" + email + '\'' +'}';}

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

public void testP10(){  //生成P10String 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();}}
}

http://www.ppmy.cn/news/187298.html

相关文章

使用PowerMock报错java.lang.LinkageError: 装入约束违例

使用PowerMock报错java.lang.LinkageError: 装入约束违例 报错信息&#xff08;限于篇幅有删减&#xff09;&#xff1a;分析解决延伸 报错信息&#xff08;限于篇幅有删减&#xff09;&#xff1a; java.lang.LinkageError: 装入约束违例&#xff1a;装入器“org/powermock/c…

java实现解析x509数字证书DN的各项属性,并校验DN是否符合标准

目录 前言一、使用 javax.naming.ldap.LdapName 类二、使用 org.bouncycastle.asn1.x500.X500Name 类&#xff08;推荐&#xff09;总结 前言 公司产品中一个业务需要解析证书DN的各项属性&#xff0c;并提取某项属性的属性值。之前的实现是将DN作为字符串进行操作&#xff0c…

IBM Power 550

特性和优势 特性 优势 领先的 POWER6 性能 更快速地访问数据并缩短响应时间 以更少的服务器完成更多工作并通过减少服务器和软件许可的数量实现基础架构成本节省 出色的可扩展性和容量 随您的企业的增长轻松扩展系统 利用 PowerVM 版本整合 UNIX …

高性能计算工作站的尴尬

http://blog.daviesliu.net/ 我原来的论文工作进展不下去&#xff0c;调剂到了隔壁实验室做课题&#xff0c;需要用ANSYS做电磁场仿真&#xff0c;分析管道的涡流场。ANSYS对计算机的性能要求比较高&#xff0c;尤其是内存容量&#xff0c;同学要做一个70万自由度的分析&#x…

R语言:作业六(逆变换法生成随机变量;线性同余发生器LCG的编写)

1. 用逆变换法编写产生下述随机变量的程序&#xff1a; X 0 1 p 0.4 0.6 模拟10000次&#xff0c;并确定随机变量的值0的比例。 f <- function(n){{x <- rep(0,n)for (i in 1:n){u <- runif(1)if(u < 0.6) x[i] <- 1else x[i] <- 0}x} } test <- f(1000…

SAML入门

SAML (Security Assertion Markup Language)入门 提到SAML (Security Assertion Markup Language), 很多人都会联想到单点登录SSO。那么Saml到底是什么&#xff0c;它跟sso到底有什么联系&#xff1f;这里给大家分享一下我在读完了saml差不多全部规范之后的一些心得。希望给sa…

深入浅出单点登录---3、基于SAML实现的统一认证

概述 SAML 2.0 用来在安全域中交换身份验证&#xff08;Authentication&#xff09;数据和 授权&#xff08;Authorization&#xff09;数据。SAML 2.0基于 XML协议&#xff0c;使用包含断言&#xff08;Assertions&#xff09;的安全令牌在SAML授权方&#xff08;即身份提供者…

神基X500笔记本系统故障无法启动怎么重装系统?

神基X500笔记本系统故障无法启动怎么重装系统&#xff1f;在使用这款神基X500笔记本的时候&#xff0c;用户遇到了一些系统问题&#xff0c;导致电脑无法正常的开机使用。系统不能启动的时候一般是系统损坏&#xff0c;或者电脑受到攻击。这个情况可以去进行电脑系统的重装&…