Java安全之数字证书
在前面说到。消息摘要用于验证数据完整性,对称与非对称加密用于保证数据保密性,数据签名用于数据的抗否认性,于是集这些安全手段于一身的终极武器--数字证书出现了。数字证书具备了加密/解密的必要信息。包括签名算法,可用于网络数据加密/解密交互。标识网络用户(计算机)身份。数据证书为公布公钥提供了一种简便途径,成为加密算法以及公钥的载体。
数字证书有多种文件编码格式,主要包括CER编码、DER编码等:
a.CER(Canonical Encoding Rules。规范编码格式)。是数字证书的一种编码格式。它是BER(Basic Encoding Rules,基本编码格式)的一个变种,比BER规定得更加严格。
b.DER(Distinguished Encoding Rule, 卓越编码格式),相同是BER的一个变种,与CER不的同之处在于:DER使用定长模式。而CER使用变长模式。
c.PKCS(Public-Key Cryptography Standards,公钥加密标准),由RSA实验室和其他安全系统开发商为促进公钥password发展而制定的一系列标准。
当中CER、DER格式证书都符合公钥基础设施(PKI)制定的X509国际标准(X.509标准),统称为X509格式证书。PKCS至今共公布过15个标准。经常使用标准包括PKCS#7、PKCS#10和PKCS#12。PKCS#7为password消息语法标准,文件名称后缀一般为:.p7b、.p7c、.spc;PKCS10#为证书请求语法标准,故证书请求文件採用该格式,文件名称后缀一般为:.p10、.csr;PKCS#12为个人信息交换语法标准。故个人信息证书採用该格式,文件名称后缀一般为:.p12、.pfx。
值得一提的是尽管PKCS#12为一种证书格式。但在Java中,个人更认为是一种KeyStore格式。由于PKCS#12格式文件里既能够存储证书,还能够存储私钥,而一般意义说来,证书是不包括私钥信息的。
一、数字证书详细包括了哪些信息,我们以12306的数字证书为例:
从上面的截图能够看到,一张数字证书中包括了非常多信息,主要有,版本、序列号、签名算法、签名哈希算法、颁发者、有效期、使用者、公钥、指纹算法、指纹以及一些数字证书的扩展属性信息。
二、证书怎样获取
假如你的公司要上线一个购物站点。那么肯定会使用到https协议,也就肯定会使用到数字证书,那么数字证书从哪里来?是自己生成吗?当然不是,正确的做法是。公司生成一个证书请求文件,再把证书请求文件提交给证书认证机构。然后证书认证机构使用其根证书再依据证书请求文件里的信息为您生成受信任证书。也就是颁发证书,当然要让证书认证机构为您公司颁发证书这是须要money的。可是有些时候也能够自己创建证书。仅仅只是这时候的证书颁者是你自己,仅仅是别人信息你自己的根证书,证书也能够照常使用。
三、证书是否合法(受信任)
说到证书是否受信任的问题就得先知道一条规则:受信任的证书所颁发的证书也是受信任的。那么先有鸡还是先有蛋的问题来了,第一个受信任的证书是从哪里来的。为了解决问题就引出了根证书,根证书是自己颁发给自己的证书,仅仅要信任了根证书,这样由根证书颁发的证书也就能够被信任。所以证书颁发事实上是一种树形结构,根证书能够颁发一级证书。一级证书在同意的情况下也能够为其他用户颁发二级证书。以Windows, IE为例(IE共用Windows系统中的证书),在Windows安装好后,系统就已经信任了一些权威证书认证机构的根证书,当然你也能够导入你自己制作的根证书。
四、何为证书颁发
证书颁发是个专业术语,事实上就是使用证书颁发者的私钥对证书使用者的证书进行签名。并设置使用者证书的颁发者,证书普通情况下须要由权威的证书认证机构颁发。其原就是对证书进行签名使用的是私钥,私钥仅仅有颁发机构才有。
以下就看看在Java中是怎样完毕对证书的各种操作的:
package com.xtayfjpk.security.certificate; import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.math.BigInteger;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.RSAPublicKeySpec;
import java.util.Date;
import java.util.HashMap;
import java.util.Map; import javax.security.auth.x500.X500Principal; import org.bouncycastle.asn1.DERBMPString;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.Certificate;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.RSAKeyParameters;
import org.bouncycastle.crypto.util.PrivateKeyFactory;
import org.bouncycastle.crypto.util.PublicKeyFactory;
import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory;
import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
import org.bouncycastle.operator.bc.BcRSAContentSignerBuilder;
import org.bouncycastle.pkcs.PKCS10CertificationRequest;
import org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder;
import org.bouncycastle.x509.X509V3CertificateGenerator;
import org.junit.Before;
import org.junit.Test; /**
* issuer 证书颁发者
* subject 证书使用者
*
* DN:Distinguish Name
* 格式:CN=姓名,OU=组织单位名称,O=组织名称,L=城市或区域名称,ST=省/市/自治区名称,C=国家双字母
*
*/
@SuppressWarnings("deprecation")
public class CertifacateGenerateTest { private static final String KEY_PAIR_ALG = "RSA";
private static final String SIG_ALG = "SHA1withRSA";
private static final String DN_ZHANGSAN = "CN=zhangsan,OU=development,O=Huawei,L=ShenZhen,ST=GuangDong,C=CN";
private static final String DN_CA = "CN=Kingyea,OU=Kingyea,O=Kingyea,L=GuangZou,ST=GuangDong,C=CN";
private static Map<String, String> algorithmMap = new HashMap<>(); static {
/**
* 算法名称与算法标识符映射
*/
algorithmMap.put("1.2.840.113549.1.1.5", SIG_ALG);
algorithmMap.put("1.2.840.113549.1.1.1", KEY_PAIR_ALG);
} @Before
public void before() {
//注冊BC Provider,由于有些关于证书的操作使用到了BouncyCastle这个第三方库就顺便注冊上了,事实上不注冊也行
Provider provider = new BouncyCastleProvider();
Security.addProvider(provider);
} /**
* 生成根证书公钥与私钥对
*/
@Test
public void testGenRootKeyPair() throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_PAIR_ALG);
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
writeObject("H:/certtest/Kingyea.public", keyPair.getPublic());
writeObject("H:/certtest/Kingyea.private", keyPair.getPrivate());
} /**
* 生成用户证书公钥与私钥对
* @throws Exception
*/
@Test
public void testZhangsanKeyPair() throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_PAIR_ALG);
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
writeObject("H:/certtest/zhangsan.public", keyPair.getPublic());
writeObject("H:/certtest/zhangsan.private", keyPair.getPrivate());
} /**
* 生成根证书(被BC废弃,但能够使用)
*/
@Test
public void testGenRootCert() throws Exception {
X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
//设置证书颁发者
certGen.setIssuerDN(new X500Principal(DN_CA));
//设置证书有效期
certGen.setNotAfter(new Date(System.currentTimeMillis()+ 100 * 24 * 60 * 60 * 1000));
certGen.setNotBefore(new Date());
//设置证书公钥
certGen.setPublicKey(getRootPublicKey());
//设置证书序列号
certGen.setSerialNumber(BigInteger.TEN);
//设置签名算法
certGen.setSignatureAlgorithm(SIG_ALG);
//设置证书使用者
certGen.setSubjectDN(new X500Principal(DN_CA));
//使用私钥生成证书。主要是为了进行签名操作
X509Certificate certificate = certGen.generate(getRootPrivateKey());
PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)certificate;
bagAttr.setBagAttribute(
PKCSObjectIdentifiers.pkcs_9_at_friendlyName,
new DERBMPString("Kingyea Coperation Certificate"));
writeFile("H:/certtest/ca.cer", certificate.getEncoded());
} /**
* 生成根证书的第二种方式
* @throws Exception
*/
@Test
public void testGenRootCertWithBuilder() throws Exception {
final AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find(SIG_ALG);
final AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId); PublicKey publicKey = getRootPublicKey();
PrivateKey privateKey = getRootPrivateKey(); X500Name issuer = new X500Name(DN_CA);
BigInteger serial = BigInteger.TEN;
Date notBefore = new Date();
Date notAfter = new Date(System.currentTimeMillis()+ 100 * 24 * 60 * 60 * 1000);
X500Name subject = new X500Name(DN_CA); AlgorithmIdentifier algId = AlgorithmIdentifier.getInstance(PKCSObjectIdentifiers.rsaEncryption.toString());
System.out.println(algId.getAlgorithm());
AsymmetricKeyParameter publicKeyParameter = PublicKeyFactory.createKey(publicKey.getEncoded());
SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(publicKeyParameter);
//此种方式不行,生成证书不完整
//SubjectPublicKeyInfo publicKeyInfo = new SubjectPublicKeyInfo(algId, publicKey.getEncoded());
X509v3CertificateBuilder x509v3CertificateBuilder = new X509v3CertificateBuilder(issuer, serial, notBefore, notAfter, subject, publicKeyInfo); BcRSAContentSignerBuilder contentSignerBuilder = new BcRSAContentSignerBuilder(sigAlgId, digAlgId);
AsymmetricKeyParameter privateKeyParameter = PrivateKeyFactory.createKey(privateKey.getEncoded());
ContentSigner contentSigner = contentSignerBuilder.build(privateKeyParameter); X509CertificateHolder certificateHolder = x509v3CertificateBuilder.build(contentSigner);
Certificate certificate = certificateHolder.toASN1Structure();
writeFile("H:/certtest/ca.cer", certificate.getEncoded());
} /**
* 生成用户证书
*/
@Test
public void testGenZhangsanCert() throws Exception {
X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
certGen.setIssuerDN(new X500Principal(DN_CA));
certGen.setNotAfter(new Date(System.currentTimeMillis()+ 100 * 24 * 60 * 60 * 1000));
certGen.setNotBefore(new Date());
certGen.setPublicKey(getZhangsanPublicKey());
certGen.setSerialNumber(BigInteger.TEN);
certGen.setSignatureAlgorithm(SIG_ALG);
certGen.setSubjectDN(new X500Principal(DN_ZHANGSAN));
X509Certificate certificate = certGen.generate(getRootPrivateKey()); writeFile("H:/certtest/zhangsan.cer", certificate.getEncoded());
} /**
* 验证根证书签名
*/
@Test
public void testVerifyRootCert() throws Exception {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
FileInputStream inStream = new FileInputStream("H:/certtest/ca.cer");
X509Certificate certificate = (X509Certificate) certificateFactory.generateCertificate(inStream);
System.out.println(certificate);
Signature signature = Signature.getInstance(certificate.getSigAlgName());
signature.initVerify(certificate);
signature.update(certificate.getTBSCertificate());
boolean legal = signature.verify(certificate.getSignature());
System.out.println(legal);
} /**
* 验证用户证书签名
*/
@Test
public void testVerifyZhangsanCert() throws Exception {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
FileInputStream inStream = new FileInputStream("H:/certtest/zhangsan.cer");
X509Certificate certificate = (X509Certificate) certificateFactory.generateCertificate(inStream);
System.out.println(certificate.getPublicKey().getClass());
Signature signature = Signature.getInstance(certificate.getSigAlgName());
signature.initVerify(getRootPublicKey());
signature.update(certificate.getTBSCertificate());
boolean legal = signature.verify(certificate.getSignature());
System.out.println(legal);
} /**
* 生成证书请求文件
*/
@Test
public void testGenCSR() throws Exception {
X500Name subject = new X500Name(DN_ZHANGSAN);
AsymmetricKeyParameter keyParameter = PrivateKeyFactory.createKey(getZhangsanPrivateKey().getEncoded());
SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(keyParameter);
PKCS10CertificationRequestBuilder certificationRequestBuilder = new PKCS10CertificationRequestBuilder(subject, publicKeyInfo);
final AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find(SIG_ALG);
final AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
BcRSAContentSignerBuilder contentSignerBuilder = new BcRSAContentSignerBuilder(sigAlgId, digAlgId);
PKCS10CertificationRequest certificationRequest = certificationRequestBuilder.build(contentSignerBuilder.build(keyParameter));
System.out.println(certificationRequest);
writeFile("H:/certtest/zhangsan.csr", certificationRequest.getEncoded());
} /**
* 依据证书请求文件生成用户证书,事实上主要是使用根证书私钥为其签名
*/
@Test
public void testZhangsanCertWithCSR() throws Exception {
byte[] encoded = readFile("H:/certtest/zhangsan.csr");
PKCS10CertificationRequest certificationRequest = new PKCS10CertificationRequest(encoded); RSAKeyParameters parameter = (RSAKeyParameters) PublicKeyFactory.createKey(certificationRequest.getSubjectPublicKeyInfo());
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(parameter.getModulus(), parameter.getExponent());
String algorithm = algorithmMap.get(certificationRequest.getSubjectPublicKeyInfo().getAlgorithm().getAlgorithm().toString());
PublicKey publicKey = KeyFactory.getInstance(algorithm).generatePublic(keySpec);
System.out.println(certificationRequest.getSubject());
X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
certGen.setIssuerDN(new X500Principal(DN_CA));
certGen.setNotAfter(new Date(System.currentTimeMillis()+ 100 * 24 * 60 * 60 * 1000));
certGen.setNotBefore(new Date()); certGen.setPublicKey(publicKey);
certGen.setSerialNumber(BigInteger.TEN);
certGen.setSignatureAlgorithm(algorithmMap.get(certificationRequest.getSignatureAlgorithm().getAlgorithm().toString()));
certGen.setSubjectDN(new X500Principal(certificationRequest.getSubject().toString()));
X509Certificate certificate = certGen.generate(getRootPrivateKey()); writeFile("H:/certtest/zhangsan.cer", certificate.getEncoded()); } public PrivateKey getRootPrivateKey() throws Exception {
return PrivateKey.class.cast(readKey("H:/certtest/Kingyea.private"));
}
public PublicKey getRootPublicKey() throws Exception {
return PublicKey.class.cast(readKey("H:/certtest/Kingyea.public"));
} public PrivateKey getZhangsanPrivateKey() throws Exception {
return PrivateKey.class.cast(readKey("H:/certtest/zhangsan.private"));
}
public PublicKey getZhangsanPublicKey() throws Exception {
return PublicKey.class.cast(readKey("H:/certtest/zhangsan.public"));
} public byte[] readFile(String path) throws Exception {
FileInputStream cntInput = new FileInputStream(path);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int b = -1;
while((b=cntInput.read())!=-1) {
baos.write(b);
}
cntInput.close();
byte[] contents = baos.toByteArray();
baos.close();
return contents;
} public void writeFile(String path, byte[] content) throws Exception {
FileOutputStream fos = new FileOutputStream(path);
fos.write(content);
fos.close();
} public void writeObject(String path, Object object) throws Exception {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path));
oos.writeObject(object);
oos.close();
} public Object readObject(String path) throws Exception {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));
Object obj = ois.readObject();
ois.close();
return obj;
} public Key readKey(String path) throws Exception {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));
Key key = Key.class.cast(ois.readObject());
ois.close();
return key;
}
}
在根证书生成后双击打开。Windows会提示:该CA根证书不受信任。要启用信任,将该证书安装到”受信任的根证书颁发机构“存储区。将自己生成的根证书安装到受信任的根证书颁发机构后,你会发现其颁发的用户证书也受信任了。
Java安全之数字证书的更多相关文章
- JAVA对数字证书的常用操作(转载)
一:需要包含的包 import java.security. * ; import java.io. * ; import java.util. * ; import java.security. * ...
- 数字证书简介及Java编码实现
1.数字证书简介 数字证书具备常规加密解密必要的信息,包含签名算法,可用于网络数据加密解密交互,标识网络用户(计算机)身份.数字证书为发布公钥提供了一种简便的途径,其数字证书则成为加密算法以及公钥的载 ...
- Java加密解密与数字证书的操作
1 keytool命令总结 一.创建数字证书 交互模式 使用默认的密钥库.keystore(文件夹是c: Documents and Settingusername)和算法(DSA) keytool ...
- Java使用数字证书加密通信(加解密/加签验签)
本文中使用的Base64Utils.java可参考:http://www.cnblogs.com/shindo/p/6346618.html 证书制作方法可参考:http://www.cnblogs. ...
- java中的数据加密5 数字证书
数字证书 A用私钥加密了,那么B接受到消息后,用A提供的公钥解密:那么现在有个讨厌的C,他把消息拦截了,然后用自己的私钥加密,同时把自己的公钥发给B,并告诉B,那是A的公钥,结果....,这时候就需要 ...
- 数字签名、数字证书的原理以及证书的获得java版
数字签名原理简介(附数字证书) 首先要了解什么叫对称加密和非对称加密,消息摘要这些知识. 1. 非对称加密 在通信双方,如果使用非对称加密,一般遵从这样的原则:公钥加密,私钥解密.同时,一般一个密钥加 ...
- 如何利用java程序实现加密所需的公钥、密钥、数字证书
本篇的主要目的在于实现pdf的数字签名问题,只是作为我学习知识的总结. 1.数字签名算法的概述 本部分主要参考于:https://blog.csdn.net/lovelichao12/article/ ...
- 【Java】Java与数字证书
Java与数字证书 Java与数字证书 证书的签发和应用 证书的内容和意义 其它 证书(Certificate,也称public-key certificate)是用某种签名算法对某些内容(比如公钥) ...
- Java加密技术(八)——数字证书
原文:http://snowolf.iteye.com/blog/391931 请大家在阅读本篇内容时先阅读 Java加密技术(四),预先了解RSA加密算法. 在构建Java代码实现前,我们需要完成证 ...
随机推荐
- 【bug】 1118 Row size too large
1118 Row size too large Every table (regardless of storage engine) has a maximum row size of 65,535 ...
- iOS使用Reveal分析他人app界面
本文转自http://blog.csdn.net/cuibo1123/article/details/45694657 安装: 首先前往 http://revealapp.com/download/ ...
- Python中摘要算法MD5,SHA1讲解
摘要算法又称哈希算法.散列算法.它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示).摘要算法就是通过摘要函数f()对任意长度的数据data计算出固定长度的摘要di ...
- python基础学习笔记——开发规范
> 编码 1 2 3 4 5 所有的 Python 脚本文件都应在文件头标上 # -*- coding:utf-8 -*- 用于设置编辑器,默认保存为 utf-8 格式. > 注释 ...
- 00031_ArrayList集合中常用的方法
1.ArrayList集合提供的一些常用方法 import java.util.ArrayList; public class ArrayListDemo01 { public static void ...
- 【04】Math图解
[04]Math知识图
- ListView虚拟模式封装
public class ListViewAH : ListViewEx { #region 虚拟模式相关操作 ///<summary> /// 前台行集合 ///</summary ...
- HDU-4825 Xor Sum,字典树好题!
Xor Sum 一遍A了之后大呼一声好(keng)题!debug了两小时~~~~百度之星资格赛,可以. 题意:给你一个n个元素的数组,m次查询,每次输入一个数k要求从数组中找到一个数与k异或值最大,输 ...
- 九度oj 题目1108:堆栈的使用
题目描述: 堆栈是一种基本的数据结构.堆栈具有两种基本操作方式,push 和 pop.Push一个值会将其压入栈顶,而 pop 则会将栈顶的值弹出.现在我们就来验证一下堆栈的使用. 输入: 对于每组测 ...
- LeetCode--二分查找相关算法
-(1)有一个升序排列的非负数组,要求利用o(logn)的时间复杂度找到数组中确定数字target的第一次出现的位置下标和最后一次出现的位置下标,如果不存在该target返回[-1,-1] 解决方案: ...