什么是维吉尼亚密码(Vigenère Cipher)?
维吉尼亚密码是一种多表替换密码:它用重复关键词为每个字母选择不同的凯撒位移。 例如关键词为 KEY 时,位移会按 K=10、E=4、Y=24、K=10 循环。因此,同一个明文字母在同一条消息中也可能变成不同的密文字母。
今天通常称为维吉尼亚密码的方法,实际上由意大利密码学家 Giovan Battista Bellaso 于 1553 年描述,他在莱昂·巴蒂斯塔·阿尔贝蒂的多表密码盘和约翰内斯·特里塞缪斯的 tabula recta 基础上发展而来。19 世纪误将此密码归名于法国外交官 Blaise de Vigenère(1523-1596),这个名字此后一直沿用,尽管 Vigenère 自己真正的贡献是一种更强的自动密钥变体。
在大约三百年间,这种密码被称为 le chiffre indéchiffrable(不可破译的密码),因为它的重复密钥能隐藏破解单表替换密码所依赖的简单字母频率模式。这个名声最终在 19 世纪崩塌。普鲁士步兵军官 Friedrich Kasiski 在其 1863 年的著作 Die Geheimschriften und die Dechiffrir-Kunst 中首次公开了通用破解法,展示了重复密文片段如何暴露密钥长度。英国博学家 Charles Babbage 几乎可以肯定更早就破解了维吉尼亚密码(约在 1850 年代),但他从未发表自己的方法,所以破解法的功劳归给了 Kasiski。
维吉尼亚密码如何工作
加密公式
对位置 i 处的每个明文字母:
Cᵢ = (Pᵢ + Kᵢ) mod 26
其中 Pᵢ 是明文字母值(A=0,B=1,... Z=25),Kᵢ 是对应关键词字母值。
解密公式
Pᵢ = (Cᵢ - Kᵢ + 26) mod 26
快速示例
用密钥 LEMON 加密 ATTACK AT DAWN:
明文: A T T A C K A T D A W N
密钥: L E M O N L E M O N L E
密文: L X F O P V E F R N H R
结果: ATTACK AT DAWN -> LXFOPV EF RNHR
两个 T 分别加密为 X 和 F,因为它们对应不同的密钥字母。这种按位置变化的替换,就是维吉尼亚密码的核心。
Tabula Recta、维吉尼亚方阵与维吉尼亚表
Tabula recta、维吉尼亚方阵和维吉尼亚表通常指同一个 26x26 移位字母网格。常见读法是:
- 将密钥字母作为行。
- 将明文字母作为列。
- 读取行列交点处的密文字母。
有些教材会交换行列标签。标准维吉尼亚加密中结果相同,但解密步骤会依赖你选择的方向。可以用交互式维吉尼亚表直观看加密和解密方向。
维吉尼亚密码与凯撒密码对比
| 属性 | 凯撒密码 | 维吉尼亚密码 |
|---|---|---|
| 替换类型 | 单表替换 | 多表替换 |
| 密钥 | 0 到 25 的单个位移 | 任意长度关键词 |
| 重复明文字母 | 容易保留可见模式 | 可能加密成不同字母 |
| 基本攻击 | 尝试 26 种位移 | 先估计密钥长度,再按列分析 |
| 主要弱点 | 固定字母表 | 重复关键词 |
如果维吉尼亚密钥只有一个字母,它就等同于凯撒密码的位移。更长的重复关键词会把字母频率分散到多套移位字母表中。
为什么维吉尼亚密码比凯撒密码更强
凯撒密码会败给一种简单攻击:因为每个字母使用相同的位移,密文中出现频率最高的字母几乎总是对应明文 E,而整段密文的频率轮廓不过是英语轮廓整体旋转了密钥个位移。攻击者可以直接从频率图上读出位移,或者干脆尝试全部 26 种可能。
维吉尼亚密码通过轮换多个凯撒密码来挫败这种攻击。当密钥长度为 n 时,第 1 个字母、第 (n+1) 个字母、第 (2n+1) 个字母等都共用一个位移,但相邻位置使用不同位移。因此,每个明文 E 会根据它在密钥循环中的位置落到不同的密文字母上。英语频率的波峰和波谷被抹散到 n 套独立的字母表中,所以整段密文的频率图看起来平坦得多,也远不像英语。密钥越长、越多样,单表信号被抹除得越彻底——这正是简单频率分析无法直接破解维吉尼亚密码的原因,也是攻击者必须先恢复密钥长度、把密码还原成底层凯撒列的原因。
维吉尼亚密码的安全性与弱点
尽管维吉尼亚密码有三个世纪的名声,但按任何现代标准它都不安全,绝不应该用来保护真实信息。
- 重复密钥是致命缺陷。 重复使用关键词会给密文带来一个周期。这种周期性正是 Kasiski 检验和重合指数所探测的对象,一旦密钥长度已知,密码就会瓦解成可独立求解的凯撒列。
- 短密钥非常脆弱。 密钥相对消息越短,周期模式越强,攻击越容易。单字母密钥就是凯撒密码;即使是一个短单词,面对自动求解器也几乎提供不了保护。
- 长密文反而帮助攻击者。 统计攻击需要数据。同一密钥下可用的密文越多,密钥长度估计和按列频率分析就越可靠。
与一次性密码本的关系
只有在一种极端情况下,维吉尼亚密码才真正不可破解。如果密钥是真正随机的、长度至少与消息相等、且从不重复使用,那么它就不再是重复密钥的维吉尼亚密码——而是一次性密码本,能提供完美保密性。没有重复就没有周期可供 Kasiski 检验发现,而且每一个长度合适的可能明文都同样与密文一致。换句话说,一次性密码本是密钥无限长、随机、单次使用时维吉尼亚密码的极限情形。让日常维吉尼亚密码可破解的,恰恰是它与这个理想之间的差距——一个短的、重复的、基于单词的密钥。
如何识别维吉尼亚密文
维吉尼亚密文常见特征包括:
- 主要由字母构成。 教学和谜题示例通常保留空格和标点。
- 字母频率被压平。 分布不像凯撒密文那样接近普通英语的整体形状,但也不像随机文本那样完全均匀。
- 重合指数处于中间值。 英文维吉尼亚密文的 IC 通常介于随机文本和普通英语之间,常见在 0.04 到 0.05 附近,具体取决于密钥长度。
- 重复片段间距有关联。 如果重复三字母或更长片段的间距有共同因数,Kasiski 检验可能据此推断密钥长度。
密码识别器会利用这些信号识别类似维吉尼亚的密文,并估计可能的密钥长度。
如何破解维吉尼亚密码
三个世纪以来,维吉尼亚密码之所以能抵抗分析,是因为重复密钥抹平了暴露简单替换密码的字母频率。突破口在于意识到:维吉尼亚密码并不是一种密码,而是若干个凯撒密码交错在一起。如果能恢复密钥长度,就可以把密文拆成若干列,每一列都是用单个凯撒位移加密的,从而可以独立求解。现代对维吉尼亚密码的密码分析遵循三个经典步骤。
第一步:Kasiski 检验
Kasiski 检验由 Friedrich Kasiski 在 1863 年发表,它通过查找密文中的重复序列来求密钥长度。当明文中的重复词恰好与密钥的同一部分对齐时,就会产生完全相同的密文片段。因此,两个这样的重复片段之间的距离是密钥长度的倍数。
要进行 Kasiski 检验,需扫描密文中的重复三字母组或更长序列,测量每一对出现位置之间的间距,并对这些间距做因数分解。在许多间距中反复出现的因数——例如 3、5 或 6——就是密钥长度的有力候选。偶然产生的重复会带来随机间距,所以真正的密钥长度会作为最常见的共同因数突显出来。
第二步:重合指数与 Friedman 检验
**重合指数(IC)**衡量从一段文本中随机抽取两个字母、它们相同的可能性。普通英语的 IC 约为 0.067,而均匀随机文本约在 0.038。维吉尼亚密文落在两者之间,且密钥越长,IC 越向随机值漂移。
Friedman 检验把这一观察转化为对密钥长度的估计:它把整段密文的 IC 与英语和随机文本已知的 IC 值进行比较。一种更可靠的变体会针对每个可能的密钥长度把密文拆成候选列分组,然后测量这些列内部的平均 IC。当按正确的密钥长度拆分时,每一列都是单个凯撒位移,所以它的 IC 会重新跳回接近自然英语的 0.067。哪个密钥长度使各列的平均 IC 最高,就是最佳估计。Kasiski 检验和重合指数结合使用时,通常会在密钥长度上达成一致并互相印证。
第三步:对每一列做频率分析
一旦密钥长度 n 已知,就把密文写成 n 列:第 1 列包含第 1、n+1、2n+1……个字母。同一列中的每个字母都是用相同的密钥字母加密的,这意味着每一列都只是一个凯撒密码。
现在对每一列应用普通的频率分析。对 26 种可能位移中的每一种,撤销该位移,并把得到的字母分布与标准英语频率比较——卡方评分或简单的频率匹配都行之有效。最符合英语的那个位移就揭示了该列的密钥字母。对全部 n 列重复这一过程,就恢复了完整的关键词;之后解密消息就轻而易举了。
手工完成全部步骤很慢。维吉尼亚解码器与求解器会自动完成每个步骤:它运行 Kasiski 检验、为候选密钥长度计算重合指数、按列做频率分析,并为你排出最可能的密钥和明文。
用 Python、Java 和 JavaScript 实现维吉尼亚密码
核心实现很短:循环使用关键词,加密时加上密钥位移,解密时减去密钥位移。下面示例会保留大小写,并原样保留非字母字符。
Python
def vigenere_encrypt(text: str, key: str) -> str:
key = key.upper()
out, j = [], 0
for ch in text:
if ch.isalpha():
base = 65 if ch.isupper() else 97
shift = ord(key[j % len(key)]) - 65
out.append(chr((ord(ch) - base + shift) % 26 + base))
j += 1
else:
out.append(ch)
return "".join(out)
Java
static String vigenereEncrypt(String text, String key) {
key = key.toUpperCase();
StringBuilder out = new StringBuilder();
int j = 0;
for (char ch : text.toCharArray()) {
if (Character.isLetter(ch)) {
int base = Character.isUpperCase(ch) ? 'A' : 'a';
int shift = key.charAt(j % key.length()) - 'A';
out.append((char) ((ch - base + shift) % 26 + base));
j++;
} else {
out.append(ch);
}
}
return out.toString();
}
JavaScript
function vigenereEncrypt(text, key) {
key = key.toUpperCase();
let out = "", j = 0;
for (const ch of text) {
if (/[a-zA-Z]/.test(ch)) {
const base = ch >= "a" ? 97 : 65;
const shift = key.charCodeAt(j % key.length) - 65;
out += String.fromCharCode((ch.charCodeAt(0) - base + shift) % 26 + base);
j++;
} else {
out += ch;
}
}
return out;
}
解密时减去位移即可:(value - shift + 26) % 26。
如何读 "Vigenère"
英语中 Vigenère 常读作 /ˌviːʒəˈnɛər/,近似 vee-zhuh-NAIR。这个名称来自法国外交官和密码学家 Blaise de Vigenère(1523-1596)。
正确拼写在第二个 e 上带抑音符:Vigenère。搜索 "Vigenere cipher" 通常指同一密码,但带重音符的形式是标准写法。
维吉尼亚密码今天在哪里出现
- CTF 和谜题寻宝: 解题者需要识别密码、找密钥长度并恢复密钥。
- 密室逃脱: 关键词可以作为单独线索隐藏,适合多步骤谜题。
- 密码学课程: 用来讲解多表替换、密钥重复、Kasiski 检验和重合指数。
- 流行文化: 影视和游戏常用它,因为它知名、可手算,也适合设置线索。
- 历史密码学: 它说明了为什么简单替换密码之后需要更强的统计分析方法。
相关多表替换密码
- 博福特密码 — 一种互逆变体,加密和解密使用同一操作。
- 自动密钥密码 — 用明文扩展密钥,而不是只重复引导关键词。
- 格伦斯菲尔德密码 — 使用 0 到 9 的数字密钥,是维吉尼亚密码的数字变体。
- 流水密钥密码 — 使用一段长文本作为密钥。
- 特里塞缪斯密码 — 使用固定递进位移,而不是秘密重复关键词。
- 波尔塔密码 — 基于成对字母表的互逆多表密码。
- 泥淖密码 — 将混合字母表与维吉尼亚式位移结合。
- 阿尔贝蒂密码 — 早期多表密码盘,早于 Bellaso 和 Vigenère。
延伸阅读
- 维吉尼亚解码器与求解器 — 用已知密钥解密,或在未知密钥时分析密文
- 维吉尼亚示例与教程 — 学习短例、对齐示例和解密示例
- 维吉尼亚表 — 理解 tabula recta 的行列方向
- 破解维吉尼亚密码:Kasiski 检验与重合指数 — 更深入的密码分析 walkthrough