You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

145 lines
11 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 24 | 固若金汤的根本(上):对称加密与非对称加密
在上一讲中我们初步学习了HTTPS知道HTTPS的安全性是由TLS来保证的。
你一定很好奇它是怎么为HTTP增加了机密性、完整性身份认证和不可否认等特性的呢
先说说机密性。它是信息安全的基础缺乏机密性TLS就会成为“无水之源”“无根之木”。
实现机密性最常用的手段是“**加密**”encrypt就是把消息用某种方式转换成谁也看不懂的乱码只有掌握特殊“钥匙”的人才能再转换出原始文本。
这里的“钥匙”就叫做“**密钥**”key加密前的消息叫“**明文**”plain text/clear text加密后的乱码叫“**密文**”cipher text使用密钥还原明文的过程叫“**解密**”decrypt是加密的反操作加密解密的操作过程就是“**加密算法**”。
所有的加密算法都是公开的,任何人都可以去分析研究,而算法使用的“密钥”则必须保密。那么,这个关键的“密钥”又是什么呢?
由于HTTPS、TLS都运行在计算机上所以“密钥”就是一长串的数字但约定俗成的度量单位是“位”bit而不是“字节”byte。比如说密钥长度是128就是16字节的二进制串密钥长度1024就是128字节的二进制串。
按照密钥的使用方式,加密可以分为两大类:**对称加密和非对称加密**。
## 对称加密
“对称加密”很好理解,就是指加密和解密时使用的密钥都是同一个,是“对称”的。只要保证了密钥的安全,那整个通信过程就可以说具有了机密性。
举个例子,你想要登录某网站,只要事先和它约定好使用一个对称密钥,通信过程中传输的全是用密钥加密后的密文,只有你和网站才能解密。黑客即使能够窃听,看到的也只是乱码,因为没有密钥无法解出明文,所以就实现了机密性。
![](https://static001.geekbang.org/resource/image/8f/49/8feab67c25a534f8c72077680927ab49.png)
TLS里有非常多的对称加密算法可供选择比如RC4、DES、3DES、AES、ChaCha20等但前三种算法都被认为是不安全的通常都禁止使用目前常用的只有AES和ChaCha20。
AES的意思是“高级加密标准”Advanced Encryption Standard密钥长度可以是128、192或256。它是DES算法的替代者安全强度很高性能也很好而且有的硬件还会做特殊优化所以非常流行是应用最广泛的对称加密算法。
ChaCha20是Google设计的另一种加密算法密钥长度固定为256位纯软件运行性能要超过AES曾经在移动客户端上比较流行但ARMv8之后也加入了AES硬件优化所以现在不再具有明显的优势但仍然算得上是一个不错的算法。
## 加密分组模式
对称算法还有一个“**分组模式**”的概念,它可以让算法用固定长度的密钥加密任意长度的明文,把小秘密(即密钥)转化为大秘密(即密文)。
最早有ECB、CBC、CFB、OFB等几种分组模式但都陆续被发现有安全漏洞所以现在基本都不怎么用了。最新的分组模式被称为AEADAuthenticated Encryption with Associated Data在加密的同时增加了认证的功能常用的是GCM、CCM和Poly1305。
把上面这些组合起来就可以得到TLS密码套件中定义的对称加密算法。
比如AES128-GCM意思是密钥长度为128位的AES算法使用的分组模式是GCMChaCha20-Poly1305的意思是ChaCha20算法使用的分组模式是Poly1305。
你可以用实验环境的URI“/24-1”来测试OpenSSL里的AES128-CBC在URI后用参数“key”“plain”输入密钥和明文服务器会在响应报文里输出加密解密的结果。
```
https://www.chrono.com/24-1?key=123456
algo = aes_128_cbc
plain = hello openssl
enc = 93a024a94083bc39fb2c2b9f5ce27c09
dec = hello openssl
```
## 非对称加密
对称加密看上去好像完美地实现了机密性,但其中有一个很大的问题:如何把密钥安全地传递给对方,术语叫“**密钥交换**”。
因为在对称加密算法中只要持有密钥就可以解密。如果你和网站约定的密钥在传递途中被黑客窃取,那他就可以在之后随意解密收发的数据,通信过程也就没有机密性可言了。
这个问题该怎么解决呢?
你或许会说:“把密钥再加密一下发过去就好了”,但传输“加密密钥的密钥”又成了新问题。这就像是“鸡生蛋、蛋生鸡”,可以无限递归下去。只用对称加密算法,是绝对无法解决密钥交换的问题的。
所以,就出现了非对称加密(也叫公钥加密算法)。
它有两个密钥,一个叫“**公钥**”public key一个叫“**私钥**”private key。两个密钥是不同的“不对称”公钥可以公开给任何人使用而私钥必须严格保密。
公钥和私钥有个特别的“**单向**”性,虽然都可以用来加密解密,但公钥加密后只能用私钥解密,反过来,私钥加密后也只能用公钥解密。
非对称加密可以解决“密钥交换”的问题。网站秘密保管私钥,在网上任意分发公钥,你想要登录网站只要用公钥加密就行了,密文只能由私钥持有者才能解密。而黑客因为没有私钥,所以就无法破解密文。
![](https://static001.geekbang.org/resource/image/89/17/89344c2e493600b486d5349a84318417.png)
非对称加密算法的设计要比对称算法难得多在TLS里只有很少的几种比如DH、DSA、RSA、ECC等。
RSA可能是其中最著名的一个几乎可以说是非对称加密的代名词它的安全性基于“**整数分解**”的数学难题,使用两个超大素数的乘积作为生成密钥的材料,想要从公钥推算出私钥是非常困难的。
10年前RSA密钥的推荐长度是1024但随着计算机运算能力的提高现在1024已经不安全普遍认为至少要2048位。
ECCElliptic Curve Cryptography是非对称加密里的“后起之秀”它基于“**椭圆曲线离散对数**”的数学难题使用特定的曲线方程和基点生成公钥和私钥子算法ECDHE用于密钥交换ECDSA用于数字签名。
目前比较常用的两个曲线是P-256secp256r1在OpenSSL称为prime256v1和x25519。P-256是NIST美国国家标准技术研究所和NSA美国国家安全局推荐使用的曲线而x25519被认为是最安全、最快速的曲线。
ECC名字里的“椭圆”经常会引起误解其实它的曲线并不是椭圆形只是因为方程很类似计算椭圆周长的公式实际的形状更像抛物线比如下面的图就展示了两个简单的椭圆曲线。
![](https://static001.geekbang.org/resource/image/b4/ba/b452ceb3cbfc5c644a3053f2054b1aba.jpg)两个简单的椭圆曲线y^2=x^3+7y^2=x^3-x
比起RSAECC在安全强度和性能上都有明显的优势。160位的ECC相当于1024位的RSA而224位的ECC则相当于2048位的RSA。因为密钥短所以相应的计算量、消耗的内存和带宽也就少加密解密的性能就上去了对于现在的移动互联网非常有吸引力。
实验环境的URI“/24-2”演示了RSA1024你在课后可以动手试一下。
## 混合加密
看到这里,你是不是认为可以抛弃对称加密,只用非对称加密来实现机密性呢?
很遗憾虽然非对称加密没有“密钥交换”的问题但因为它们都是基于复杂的数学难题运算速度很慢即使是ECC也要比AES差上好几个数量级。如果仅用非对称加密虽然保证了安全但通信速度有如乌龟、蜗牛实用性就变成了零。
实验环境的URI“/24-3”对比了AES和RSA这两种算法的性能下面列出了一次测试的结果
```
aes_128_cbc enc/dec 1000 times : 0.97ms, 13.11MB/s
rsa_1024 enc/dec 1000 times : 138.59ms, 93.80KB/s
rsa_1024/aes ratio = 143.17
rsa_2048 enc/dec 1000 times : 840.35ms, 15.47KB/s
rsa_2048/aes ratio = 868.13
```
可以看到RSA的运算速度是非常慢的2048位的加解密大约是15KB/S微秒或毫秒级而AES128则是13MB/S纳秒级差了几百倍。
那么,是不是能够把对称加密和非对称加密结合起来呢,两者互相取长补短,即能高效地加密解密,又能安全地密钥交换。
这就是现在TLS里使用的**混合加密**方式,其实说穿了也很简单:
在通信刚开始的时候使用非对称算法比如RSA、ECDHE首先解决密钥交换的问题。
然后用随机数产生对称算法使用的“**会话密钥**”session key再用公钥加密。因为会话密钥很短通常只有16字节或32字节所以慢一点也无所谓。
对方拿到密文后用私钥解密,取出会话密钥。这样,双方就实现了对称密钥的安全交换,后续就不再使用非对称加密,全都使用对称加密。
![](https://static001.geekbang.org/resource/image/e4/85/e41f87110aeea3e548d58cc35a478e85.png)
这样混合加密就解决了对称加密算法的密钥交换问题,而且安全和性能兼顾,完美地实现了机密性。
不过这只是“万里长征的第一步”,后面还有完整性、身份认证、不可否认等特性没有实现,所以现在的通信还不是绝对安全,我们下次再说。
## 小结
1. 加密算法的核心思想是“把一个小秘密(密钥)转化为一个大秘密(密文消息)”,守住了小秘密,也就守住了大秘密;
2. 对称加密只使用一个密钥运算速度快密钥必须保密无法做到安全的密钥交换常用的有AES和ChaCha20
3. 非对称加密使用两个密钥公钥和私钥公钥可以任意分发而私钥保密解决了密钥交换问题但速度慢常用的有RSA和ECC
4. 把对称加密和非对称加密结合起来就得到了“又好又快”的混合加密也就是TLS里使用的加密方式。
## 课下作业
1. 加密算法中“密钥”的名字很形象,你能试着用现实中的锁和钥匙来比喻一下吗?
2. 在混合加密中用到了公钥加密,因为只能由私钥解密。那么反过来,私钥加密后任何人都可以用公钥解密,这有什么用呢?
欢迎你把自己的学习体会写在留言区,与我和其他同学一起讨论。如果你觉得有所收获,也欢迎把文章分享给你的朋友。
![unpreview](https://static001.geekbang.org/resource/image/b4/d7/b437f2b898a2f3424bd8812d9a0dcbd7.png)