一、准备知识
在开始介绍前,需要首先了解一下消息摘要、数字签名、数字证书的知识
1、消息摘要 - Message Digest
消息摘要(Message Digest) ,又称数字摘要(Digital Digest)或数字指纹(Finger Print)。简单来说,消息摘要就是在消息数据上,执行一个单向的Hash函数,生成一个固定长度的Hash值,这个Hash值即是消息摘要,Hash算法有MD5,SHA。它有以下特征:
无论输入的消息有多长,计算出来的消息摘要的长度总是固定的。例如应用MD5算法摘要的消息有128个比特位,用SHA-1算法摘要的消息最终有160比特位的输出,SHA-1的变体可以产生192比特位和256比特位的消息摘要。一般认为,摘要的最终输出越长,该摘要算法就越安全。
消息摘要看起来是“随机的”。这些比特看上去是胡乱的杂凑在一起的。可以用大量的输入来检验其输出是否相同,一般,不同的输入会有不同的输出,而且输出的摘要消息可以通过随机性检验。但是,一个摘要并不是真正随机的,因为用相同的算法对相同的消息求两次摘要,其结果必然相同;而若是真正随机的,则无论如何都是无法重现的。因此消息摘要是“伪随机的”。
消息摘要函数是单向函数,即只能进行正向的信息摘要,而无法从摘要中恢复出任何的消息,甚至根本就找不到任何与原信息相关的信息。当然,可以采用强力攻击的方法,即尝试每一个可能的信息,计算其摘要,看看是否与已有的摘要相同,如果这样做,最终肯定会恢复出摘要的消息。但实际上,要得到的信息可能是无穷个消息之一,所以这种强力攻击几乎是无效的。好的摘要算法,没有人能从中找到“碰撞”,虽然“碰撞”是肯定存在的(由于长明文生成短摘要的Hash必然会产生碰撞)。
正是由于以上特点,消息摘要算法被广泛应用在“数字签名”领域,作为对明文的摘要算法。著名的消息摘要算法有RSA公司的MD5算法和SHA-1算法及其大量的变体。
2、数字签名 - Signature
数字签名方案是一种以电子形式存储消息签名的方法。一个完整的数字签名方案应该由两部分组成:签名算法和验证算法。在讲数字签名之前,我们先简单介绍几个相关知识点:“公钥密码体制”、“对称加密算法”、“非对称加密算法”。
公钥密码体制(public-key cryptography):
公钥密码体制分为三个部分,公钥、私钥、加密解密算法,它的加密解密过程如下:
加密:通过加密算法和公钥对内容(或者说明文)进行加密,得到密文。加密过程需要用到公钥。
解密:通过解密算法和私钥对密文进行解密,得到明文。解密过程需要用到解密算法和私钥。注意,由公钥加密的内容,只能由私钥进行解密,也就是说,由公钥加密的内容,如果不知道私钥,是无法解密的。
公钥密码体制的公钥和算法都是公开的(这是为什么叫公钥密码体制的原因),私钥是保密的。大家都以使用公钥进行加密,但是只有私钥的持有者才能解密。在实际 的使用中,有需要的人会生成一对公钥和私钥,把公钥发布出去给别人使用,自己保留私钥。目前使用最广泛的公钥密码体制是RSA密码体制。
对称加密算法(symmetric key algorithms):
在对称加密算法中,加密和解密都是使用的同一个密钥。因此对称加密算法要保证安全性的话,密钥要做好保密,只能让使用的人知道,不能对外公开。
非对称加密算法(asymmetric key algorithms):
在非对称加密算法中,加密使用的密钥和解密使用的密钥是不相同的。前面所说的公钥密码体制就是一种非对称加密算法,他的公钥和是私钥是不能相同的,也就是说加密使用的密钥和解密使用的密钥不同,因此它是一个非对称加密算法。
RSA简介:
RSA密码体制是一种公钥密码体制,公钥公开,私钥保密,它的加密解密算法是公开的。 由公钥加密的内容可以并且只能由私钥进行解密,而由私钥加密的内容可以并且只能由公钥进行解密。也就是说,RSA的这一对公钥、私钥都可以用来加密和解密,并且一方加密的内容可以由并且只能由对方进行解密。
加密:公钥加密,私钥解密的过程,称为“加密”。因为公钥是公开的,任何公钥持有者都可以将想要发送给私钥持有者的信息进行加密后发送,而这个信息只有私钥持有者才能解密。
签名: 私钥加密,公钥解密的过程,称为“签名”。它和加密有什么区别呢?因为公钥是公开的,所以任何持有公钥的人都能解密私钥加密过的密文,所以这个过程并不能 保证消息的安全性,但是它却能保证消息来源的准确性和不可否认性,也就是说,如果使用公钥能正常解密某一个密文,那么就能证明这段密文一定是由私钥持有者 发布的,而不是其他第三方发布的,并且私钥持有者不能否认他曾经发布过该消息。故此将该过程称为“签名”。
数字签名
事实上,任何一个公钥密码体制都可以单独地作为一种数字签名方案使用。如RSA作为数字签名方案使用时,可以定义如下:
这种签名实际上就是用信源的私钥加密消息,加密后的消息即成了签体;而用对应的公钥进 行验证,若公钥解密后的消息与原来的消息相同,则消息是完整的,否则消息不完整。它正好和公钥密码体制用于消息保密是相反的过程。因为只有信源才拥有自己的私钥,别人无法重新加密源消息,所以即使有人截获且更改了源消息,也无法重新生成签体,因为只有用信源的私钥才能形成正确地签体。同样信宿只要验证用信源的公钥解密的消息是否与明文消息相同,就可以知道消息是否被更改过,而且可以认证消息是否是确实来自意定的信源,还可以使信源不能否认曾经发送的消息。所以 这样可以完成数字签名的功能。
但这种方案过于单纯,它仅可以保证消息的完整性,而无法确保消息的保密性。而且这种方案要对所有的消息进行加密操作,这在消息的长度比较大时,效率是非常低的,主要原因在于公钥体制的加解密过程的低效性。所以这种方案一般不可取。
几乎所有的数字签名方案都要和快速高效的摘要算法(Hash函数)一起使用,当公钥算法与摘要算法结合起来使用时,便构成了一种有效地数字签名方案。
这个过程是:
用摘要算法对消息进行摘要。
再把摘要值用信源的私钥加密。
通过以上两步得到的消息就是所谓的原始信息的数字签名,发送者需要将原始信息和数字签名一同发送给接收者。而接收者在接收到原始信息和数字签名后,通过以下3步验证消息的真伪:
先把接收到的原始消息用同样的摘要算法摘要,形成“准签体”。
对附加上的那段数字签名,使用预先得到的公钥解密。
比较前两步所得到的两段消息是否一致。如果一致,则表明消息确实是期望的发送者发的,且内容没有被篡改过;相反,如果不一致,则表明传送的过程中一定出了问题,消息不可信。
这种方法使公钥加密只对消息摘要进行操作,因为一种摘要算法的摘要消息长度是固定的,而且都比较“短”(相对于消息而言),正好符合公钥加密的要求。这样效率得到了提高,而其安全性也并未因为使用摘要算法而减弱。
综上所述,数字签名是非对称加密技术 + 消息摘要技术的结合。
3、数字证书 - Certificate
通过数字签名技术,确实可以解决可靠通信的问题。一旦验签通过,接收者就能确信该消息是期望的发送者发送的,而发送者也不能否认曾经发送过该消息。大家有没有注意到,前面讲的数字签名方法,有一个前提,就是消息的接收者必须事先得到正确的公钥。如果一开始公钥就被别人篡改了,那坏人就会被你当成好人,而真正的消息发送者给你发的消息会被你视作无效的。而且,很多时候根本就不具备事先沟通公钥的信息通道。那么如何保证公钥的安全可信呢?这就要靠数字证书来解决了。
数字证书是一个经证书授权(Certificate Authentication)中心数字签名的包含公钥拥有者信息以及公钥的文件。数字证书的格式普遍采用的是X.509V3国际标准,一个标准的X.509数字证书通常包含以下内容:
证书的发布机构(Issuer)
- 该证书是由哪个机构(CA中心)颁发的。证书的有效期(Validity)
- 证书的有效期,或者说使用期限。过了该日期,证书就失效了。证书所有人的公钥(Public-Key)
- 该证书所有人想要公布出去的公钥。证书所有人的名称(Subject)
- 这个证书是发给谁的,或者说证书的所有者,一般是某个人或者某个公司名称、机构的名称、公司网站的网址等。证书所使用的签名算法(Signature algorithm)
- 这个数字证书的数字签名所使用的加密算法,这样就可以使用证书发布机构的证书里面的公钥,根据这个算法对指纹进行解密。证书发行者对证书的数字签名(Thumbprint)
- 也就是该数字证书的指纹,用于保证数字证书的完整性,确保证书没有被修改过。其原理就是在发布证书时,CA机构会根据签名算法(Signature algorithm)对整个证书计算其hash值(指纹)并和证书放在一起,使用者打开证书时,自己也根据签名算法计算一下证书的hash值(指纹),如 果和证书中记录的指纹对的上,就说明证书没有被修改过。
可以看出,数字证书本身也用到了数字签名技术,只不过签名的内容是 整个证书(里面包含了证书所有者的公钥以及其他一些内容)。与普通数字签名不同的是,数字证书的签名者不是随随便便一个普通机构,而是CA机构。这就好像 你的大学毕业证书上签名的一般都是德高望重的校长一样。一般来说,这些CA机构的根证书已经在设备出厂前预先安装到了你的设备上了。所以,数字证书可以保 证证书里的公钥确实是这个证书所有者的,或者证书可以用来确认对方的身份。可见,数字证书主要是用来解决公钥的安全发放问题。
HTTPS加密过程
建议可以在电脑上安装一下Woreshark,这个软件方便直观的观察加密流程。
https:在http(超文本传输协议)基础上提出的一种安全的http协议,因此可以称为安全的超文本传输协议。http协议直接放置在TCP协议之上,而https提出在http和TCP中间加上一层加密层。从发送端看,这一层负责把http的内容加密后送到下层的TCP,从接收方看,这一层负责将TCP送来的数据解密还原成http的内容。
密钥交换/协商机制的几种类型
依靠非对称加密算法
原理:拿到公钥的一方先生成随机的会话密钥,然后利用公钥加密它;再把加密结果发给对方,对方用私钥解密;于是双方都得到了会话密钥。
举例:RSA依靠专门的密钥交换算法
原理:这个比较复杂,一两句话说不清楚,待会儿聊到 DH 的那个章节会详谈。
举例:DH(Diffie–Hellman的简写),ECDH(DH 的变种)
基于RSA的秘钥交换
这大概是 SSL 最古老的密钥协商方式(我更倾向称之为秘钥交换)——早期的 SSLv2 只支持一种密钥协商机制,就是它。交换过程如下:
现在,假设A与B通信,A是SSL客户端(上图左侧),B是SSL服务器端(上图右侧):
A(客户端):我想和你(服务端)安全的通话,我支持的加密算法组合有这些,并生成了一随机数Client Random(把消息封装成Client Hello发送给B)。
B(服务端):我们用ECDHE-RSA-SHA这对组合好了,我也生成一个随机值Server Random(把消息封装成Server Hello发送给A)。
B(服务端):这是我的证书,里面有我的信息和公钥,你拿去验证一下我的身份吧(把证书Certificate发给A)。
A(客户端):(收到B发来的加密方式和证书Certificate,验证B的证书的真实性,如果其中一项有误,发出警告并断开连接,这一步保证了B的公钥的真实性,至于如何验证下面详细讲)
确认数字证书有效,然后生成一个新的随机数(Premaster secret),并使用数字证书中的公钥加密了这个随机数,发给服务器B。
接着,A和B分别根据约定的加密方法,使用前面的三个随机数(Client Random,Server Random,Premaster secret),生成"对话密钥"(session key),用来加密接下来的整个对话过程。
握手阶段有三点需要注意:
(1)生成对话密钥一共需要三个随机数。
(2)握手之后的对话使用"对话密钥"加密(对称加密),服务器的公钥和私钥只用于加密和解密"对话密钥"(非对称加密),无其他作用。
(3)服务器公钥放在服务器的数字证书之中。
通过上面的分析,可以看到整个握手阶段都不加密(也没法加密),都是明文的。因此,如果有人窃听通信,他可以知道双方选择的加密方法,以及三个随机数中的两个。整个通话的安全,只取决于第三个随机数(Premaster secret)能不能被破解。
虽然理论上,只要服务器的公钥足够长(比如2048位),那么Premaster secret可以保证不被破解。但是为了足够安全,我们可以考虑把握手阶段的算法从默认的RSA算法,改为 Diffie-Hellman算法(简称DH算法)。
基于DH(ECDH,ECDHE)算法的秘钥协商
DH 算法又称“Diffie–Hellman 算法”。这是两位数学牛人的名称,他们创立了这个算法。该算法用来实现【安全的】“密钥交换”。它可以做到——“通讯双方在完全没有对方任何预先信息的条件下通过不安全信道创建起一个密钥”。这句话比较绕口。
先看看DH的具体算法:
通讯双方(张三、李四)需要先约定好算法参数(algorithm parameters):一个素数 p 作为模数,一个素数 g 作为基数(g 也称为“生成元”)。这两个算法参数是可以对外公开滴。
对于张三而言,需要先想好一个秘密的自然数 a 作为私钥(不能公开),然后计算 A = g^a mod p 作为自己的公钥(可以公开)。
对李四而言也类似,先想好一个秘密的自然数 b 作为私钥(不能公开),然后计算 B = g^b mod p 作为自己的公钥(可以公开)。
张三和李四互相交换各自的公钥。
然后张三计算出 k = Ba mod p,李四计算出 k = Ab mod p
该算法至少确保了如下几点:
- 张三和李四分别计算出来的 k 必定是一致的
- 张三和李四都无法根据已知的数来推算出对方的私钥(张三无法推算出 b,李四无法推算出 a)
- 对于一个旁观者(偷窥者),虽然能看到 p,g,A,B,但是无法推算出 a 和 b(就是说,旁观者无法推算出双方的私钥),自然也无法推算出 k
采用DH算法后,Premaster secret不需要传递,双方只要交换各自的参数,就可以算出这个随机数。
ECDH是DH算法一个变种,它是ECC算法和DH的结合。ECC是建立在基于椭圆曲线的离散对数问题上的密码体制,给定椭圆曲线上的一个点P,一个整数k,求解Q=kP很容易;给定一个点P、Q,知道Q=kP,求整数k确是一个难题。所以看得出DH 依赖的是——求解“离散对数问题”的困难,而ECDH 依赖的就是——求解“椭圆曲线离散对数问题”的困难。DH和ECDH的主要的作用就是在通信双方发送一些公有参数,保留私有参数,而后通过一系列计算双方都能够得到一个一致的结果。而这个运算的逆运算复杂度过高,在有限时间内不可解(至少量子计算机问世以前不可解),以保证密钥安全性。在实际使用过程中我们可能更多的会看到ECDHE这个词,这个多出来的E的意思是指每次公钥都随机生成,可以说是对ECDH的一个升级版,算法是一样的。
让我们领略一下ECDH算法的大概思路:
假设密钥交换双方为Alice、Bob,其有共享曲线参数(椭圆曲线E、阶N、基点G)。
Alice生成随机整数a,计算A=a*G。 A作为Alice公钥
Bob生成随机整数b,计算B=b*G。 B作为Bob公钥
-
Alice将自己的公钥A传递给Bob。A的传递可以公开,即攻击者可以获取A。
(由于椭圆曲线的离散对数问题是难题,所以攻击者不可以通过A、G计算出a。)
Bob将B传递给Alice。同理,B的传递可以公开。
Bob收到Alice传递的A,计算Q =b*A #Bob通过自己的私钥和Alice的公钥得到对称密钥Q
Alice收到Bob传递的B,计算Q`=a*B #Alice通过自己的私钥和Bob的公钥得到对称密钥Q'
Alice、Bob双方即得Q=bA=b(aG)=(ba)G=(ab)G=a(bG)=aB=Q' (交换律和结合律),即双方得到一致的密钥Q。
在了解了ECDH秘钥协商算法后,开始分析基于ECDH的TLS握手过程:
现在来说一下客户端是如何验证服务端发来的证书Certificate的:
客户端接到服务器传来的证书,从本机得到CA的公钥值,这样就可以解密数字证书末尾的数字签名了,解密签名得到原始的证书摘要HASHs,然后自己也按照证书中的HASH算法,自己也对证书计算一个摘要HASHc,如果HASHs == HASHc,则认证通过,否则认证失败。