对称加密
对称加密是早期的加密算法。多方维护同一份秘钥K,A将报文T用K加密得到加密信息K(T),B获得K(T),通过秘钥T解密得到原报文T。
对称加密最大的隐患在于秘钥的分发不方便,如果没有安全的渠道,一旦秘钥被窃听,加密机制就作废了。
非对称加密
Part 1 工作原理
A和B各自维护一对公私钥,<A_PUB_KEY,A_PRI_KEY>和<B_PUB_KEY,B_PRI_KEY>,公钥可以直接广播出去让所有人看到,而私钥自己留存。
加密过程也十分简单:A意图向B发送报文T,则A只需通过B的公钥(B的公钥被广播了)将T加密为B_PUB_KEY(T),并将加密报文以任意形式发出。无论是点对点发送还是广播,只有B收到报文,才可以使用B_PRI_KEY将加密报文还原为T,因为只有B拥有B_PRI_KEY。
B向A发送回复信息的过程同理,只需用A的公钥加密并发出,只有A使用自己的私钥解密才会获得正确的信息。
Part 2 应用:虚拟货币
非对称加密机制在生活中是很常见的,比如银行账户。银行账户的<账号,密码>就是一对公私钥。账号作为公钥,可以任意传播,别人只需知道你的账号就可以向你转账,而密码作为私钥,只有自己知道,只有知道密码,才能从账户中提款。这样,一笔交易就通过公私钥的使用而被加密。
虚拟货币作为另一种形式上的“银行”,当然也存在着非对称加密机制的应用。
以比特币系统为例,比特币是一条公链,即链上的信息不做加密,对所有人公开,那非对称加密体系如何应用呢?这就牵涉到一个重要的思想,加密技术不仅可以用于信息的加密,还可以用于信息的正确性校验。
区块链上信息的正确性校验,在比特币系统中称为“签名”。假如区块链上发布了这样一条交易信息(每一笔交易以区块的形式加入区块链):用户A要向用户B发起一笔交易,A将一个比特币转账给B。
区块链中的其他参与者如何知道交易的真实性?他们也许会有这样的疑问:这条交易信息真的是A本人发布的吗?是不是B试图冒名顶替A,以转走他账户里的余额?
因此,比特币的签名机制规定:上传到区块链上的区块,需要被上传者通过自己的私钥签名,而其他人只需要使用“声称是这笔交易的发起者”的这个人的公钥对区块上的签名进行验证,就可以判断这个“声称者”是不是本人。
理论上是存在一种可能的:某人大量生成公私钥对,发现某个自己随机生成的公钥和现在已有的某个人的公钥一致,说明生成的这个私钥也就是他的私钥,那这样就可以狸猫换太子,用他的私钥伪装成他,骗他的钱。当然这只是理论上的一种可能,理论上的可能就等于不可能。
因为比特币用于随机生成公私钥的算法是很好的,理论上不存在生成相同公私钥对的可能,不过如果一些系统中的随机源算法不那么给力,可能就会出现相同公私钥的情况。比特币系统中的每一次签名,都会随机生成一次公私钥,避免重用,这也规避了私钥泄露导致的安全隐患。一年不换一次门锁,钥匙丢了就完蛋了。一天换一次门锁,那今天的钥匙被偷了也无所谓,明天老子换锁了。
所以公私钥体系的两种玩法我们都已经清楚:
- 信息加密:公钥加密,私钥解密
- 信息校验:私钥签名,公钥验证
Part 3 RSA非对称加密算法
阮一峰:RSA算法原理
RSA被称为“地球上最重要的加密算法”,使用github的时候我们会配置SSH,git在本地生成一对公私钥,使用的就是RSA加密算法。本文不去讨论RSA背后复杂的数学推导。
其实加密的基本思想很简单,举个例子:15684×86196,这个乘法其实很容易就算到结果,比如结果是n,因为我没有算。但如果现在我给出一个n,想让你计算出这个数是哪两个数字相乘得到的,这个就很复杂了。所以其实我就相当于仅仅用了一次乘法,就加密了(15684,86196这对信息。RSA也是这样的,只不过它所使用的加密方式更加复杂,同样的,根据密文倒推原信息的难度也就更大。
公私钥的生成在上面引用的blog里有很详细的过程,在这里简单复述原作者的描述:
- Step 1:随机选择两个不相等的质数 p 和 q ,如 61 和 53 ,这两个质数越大,就越难破解;
- Step 2:计算p和q的乘积n,此时 n = 3233 ,写成二进制有12位,因此公钥的长度就是12,RSA的公钥长度一般为1024;
- Step 3:计算n的欧拉函数
φ(n) = (p-1)(q-1)
,这里φ(n) = (61-1)(53-1) = 3120;- Step 4:在1与φ(n)间任取一个与φ(n)互质的整数e,这里选择 17 好了(实际通常选择65537);
- Step 5:计算 e 对于 φ(n) 的模反元素d,即求解
17x + 3120y = 1
,这里得到(x,y) = (2753,-15),即 d = 2753;- Step 6:将n和e封装成公钥,n和d封装成私钥,此时公钥为(3233,17),私钥为(3233, 2753)。
下一步,就是公私钥的加密和解密,就不再赘述了。
Part 4 应用:HTTPS协议
HTTP协议采用的是明文传输不加密的形式,那自然就有很多问题,比如篡改、窃听、冒充。所谓HTTPS协议,就是在HTTP协议应用层和传输层间加了一个SSH/TLS层。这个安全协议层实现了三件事:信息加密、信息校验、数字证书。
信息加密
采用的是一种 对称加密 + 非对称加密 的混合加密 :
- 通信建立前,采用非对称加密交换公钥;
- 通信过程中,一律采用对称加密对报文进行加密。
假设一个web服务器S与浏览器B通信的场景,则HTTPS协议的通信模式如下:
- S生成一对公私钥<S_PUB,S_PRI>;
- B向S发出连接请求,获得S的公钥S_PUB;
- B随机生成一个对称加密的密钥K,K通过S_PUB加密得到S_PUB(K);
- S收到S_PUB(K),解密拿到K,S和B通过对称加密通信,即每次只使用K加密报文。
对称加密速度快,可靠性低,非对称加密更安全,然而解密开销极大。混合加密的过人之处就在于:为了保障服务质量,需要更高效的对称加密。然而对称加密的安全隐患,就在于秘钥K可能泄露。那么干脆就用非对称加密技术把这个K加密,这样就解决了对称加密的安全问题。
数字证书
看似完美无缺的混合加密机制也存在漏洞:
- 一旦有人(比如H)在S向B传输S_PUB的过程中截获了S_PUB,并将自己生成的公钥H_PUB封装好传输给B;
- 等到B向S传输S_PUB(K)(实质依旧是H_PUB(K))的过程中再次截获H_PUB(K),并用自己的H_PRI解密得到K,再偷偷摸摸地用自己截获的S_PUB将K封好传给S。
那么这个劫持者H,就神不知鬼不觉地获得了S和B间的秘钥X,而S和B一无所知。这就是中间人攻击,根本原因是:浏览器不知道自己收到的公钥到底是不是服务器自己的。
计算机世界有很多的问题,但并不是每个问题都有最合适的算法去求解。换句话说,算法只是解决问题的工具,真正能解决问题的不是算法,是人。
于是人规定:每个web服务器使用HTTPS之前,必须得去第三方权威机构 CA (数字证书认证机构)申请一张数字证书,你的个人信息和公钥,都存放在这张证书里。这张证书,就采用数字签名技术做防伪,当浏览器向服务器请求公钥的时候,它将不再得到一个不知道是谁的公钥,而是一张写好了姓名和公钥、并且得到第三方认证的证书。
CA机构使用自己的私钥对签名进行加密,浏览器只需要使用CA的公钥验证签名即可。那么如果浏览器和CA服务器之间发生中间人攻击呢?大可放心,CA自己的证书上还有许许多多的信息(比如域名),它会保证自己是独一无二、不可伪造的。
当然,证书之间也可以存在信任链,也叫数字证书的证书链。A颁发证书给B,B颁发证书给C,C再颁发证书给D。D想知道C的证书是否可信,就会一层一层地向上找给C颁发证书的人,找到了A。A是绝对可信的,称为根证书,根证书是自签名的,即不需再向上找公钥去验证它的真实性。那么D从A那里拿到了A的公钥,用A的公钥去验证B,再拿到B的公钥验证C,就可以判断C是否可信。
平时遇到 “该网站证书不可信” 的情况,多半是这个网站的根证书有问题。那想上这个网站就得自己去手动下载根证书,当然后果也是自负的。
摘要算法
最后来说一说摘要算法。它的特点是它根本就不需要秘钥,也就不存在密钥的管理与分发问题,并且经过加密的数据无法被解密,适用于分布式系统。
其实所有数据校验的方法,思想都跟什么汉明码、CRC是一样的,只不过用的数学工具不同罢了:发送端生成一个代表原文件的独一无二的码1,码1跟原文件一起发出去。接收端收到文件,对收到的文件计算一个码2,跟同时收到的码1对比,如果一致,说明文件没被篡改。
在发送报文之前,摘要算法会先对这个报文做一次Hash,结果是一个定长的数(长度与报文长度无关)。这个数就是摘要,又叫数字指纹。这里涉及到哈希了,那其实我们只需要知道这个Hash函数性质很好,对于不同的明文,会生成不同的摘要就行(即不发生哈希碰撞)。比较好的摘要算法比如MD5、SHA。
我们抛开公私钥体系下数字签名的做法,其实这个摘要算法,也是在做一个数字签名,目的就是验证这个东西是不是真的,只是不需要公私钥罢了。