对称密码快,但钥匙送不出去;公钥密码能送钥匙,但慢得离谱。 所以它们从来不是二选一——HTTPS 用的是两者接力。
前面三节讲的都是「怎么发现坏人」。这一节开始讲「怎么让坏人看见了也没用」。 Demo 算两张表:口令长度对应的爆破时间,和「RSA 一次只能加密多少字节」。
一、对称密码:一把钥匙开两把锁
对称的意思是加密和解密用同一把钥匙。 它的代表是 AES,工作方式是把数据切成固定长度的块,一块一块地变换。 它的优点是快:今天的 CPU 有专门的指令,AES 能跑到每秒几个 GB。 它的问题只有一个,但很致命:钥匙怎么送过去。 你要给对面一把钥匙,就得先有一条安全的通道,而这条通道本身又需要钥匙——这是一个死循环。 历史上所有对称密码的失败,几乎都失败在「钥匙管理」上,而不是算法被破解。 还有一个坑叫「工作模式」:同样的 AES,配不同的模式,安全性天差地别。 ECB 模式是把每个块独立加密, 于是同样的明文块会得到同样的密文块——一张纯色背景的图片加密之后,轮廓还看得见。 CBC 让每块先和前一块异或,GCM 还顺带给了完整性校验。 所以「用了 AES」这句话不完整,必须说「用了哪个模式」。
二、公钥密码:两把钥匙,一人一套
公钥密码把钥匙拆成一对:公钥公开,谁都能拿去加密;私钥自己留着,只有它能解开。 于是「送钥匙」这个死循环被解开了——公钥本来就不怕被人看见。 它的安全性建立在一个数学难题上:RSA 靠「大数分解」, 给你两个大素数相乘的结果,你很难反推出那两个素数。 椭圆曲线靠「离散对数」,同样的强度下密钥短得多,所以手机和物联网上更常用。 代价有两个,都很硬: 一是慢,同样强度的运算,公钥密码比对称密码慢三个数量级; 二是一次只能加密一小块,RSA-2048 一次最多 245 字节, 因为它的数学结构只对「比模数小的数」成立。 所以「用 RSA 加密一个文件」这个想法,从原理上就走不通——不是慢,是装不下。
三、混合加密:两者的接力
真实的做法是把两件事分开: 公钥只用来送一把临时的对称密钥,数据本身全部用对称密钥加密。 这个流程只有三步:客户端生成一把随机的对称密钥,用服务器的公钥把它加密后发过去, 之后双方就用那把对称密钥说话。 这就是 HTTPS 的全部秘密,也是 SSH、IPsec、VPN 的共同骨架。 所以「公钥密码比对称密码高级」这个印象是错的: 它们分工不同——公钥负责「把钥匙安全地送到对面」,对称密钥负责「把数据快速地搬过去」。 一个管信任,一个管吞吐。 最后记住这张表里的一个反直觉数字:RSA-2048 只相当于 112 位强度,而不是 2048 位。 因为公钥密码的密钥里有一大半是结构信息,它们不提供任何安全性,只是让运算能成立。 所以「位数」和「强度」不是一比一,跨算法比较位数是没有意义的。
四、动手 Demo:口令长度和密钥长度,到底差在哪儿
假设字符集 95 个、离线爆破每秒十亿次,算长度 6 到 12 位的破解时间; 再算 RSA-2048 加密 1 MB 要多少次。
rate = 1e9 # 每秒尝试次数
for n in (6, 8, 10, 12):
space = 95 ** n
print(n, "%.3e" % space, round(space / rate / 86400 / 365, 1), "年")
blocks = (1 << 20) // 245 + 1 # RSA-2048 一次最多 245 字节
print(blocks, "次", blocks * 0.001, "秒")
实跑输出:
--------------------------------------------------------------------
口令长度和密钥长度,到底差在哪儿
--------------------------------------------------------------------
**「密码要长一点」这句话背后是一张指数表。**
**假设字符集有 95 个可选字符、离线爆破每秒十亿次,把长度从 6 加到 12 会发生什么。**
口令长度 组合数 爆破耗时
------------------------------------------
**6 位** 7.351e+11 **735 秒**
**8 位** 6.634e+15 **76.8 天**
**10 位** 5.987e+19 **1899 年**
**12 位** 5.404e+23 **1713 万年**
**每多一位,时间乘 95。**
**从 6 位到 12 位是六次乘 95,大约是 7350 亿倍**——**这就是「长度比复杂度更重要」的全部数学。**
**换成一个符号(把字符集从 26 扩到 95)只是乘三倍多,而多一位就乘 95。**
**对称和公钥的密钥长度不能用同一把尺子量**:
算法 密钥长度 等效强度 为什么
------------------------------------------------------------------------------
**AES-128** **128 位** **128 位** **对称,加解密同一把钥匙**
**AES-256** **256 位** **256 位** **对称,钥匙更长**
**RSA-2048** **2048 位** **约 112 位** **公钥,靠大数分解难**
**RSA-3072** **3072 位** **约 128 位** **等效 AES-128**
**第三列是这行表的意义**:**RSA 的 2048 位并不等于「比 AES-256 强八倍」,它只相当于 112 位。**
**公钥密码的密钥里有一半是结构信息,不提供安全性**,所以「位数」和「强度」不是一比一。
**公钥密码还有一个硬限制:一次只能加密一小块。**
**RSA-2048 的模数是 256 字节,去掉 11 字节填充,一次最多 245 字节。**
项目 结果
---------------------------------------
一次能加密 **245 字节**
1 MB 要加密几次 **4280 次**
用时(按每次 1 毫秒) **4.3 秒**
**所以现实中从来不用公钥加密数据本身**,
**而是「用公钥加密一把临时的对称密钥,再用它加密数据」**——**这叫混合加密,HTTPS 就是这么干的。**
**公钥负责「把钥匙安全地送到对面」,对称密钥负责「把数据快速地搬过去」。**
**两者各干自己擅长的事,这是全书最漂亮的一处分工。**
第一张表的斜率是这一节的重点:每多一位,时间乘 95。 从 6 位到 12 位是六次乘 95,大约七千多亿倍。 而把字符集从 26 个字母扩到 95 个可打印字符,只是乘三倍多。 所以「加长」比「加符号」划算得多——这就是为什么现在的建议是「长度优先」。 第二张表解释了一件常被误解的事: RSA-2048 的 2048 位,并不等于「比 AES-256 强八倍」,它只相当于 112 位。 跨算法比位数是没有意义的,要比就比「等效强度」。 最后那张小表是混合加密的存在理由:1 MB 就要加密四千多次、四秒多, 而 AES 干同样的事是毫秒级。 所以数据永远交给对称密码,公钥只负责送钥匙——这个分工不是设计者的偏好,是被数学逼出来的。
30 秒实验
- 算一下:12 位口令、每秒十亿次,要多少年?(约一千七百万年,量级已经超过宇宙年龄的百分之一)
- 想一下:为什么不能「用 RSA 直接加密一个文件」?
- 想一下:公钥密码安全的基础是什么数学难题?
常见误区
- 以为「公钥密码比对称密码高级」。 两者分工不同,一个管信任,一个管吞吐。
- 以为「用了 AES 就安全」。 还要看工作模式,ECB 会把明文图案泄露出去。
- 以为「密钥越长越安全,所以直接比位数」。 跨算法比位数没意义,RSA-2048 只相当于 112 位。
自测三问(点开对答案)
1. 对称密码的根本难题是什么? —— **钥匙怎么安全地送过去**,所有历史事故几乎都出在这儿。 2. 为什么 RSA 一次只能加密 245 字节? —— **它的数学只对「比模数小的数」成立**,2048 位模数减去填充就是 245 字节。 3. 混合加密的三步是什么? —— **生成对称密钥、用公钥送过去、之后全程用对称密钥**。下一节换一个问题:加密解决了「看不见」,但「你是谁」还没解决。
- ☐ (本节完,下一节 9.3.2 身份认证技术)