凯撒密码

凯撒密码暴力破解攻击:如何破解简单加密

学习如何使用暴力破解攻击破解凯撒密码加密。涵盖密码仅有 25 个可能密钥的脆弱性、手动与自动化方法、频率分析,以及完整的 Python 实现。

发布于 2025年8月11日
12 分钟阅读
密码学指南

凯撒密码是最容易被破解的加密系统之一。尽管它在大多数人目不识丁、系统性密码分析尚未出现的时代帮助了朱利叶斯·凯撒,但这种密码有一个根本性弱点,使其对暴力破解攻击毫无抵抗力:它只有 25 个可能的密钥。攻击者不需要聪明才智,不需要专业的数学知识,甚至不需要计算机——只需逐一尝试每个可能的密钥,直到明文出现为止。

本文详细解释暴力破解攻击为何能在凯撒密码上奏效,手动演练整个过程,展示如何用 Python 自动化这一流程,并探讨如何借助频率分析来自动识别正确密钥。我们还会审视这一问题对理解密码学安全性的深层意义。

亲自试试:使用我们的凯撒密码解码器,通过不同位移值实验解密消息。

什么是暴力破解攻击?

暴力破解攻击是破解加密最直接的方式:系统性地尝试每一个可能的密钥,直到找到能产生可读明文的那个。它不需要任何数学洞察,不需要模式识别,也不需要了解明文内容。攻击者只是穷尽所有可能性。

暴力破解是否可行,完全取决于密钥空间的大小——即可能的密钥总数。如果密钥空间足够小,能在合理时间内逐一测试所有密钥,那么加密系统就容易受到暴力破解。

现代加密算法(如 AES-256)的密钥空间为 2^256,约为 1.16 x 10^77 个可能密钥。即使用最快的计算机,测试所有密钥也需要比宇宙年龄更长的时间。这正是现代加密能够抵御暴力破解的原因。

相比之下,凯撒密码的密钥空间仅有 25 个。不是 2500 万,不是 2.5 万,而是字面意义上的二十五个。这使其成为实际使用过的密码中,对暴力破解最为脆弱的一种。

为何凯撒密码只有 25 个密钥

凯撒密码通过将每个字母在字母表中向后移动固定位数来加密文本。位移值(即密钥)决定了每个字母移动多少个位置。由于英文字母表有 26 个字母,位移值可以是 0 到 25 中的任意一个,共 26 种可能。

然而,位移为 0 相当于没有加密,因为文本保持不变。因此,实际上只有 25 个有意义的密钥:

位移A 变为示例:"HELLO" 变为
1BIFMMP
2CJGNNQ
3DKHOOR
4ELIPPS
5FMJQQT
.........
13NURYYB
.........
25ZGDKKN

截获凯撒加密消息的攻击者,最多只需尝试 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 个可能密钥,这一跨越代表了密码学界对凯撒密码所揭示的根本教训的回应:如果能够尝试每一个密钥,密码就已经被破解了。

深入探索:阅读凯撒密码算法,了解加密背后的数学原理,或使用我们的凯撒密码解码器亲自尝试破解密码。

关于本文

本文是我们综合 凯撒密码 教程系列的一部分。继续了解古典密码学,并探索我们的交互式密码工具。

更多 凯撒密码 教程

试用 凯撒密码 工具

通过我们的交互式凯撒密码工具,将所学知识付诸实践。

试用 凯撒密码 工具