Java 生成数字证书系列.docx
《Java 生成数字证书系列.docx》由会员分享,可在线阅读,更多相关《Java 生成数字证书系列.docx(25页珍藏版)》请在冰豆网上搜索。
![Java 生成数字证书系列.docx](https://file1.bdocx.com/fileroot1/2023-4/17/181c8fc3-e57d-4679-8de8-a72584fc669b/181c8fc3-e57d-4679-8de8-a72584fc669b1.gif)
Java生成数字证书系列
(一)了解数字证书
最近的工作一直围绕着数字证书,对于CA证书的了解还是多少有一点的,只不过没有那么深入,现在要用到这方面的东西,显然还是有点欠缺,那么从这篇开始,我就将我自己的学习、工作历程跟大家一同分享,希望对想了解CA证书的童鞋有所帮助吧。
很显然,这篇文章大部分都是理论介绍,后续会有相关的一些实例。
不喜欢看理论的童鞋,可以直接略过此章,直接看后续的文章。
1.概要
这篇文章,我主要是想谈一下CA证书的工作原理,数字签名,证书格式等几个比较重要的概念。
因为在后续的文章中,都会用到这几个概念,而且,想要自己做证书,这几个概念是必须要弄懂的。
2.什么是数字证书
数字证书就是互联网通讯中标志通讯各方身份信息的一串数字,提供了一种在Internet上验证通信实体身份的方式,其作用类似于司机的驾驶执照或日常生活中的身份证。
它是由一个由权威机构——CA机构,又称为证书授权(CertificateAuthority)中心发行的,人们可以在网上用它来识别对方的身份。
数字证书是一个经证书授权中心数字签名的包含公开密钥拥有者信息以及公开密钥的文件。
最简单的证书包含一个公开密钥、名称以及证书授权中心的数字签名。
数字证书还有一个重要的特征就是只在特定的时间段内有效。
3.原理
数字证书里存有很多数字和英文,当使用数字证书进行身份认证时,它将随机生成128位的身份码,每份数字证书都能生成相应但每次都不可能相同的数码,从而保证数据传输的保密性,即相当于生成一个复杂的密码。
数字证书绑定了公钥及其持有者的真实身份,它类似于现实生活中的居民身份证,所不同的是数字证书不再是纸质的证照,而是一段含有证书持有者身份信息并经过认证中心审核签发的电子数据,可以更加方便灵活地运用在电子商务和电子政务中。
4.颁发
数字证书颁发过程一般为:
用户首先产生自己的密钥对,并将公共密钥及部分个人身份信息传送给认证中心。
认证中心在核实身份后,将执行一些必要的步骤,以确信请求确实由用户发送而来,然后,认证中心将发给用户一个数字证书,该证书内包含用户的个人信息和他的公钥信息,同时还附有认证中心的签名信息。
用户就可以使用自己的数字证书进行相关的各种活动。
数字证书由独立的证书发行机构发布。
数字证书各不相同,每种证书可提供不同级别的可信度。
可以从证书发行机构获得您自己的数字证书。
5.工作原理
数字证书采用公钥体制,即利用一对互相匹配的密钥进行加密、解密。
每个用户自己设定一把特定的仅为本人所知的私有密钥(私钥),用它进行解密和签名;同时设定一把公共密钥(公钥)并由本人公开,为一组用户所共享,用于加密和验证签名。
当发送一份保密文件时,发送方使用接收方的公钥对数据加密,而接收方则使用自己的私钥解密,这样信息就可以安全无误地到达目的地了。
通过数字的手段保证加密过程是一个不可逆过程,即只有用私有密钥才能解密。
在公开密钥密码体制中,常用的一种是RSA体制。
其数学原理是将一个大数分解成两个质数的乘积,加密和解密用的是两个不同的密钥。
即使已知明文、密文和加密密钥(公开密钥),想要推导出解密密钥(私密密钥),在计算上是不可能的。
按现在的计算机技术水平,要破解目前采用的1024位RSA密钥,需要上千年的计算时间。
公开密钥技术解决了密钥发布的管理问题,商户可以公开其公开密钥,而保留其私有密钥。
购物者可以用人人皆知的公开密钥对发送的信息进行加密,安全地传送给商户,然后由商户用自己的私有密钥进行解密。
6.数字签名
用户也可以采用自己的私钥对信息加以处理,由于密钥仅为本人所有,这样就产生了别人无法生成的文件,也就形成了数字签名。
采用数字签名,能够确认以下两点:
▪保证信息是由签名者自己签名发送的,签名者不能否认或难以否认。
▪保证信息自签发后到收到为止未曾作过任何修改,签发的文件是真实文件。
将报文按双方约定的HASH算法计算得到一个固定位数的报文摘要。
在数学上保证:
只要改动报文中任何一位,重新计算出的报文摘要值就会与原先的值不相符。
这样就保证了报文的不可更改性。
将该报文摘要值用发送者的私人密钥加密(对明文进行解密完全没问题,会得出一个不可读的“明文”),然后连同原报文一起发送给接收者,而“加密”后的报文即称数字签名。
接收方收到数字签名后,用同样的HASH算法对原报文计算出报文摘要值,然后与用发送者的公开密钥对数字签名进行解密(原先已经把签名加密了,现在再解密就能还原)得到的报文摘要值相比较。
如相等则说明报文确实来自所称的发送者。
由于只有拥有私钥的签名者能通过“解密”摘要生成签名,因此具有安全和不可抵赖性。
那为什么是对报文摘要进行加密,而不是对原报文进行加密呢?
这是因为RSA加解密非常耗时,被加密的报文越大,耗得时间越多,因此聪明的人类对其摘要进行加密,(因为报文摘要是要比原报文小得多),仍然能够起到同样的作用。
这是为什么多了个报文摘要。
7.证书格式
目前数字证书的格式普遍采用的是X.509V3国际标准,一个标准的X.509数字证书包含以下一些内容:
▪证书的版本信息;
▪证书的序列号,每个证书都有一个唯一的证书序列号;
▪证书所使用的签名算法;
▪证书的发行机构名称,命名规则一般采用X.500格式;
▪证书的有效期,现在通用的证书一般采用UTC时间格式,它的计时范围为1950-2049;
▪证书所有人的名称,命名规则一般采用X.500格式;
▪证书所有人的公开密钥;
▪证书发行者对证书的签名。
作为文件形式存在的证书一般有这几种格式:
带有私钥的证书由PublicKeyCryptographyStandards#12,PKCS#12标准定义,包含了公钥和私钥的二进制格式的证书形式,以pfx作为证书文件后缀名。
二进制编码的证书中没有私钥,DER编码二进制格式的证书文件,以cer作为证书文件后缀名。
Base64编码的证书证书中没有私钥,BASE64编码格式的证书文件,也是以cer作为证书文件后缀名。
由此可看出,只有pfx格式的数字证书是包含有私钥的,cer格式的数字证书里面只有公钥没有私钥。
当然,我们经常使用的数字证书就是cer格式的,比如,12306颁发的数字证书,就是这种格式的,购票之前,需要在自己的电脑上安装证书,以确保我们的客户端可以与正确的服务器进行通信。
当然,正如上面所说,CA证书还是可以自己生成的,只不过自己生成的证书对于操作系统来说,是识别不了的,因为操作系统中并没有存在生成证书的发行机构。
不过,这并不妨碍我们正常的使用证书。
(二)剖析数字证书
上一篇介绍了一下CA证书的几个相关概念,这几个概念还是很重要的,目的在于了解数字证书,以及其的工作原理。
这篇文章主要是对CA证书进行剖析,讲一下证书的基本构成,这对于生成正确的、可以访问的证书是必不可少的。
8.构成
先看一下证书到底是什么,在Windows下查看证书时(这里以cer为例),界面是这样的。
常规选项卡里,主要介绍了证书信息,颁发者,和有效日期等。
而详细信息选项卡中,包含的信息是比较多的,他们都是以一种Key—Value的形式存在的,其中字段包括:
版本、序列号、签名算法、颁发者、有效期、公钥、指纹等等。
在上一篇文章中也有提到。
下面我们就详细的来看看这些字段到底是干什么用的。
9.详细信息
1)版本(Version)
很明显,这个是证书的版本号,不同版本的证书格式是不同的。
这里,我用的是V3版本。
2)序列号(Serial Number)
证书序列号,同一身份验证机构签发的证书序列号是唯一的。
3)签名算法(Signature algorithm)
签名算法,指的是这个数字证书中的数字签名所使用的加密算法,可以通过根证书中的公钥对这个证书中的指纹进行解密。
4)颁发者(Issuer)
证书发布机构,指出这个证书是哪个公司创建的,这是哪个CA中心的证书。
当然,如果是你自己公司生成的证书,那么颁发者就是你自己的公司了。
5)有效期(Validfromto)
证书的生成日期,以及证书使用的截至日期。
证书有效期失效之后,在认证服务器中会进行校验,校验失败后,重新生成新证书或者是其他的操作。
这个依据证书的发布机构而定。
6)使用者(Subject)
这个证书是发布给谁的,或者说是证书的所有者,一般是某个人或者某个公司的名称、机构的名称、公司网站的网址等。
当然,如果是根证书的话,那么,使用者就是自己的公司了。
7)公钥(Public key)
证书的公钥,主要是用来对消息进行加密的,这个证书的公钥是2048位的,他的值可以在对话框中看到,是很长的一段十六进制数。
8)指纹及指纹算法(Thumbprint、Thumbprint algorithm)
指纹以及指纹算法,在证书发布的时候,发布机构会根据指纹算法先计算出整个证书的hash值,并使用证书发布机构的私钥对其进行签名构成一个指纹,并将指纹与该证书放在一起。
在生成证书的时候,需要自己设定颁发者、有效期、使用者等等。
版本、签名算法、以及证书公钥等都是要设定的,否则生成的证书是无法正常使用的。
(三)生成数字证书
前两篇把基本的概念和构成都大致的说了一下,今天这篇文章,主要是讲一下,如何使用Java代码生成CA证书,以及在生成证书的时候,需要设置的一些属性。
这里使用的是Java的api,以及第三方的一个组件——BC,(BouncyCastle)。
稍微介绍一下BC,BouncyCastle是一种用于Java平台的开放源码的轻量级密码术包。
它支持大量的密码术算法,并提供JCE1.2.1的实现。
而我们将要使用的就是非常常用的非对称算法RSA加密算法。
下面我们来看一下具体的代码。
CAConfig(配置接口)
public interface CAConfig {
String CA_C = "CN";
String CA_ST = "BJ";
String CA_L = "BJ";
String CA_O = "SICCA";
String CA_ROOT_ISSUER="C=CN,ST=BJ,L=BJ,O=SICCA,OU=SC,CN=SICCA";
String CA_DEFAULT_SUBJECT="C=CN,ST=BJ,L=BJ,O=SICCA,OU=SC,CN=";
String CA_SHA="SHA256WithRSAEncryption";
}
BaseCert(证书类)
import com.cacss.jsceu.context.CAConfig;
import com.cacss.jsceu.util.CertUtil;
import com.cacss.jsceu.util.DateUtil;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.x509.X509V3CertificateGenerator;
import javax.security.auth.x500.X500Principal;
import java.security.*;
import java.security.cert.X509Certificate;
@SuppressWarnings("all")
public class BaseCert {
static {
Security.addProvider(new BouncyCastleProvider());
}
protected static KeyPairGenerator kpg = null;
public BaseCert() {
try {
// 采用 RSA 非对称算法加密
kpg = KeyPairGenerator.getInstance("RSA");
// 初始化为 1023 位
kpg.initialize(1024);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
/**
* 生成 X509 证书
* @param user
* @return
*/
public X509Certificate generateCert(String user) {
X509Certificate cert = null;
try {
KeyPair keyPair = this.kpg.generateKeyPair();
// 公钥
PublicKey pubKey = keyPair.getPublic();
// 私钥
PrivateKey priKey = keyPair.getPrivate();
X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
// 设置序列号
certGen.setSerialNumber(CertUtil.getNextSerialNumber());
// 设置颁发者
certGen.setIssuerDN(new X500Principal(CAConfig.CA_ROOT_ISSUER));
// 设置有效期
certGen.setNotBefore(DateUtil.getCurrDate());
certGen.setNotAfter(DateUtil.getNextYear());
// 设置使用者
certGen.setSubjectDN(new X500Principal(CAConfig.CA_DEFAULT_SUBJECT + user));
// 公钥
certGen.setPublicKey(pubKey);
// 签名算法
certGen.setSignatureAlgorithm(CAConfig.CA_SHA);
cert = certGen.generateX509Certificate(priKey, "BC");
} catch (Exception e) {
System.out.println(e.getClass() + e.getMessage());
}
return cert;
}
}
GenerateCa(测试类)
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
public class GenerateCa {
private static String certPath = "d:
/lee.cer";
public static void main(String[] args) {
BaseCert baseCert = new BaseCert();
X509Certificate cert = baseCert.generateCert("Lee");
System.out.println(cert.toString());
// 导出为 cer 证书
try {
FileOutputStream fos = new FileOutputStream(certPath);
fos.write(cert.getEncoded());
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (CertificateEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
效果图
下面是生成的证书,以及导出为cer格式的证书。
控制台打印
[plain] viewplain copy
Microsoft YaHei;font-size:
12px;">Version:
3
SerialNumber:
1419920991041
IssuerDN:
CN=SICCA,OU=SC,O=SICCA,L=BJ,ST=BJ,C=CN
Start Date:
Tue Dec 30 14:
29:
51 CST 2014
Final Date:
Wed Dec 30 14:
29:
51 CST 2015
SubjectDN:
CN=Lee,OU=SC,O=SICCA,L=BJ,ST=BJ,C=CN
Public Key:
RSA Public Key
modulus:
a9d5cc7de42c9afb468d7eb493bc69721443c0734edcb170ff13e062cc1b8d12e92edd347403d702288c5094ef2d0b2e811e0ee779a5e0a0cb7d5c75f30c5063eaa87aae7ba06bb3cf6ce6b0a5b0cd0cc2756255aff91fb09266b5dbbb6af491b5313947529d6a1fc30b9407ba1059bae909226c34e196b53c757a5826ffe147
public exponent:
10001
Signature Algorithm:
SHA256WITHRSA
Signature:
8b8b725292147e9dbe8054ed99453386e1e6ba3d
8248b31a2dcb477900005207c039898dd2af4675
310471d3097f1aa3b6ff7e197f2ccf292dcd8ad1
ce6f19204a54a2dc8fe1fe118eaf81004ad06c7c
a04631f8a376272ddda5d4ae4980a1e2a3ee444e
a6b80a8532358f5e1a1b82c6a54ea2e36a02d3ea
8758c799df308d78
cer证书
结束语
我这里使用的是第三方的组件BC包进行加密的,采用的是RSA的加密算法,证书中的密钥长度为1024位,当然,你也可以设置为2048位,根据你自己的需要选择即可。
不过,需要说明的一点是,在使用公(私)钥加密的时候,需要加密的字符串的长度是有要求的,以1024位的密钥长度来说,那么需要加密的字符串的长度不能超过117个字符,计算公式:
1024/8-11=117。
所以,在加密长字符串的时候,就需要采用分片加密的方法了,这一点需要注意,当然,后续讲加密的文章中,我也会说明这一点。
(四)生成数字证书(续)
上一篇文章讲到了Java生成数字证书,使用的是第三方的组件BC。
这篇文章也是介绍生成数字证书的,只不过与上一篇不同的是,这篇采用的是KeyStore的存储方式,导出的证书文件格式为pfx,这种格式的证书不仅包含有公钥,还包含有私钥。
从证书中就可以读取到私钥。
正文
废话不多说,直接上内容。
与上一篇相同,这里也是使用的BouncyCastle提供的组件,不同的是,这里的证书采用的是公钥加密技术12号标准生成的,简写PKCS12。
具体内容这里就不再详细的介绍了,有需要的童鞋们直接Google就行了。
下面直接上代码。
PKCS12Test(测试证书类)
[java] viewplain copy
Comic Sans MS;font-size:
12px;">package com.cacss.jsceu.core;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.x509.X509V3CertificateGenerator;
import javax.security.auth.x500.X500Principal;
import java.io.FileOutputStream;
import java.io.IOException;
import java.ma