🛡️ 第五章 什么是密码、数字签名、数字证书
📄 一句话概括

古典密码把安全感押在【别人不知道我用了什么秘方】上,现代密码把这件事整个翻过来——算法完全公开,全天下只有一把钥匙是保密的;这一字之差,是本章后面所有技术(共享密钥、公开密钥、哈希、签名、HTTPS)共同的地基。

📝 本节和前面几节的关系

前面四章讲的都是【怎么被攻破】:网络被窃听、病毒进来了、漏洞被利用。从这一章开始,讲的是防守方手里那件真正管用的工具——密码学。

它直接接着说 针对密码的攻击 与 密码使用环境的变化:那两节里的【密码】指的是登录口令,讲的是这个词语义怎么漂移的;而这一章的【密码】是另一件事——密码学(cryptography),它是数学,不是口令。

一、古典密码:只做一件事——把字母换掉

古典密码的思路非常朴素:把字母表重新排一遍,然后照着抄。

最有名的就是凯撒移位(Caesar shift):把全部字母整体往后挪 k 格。k=3 时 A 变 D、B 变 E,于是 ATTACK AT DAWN 就变成 DWWDFN DW GDZQ。

再复杂一点的是维吉尼亚密码(Vigenère):不再固定挪几格,而是按一个关键词逐字变换移位量(关键词是 KEY 时,三个字母分别是 10、4、24 格,循环使用)。这样同一个字母在不同位置会变成不同的字母,直接顶掉了"哪个字母最常见"这个抓手。

但注意它们的共同点:无论怎么排字母表,加密规则本身必须是保密的。一旦对手知道了你用凯撒移位,剩下的就只是"试几次"的问题。

二、古典密码的两种破法:穷举,和统计

为什么第二种更值得记住:它说明古典密码的弱点不在密钥太短,而在【明文的统计特征会原样漏到密文里】。这个教训会一直用到今天——现代密码设计的一大目标,就是让密文在统计上【看起来像随机数】。

三、动手 Demo:二十五种移位,和一次自动破解

先看穷举有多轻松(只贴几行):

def caesar(s, k):
    r = []
    for ch in s:
        if "A" <= ch <= "Z":
            r.append(chr((ord(ch) - 65 + k) % 26 + 65))
        else:
            r.append(ch)
    return "".join(r)

# 穷举 26 种移位
for k in range(1, 26):
    print("k=%2d  %s" % (k, caesar("ATTACK AT DAWN", k)))

# 频率分析:对 26 种移位各解一遍,用英文字母常见程度打分
ref = "ETAOINSHRDLCUMWFGYPBVKJXQZ"
scores = []
for k in range(26):
    dec = caesar(ct2, -k)
    c2 = Counter(c for c in dec if "A" <= c <= "Z")
    sc = sum(c2.get(ch, 0) * (26 - i) for i, ch in enumerate(ref))
    scores.append((sc, k, dec))
scores.sort(reverse=True)

实跑输出:

一、古典密码的代表:凯撒移位(把字母表整体挪 k 格)
  明文      ATTACK AT DAWN
  密钥 k    3
  密文      DWWDFN DW GDZQ

二、它的密钥空间只有 25 种,挨个试一遍就破完了
    k= 1   BUUBDL BU EBXO
    k= 2   CVVCEM CV FCYP
    k= 3   DWWDFN DW GDZQ  ← 可读的英文
    k= 4   EXXEGO EX HEAR
    k= 5   FYYFHP FY IFBS
    k= 6   GZZGIQ GZ JGCT
    k= 7   HAAHJR HA KHDU
    k= 8   IBBIKS IB LIEV
    k= 9   JCCJLT JC MJFW
    k=10   KDDKMU KD NKGX
    k=11   LEELNV LE OLHY
    k=12   MFFMOW MF PMIZ
    k=13   NGGNPX NG QNJA
    k=14   OHHOQY OH ROKB
    k=15   PIIPRZ PI SPLC
    k=16   QJJQSA QJ TQMD
    k=17   RKKRTB RK URNE
    k=18   SLLSUC SL VSOF
    k=19   TMMTVD TM WTPG
    k=20   UNNUWE UN XUQH
    k=21   VOOVXF VO YVRI
    k=22   WPPWYG WP ZWSJ
    k=23   XQQXZH XQ AXTK
    k=24   YRRYAI YR BYUL
    k=25   ZSSZBJ ZS CZVM
  → 26 种可能,机器一瞬间试完。古典密码的安全感全押在
     【对手不知道你用了移位、也不知道挪了几格】上。

