本文主要依据 https://www.cnblogs.com/JeffreySun/archive/2010/06/24/1627247.html 整理
文中首先解释了加密解密的一些基础知识和概念,然后通过一个加密通信过程的例子说明了加密算法的作用,以及数字证书的出现所起的作用。
1 基础知识
1.1 公钥密码体制
公钥密码体制分为三部分,公钥、私钥、加解密算法,过程如下:
- 加密:通过加密算法和公钥对内容进行加密,得到密文。
- 解密:通过解密算法和私钥对密文进行解密,得到明文。
1.2 对称加密算法
对称加密算法中,加密和解密使用的密钥是同一个密钥。
1.3 签名和加密
签名是就是在信息
的后面加上一段内容,可以证明信息没有被篡改。一般通过对信息
做一个hash计算。这个hash计算是不可逆的,无法通过hash值得到原来的信息
内容。在把信息
发出去时,把这个hash值加密后作为一个签名和信息
一起发出去。接收方在收到信息
后,会计算信息的hash值,并和信息
附带的hash值(解密后)进行对比。如果一致,就说明信息的内容没有被篡改。 因为这里hash计算可以保证不同的内容一定会得到不同的hash值,所以只要信息被篡改,根据信息计算的hash值必然会变化。也有不怀好意的人,可以同时篡改信息
和hash值,让他们可以匹配。为了防止这种情况,hash值一般都会加密后(也就是签名)再和信息
一起发送,保证这个hash值不被篡改。至于如何让对方可以解密这个信息
,这就需要依靠数字证书了。
2.一个加密通信过程的演化
看一个例子,假设“服务器”和“客户”要在网络上通信,并且打算用RSA来对通信内容进行加密。 “服务器”要对外发布公钥(如何发布公钥,后面提到),自己保留私钥。
2.1第一回合:
C -> S: 你好
S -> C: 你好,我是服务器
C -> S: ????
因为消息是在网络上传输的,有人可以冒充自己是“服务器”来向客户发送信息。比如:
C -> S: 你好
S -> C: 你好,我是服务器
C -> 黑客: 你好//黑客在客户和服务器之间的某个路由上解惑客户发给服务器的信息,然后自己冒充“服务器”
黑客 -> C: 你好,我是服务器
因此,客户在收到消息后,并不能肯定这个消息就是服务器发过来的。
因为只有服务器有私钥,只要能证明对方有私钥,那么对方就是服务器,于是通信过程做了如下改进:
2.2 第二回合:
C -> S: 你好
S-> C: 你好我是服务器
C -> S: 向我证明你是服务器
S-> C: 你好,我是服务器{你好我是服务器[私钥|RSA]}
花括号内表示用rsa私钥对信息加密后的结果。
当客户收到信息后,用持有的公钥解密密文,与明文比对,如果一致,说明信息的确是由服务器发来的。
客户可以确认服务器身份了,但是还有一个问题,通信的内容在网络上还是无法保密。看如下演示:
2.3第三回合:
C -> S: 你好
S-> C: 你好我是服务器
C -> S: 向我证明你是服务器
S-> C: 你好,我是服务器{你好我是服务器[私钥|RSA]}
C -> S: {我的账号是aaa,密码是123,把账户余额告诉我}[公钥|RSA]
S -> C: {你的余额是100元}[私钥|RSA]}
最后服务器把余额发送给客户时,虽然是用私钥加密的。但是私钥对应的公钥是公开的。只要持有公钥,就能解密该内容(所以一般场景不应该用rsa私钥加密数据
)。如何解决这个问题?实际应用过程中,一般是通过引入对称密钥来解决。看如下演示:
2.4第四回合:
C -> S: 你好
S-> C: 你好我是服务器
C -> S: 向我证明你是服务器
S-> C: 你好,我是服务器{你好我是服务器[私钥|RSA]}
C -> S: {我们后面的通信过程,用对称加密来进行,这里是对称加密算法
和密钥
}[公钥|RSA]
S -> C: {ok,收到!}[密钥|对称加密算法]
C -> S: {我的账号是aaa,密码是123,把账户余额告诉我}[密钥|对称加密算法]
S -> C: {你的余额是100元}[密钥|对称加密算法]}
上面过程中,客户在确认服务器身份之后,客户选择一个对称加密算法和一个密钥,用rsa公钥加密发送给服务器。由于是公钥加密的,就算密文被黑客截获,由于没有私钥,黑客也无从知道对称加密算法和密钥的内容。
总结一下,RSA加密算法在通信过程起到的作用,主要有两个:
因为
私钥
只有服务器拥有,因此客户可以通过判断对方是否有私钥
,来判断是否是服务器客户通过RSA公钥的保护,安全的和服务器协商一个
对称加密算法
和密钥
,来保证后面通信过程内容的安全。
到这里,客户就可以确认服务器的身份,并且双方的通信内容可以进行加密,其他人就算截获了通信内容,也无法解密。的确,好像通信的过程比较安全了???
但是这里还留有一个问题,服务器要对外发布公钥,那服务器如何把公钥给到客户?你可能会采取这两个方法:
a. 把公钥
放到互联网的一个下载地址,让客户去下载。
b. 每次和客户开始通信是,服务器把公钥
发给客户。
但是这两个方法都有一定的问题。
对于方法a,客户无法确定这个下载地址是不是服务器发布的。凭什么相信这个地址下载的东西就是服务器发布的,而不是别人伪造的。
对于方法b,因为任何人都可以自己生成一对公钥和私钥,他只要向客户发送自己的私钥就可以冒充服务器了。
示意如下:
C -> 黑客: 你好
黑客截获客户发给服务器的消息
黑客 -> C: 你好我是服务器,这是我的公钥黑客自己生成一对公钥和私钥,把公钥发给客户,自己保留私钥
C -> 黑客: 向我证明你是服务器
黑客 -> C: 你好,我是服务器{你好,我是服务器}[黑客自己的私钥|RSA]客户收到黑客用私钥加密的信息后,是可以用黑客发给自己的公钥解密的,从而会误认为黑客是服务器
这里问题的根源在于,大家都可以生成公私钥,无法确认公钥到底是谁的! 如果能确定公钥是谁的,就不会有这个问题了。例如,如果收到黑客冒充服务器发来的公钥,通过某种检查,如果能够发现这个 公钥
不是服务器的就好了。
为了解决这个问题,数字证书 就出现了,它可以解决上面的问题。先大概看下什么是数字证书。
一个证书包含下面具体内容:
- 证书的发布机构(ISSUER)
- 证书的有效期
- 公钥
- 证书所有者(SUBJECT)
- 签名所使用的算法
- 指纹以及指纹算法
证书的内容详细解释稍后介绍,这里先明确 数字证书可以保证证书里的公钥确实是证书所有者(Subject)的,或者证书可以用来确认对方的身份。 也就是说,我们拿到一个数字证书,就可以判断出这个数字证书到底是谁的。如何判断,后面会详细介绍。现在把前面的通信过程用数字证书修改为如下:
2.5 第五回合:
C -> S: 你好
S -> C: 你好,我是服务器,这里是我的数字证书用证书代替公钥
C -> S: 向我证明你是服务器
S -> C: 你好,我是服务器{你好,我是服务器}[私钥|RSA]
服务器把自己的证书发给了客户,客户可以校验这个证书的所有者是不是服务器,从而确认这个证书中的公钥的确是服务器的。后面的过程和之前一样,客户会用数字证书中的公钥解密服务器发来的信息,然后双方再协商一个对称加密来保证通信过程的安全。
2.6完整的过程
step1: 客户向服务器发送一个通信请求
C -> S: 你好
step2: 服务器向客户发送一个数字证书
。证书中有一个公钥用来加密信息,私钥由服务器持有
S -> C: 你好,我是服务器,这是我的
数字证书
step3: 客户收到服务器的证书后,去验证这个数字证书到底是不是服务器的,数字证书有没有什么问题。数字证书如果检查没有问题,客户会发送一个随机字符串,让服务器用私钥去加密。服务器把加密结果发给客户,客户用证书中的公钥解密返回结果。如果解密结果与之前生成的随机字符串一致,那说明对方确实是撕咬的持有者,或者说对方就是服务器。
C -> S: 向我证明你是服务器,这是
一个随机字符串
S -> C: {一个随机字符串}[私钥|RSA]
step4: 验证服务器的身份后,客户生成一个对称密钥算法和密钥,用于后面的通信的加密和解密。这个对称密钥算法和密钥,客户会用证书中的公钥加密后发送给服务器。别人截获也没有用,因为只有服务器手中有能解密的rsa私钥。后面服务器和客户的通信,都可以用对称加密算法来加密和解密了。
- S -> C: {OK,已经收到你发来的对称加密算法和密钥!有什么可以帮到你的?}[密钥|对称加密算法]
- C -> S: {我的帐号是aaa,密码是123,把我的余额的信息发给我看看}[密钥|对称加密算法]
- S -> C: {你好,你的余额是100元}[密钥|对称加密算法]
......//继续其他通信
2.7 其它问题:
上面的过程已经十分接近HTTPS的真实通信过程了,完全可以按照这个过程去理解HTTPS的工作原理。但是为了方便。上面有些细节没有说到。
- 问题一,上面的通信过程中,在检查完证书后,客户发送要给随机字符串给服务器去用撕咬加密。但是有一个问题,黑客也可以发送一个字符串给服务器去加密,并且得到加密后的内容,这样对于服务器来说是不安全的。因为黑客可以发送一些简单有规律的字符串给服务器去加密,从而寻找加密的规律,有可能威胁到私钥的安全。所以说,服务器随便用私钥加密一个来路不明的字符串,并把结果发送给对方,是不安全的。
解决办法:
每次收到客户发来的要求加密的字符串时,服务器并不是真正加密这个字符串本身。
而是把这个字符串进行一个hash计算,加密这个字符串的hash值后发给客户,
客户收到后,解密这个hash值,并自己计算字符串的hash值,然后比对hash值是否一致。
这样避免了加密那些有规律的字符串。
- 问题二,在双方通信过程中,黑客可以截获发送的加密了的内容,虽然他无法解密,但是可以捣乱,例如,把信息原封不动的发送多次,扰乱通信过程。
解决办法:
可以给通信的内容加上一个序号或者一个随机的值。如果客户或者服务器
收到信息中有之前出现过的序号或者随机值,那么就说明有人在通信过程中
重发信息内容进行捣乱。双发可以立即停止通信。
- 问题三,在双方的通信过程中,黑客除了简单的重复发送截获的消息之外,还可以篡改密文,再发送。会导致解密后明文产生变化。
解决办法:
在每次发送信息时,现对信息的内容进行一个hash计算,将信息的内容
和hash值一起加密后发送。接收方进行解密,得到明文内容和hash值,
然后再对明文内容计算一次hash值,比对与解密出来的hash值是否一致
3.证书的构成和原理
3.1 证书的构成和原理
对于pem格式的X.509证书,可以用openssl命令查看证书的内容。
$ openssl x509 -in httpbinorg.crt -text -noout
如下图:
- Issuer(证书发布者或叫签发机构)
指出是什么机构发布的这个证书,也就是证明这个证书是哪个公司创建的
- Valid from, Valid to (证书的有效期)
指证书的有效时间,或者使用期限
- Public key (公钥)
公钥,是用来对消息进行加密的。这个公钥是2048位,有模数(Modulus)和指数(Exponent)组成。
- Subject(证书的使用者)
这个证书是颁发给谁的,或者说证书的所有者,一般是某人或者某个公司。图中,这个证书的所有者是httpbin.org这个网站。
*Signature algorithm (签名使用的算法)
就是指的这个数字证书的数字签名所使用的加密算法。这样就可以使用证书里的公钥,根据这个算法对
证书指纹
进行解密。证书指纹
的加密结果就是数字签名。如上图。
- 指纹及指纹算法
这个是用来保证证书的完整性,确保证书没有被修改过。和2.7节说到的第三个问题类似。其原理就是在发布证书时,发布者根据指纹算法(一种hash算法)计算整个证书的hash值(指纹)并和证书放在一起。使用者在打开证书时,自己根据指纹算法,计算一下证书的hash值(指纹),如果对得上就说明证书没有被篡改。
用openssl查看证书指纹的命令:
$ openssl x509 -in httpbinorg.crt -fingerprint -noout
SHA1 Fingerprint=7B:4C:0A:BA:34:D3:85:7D:84:D7:58:E5:34:F5:C4:21:9A:7D:65:3D
注意,为了保证安全,在证书的发布机构发布证书时,证书的指纹和指纹算法,都会加密后再和证书放到一起发布,以防有人修改指纹后伪造相应的数字证书。这里问题又来了,证书的指纹和指纹算法用什么加密呢?他们是用证书发布机构的私钥进行加密的。可以用证书发布机构的公钥对指纹和指纹算法解密,也就是说证书发布机构除了给别人发布证书外,他自己本身也有自己的证书。证书发布机构的证书是哪里来的呢???这个证书发布机构的数字证书(一般由他自己生成)在我们的操作系统刚安装好时(例如windows xp等操作系统),这些证书发布机构的数字证书就已经被微软(或者其它操作系统的开发机构)安装在操作系统中了,微软等公司会根据一些权威安全机构的评估选取一些信誉很好并且通过一定的安全认证的证书发布机构,把这些证书发布机构的证书默认就安装在操作系统里面了,并且设置为操作系统信任的数字证书。这些证书发布机构自己持有与他自己的数字证书对应的私钥,他会用这个私钥加密所有他发布的证书的指纹作为数字签名。
3.2如何向证书的发布机构去申请证书
举个例子方便大家理解,假设我们公司"ABC Company"花了1000块钱,向一个证书发布机构"SecureTrust CA"为我们自己的公司"ABC Company"申请了一张证书,注意,这个证书发布机构"SecureTrust CA"是一个大家公认并被一些权威机构接受的证书发布机构,我们的操作系统里面已经安装了"SecureTrust CA"的证书。"SecureTrust CA"在给我们发布证书时,把Issuer,Public key,Subject,Valid from,Valid to等信息以明文的形式写到证书里面,然后用一个指纹算法计算出这些数字证书内容的一个指纹,并把指纹和指纹算法用自己的私钥进行加密,然后和证书的内容一起发布,同时"SecureTrust CA"还会给一个我们公司"ABC Company"的私钥给到我们。我们花了1000块钱买的这个证书的内容如下:
×××××××××××××××证书内容开始×××××××××××××××××
Issuer : SecureTrust CA
Subject : ABC Company
Valid from : 某个日期
Valid to: 某个日期
Public Key : 一串很长的数字
…… 其它的一些证书内容……
{证书的指纹和计算指纹所使用的指纹算法}[SecureTrust CA的私钥|RSA] //这个就是"SecureTrust CA"对这个证书的一个数字签名,表示这个证书确实是他发布的,有什么问题他会负责(收了我们1000块,出了问题肯定要负责任的)
×××××××××××××××证书内容结束×××××××××××××××××
// 记不记得前面的约定?{} 表示RSA加密后的内容,[ | ]表示用什么密钥和算法进行加密
我们"ABC Company"申请到这个证书后,我们把证书投入使用,我们在通信过程开始时会把证书发给对方,对方如何检查这个证书的确是合法的并且是我们"ABC Company"公司的证书呢?首先应用程序(对方通信用的程序,例如IE、OUTLook等)读取证书中的Issuer(发布机构)为"SecureTrust CA" ,然后会在操作系统中受信任的发布机构的证书中去找"SecureTrust CA"的证书,如果找不到,那说明证书的发布机构是个水货发布机构,证书可能有问题,程序会给出一个错误信息。 如果在系统中找到了"SecureTrust CA"的证书,那么应用程序就会从证书中取出"SecureTrust CA"的公钥,然后对我们"ABC Company"公司的证书里面的指纹和指纹算法用这个公钥进行解密,然后使用这个指纹算法计算"ABC Company"证书的指纹,将这个计算的指纹与放在证书中的指纹对比,如果一致,说明"ABC Company"的证书肯定没有被修改过并且证书是"SecureTrust CA" 发布的,证书中的公钥肯定是"ABC Company"的。对方然后就可以放心的使用这个公钥和我们"ABC Company"进行通信了。
★这个部分非常重要,一定要理解,您可以重新回顾一下之前的两章“1、基础知识”和“ 2、一个加密通信过程的演化”,然后再来理解这部分的内容。