最近刚尝试实现java RSA证书生成,网上倒是有现成但变成自己的还有一段距离,首先记录一下以备自己以后查看。
第一部分:首先说明对证书内容的处理,做到能够知道证书的结构,能够替换证书的公钥以及相应的签名达到自签的目的。PS:主要是整理代码所用到的语句,因此将所有的代码罗列到一起整理。
File rootfile = new File("RSARoot.cer");
File userfile = new File("RSAUser.cer");
FileInputStream frootin = new FileInputStream(rootfile);
FileInputStream fuserin = new FileInputStream(userfile);
byte[] rootcertencoded=Streams.readAll(frootin);
byte[] usercertencoded=Streams.readAll(fuserin);
//得到X509CertificateStructure 这里只写明得到根证书的
ASN1Sequence seq=ASN1Sequence.getInstance(ASN1Object.fromByteArray(rootcertencoded)); //写入证书数据的时候是DEREncode形式
X509CertificateStructure X509cert=new X509CertificateStructure(seq);
//从X509CertificationStructrue结构中得到根证书公钥信息, X509CertificateStructure——>证书体TBSCertificateStruct——>公钥信息
TBSCertificateStructure tbscert=X509cert.getTBSCertificate();
SubjectPublicKeyInfo pubkeyInfo=tbscert.getSubjectPublicKeyInfo();
DERBitString pubkeybit=pubkeyInfo.getPublicKeyData();
byte[] pubkey = pubkeybit.getBytes[]; //可以通过System.out.println(new String (Hex.encode(pubkey)));格式输出
//271位长度的公钥中提取出256位(nn)与(e)10001,其实结合放入的时候编码规则理解更好
ASN1StreamParser aIn = new ASN1StreamParser(pubkey);
ASN1SequenceParser pubseq = (ASN1SequenceParser)aIn.readObject();
DERInteger derbN= DERInteger.getInstance(pubseq.readObject()); //公钥写入就是DERInteger的形式所以。。。
DERInteger derbE= DERInteger.getInstance(pubseq.readObject()); //这种内部代码实现知道相对应的数据值
BigInteger bN = derbN.getValue();
BigInteger bE = derbE.getValue();
//得到证书体的hash值,验证最后明文是否正确的
byte[] CertTBS=x509cert.getTBSCertificate().getDEREncoded();
//System.out.println("=="+new String(Hex.encode(CertTBS)));
java.security.MessageDigest md = java.security.MessageDigest.getInstance( "SHA-256" );
md.update(CertTBS);
byte hashvalue[] = md.digest();
System.out.println("hash value is");
System.out.println(new String(Hex.encode(hashvalue)));
//得到签名值,是从X509CertificateStruct得到
DERBitString certsig=x509cert.getSignature();
BigInteger bsign = new BigInteger(1,certsig.getBytes());
System.out.println("Signature is");
System.out.println(bsign.toString(16));
//使用公钥验证签名
BigInteger Message=bsign.modPow(bE, bN);
输出形式为256byte(2048位)的(1fffff。。。。。。。。+hash)值
第二部分:生成RSA证书
方法一:X509V3CertificateGenerator 这种方法不需要自己进行签名,但有一个问题就是不鞥自己对hash值进行填充签名
Security.addProvider(new BouncyCastleProvider());
String issue = "C=CN,O=sdk,ST=wuhan,L=wuhan,CN=root,EmailAddress=**";
String subject ="C=CN,O=sdk,ST=wuhan,L=wuhan,CN=root,EmailAddress=**";
RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(new BigInteger("",16), new BigInteger("10001",16)); //(n,e)
RSAPrivateKeySpec privateKeySpec = new RSAPrivateKeySpec(new BigInteger("",16), new BigInteger("",16)); // (n,privatekey)
KeyFactory fact;
fact = KeyFactory.getInstance("RSA", "BC");
PublicKey publicKey = fact.generatePublic(publicKeySpec); //publickey中包含加密信息RSA
PrivateKey privateKey = fact.generatePrivate(privateKeySpec);
//设置证书信息生成证书
X509Certificate cert = null;
X509V3CertificateGenerator v = new X509V3CertificateGenerator();
//设置证书扩展信息
KeyUsage keyUsage = new KeyUsage(KeyUsage.digitalSignature|KeyUsage.dataEncipherment);
xeg.addExtension(X509Extensions.KeyUsage, false, keyUsage);
xeg.addExtension(X509Extensions.BasicConstraints, false, new BasicConstraints(true));
xeg.addExtension(X509Extensions.SubjectKeyIdentifier, false, new DEROctetString(digest));
X509Extensions xes = xeg.generate();
v.setExtensions(xes);
v.setIssuerDN(new X509Principal(issuer));
v.setSubjectDN(new X509Principal(subject));
v.setSerialNumber(serial);
v.setNotBefore(notBefore);
v.setNotAfter(notAfter);
KeyFactory fact;
fact = KeyFactory.getInstance("RSA", "BC");
PublicKey publicKey = fact.generatePublic(publicKeySpec);
v.setPublicKey(publicKey);
v.setSignatureAlgorithm("SHA256WithRSAEncryption"); //这个函数拿不到证书主体部分
cert = v.generateX509Certificate(privKey,"BC");
//将证书写出
byte[] buf = cert.getEncoded();
FileOutputStream fOut = new FileOutputStream("RSARoot.cer");
fOut.write(buf);
fOut.close();
System.out.println("creat root cert over.........");
方法二:V3TBSCertificateGenerator可以自己对消息进行填充,主要用到的也是这个
1. 证书参数
Security.addProvider(new BouncyCastleProvider());
String issue = "C=CN,O=sdk,ST=wuhan,L=wuhan,CN=root,EmailAddress=**";
String subject ="C=CN,O=sdk,ST=wuhan,L=wuhan,CN=root,EmailAddress=**";
RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(new BigInteger("",16), new BigInteger("10001",16)); //(n,e)
RSAPrivateKeySpec privateKeySpec = new RSAPrivateKeySpec(new BigInteger("",16), new BigInteger("",16)); // (n,privatekey)
KeyFactory fact;
fact = KeyFactory.getInstance("RSA", "BC");
PublicKey publicKey = fact.generatePublic(publicKeySpec); //publickey中包含加密信息RSA
PrivateKey privateKey = fact.generatePrivate(privateKeySpec);
//设置签名算法 sha256withRSA OID1.2.840.113549.1.1.11
DERObjectIdentifier sigOID = new DERObjectIdentifier("1.2.840.113549.1.1.11");
AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(sigOID , new DERNull());
2.设置证书信息
V3TBSCertificateGenerator v3 = new V3TBSCertificateGenerator();
X509ExtensionsGenerator xeg = new X509ExtensionsGenerator();
//// //有效使用时间
KeyUsage keyUsage = new KeyUsage(KeyUsage.digitalSignature|KeyUsage.dataEncipherment);
xeg.addExtension(X509Extensions.KeyUsage, false, keyUsage);
xeg.addExtension(X509Extensions.BasicConstraints, false, new BasicConstraints(true));
xeg.addExtension(X509Extensions.SubjectKeyIdentifier, false, new DEROctetString(digest));
X509Extensions xes = xeg.generate();
v.setExtensions(xes);
v3.setIssuer(issuer);
v3.setSubject(subject);
v3.setSerialNumber(new DERInteger(serial));
v3.setStartDate(new DERUTCTime(notBefore));
v3.setEndDate(new DERUTCTime(notAfter));
v3.setSignature(algorithmIdentifier);
//特别注意一下这个设置publickeyinfo方法,如果直接这样写的话,证书产生的RSApublicke>271个byte,多一个RSA算法信息,由于publickey中
//本身含有RSA算法信息,因此在验证提取公钥的时候需要注意一下
DERObjectIdentifier sigOID = new DERObjectIdentifier("1.2.840.113549.1.1.1"); //RSA的OID
AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(sigOID, new DERNull());
SubjectPublicKeyInfo publicKeyInfo1 = new SubjectPublicKeyInfo(algorithmIdentifier, publicKey.getEncoded());
v3.setSubjectPublicKeyInfo(publicKeyInfo1);
//可以直接作如下处理将RSA(n,e)公钥对放入,产生271位公钥信息,则可以直接用上面的证书提取公钥的方法将n,e提出
byte[] nn= publicKeySpec.getModulus().toByteArray();
// //如果不是1 就系统自动进行添加字段00 ,不用自己另外添加?最后的公钥长度为271 不添加也是可以的??<271byte就能够正确读出
//公钥值
byte[] publikey= new byte[257]; pubkey[0]= 0x00; //n
System.arraycopy(pubkey1, 0x00, pubkey, 0x01, 256);
//RSA OID 1.2.840.113549.1.1.1
byte[] ee= publicKeySpec.getPublicExponent().toByteArray();
DERObjectIdentifier sigOID = new DERObjectIdentifier("1.2.840.113549.1.1.1");
AlgorithmIdentifier algorithmIdentifier1 = new AlgorithmIdentifier(sigOID , new DERNull());
//什么时候用DERInteger,什么时候用DERBitString下面这些是正确的
DERInteger pub = new DERInteger(nn);
DERInteger exp= new DERInteger(ee);
ASN1EncodableVector vector= new ASN1EncodableVector();
vector.add(pubBitString);
vector.add(expBitString);
DERSequence sequence = new DERSequence(vector);
SubjectPublicKeyInfo publicKeyInfo2 = new SubjectPublicKeyInfo(algorithmIdentifier1 ,sequence);
v3.setSubjectPublicKeyInfo(publicKeyInfo2);
3.进行hash签名
ASN1EncodableVector vector= new ASN1EncodableVector();
ASN1EncodableVector vector = new ASN1EncodableVector();
vector.add(v3.generateTBSCertificate());
vector.add(algorithmIdentifier);
byte[] certBlock = v3.genrerateTBSCertificate.getDEREncoded();
byte[] signature = null;
java.security.MessageDigest = java.security.MessageDigest.getInstance( "SHA-256" );
md.update(certBlock);
byte[] hashvalue = md.digest();
System.out.println("hash value is");
System.out.println(new String(Hex.encode(hashvalue)));
//对hash值进行填充,占2048位,这样签名出来的数据也是2048位的(这里的2048位指的是存储占用的空间)
String add1="1fffffffff...... "
// System.out.println(Hex.decode(add1).length); //这里为什么不行,长度不是2的整数倍,不能计算
String Hash=add1+( new String(Hex.encode(hashvalue)));
System.out.println("待签名值:");
System.out.println(Hash);
BigInteger Mm=new BigInteger(Hash,16);
//签名证书的公私钥对
BigInteger nn=new BigInteger(" ",16);
BigInteger privatekey=new BigInteger("",16);
//进行签名
BigInteger signInfo=Mm.modPow(privatekey, nn);
signature = result.toByteArray();
//如果首位为1则需要进行下面这种操作!
//注意这种bytetoArray()方法是以反码形式存储的,因此如果最高为为1,则会多出8位(0x00)257byte
//System.arraycopy(signInfo, 0x01, signInfo1 , 0x00, 0x100);
vector.add(new DERBitString(signInfo));
X509CertificateStructure cert1=new X509CertificateStructure(new DERSequence(vector));
byte[] buf = cert1.getEncoded();
FileOutputStream fOut = new FileOutputStream("RSARoot.cer");
fOut.write(buf);
fOut.close();
System.out.println("creat root cert over.........");
基本的RSA证书生成都语句在里,相应的数据操作自己再做对应的研究。
阅读(1201) | 评论(0) | 转发(0) |