三、更聪明的破法:不穷举,用统计规律(频率分析)
  样本密文(用 k=7 加密,共 392 个字母)
  AOL ZLJYLA TLZZHNL PZ OPKKLU PU AOPZ ZLUALUJL HUK AOL SLAALY L HWWLHYZ TVYL VMAL...
  出现最多的 5 个字母:L(84)  A(56)  U(40)  Z(32)  O(28)

  对 26 种移位各解一遍,用【英文字母常见程度】给每种打分,看前三名:
    k= 7   得分   8264   THE SECRET MESSAGE IS HIDDEN IN THIS SENTENC...
    k=18   得分   6760   IWT HTRGTI BTHHPVT XH WXSSTC XC IWXH HTCITCR...
    k=11   得分   6232   PDA OAYNAP IAOOWCA EO DEZZAJ EJ PDEO OAJPAJY...
  → 得分最高的是 k=7,与实际加密用的 k=7 一致
  → 一条几百个字母的密文根本不用试 25 种:
     单看【哪个字母出现得最多】就能把 k 猜个八九不离十。

读这个输出:

四、现代密码学换了一条赛道:算法公开,只守密钥

现代密码学有一条被称作 Kerckhoffs 原则的铁律:

一个密码系统的安全性,只能依赖密钥的保密,不能依赖算法本身的保密。

算法 保密的是什么
古典密码 保密(秘方不外传) 算法本身 + 密钥
现代密码 完全公开(AES/RSA 的规范人人可下载) 只有密钥

这个转变看上去很不合直觉——公开了还怎么保密?原因有三条:

  1. 公开才经得起检验。AES 从 1997 年开始面向全世界征集算法,被全世界的密码学家拿着放大镜攻了二十年,活到今天。一个只被自家几个人看过的算法,安全性只是"还没被人看"而已。
  2. 保密算法没法升级。算法一旦泄露或被人逆出来,所有历史密文会一起作废——你连"以前发出去的东西要不要重新保护"都没法评估。
  3. 保密算法在工程上根本守不住。算法要写进软件、发到客户端、告诉合作方,一个环节漏了就等于全漏。相比之下,密钥只有几十个字节,可以放进一个很小的保险箱(硬件模块)里。

所以从这一节往后,你看到的每一个名字(DES、AES、RSA、SHA-256)都是完全公开的算法——它们的安全,全部押在"密钥没被拿走"这一件事上。

五、⚠️ 2026 现状

30 秒实验

今天做两个动作,各 15 秒:

  1. 拿一个词自己手算一次凯撒移位:随便选一个英文单词(比如 HELLO),往后挪 3 格,写出结果;然后再把结果往前挪 3 格还原。这一步是全部密码学的缩影:正向是加密,反向是解密,而"挪几格"就是密钥。
  2. 打开手机里任何一个需要密码的 App,问自己一句:这个 App 的加密算法我知不知道?——答案通常是你不知道,但它一定是公开的标准算法(AES、RSA、SHA 之一)。这就是"算法公开"这条原则在你身上的具体体现:安全感来自"密钥只有我知道",而不是"没人知道它怎么算"。

这一节要带走的一句是:密码学的发展方向不是"把算法藏得越来越深",而是"把算法全部摊开、把力气全部用在密钥上"——因为能藏住的东西会漏,能算清的东西才靠得住。

