CA认证原理以及实现(上)
转自:http://yale.iteye.com/blog/1675344
原理基础
数字证书为发布公钥提供了一种简便的途径,其数字证书则成为加密算法以及公钥的载体,依靠数字证书,我们可以构建一个简单的加密网络应用平台,数字证书就好比我们生活中的身份证,现实中,身份证由公安机关签发,而网络用户的身份凭证由数字证书颁发认证机构—CA签发,只有经过CA签发的证书在网络中才具备可认证性,CA并不是一个单纯的防御手段,它集合了多种密码学算法:
消息摘要算法:MD5、和SHA(对数字证书本省做摘要处理,用于验证数据完整性服务器)
对称加密算法:RC2、RC4、IDEA、DES、AES(对数据进行加密/解密操作,用于保证数据保密性服务)
非对称加密算法:RSA、DH(对数据进行加密/解密操作,用于保证数据保密性服务)
数字签名算法:RSA、DSA(对数据进行签名/验证操作,保证数据的完整性和抗否认性)。
证书的签发过程实际上是对申请数字证书的公钥做数字签名,证书的验证过程实际上是对数字证书的公钥做验证签名,其中还包含证书有效期验证,通过CA数字证书,我们对网络上传输的数据进行加密/解密和签名/验证操作,确保数据机密性、完整性、抗否认性、认证性,保证交易实体身份的真实性,保证网络安全性。
所有证书有多种文件编码格式,主要包括:
CER编码(规范编码格式):是数字证书的一种编码格式,它是BER(基本编码格式)的一个变种,比BER规定得更严格
DER(卓越编码格式):同样是BER的一个变种,与CER的不同在于,DER使用定长模式,而CER使用变长模式。
所有证书都符合公钥基础设施(PKI)制定的ITU-T X509国际标准,PKCS(公钥加密标准)由RSA实验室和其他安全系统开发商为促进公钥密码的发展而制定的一系列标准,比如:PKCS#7(密码消息语法标准----文件后缀名:.p7b、.p7c、.spc)、PKCS#10(证书请求语法标准----文件后缀名:.p10、.csr)、PKCS#12(个人信息交换语法标准----文件后缀名:.p12、.pfx)等
在获得数字证书后,可以将其保存在电脑中,也可以保存在USB Key等相应的设备中。
我们先来看一个简单的证书机构签发的流程:
这里的认证机构如何是证书申请者本身,将获得自签名证书。
当客户端获得服务器下发的数字证书后,即可使用数字证书进行加密交互:
数字证书的应用环境是在https安全协议中,使用流程远比上述加密交互流程复杂,但是相关操作封装在传输层,对于应用层透明,在https安全协议中使用非对称加密算法交换密钥,使用对称加密算法对数据进行加密/解密操作,提高加密/解密效率
要获得数字证书,我们需要使用数字证书管理工具:KeyTool和OpenSSL构建CSR(数字证书签发申请),交由CA机构签发,形成最终的数字证书,这里我们不对KeyTool做讲解(KeyTool不含有根证书,因此KeyTool没有办法作为CA),网上资料对keytool讲解的也挺多的,我们下面针对OpenSSL进行讲解。
在我们搭建OPEN SSL环境前,我们要知道HTTPS协议和SSL/TLS协议,简单的说,HTTPS就是HTTP+SSL(secure socket layer)/TLS(Transport Layer Security)协议,HTTPS协议为数字证书提供了最佳的应用环境,HTTPS协议一般在服务器中配置,如HTTP服务器APACHE、TOMCAT等。
SSL:位于TCP/IP中的网络传输层,作为网络通讯提供安全以及数据完整性的一种安全协议
TLS:作为SSL协议的继承者,成为下一代网络安全性和数据完整性安全协议
SSL共有3个版本:1.0、2.0、3.0,TLS也有1.0、2.0、3.0,通常我们说的SSL/TLS协议指的是SSL3.0/TLS1.0的网络传输层安全协议
SSL/TLS协议分为两层:
记录协议:建议在可靠的传输协议之上,为高层协议提供数据封装、压缩、加密等基本功能的支持
握手协议:建立在SSL记录协议之上,用于在实际的数据传输开始前,通讯双方进行身份认证、协商加密算法、交换加密密钥等
经过了SSL/TLS握手协议交互后,数据交互双方确定了本次会话使用的对称加密算法以及密钥,就可以开始进行加密数据交互了,以下是握手协议服务器端和客户端构建加密交互的相关流程图:
协商算法
1、 随机数为后续构建密钥准备
2、 其他信息包括服务器证书、甚至包含获取客户端证书的请求
验证算法
如果服务器端回复客户端时带有其他信息,则进入数字证书验证阶段
客户端验证服务器端证书:
服务器端验证客户端证书:
产生密钥
当服务器端和客户端经过上述流程后,就开始密钥构建交互了,服务器端和客户端最初需要主密钥为构建会话密钥做准备:
上述5、6不存在次序关系,因为是异步完成
会话密钥
完成上述主密钥构建操作后,服务器端和客户端将建立会话密钥,完成握手协议:
加密交互
上述服务器端和客户端完成了握手协议以后就进入正式会话阶段,如果上述流程中有任何一端受到外界因素干扰发生异常,则重新进入协商算法阶段,下面流程表现进入会话阶段后,服务器端和客户端将使用会话密钥进行加密交互:
代码解释
在JAVA 6 以上版本中提供了完善的数字证书管理的实现,我们不需要关注相关具体算法,仅通过操作密钥库和数字证书就可以完成相应的加密/解密和签名/验证操作,密钥库管理私钥,数字证书管理公钥,私钥和密钥分属消息传递两方,进行加密消息的传递。
因此,我们可以将密钥库看做私钥相关操作的入口,数字证书则是公钥相关操作的入口:
- /****
- * 获得私钥,获得私钥后,通过RSA算方法实现进行"私钥加密,公钥解密"和"公钥加密,私钥解密"操作
- * @param keyStorePath 密钥库路径
- * @param alias 别名
- * @param password 密码
- * @return 私钥
- */
- private static PrivateKey getPrivateKeyByKeyStore(String keyStorePath,String alias,String password)throws Exception{
- //获得密钥库
- KeyStore ks = getKeyStore(keyStorePath,password);
- //获得私钥
- return (PrivateKey)ks.getKey(alias, password.toCharArray());
- }
- /****
- * 由Certificate获得公钥,获得公钥后,通过RSA算方法实现进行"私钥加密,公钥解密"和"公钥加密,私钥解密"操作
- * @param certificatePath 证书路径
- * @return 公钥
- */
- private static PublicKey getPublicKeyByCertificate(String certificatePath)throws Exception {
- //获得证书
- Certificate certificate = getCertificate(certificatePath);
- //获得公钥
- return certificate.getPublicKey();
- }
- /****
- * 加载数字证书,JAVA 6仅支持x.509的数字证书
- * @param certificatePath 证书路径
- * @return 证书
- * @throws Exception
- */
- private static Certificate getCertificate(String certificatePath) throws Exception{
- //实例化证书工厂
- CertificateFactory certificateFactory = CertificateFactory.getInstance("x.509");
- //取得证书文件流
- FileInputStream in = new FileInputStream(certificatePath);
- //生成证书
- Certificate certificate = certificateFactory.generateCertificate(in);
- //关闭证书文件流
- in.close();
- return certificate;
- }
- /****
- * 获得Certificate
- * @param keyStorePath 密钥库路径
- * @param alias 别名
- * @param password 密码
- * @return 证书
- * @throws Exception
- */
- private static Certificate getCertificate(String keyStorePath,String alias,String password) throws Exception{
- //由密钥库获得数字证书构建数字签名对象
- //获得密钥库
- KeyStore ks = getKeyStore(keyStorePath,password);
- //获得证书
- return ks.getCertificate(alias);
- }
- /****
- * 加载密钥库,加载了以后,我们就能通过相应的方法获得私钥,也可以获得数字证书
- * @param keyStorePath 密钥库路径
- * @param password 密码
- * @return 密钥库
- * @throws Exception
- */
- private static KeyStore getKeyStore(String keyStorePath,String password) throws Exception{
- //实例化密钥库
- KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
- //获得密钥库文件流
- FileInputStream is = new FileInputStream(keyStorePath);
- //加载密钥库
- ks.load(is,password.toCharArray());
- //关闭密钥库文件流
- is.close();
- return ks;
- }
- /****
- * 私钥加密
- * @param data 待加密的数据
- * @param keyStorePath 密钥库路径
- * @param alias 别名
- * @param password 密码
- * @return 加密数据
- * @throws Exception
- */
- public static byte[] encryptByPriateKey(byte[] data,String keyStorePath,String alias,String password) throws Exception{
- //获得私钥
- PrivateKey privateKey = getPrivateKeyByKeyStore(keyStorePath,alias,password);
- //对数据加密
- Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
- return cipher.doFinal(data);
- }
- /****
- * 私钥解密
- * @param data 待解密数据
- * @param keyStorePath 密钥库路径
- * @param alias 别名
- * @param password 密码
- * @return 解密数据
- * @throws Exception
- */
- public static byte[] decryptByPrivateKey(byte[] data,String keyStorePath,String alias,String password) throws Exception{
- //取得私钥
- PrivateKey privateKey = getPrivateKeyByKeyStore(keyStorePath,alias,password);
- //对数据解密
- Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
- cipher.init(Cipher.DECRYPT_MODE,privateKey);
- return cipher.doFinal(data);
- }
- /****
- * 公钥加密
- * @param data 等待加密数据
- * @param certificatePath 证书路径
- * @return 加密数据
- * @throws Exception
- */
- public static byte[] encryptByPublicKey(byte[] data,String certificatePath) throws Exception{
- //取得公钥
- PublicKey publicKey = getPublicKeyByCertificate(certificatePath);
- //对数据加密
- Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
- cipher.init(Cipher.ENCRYPT_MODE,publicKey);
- return cipher.doFinal(data);
- }
- /****
- * 公钥解密
- * @param data 等待解密的数据
- * @param certificatePath 证书路径
- * @return 解密数据
- * @throws Exception
- */
- public static byte[] decryptByPublicKey(byte[] data,String certificatePath)throws Exception{
- //取得公钥
- PublicKey publicKey = getPublicKeyByCertificate(certificatePath);
- //对数据解密
- Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
- cipher.init(Cipher.DECRYPT_MODE, publicKey);
- return cipher.doFinal(data);
- }
- /****
- * @param sign 签名
- * @param keyStorePath 密钥库路径
- * @param alias 别名
- * @param password 密码
- * @return 签名
- * @throws Exception
- */
- public static byte[] sign(byte[] sign,String keyStorePath,String alias,String password)throws Exception{
- //获得证书
- X509Certificate x509Certificate = (X509Certificate) getCertificate(keyStorePath,alias,password);
- //构建签名,由证书指定签名算法
- Signature signature = Signature.getInstance(x509Certificate.getSigAlgName());
- //获取私钥
- PrivateKey privateKey = getPrivateKeyByKeyStore(keyStorePath,alias,password);
- //初始化签名,由私钥构建
- signature.initSign(privateKey);
- signature.update(sign);
- return signature.sign();
- }
- /****
- * 验证签名
- * @param data 数据
- * @param sign 签名
- * @param certificatePath 证书路径
- * @return 验证通过为真
- * @throws Exception
- */
- public static boolean verify(byte[] data,byte[] sign,String certificatePath) throws Exception{
- //获得证书
- X509Certificate x509Certificate = (X509Certificate)getCertificate(certificatePath);
- //由证书构建签名
- Signature signature = Signature.getInstance(x509Certificate.getSigAlgName());
- //由证书初始化签名,实际上是使用了证书中的公钥
- signature.initVerify(x509Certificate);
- signature.update(data);
- return signature.verify(sign);
- }
- //我们假定密钥库文件yale.keystore存储在D盘根目录,数字证书文件yale.cer也存储在D盘根目录
- /****
- * 公钥加密---私钥解密
- * @throws Exception
- */
- public static void test1() throws Exception{
- System.err.println("公钥加密---私钥解密");
- String inputStr = "数字证书";
- byte[] data = inputStr.getBytes();
- //公钥加密
- byte[] encrypt = CertificateCoder.encryptByPublicKey(data, certificatePath);
- //私钥解密
- byte[] decrypt = CertificateCoder.decryptByPrivateKey(encrypt, keyStorePath, alias, password);
- String outputStr = new String(decrypt);
- System.err.println("加密前:\n" + inputStr);
- System.err.println("解密后:\n" + outputStr);
- }
- /****
- * 私钥加密---公钥解密
- * @throws Exception
- */
- public static void test2()throws Exception{
- System.err.println("私钥加密---公钥解密");
- String inputStr = "数字签名";
- byte[] data = inputStr.getBytes();
- //私钥加密
- byte[] encodedData = CertificateCoder.encryptByPriateKey(data, keyStorePath, alias, password);
- //公钥加密
- byte[] decodeData = CertificateCoder.decryptByPublicKey(encodedData, certificatePath);
- String outputStr = new String (decodeData);
- System.err.println("加密前:\n" + inputStr);
- System.err.println("解密后:\n" + outputStr);
- }
- public static void testSign()throws Exception{
- String inputStr = "签名";
- byte[] data = inputStr.getBytes();
- System.err.println("私钥签名---公钥验证");
- //产生签名
- byte[] sign = CertificateCoder.sign(data, keyStorePath, alias, password);
- System.err.println("签名:\n" + Hex.encodeHexString(sign));
- //验证签名
- boolean status = CertificateCoder.verify(data, sign, certificatePath);
- System.err.println("状态:\n " + status);
- }
CA认证原理以及实现(上)的更多相关文章
- CA认证原理以及实现(下)
在上述的文章后了解到原理之后,我们这篇文章来进行CA的搭建. OPEN SSL 环境搭建在基础原理中我们提到了两种认证服务,单项认证服务和双向认证服务,我们就以双向认证服务举例说明.OpenSSL是一 ...
- [加密]openssl之数字证书签名,CA认证原理及详细操作
转自:http://blog.sina.com.cn/s/blog_cfee55a70102wn3h.html 1 公钥密码体系(Public-key Cryptography) 公钥密码体系,又称非 ...
- CA证书申请、认证原理
(一) 证书的申请 密钥文件的格式用OpenSSL生成的就只有PEM和DER两种格式,PEM的是将密钥用base64编码表示出来的,直接打开你能看到一串的英文字母,DER格式是二进制的密钥文件,直接打 ...
- CA认证和颁发吊销证书
摘要:涉及到网络安全这一块,想必大家都听过CA吧.像百度.淘宝.京东等这些知名网站,每年都要花费一笔money来买CA证书.但其实简单的企业内的CA认证,我们自己就可以实现,今天小编我就讲解一下怎么在 ...
- SSL、数字签名、CA 工作原理
SSL.数字签名.CA 工作原理 对称加密和非对称加密介绍和区别 什么是对称加密技术? 对称加密采用了对称密码编码技术,它的特点是文件加密和解密使用相同的密钥,即加密密钥也可以用作解密密钥,这种方 ...
- Kerberos认证原理简介
1.1 What is Kerberos 1.1.1 简单介绍 Kerberos是一个用于鉴定身份(authentication)的协议, 它采取对称密钥加密(symmetric-key crypto ...
- 公钥、私钥、CA认证、数字签名、U盾
感谢传智播客的方立勋老师,在一个教学视频上,他巧妙地以蒋介石给宋美龄写密信作为例子,生动地讲述了软件密码学知识. 加密分为对称加密和非对称加密,我们传统理解的,发送数据之前使用一个加密器加密,接到数据 ...
- SSL、数字签名、CA 工作原理通俗描述
SSL(Secure Socket Layer) 是一种加密技术,可以提供对称加密和非对称加密.由于它在协议层里正好是在传输层与应用层之间,这就决定了上层应用必须经过它,这就是它广泛流行和易于实现的原 ...
- SSH认证原理和批量分发管理
SSH密码认证原理 几点说明: 1.服务端/etc/ssh目录下有三对公钥私钥: [root@m01 ssh]# ls moduli ssh_config sshd_config ssh_host_d ...
随机推荐
- mysql获取一个表中的下一个自增(id)值的方法
SELECT Auto_increment FROM information_schema.`TABLES` WHERE Table_Schema='数据库名' AND table_name = '表 ...
- [从产品角度学excel 04]-单元格的“衣服”
忘记发这里了..补发一下 这是<从产品角度学EXCEL>系列——单元格篇. 前言请看: 0 为什么要关注EXCEL的本质 1 excel是怎样运作的 2 EXCEL里的树形结构 3 单元格 ...
- Load Test Analyzer Overview
reference url: https://msdn.microsoft.com/en-us/library/ms404677.aspx
- WebApi官方系列
一.入门 1.1Asp.Net WebApi2 入门 1.2WebApi2的Action返回值 1.3WebApi2自动生成帮助页 二.路由 2.1WebApi2的路由规则 2.2WebApi2的Ac ...
- js瀑布流 原理实现揭秘 javascript 原生实现
web,js瀑布流揭秘 瀑布流再很久之前流行,可能如我一样入行晚的 ,可能就没有机会去使用.但是这个技术终究是个挺炫酷的东西,花了一个上午来研究,用原生js实现了一个,下面会附上源码,供大家解读. 说 ...
- int与CString互相转化
int num; CString str; //int转CString num=; str.Format(_T("%d"),num); //CString转int str=L&qu ...
- Best Time to Buy and Sell Stock1,2,3,4
找到最低值和最高值 int maxProfit(vector<int>& prices) { ); ; ]; ;i<prices.size();i++) { profit=m ...
- Java中关于String类型的10个问题
1. 如何比较两个字符串?用“=”还是equals 简单来说,“==”是用来检测俩引用是不是指向内存中的同一个对象,而equals()方法则检测的是两个对象的值是否相等.只要你想检测俩字符串是不是相等 ...
- tomcat7 IP限制配置
server.xml </Host>前添加<Valve className="org.apache.catalina.valves.RemoteAddrValve&quo ...
- MySQL 日期、时间转换函数
MySQL 日期.时间转换函数:date_format(date,format), time_format(time,format) 能够把一个日期/时间转换成各种各样的字符串格式.它是 str_to ...