加密解密技术基础、PKI和OpenSSL
一、 通信安全基础概念
1. 数据的通信安全特性
- 保密性(confidentiality):通信要具有保密性,确保自己的通信不被任何无关的第三方解密
- 完整性(integrity):通信双方在通信过程中不会产生信息丢失
- 可用性(availability):任何信息对授权方是可用的
2. 安全攻击类型
(1)对保密性产生威胁的攻击
- 窃听
- 通信分析:虽然数据加密无法获取具体内容,但是可以通过监视通讯量的方式获取到一些额外的信息
(2)对完整性产生威胁的攻击
- 更改:通信报文被截获到之后,对其内容进行更改
- 伪装:假装成某个身份向目标发送报文
- 重放:截获通信某方的报文,无限的重复发送这个报文
- 否认:通信双方中某方否认发送过某个信息
(3)对可用性产生的攻击
- 拒绝服务:把目标可正常访问的资源通过非正常手段占用,导致服务不可用
二、加密算法相关概念
使用某种算法将明文数据转换为另外一种形式,接收者使用对应的解密方式进行解密,建议一种算法或者对应的一对儿密钥只用在一个功能上,而不要用一个密钥完成多种功能
1. 分类
(1)传统加密方法
- 替代加密算法:把明文中所有的奇数字母都向前移三位,把所有偶数字母都向后移五位,这种算法在没有计算机的时候是很有效的,人为暴力破解比较难,但是现在使用计算机进行排列组合完成暴力破解还是很简单的
- 置换加密算法:不但具有替代的特性,还有置换的特性
(2) 现代加密方法
现代加密算法中主要用的是块加密方式,它不像传统加密算法将字母一个一个加密,而是将要发送的数据切分为大小固定的多个块单独进行加密,而且后一块和前一块之间还要建立关联关系。这里说的简单,其实现代加密方式非常复杂,是由置换单元、替算单元、异或与运算单元、位移要素、对换要素等等一系列复杂机制构成的,加密算法一般都是由数学家发明的
2. 常见的加密算法和协议
(1)对称加密
简单来讲就是加密和解密使用同一个密钥,实现方式是使用秘钥结合加密算法对明文进行加密,接收者使用同一个秘钥结合解密算法还原数据。但是作为服务器端,如果通信对象过多时,需要管理的密钥也会很多。并且密钥如何安全分发也称为难题
- DES:数据加密标准(Data Encryption Standard),据说是由IBM的安全实验室研发的。在加密端DES使用64位的明文产生64位的密文,在解密端使用64位密文还原64位明文。在2003年前后,有一个叫做电子边境委员会的组织用当时价值100W美元左右的服务器,实现2小时内破解DES加密的任何数据,从此DES就失效了
- 3DES:改版后的DES加密算法,但是其和DES算法是同根生的,所以人们依然对它忧心忡忡
- AES:高级加密标准(Advanced Encryption Standard),替换3DES算法的算法,使用变长的加密长度128、192、256、384、512bits
- Blowfish
- Twofish
- IDEA:商业加密算法
- RC6
- CAST5
(2)公钥加密
密钥是成对出现的,分为公钥和私钥。用公钥加密的数据只能使用与之配对的私钥解密,反之亦然。公钥(pubkey)可以公开给所有人,是由私钥中提取特定数据生成的。私钥(secret key)自己留存,必须保证其私密性
① 能够实现的功能
- 数字签名:主要用于让接收方确认发送方的身份,实现方式是通过自己的私钥加密一段数据,让接收方使用配对的公钥解密,如果解密成功则验证了发送方的身份
- 密钥交换:发送方使用对方的公钥加密一个对称秘钥并发送给对方,对方通过自己的私钥完成解密获取密码
- 数据加密:虽然说公钥加密数据可用于数据加密,但没有人拿来用它做数据加密,因为秘钥长度太长,加密性能极低
② 常见算法
- RSA:既能实现加密,又能实现数字签名
- DSA:只能用于数字签名,不能用于加密
- ELGamal:商业加密算法
(3)单向加密
只能加密,不能解密,实现完整性校验
① 特性
- 定长输出
- 雪崩效应:原始数据的微小改变将会导致结果的巨大差异
② 常见算法
- MD5:128bits定长输出,message digest(消息摘要)
- sha1:160bits定长输出,secure hash algorithm(安全的哈希算法)
- sha256:
- sha384:
- sha512:
(4)秘钥交换
① 使用公钥加密完成秘钥交换
使用对方的公钥加密一个对称秘钥发送给对方,对方通过私钥解密,就可以完成秘钥交换,虽然很安全,但是对称秘钥还是在网络上传输了,所以依然存在安全风险
②使用DH算法完成秘钥交换
Deffle-Hellman算法,此种算法不用在网络上传输就可以完成秘钥交换,实现过程如下
- 第一步:通信双方通过协商生成两个数字(一个质数和一个取模数)
A方:p、g
B方:p、g
- 第二步:通信双方各自生成一个隐私的数字,不会将隐私数字发送给对方
A方:p、g、x
B方:p、g、y
- 第三步:A使用p求x次方并对g取模,B使用p求y次方对g取模,各自将结果发送给对方。(注意只是运算结果发送给对方)
A方:p^x%g=abc
B方:p^y%g=def
前三步中,假设中间人可以得到数字p、数字g及各自取模的结果,但是中间人想去反推数字x或y几乎是不可能的
- 第四步:双方拿到对方取模的结果后,将结果取隐私数字次方,计算的结果一定是相等的,就可以作为秘钥使用了
A计算:def^x
B计算:abc^y
结果相同的依据就是
A:(p^y%g)^x
= p^xy%g
B:(p^x%g)^y
= p^xy%g
3. 一次加密的通信过程
结合上图叙述一下一次加密的安全通信过程
(1)发送数据的过程
- 第一步:使用单向加密算法对数据ABC进行特征码计算,将计算结果附加在数据ABC的后面并使用李四自己的私钥对这段特征码进行加密
- 第二步:使用对称加密方式将数据及特征码进行加密,然后使用张三的公钥把对称加密算法的秘钥进行加密并附加在后方发送给张三
(2)解密数据的过程
- 第一步:使用张三自己的私钥解密对称秘钥密码,并完成对称算法解密
- 第二步:使用李四的公钥将单向加密结果解密,如果可以解密则证明数据的来源合法性
- 第三步:使用同样的单向加密算法对数据ABC进行计算,如果计算结果与解密结果一致,则证明数据的完整性
上述通信过程中,如果出现中间人在其中进行身份假冒,那么通信就毫无私密可言。所以如何安全的获取对方的公钥是重中之重,而CA就是用来弥补这一环的
三、CA相关概念
CA是一个独立的第三方机构,可以向用户发送带防伪标志的证书,这样甲乙之间通信前,就可以向对方发送大家都认可的CA颁发的证书,通过CA的公钥去验证证书的合法性,从而开始安全通信。而CA的证书获取方式也很简单,例如window系统,在你安装完操作系统后,具有公信力的CA机构的证书已经帮你安装完毕了。并且CA信任关系可以传递的,意思是你信任甲CA,那么甲CA信任的其他CA也就自动信任了
1. PKI
Public Key Infrastructure,公钥基础设施
- 签证机构:CA,为了保证通信双方都能够可靠的拿到对方的公钥而特地设立的第三方可信机构
- 注册机构:RA,只接受证书注册请求,没有签发权利的派出机构
- 证书吊销列表:CRL
- 证书存取库:CB
2. X.509
国际标准化组织定义的数字证书格式及认证协议标准,下为第三版格式
- 版本号:证书的版本号,表示使用的是第几版的x509
- 序列号:证书的号码,表示ca发的第几个证书
- 签名算法:证书使用的签名算法
- 发行者的名称:ca的名称
- 有效期限
- 主体名称:证书拥有者的名字
- 主体公钥
- 发行者的唯一标示:ca的唯一标识
- 主体的唯一标示:证书拥有者的唯一标识
- 扩展信息
- 发行者签名:ca会把上述所有内容使用单向加密计算出特征码,并用自己的私钥加密这段特征码签在本项上
3. 通信前验证
当有了ca,双方再通信时,情况如下
- 第一步:使用CA的公钥解密对方证书的特征码,如果能解密则来源合法性得到验证
- 第二步:使用同样的单向加密算法对证书内容计算,得到的结果与CA签名一致则完整性得到验证
- 第三步:查看证书有限期限
- 第四步:查看证书主体是否与通信方一致
- 第五步:查看证书是否被吊销了
4. CA的配置文件
配置文件位置:/etc/pki/tls/openssl.cnf
|
5. 构建私有CA
(1)创建需要的文件文件
- 创建CA工作目录:
mkdir -pv /etc/pki/CA/{certs,crl,newcerts}
- 创建数据库文件:
touch index.txt
- 指定第一个颁发证书的序列号:
echo 01 > serial
(2)CA自签证书
- 生成CA私钥并存到指定位置:
(umask 077; openssl genrsa -out /etc/pki/CA/private/cakey.pem 2048)
- 生成自签证书:
openssl req -new -x509 -key /etc/pki/CA/private/cakey.pem -days 1111 -out /etc/pki/CA/cacert.pem
|
|
(3)发证
① 生成证书请求
- 服务器端生成自己的私钥:
(umask 077;openssl genrsa -out httpd.key 2048)
- 生成证书签署请求:
openssl req -new -key httpd.key -days 365 -out httpd.csr
- 把请求文件传输给CA
② CA签署证书,并将证书发还给客户端
- ca签署证书:
openssl ca -in /tmp/httpd.csr -out /tmp/httpd.crt -days 365
证书的后缀后.crt
,请求的后缀为.csr
- 手动查看证书信息:
openssl x509 -in /PATH.crt -noout -text|-subject|-serial
(4)吊销证书
① 客户端获取要吊销证书的serial
openssl x509 -in /path.crt -noout -serial -subject
②CA吊销证书
CA端根据客户端提交的serial与subject信息去对比是否与index.txt文件中的信息一致,一致则吊销证书
openssl ca -revoke /etc/pki/CA/newcerts/SERIAL.PEM
③ 生成吊销证书编号,仅在第一次吊销时执行
echo 01 > /etc/pki/CA/crlnumber
④ 更新证书吊销列表
openssl ca -gencrl -out myca.crl
- 查看crl文件:
openssl crl -in /crl_file -noout -text
四、Openssl
早期很多互联网应用之间通信都是没有加解密功能的,数据包通过任何设备时,都可以被截取并知悉其中内容,后来为了解决这一现状,网景公司设计了一款可被调用的功能模块,放置于应用层和传输层之间,占据半层空间。任何不具备加解密功能的应用程序都可以调用这个库使用加解密功能,这个半层库就叫做SSL(安全的套接字层Secure Socket Layer),而openssl是ssl协议的开源实现
1. openssl的组成部分
- openssl:多用途命令行工具
- libcrypto:公共加密库,主要由开发者写程序时调用
- libssl:实现ssl及tls等功能
2. tls和ssl的版本
(1)ssl
- 1994年SSL1.0诞生,由网景公司设计(Netscape),但从来没有公开过
- 1995年SSL2.0诞生,因为存在数个安全漏洞而被3.0取代
- 1996年SSL3.0诞生,后经google验证其中存在协议漏洞,现已处于废弃边缘
(2)tls
因为ssl的版权是网景一家的,而ssl机制又是很多互联网公司都需要的功能,于是国际电子工程师协会就仿照ssl研发了tls,二者基本上是兼容的
- 1999年TLS1.0诞生,(Transport Layer Secureity)RFC 4346
- 2006年TLS1.1诞生
- 2008年TLS1.2诞生
- 2015年TLS1.3诞生
3. tls的分层设计
tls的内部实现方式也是分层实现的
- 最底层:基础算法原语的实现
- 第二层:各种算法的实现
- 第三层:组合算法实现的半成品
- 第四层:用各种组件拼装成的种种成品密码学协议软件
4. SSL会话的过程
以httpd为例
- 第一步:客户端向服务器端发送hello信息,服务器端回应hello信息,过程当中双方会协商共同支持的加密算法、压缩算法,互相交换随机数用于稍后的会话秘钥
- 第二步:服务器端将自己的证书发送给客户端,客户端去检查服务器端的证书,如签发CA、有效期、完整性、主体机构、是否被吊销等等。同时在这一步中,服务器端可能会请求客户端的证书用于验证身份,常见于网上银行类的网站,U盾的随机码就是客户身份验证的一种,当然平时在访问其他的网站是一般不需要客户端提供证书
- 第三步:如果客户端需要发送证书,那么服务器端同样会检查客户端的证书,检查通过后客户端生成随机秘钥并用服务端的公钥进行加密完成秘钥交换
- 第四步:基于对称加密的方式完成通信
5. openssl的应用
openssl命令由很多的子命令,大体可以分为三类:标准命令、对称加密命令、单向加密命令
(1)对称加密
使用openssl命令跟上enc子命令,可对指定文件完成对称加密,算法可以自行更改
|
(2)单向加密
使用openssl命令跟上dgst子命令,可对指定文件计算特征码,算法可以自行更改
|
(3)非对称加密
- 生成私钥:
(umask 077; openssl genrsa -out rsakey.private 2048)
- 提取公钥:
openssl rsa -in /rsakey.private -pubout
(4)生成随机数
|
6. 随机数生成器
加密算法都严重依赖随机数,本部分讲一下Linux系统中的随机数。linux中有一段由内核维护的内存空间叫做熵池,这段空间当中存储了大量的随机数,随机数的来源一般源于系统I\O中断之间的时间间隔。比较常见的为硬盘I\O、键盘I\O时间间隔,比如用你敲击键盘两次之间的时间间隔计算为随机数,但是取随机数的速度可能会快于随机数产生的速度,所以熵池中的随机数可能会被耗尽,当耗尽时可以疯狂的敲击键盘或者复制大文件来补充随机数
/dev/random
:仅从熵池中返回随机数,一旦熵池中随机数用尽,则阻塞后面的进程,等待随机数产生/dev/urandom
:从熵池中返回随机数,一旦熵池中的随机数用尽,会用软件生成伪随机数,不会阻塞程序,但是伪随机数不安全