常见误区

  1. 错误:加密算法当然要保密,公开了大家不就都能破解了吗。——纠正:这个直觉在古典密码时代是对的,在现代密码里正好相反。 AES 的算法规范是公开文档,任何人都能下载、能实现、能研究——但它从 2001 年活到今天,没有一次"因为公开而被攻破"的记录。原因很简单:公开不等于能算出来。破解 AES 需要对 2^128 级别的密钥空间做穷举,知道算法对这个数字毫无帮助。反过来说,"算法保密"给出的安全感是虚假的——任何只靠保密才安全的算法,一旦有人逆出来(软件里总是能逆出来),那套系统就整体作废,而且是历史上所有密文一起作废。

  2. 错误:凯撒移位才 25 种可能,这也能算加密?——纠正:按今天的标准,它确实算不上加密——但这恰恰是它作为教材的价值。要把"密钥空间""穷举""频率分析""算法公开"这些概念讲清楚,最小、最可手算的例子就是它。更重要的是:所有现代密码面临的问题,它在放大几万亿倍之后完全一样——AES-128 的密钥空间不是 25 种而是 2 的 128 次方种,"频率分析"换成了更复杂的数学攻击。理解了 25 种是怎么被穷举掉的,就理解了 2^128 为什么要这么大。

  3. 错误:既然算法公开,那掌握了算法的人岂不是都能解密我的数据?——纠正:不能。算法公开的只是"怎么算",破解还需要"钥匙"。用一次性的比喻:保险箱的图纸人人都能拿到,但打开箱子要密码——知道锁的构造,不等于知道那把钥匙。 这也解释了本章后面一个反复出现的结构:所有的技术(共享密钥、公开密钥、哈希、签名、HTTPS)在本质上都在解决同一个问题——"钥匙怎么发放、怎么保管、怎么证明只有该拿的人拿到了"。

  4. 错误:古典密码已经是历史,学它只是背概念,没有实际用处。——纠正:它的用处非常实际:绝大多数真实事故,恰恰是"用对了算法、却用错了方式"。 数据上最容易看到的例子是密钥重复使用——一次性密码本(理论上绝对安全)一旦两段明文共用同一把密钥,两段密文一异或,密钥就被完全消掉(5-2 的 Demo 里有这一段)。这类错误和凯撒移位时代的错误是同一类:不是数学不够强,而是把该保密的东西用错了地方。

自测三问(点开对答案) 1. 为什么说频率分析比穷举更值得记住? —— 因为**穷举依赖"密钥空间小"这一个条件,而频率分析利用的是"明文本身的统计特征会漏到密文里"**——**后者对任何"逐字母替换"的密码都成立,跟密钥空间有多大无关**。**实际后果有两条**:① **只要密文足够长,攻击者甚至不需要知道你的加密算法**,就能从统计规律反推出结构(这也是"保密算法"这种思路必然失败的原因之一);② **现代密码设计的一个核心目标就是"消除统计特征"**——**密文要看起来像随机数,长度和分布都不能泄露原文的任何规律**(这一点在后面讲 AES 的分组模式、以及哈希的雪崩效应时会反复出现)。 2. Kerckhoffs 原则说"算法可以公开",那安全性到底靠什么? —— **靠密钥**。**算法公开之后,攻击者唯一不知道的就是那几十个字节的密钥**,于是**整个系统的安全性等于"破解这把密钥需要多少计算量"**——AES-128 是 2^128 次运算量级,RSA-2048 是大数分解的量级。**这个原则最重要的一个推论是:密钥必须能被单独替换和保管**。因为密钥只有几十字节,**它可以放进硬件模块、可以定期更换、可以在泄露后立即作废并重新发一批**——**如果把安全寄托在算法上,这三件事一件都做不到**(算法写进软件里,改一次要全量升级;而算法一旦泄露,所有历史密文一起失效)。 3. 用一次凯撒移位加密出来的密文,攻击者最短能多快破掉? —— **把它拿去和英文词典对一次得分,或者干脆把 25 种结果列出来看一眼**——**人工大约几十秒,脚本不到一毫秒**。**更值得注意的是:真正的攻击者连 25 次都不必试**。**只要那段明文够长,直接统计密文里哪个字母出现得最多,猜它对应 E,移位量就出来了**——**这是一步到位的破法,跟"试多少种"没有关系**。**这正是"密钥空间小"和"统计特征明显"两种弱点叠加的结果,也就解释了本章后面所有现代算法为什么必须同时把这两件事都解决掉。**

相关笔记