凯撒密码暴力破解攻击:如何破解简单加密
学习如何使用暴力破解攻击破解凯撒密码加密。涵盖密码仅有 25 个可能密钥的脆弱性、手动与自动化方法、频率分析,以及完整的 Python 实现。
凯撒密码是最容易被破解的加密系统之一。尽管它在大多数人目不识丁、系统性密码分析尚未出现的时代帮助了朱利叶斯·凯撒,但这种密码有一个根本性弱点,使其对暴力破解攻击毫无抵抗力:它只有 25 个可能的密钥。攻击者不需要聪明才智,不需要专业的数学知识,甚至不需要计算机——只需逐一尝试每个可能的密钥,直到明文出现为止。
本文详细解释暴力破解攻击为何能在凯撒密码上奏效,手动演练整个过程,展示如何用 Python 自动化这一流程,并探讨如何借助频率分析来自动识别正确密钥。我们还会审视这一问题对理解密码学安全性的深层意义。
亲自试试:使用我们的凯撒密码解码器,通过不同位移值实验解密消息。
什么是暴力破解攻击?
暴力破解攻击是破解加密最直接的方式:系统性地尝试每一个可能的密钥,直到找到能产生可读明文的那个。它不需要任何数学洞察,不需要模式识别,也不需要了解明文内容。攻击者只是穷尽所有可能性。
暴力破解是否可行,完全取决于密钥空间的大小——即可能的密钥总数。如果密钥空间足够小,能在合理时间内逐一测试所有密钥,那么加密系统就容易受到暴力破解。
现代加密算法(如 AES-256)的密钥空间为 2^256,约为 1.16 x 10^77 个可能密钥。即使用最快的计算机,测试所有密钥也需要比宇宙年龄更长的时间。这正是现代加密能够抵御暴力破解的原因。
相比之下,凯撒密码的密钥空间仅有 25 个。不是 2500 万,不是 2.5 万,而是字面意义上的二十五个。这使其成为实际使用过的密码中,对暴力破解最为脆弱的一种。
为何凯撒密码只有 25 个密钥
凯撒密码通过将每个字母在字母表中向后移动固定位数来加密文本。位移值(即密钥)决定了每个字母移动多少个位置。由于英文字母表有 26 个字母,位移值可以是 0 到 25 中的任意一个,共 26 种可能。
然而,位移为 0 相当于没有加密,因为文本保持不变。因此,实际上只有 25 个有意义的密钥:
| 位移 | A 变为 | 示例:"HELLO" 变为 |
|---|---|---|
| 1 | B | IFMMP |
| 2 | C | JGNNQ |
| 3 | D | KHOOR |
| 4 | E | LIPPS |
| 5 | F | MJQQT |
| ... | ... | ... |
| 13 | N | URYYB |
| ... | ... | ... |
| 25 | Z | GDKKN |
截获凯撒加密消息的攻击者,最多只需尝试 25 次解密即可找到原始文本。即使徒手操作,也只需几分钟。用计算机的话,只需数微秒。
密钥空间如此之小,是凯撒密码几乎毫无安全性的根本原因。增大字母表的大小也无济于事——即使字母表有 256 个字符,密钥空间也只有 255 个,按任何标准衡量都微不足道。
手动暴力破解演练
让我们亲手破解一条真实的加密消息,看看整个过程究竟是如何进行的。假设你截获了以下密文:
Wklv lv d vhfuhw phvvdjh wkdw qr rqh vkrxog eh deoh wr uhdg.
要暴力破解这段密文,你需要系统性地用每个可能的位移值逐一尝试解密。不必对每个密钥解密整段消息——只需看前几个词,判断它们是否构成可辨认的英语即可。
位移 1:Vjku ku c ugetgv oguucig vjcv pq qpg ujqwnf dg cdng vq tgcf.
这不是英语,继续。
位移 2:Uijt jt b tfdsfu nfttbhf uibu op pof tipvme cf bcmf up sfbe.
仍然无法辨认,继续。
位移 3:This is a secret message that no one should be able to read.
这显然是英语。加密时使用的位移值是 3,正是经典凯撒密码的位移量。
实际操作中,你很少需要尝试全部 25 个密钥。熟练的英语使用者通常在看到前几个字符时就能辨认出可读文本——在这个例子中,只需 3 次尝试就能找到正确的位移。平均而言,大约尝试 12 到 13 个密钥就能找到答案。
用 Python 自动化暴力破解
手动暴力破解虽然可行,但用代码自动化要实用得多,尤其是处理较长消息或需要解密多段密文时。以下是一个简单的 Python 脚本,可尝试全部 25 个位移:
def caesar_decrypt(ciphertext: str, shift: int) -> str:
"""通过将字母向后移动指定位数来解密密文。"""
result = []
for char in ciphertext:
if char.isalpha():
base = ord('A') if char.isupper() else ord('a')
decrypted = chr((ord(char) - base - shift) % 26 + base)
result.append(decrypted)
else:
result.append(char)
return ''.join(result)
def brute_force(ciphertext: str) -> list[tuple[int, str]]:
"""尝试全部 25 个可能的位移并返回结果。"""
results = []
for shift in range(1, 26):
decrypted = caesar_decrypt(ciphertext, shift)
results.append((shift, decrypted))
return results
# 示例用法
ciphertext = "Wklv lv d vhfuhw phvvdjh wkdw qr rqh vkrxog eh deoh wr uhdg."
print("Ciphertext:", ciphertext)
print("\n=== All 25 Possible Decryptions ===\n")
for shift, plaintext in brute_force(ciphertext):
print(f"Shift {shift:2d}: {plaintext}")
输出展示了全部 25 种可能的解密结果,其中位移 3 产生可读的英语:
Ciphertext: Wklv lv d vhfuhw phvvdjh wkdw qr rqh vkrxog eh deoh wr uhdg.
=== All 25 Possible Decryptions ===
Shift 1: Vjku ku c ugetgv oguucig vjcv pq qpg ujqwnf dg cdng vq tgcf.
Shift 2: Uijt jt b tfdsfu nfttbhf uibu op pof tipvme cf bcmf up sfbe.
Shift 3: This is a secret message that no one should be able to read.
Shift 4: Sghr hr z rdbqds ldrrzfd sgzs mn nmd rgntkc ad zkmd sn qdzc.
...
人工扫描这个列表就能立刻找到正确答案。但如果想让计算机自动识别呢?
频率分析增强
频率分析通过让计算机自动识别最可能正确的解密结果,显著提升了暴力破解的效率。这一技术的依据是:在任何足够长的英语文本中,某些字母的出现频率明显高于其他字母。字母 E 是最常见的(约占所有字母的 12.7%),其次是 T(9.1%)、A(8.2%)、O(7.5%)、I(7.0%)、N(6.7%)和 S(6.3%)。
用错误的密钥解密凯撒密码时,结果文本的字母频率分布与英语不符。用正确密钥解密时,频率分布则与预期的英语分布高度吻合。
以下是一个 Python 实现,通过频率分析为每个暴力破解结果打分,并自动识别最可能正确的解密结果:
# 英语字母频率(百分比)
ENGLISH_FREQ = {
'a': 8.167, 'b': 1.492, 'c': 2.782, 'd': 4.253, 'e': 12.702,
'f': 2.228, 'g': 2.015, 'h': 6.094, 'i': 6.966, 'j': 0.153,
'k': 0.772, 'l': 4.025, 'm': 2.406, 'n': 6.749, 'o': 7.507,
'p': 1.929, 'q': 0.095, 'r': 5.987, 's': 6.327, 't': 9.056,
'u': 2.758, 'v': 0.978, 'w': 2.360, 'x': 0.150, 'y': 1.974,
'z': 0.074,
}
def score_text(text: str) -> float:
"""
根据文本字母频率与英语预期频率的吻合程度为文本打分。
分数越低越好。使用类卡方比较法。
"""
text_lower = text.lower()
letter_count = sum(1 for c in text_lower if c.isalpha())
if letter_count == 0:
return float('inf') # 无字母的文本无法评分
# 统计实际频率
observed = {}
for c in text_lower:
if c.isalpha():
observed[c] = observed.get(c, 0) + 1
# 计算卡方统计量(越低越匹配)
chi_squared = 0.0
for letter, expected_pct in ENGLISH_FREQ.items():
expected_count = (expected_pct / 100.0) * letter_count
actual_count = observed.get(letter, 0)
if expected_count > 0:
chi_squared += ((actual_count - expected_count) ** 2) / expected_count
return chi_squared
def smart_brute_force(ciphertext: str) -> tuple[int, str]:
"""
结合频率分析评分的自动密钥检测暴力破解攻击。
"""
best_shift = 0
best_score = float('inf')
best_text = ciphertext
for shift in range(1, 26):
decrypted = caesar_decrypt(ciphertext, shift)
score = score_text(decrypted)
if score < best_score:
best_score = score
best_shift = shift
best_text = decrypted
return best_shift, best_text
# 示例
ciphertext = "Wklv lv d vhfuhw phvvdjh wkdw qr rqh vkrxog eh deoh wr uhdg."
shift, plaintext = smart_brute_force(ciphertext)
print(f"Detected shift: {shift}")
print(f"Decrypted text: {plaintext}")
输出:
Detected shift: 3
Decrypted text: This is a secret message that no one should be able to read.
卡方统计量衡量观察到的字母频率与预期英语频率之间的差异。卡方值越低,说明吻合度越高。解密得分最低的结果就是最可能正确的答案。
这种方法对于超过约 50 个字符的密文效果可靠。对于很短的消息(不足 20 个字符),字母数量可能不足以产生有意义的频率统计,自动评分可能给出错误结果。这种情况下,人工检查暴力破解的输出更为可靠。
完整攻击工具
以下脚本将所有功能整合成一个格式化输出的实用攻击工具:
def caesar_decrypt(ciphertext: str, shift: int) -> str:
result = []
for char in ciphertext:
if char.isalpha():
base = ord('A') if char.isupper() else ord('a')
result.append(chr((ord(char) - base - shift) % 26 + base))
else:
result.append(char)
return ''.join(result)
ENGLISH_FREQ = {
'a': 8.167, 'b': 1.492, 'c': 2.782, 'd': 4.253, 'e': 12.702,
'f': 2.228, 'g': 2.015, 'h': 6.094, 'i': 6.966, 'j': 0.153,
'k': 0.772, 'l': 4.025, 'm': 2.406, 'n': 6.749, 'o': 7.507,
'p': 1.929, 'q': 0.095, 'r': 5.987, 's': 6.327, 't': 9.056,
'u': 2.758, 'v': 0.978, 'w': 2.360, 'x': 0.150, 'y': 1.974,
'z': 0.074,
}
def score_text(text: str) -> float:
text_lower = text.lower()
letter_count = sum(1 for c in text_lower if c.isalpha())
if letter_count == 0:
return float('inf')
observed = {}
for c in text_lower:
if c.isalpha():
observed[c] = observed.get(c, 0) + 1
chi_sq = 0.0
for letter, expected_pct in ENGLISH_FREQ.items():
expected = (expected_pct / 100.0) * letter_count
actual = observed.get(letter, 0)
if expected > 0:
chi_sq += ((actual - expected) ** 2) / expected
return chi_sq
def attack(ciphertext: str) -> None:
print(f"Ciphertext: {ciphertext}")
print(f"Length: {len(ciphertext)} characters")
print(f"Letters: {sum(1 for c in ciphertext if c.isalpha())}")
print()
results = []
for shift in range(1, 26):
decrypted = caesar_decrypt(ciphertext, shift)
score = score_text(decrypted)
results.append((shift, decrypted, score))
# 按分数排序(卡方值最低 = 最佳匹配)
results.sort(key=lambda x: x[2])
print("=== Top 5 Most Likely Decryptions ===\n")
for i, (shift, text, score) in enumerate(results[:5]):
marker = " <-- BEST MATCH" if i == 0 else ""
print(f" Shift {shift:2d} (score: {score:8.2f}): {text}{marker}")
print("\n=== All 25 Decryptions ===\n")
# 按位移顺序展示
results.sort(key=lambda x: x[0])
for shift, text, score in results:
print(f" Shift {shift:2d}: {text}")
if __name__ == "__main__":
import sys
if len(sys.argv) > 1:
ciphertext = ' '.join(sys.argv[1:])
else:
ciphertext = input("Enter ciphertext: ")
print()
attack(ciphertext)
用法:
python3 caesar_attack.py "Wklv lv d vhfuhw phvvdjh"
# 或交互式运行:
python3 caesar_attack.py
Enter ciphertext: Ymj vznhp gwtbs ktc ozrux tajw ymj qfed itl.
暴力破解对凯撒密码如此有效的原因
多种因素叠加,使凯撒密码对暴力破解攻击极度脆弱:
密钥空间极小:只有 25 个可能的密钥,即便是孩子也能在十分钟内手动逐一尝试。计算机只需数微秒即可测试全部 25 个。
密钥即算法:在凯撒密码中,知道密钥(位移值)就意味着掌握了整个加密算法。没有额外的复杂性,没有密钥扩展,没有多轮变换——一个数字解锁一切。
确定性替换:对于给定的密钥,每个字母始终映射到同一个字母。位移为 3 时,字母 E 始终变成 H,无论它出现在消息的哪个位置。这种确定性使频率分析尤为强大。
无扩散性:改变一个明文字母只会改变一个密文字母。而在现代密码中,改变输入的一个比特会导致约一半的输出比特发生变化(雪崩效应)。凯撒密码的雪崩效应为零。
结构保留:密文中保留了空格、标点符号和单词边界,为攻击者提供了大量关于明文的结构性信息。攻击者可以立即看出单词长度、句子结构和段落格式。
暴力破解不奏效的情形
虽然暴力破解能轻松破解凯撒密码,但了解这种方法在何时会失败也很有价值——这些局限性正是更复杂攻击手段存在的原因。
多表密码:维吉尼亚密码根据关键词,为文本中每个位置使用不同的位移。设关键词长度为 k,有效密钥空间为 26^k,呈指数增长。一个 10 字母的关键词能产生 26^10(约 141 万亿)个可能密钥,远超实际暴力破解的范围。这时需要 Kasiski 检测法、Friedman 检验等不同的密码分析技术。
密码类型未知:暴力破解假设你知道加密算法,只是在搜索密钥。如果截获了一条消息却不知道使用了哪种密码,在暴力破解之前还需要进行额外的分析。
非英语明文:频率分析评分假设文本是英语。如果原始消息是其他语言,则需要该语言的频率表。如果消息根本不是自然语言(随机数据、压缩数据或另一层加密),频率分析无法帮助识别正确的解密结果。
改进的凯撒变体:某些变体使用非标准字母表,对数字和符号进行加密,或应用额外的变换。虽然本质上仍然脆弱,但这些变体可能需要经过调整的暴力破解方法。
暴力破解的历史沿革
系统性地尝试所有可能密钥的思想,与密码学本身一样古老。阿拉伯数学家 Al-Kindi 在 9 世纪的著作《密码消息解密手稿》中描述了频率分析,这被认为是已知最早的密码分析记述。
然而,直到 20 世纪密码学机械化之后,暴力破解才成为一个正式的概念。第二次世界大战期间,驻扎在布莱切利庄园的盟军密码分析员使用早期计算机(由阿兰·图灵设计的 Bombe 机,以及后来的 Colossus)对恩尼格玛密码机和 Lorenz 密码的密钥空间进行暴力搜索。这些机器每秒可测试数千种密钥组合,在当时堪称革命性突破。
如今,现代计算机每秒可测试数十亿个简单加密密钥。面对只有 25 个密钥的密码,即使是最慢的嵌入式微控制器也能瞬间完成穷举搜索。从手工计算到机械计算机再到电子计算机,这一历史演进使凯撒密码区区 25 个密钥的空间作为安全措施愈发显得荒唐可笑。
抵御暴力破解的防御方法
理解暴力破解攻击有助于解释现代加密为何使用如此大的密钥空间:
- AES-128:2^128 个可能密钥(约 3.4 x 10^38)。以每秒十亿个密钥的速度穷举,大约需要 10^22 年。
- AES-256:2^256 个可能密钥(约 1.16 x 10^77)。可能的密钥数量超过可观测宇宙中的原子总数。
- RSA-2048:安全性来自大数分解的困难性,而非单纯的密钥空间大小,但其等效安全性约相当于 2^112 次暴力破解操作。
从暴力破解凯撒密码中得到的教训是明确的:加密安全性依赖于使穷举密钥搜索在计算上不可行。任何能在实际时间内测试完所有密钥的系统,无论加密算法本身设计得多么精巧,都无法提供真正的安全保障。
小结
凯撒密码对暴力破解具有独特的脆弱性,原因正是其 25 个密钥的空间小得可以忽略不计。手动攻击只需几分钟,自动化攻击只需数微秒。结合频率分析,计算机甚至无需人工干预就能自动识别正确密钥。
理解暴力破解如何攻破凯撒密码,为理解现代加密系统为何使用如此巨大的密钥空间提供了重要背景。从 25 个可能密钥到 2^256 个可能密钥,这一跨越代表了密码学界对凯撒密码所揭示的根本教训的回应:如果能够尝试每一个密钥,密码就已经被破解了。