
“维吉尼亚密码的黄昏——关于不可破译之物”这个标题第一眼就让我这种老密码爱好者走不动道。维吉尼亚密码在密码学教材里永远占着一章它的标签是“曾被称为不可破译的密码”而“黄昏”两个字又暗示了那个神话最终被打破的时刻。最近我看到“维吉尼亚密码在线转换”“维吉尼亚密码转换器”这些词频繁出现不少刚接触密码学的朋友在找工具、想亲手验证这套古典算法到底怎么运作。这篇我就把维吉尼亚密码从原理、加密解密手算流程、到怎么自己写一个转换器、再亲手破解它完整地捋一遍。不管你是刚入门的技术爱好者、CTF新手还是只想搞懂“不可破译”为什么会被打脸的好奇读者这篇文章都能让你有所收获。很多人在网上搜转换器只是想快速把一段话加密成密文或者把密文还原成明文。但如果你不搞清楚背后的查表逻辑用起工具也是一头雾水拿到一段密文照样不知道从哪下手。我更想带你把维吉尼亚密码这层纱彻底揭开它为什么能骗过几百年前的人后来又怎么被人扒得干干净净。1. 维吉尼亚密码到底是什么为什么被喊成“不可破译”维吉尼亚密码属于古典密码里的多表替换密码。你别被“多表替换”这个词吓到其实很好理解。先看它上一代——凯撒密码那就是把明文里的每个字母都往后移动固定位数比如全部移3位A变成DB变成E。这种方式叫单表替换因为全篇只用一张“替换表”。单表替换有个致命弱点英文里字母出现频率不一样E最多T次之A、O、I、N也靠前。只要密文足够长你把每个密文字母出现的次数统计一下出现最多的那个字母基本就是E往下排一套用不了多久整篇明文就被猜出来了。这种方法叫频率分析古典密码学里的“大杀器”。维吉尼亚密码聪明在哪儿它让同一个明文字母在不同位置被加密成不同的密文字母。比如明文里的E第一次出现可能被加密成Q第二次可能变成W第三次变成G。这样一来密文字母的频率分布被抹平了频率分析那套方法直接失效。在那个年代这简直就像给文字上了一把“指纹锁”所以欧洲人喊了三百多年“不可破译的维吉尼亚密码”。1.1 核心原理一张表加一个密钥维吉尼亚密码的整个加解密操作都靠一张维吉尼亚方表。这张表长这样最上面一行是明文字母A到Z最左边一列是密钥字母A到Z表中间第i行第j列的字母就是左边第i个字母和上边第j个字母在字母表里相加的结果。比如你要加密明文字母H而当前对应的密钥字母是K。H在字母表里是第7位从A开始算第0位所以A0B1……H7K是第10位。加密结果就是(7 10) mod 26 17对应字母R。用查表的方式更直观找到最上面一行的H再找到最左边一列的K横竖交叉的那个格子就是R。密钥的使用方式是循环的。假设密钥是KEY明文是HELLOWORLD那么密钥序列就是K-E-Y-K-E-Y-K-E-Y-K一直循环下去直到覆盖所有明文。查表的时候每个明文字母配一个密钥字母各行其是。我刚接触这张表的时候有个小地方特别容易混到底是用明文字母查行、密钥字母查列还是反过来其实都行只要加密和解密保持同一套规则就行。网上有些转换器可能用不同的约定出来的密文就不一样这一点后面我会讲怎么自查免得你用工具时对不上结果。1.2 加密解密手算拿HELLOWORLD和KEY实操一遍咱们来完整算一次不依赖任何工具。明文HELLOWORLD密钥KEY。先把字母转成数字A0B1……Z25明文HELLOWORLD明文字母序号74111114221417113密钥字母KEYKEYKEYK密钥序号10424104241042410密文字母序号1783521184624213513mod 2617892118202421913密文字母RIJVSUYVJN注意L遇到密钥Y那一下11加24等于35超过25了就减掉26得到9对应J。所有超过Z的都要模26绕回A。所以HELLOWORLD用密钥KEY加密得到RIJVSUYVJN。解密就是把过程反过来。你已经有了密文字母R以及它对应的密钥字母K那么明文就是(17 - 10) mod 26 7对应H。看到没加密是加法解密是减法互为逆运算。记住这一点写转换器的时候才不会出错。2. 神话的黄昏破解是怎么发生的维吉尼亚密码号称“不可破译”但这个神话在19世纪中期就被击穿了。破解者主要有两个人一个是英国数学家查尔斯·巴贝奇一个是普鲁士军官弗里德里希·卡西斯基。巴贝奇在1854年左右就找到了破解方法可这位老兄一向神神叨叨没正经发表后来还是卡西斯基在1863年独立发表了完整的破解方法所以这套破法被命名为“卡西斯基测试”。密码学界常常感慨如果巴贝奇当时把成果发出来这个算法可能早就改名了。卡西斯基破解法的关键思路不是跟密文字母的频率硬刚而是先想办法猜出密钥长度把“多表替换”拆回“单表替换”然后再用频率分析逐个击破。这一步是整场破解的地基我建议你亲手跟着跑一遍真的很爽。2.1 卡西斯基测试让密钥长度自己露馅卡西斯基测试的原理一句话就能说清如果明文中有一段重复出现的字符串而且这两次重复恰好对应的密钥字符序列相同那么密文中会对应地出现两段相同的密文。举个例子。明文里有两处“THE”第一次出现时密钥正好处在某几个字母上第二次出现时密钥又循环到了同样几个字母上因为密钥长度和两个位置之间的距离是整数倍关系那么这两次加密出来的密文片段就一模一样。密文里出现重复片段你就测量这两段重复片段之间的距离这个距离往往是密钥长度的整数倍。实际操作是这样的先扫一遍密文把所有长度至少为3的重复片段找出来记录每对重复片段的起始位置差然后对这些差值求最大公约数这个公约数就极有可能是密钥长度。我拿刚才那个简单的例子引申一下。假设密钥长度是3密文第6位到第8位和第15位到第17位出现了相同片段间距9正好是3的倍数。真实场景里你不会只有一个重复片段而是能找到很多组把它们的间距拿去求gcd密钥长度基本就跑不掉。如果有些间距不是密钥长度的倍数只是因为巧合产生的重复这些干扰项会在求公约数的时候被排除掉因为它们的公约数不会形成稳定的公共因子。2.2 重合指数密码不怕统计时换个维度继续统计如果说卡西斯基测试是直觉和文本观察那重合指数Index of CoincidenceIC就是更数学化的武器专门用来确认密钥长度到底是多少。重合指数的概念也很简单从一段文本里随机抽两个字母它们恰好相等的概率。对于英文正常文本这个概率大约是0.065对于完全随机生成的字母串这个概率大约是0.038。这个差距就是我们判断的条件。怎么用假设密钥长度是m你把密文字母按照位置对m取模分成m组。比如m3那么第1、4、7、10位属于第一组第2、5、8、11位属于第二组第3、6、9、12位属于第三组。如果m猜对了每一组里的密文其实都是用同一个密钥字母做凯撒加密的结果它本质上就是英文文本加了固定偏移所以频率分布还是英文的分布重合指数应该在0.065附近。如果m猜错了每个组里混着不同偏移的字母频率被抹平重合指数会掉到接近0.038。所以破解的时候你就从m1开始试一直试到某个长度算出每个组的IC平均值看到哪个长度的平均IC最接近0.065那密钥长度基本就是它。我第一次手工算IC的时候密文有几百个字母把25个候选长度挨个算了一遍算到最后手指都酸了但当那个0.065左右的数字跳出来时那种“密码也不过如此”的感觉是真的上瘾。2.3 密钥长度确定后频率分析逐个击破拿到密钥长度m之后你就把密文重新分成m组每组单独看。每一组等价于一个凯撒密码因为同一组里所有字母都是被同一个密钥字母平移的。现在回到最传统的频率分析统计这一组里哪个字母出现次数最多。英文文本里E最常出现所以组里出现次数最多的那个密文字母大概率就是E移位后的产物。用这个密文字母减去E在字母表中的序号得到的差值就是该组对应的密钥字母。如果一组里最高频的字母不是E因为文本短、样本少经常会有偏差你就得多试几个候选比如高频字母除了E还有T、A、O、I、N。把频率排名前几位的字母分别当作E试一遍看解出来的明文通不通顺多试几次就能确定正确密钥。这个阶段最好用一些长文本练习我建议你拿一本英文小说的开头几段转成全大写、去掉标点自己写一串密钥加密再交给朋友破解。练习的时候你会发现密文越长频率分析的准确率越高这也解释了为什么古人强调“密文越短越安全”虽然这个安全也只是相对的。3. 实操从手算到写一个“维吉尼亚密码转换器”现在到了动手环节。我见过不少朋友在网上找“维吉尼亚密码在线转换”工具输入明文和密钥点一下加密拿到一串密文但完全不知道自己拿到的到底是不是标准的维吉尼亚结果。我建议你按我下面说的方法先手工验证一遍再自己写一个转换器以后想怎么玩就怎么玩。3.1 手工查表完整走一遍你要准备一张A到Z的维吉尼亚方表。网上很容易搜到图片但我更推荐你自己生成一张其实就是一个26乘26的字母矩阵。你可以用Excel做第一行是A到Z第二行是B到Z加A第三行是C到Z加A加B……每行都比上一行整体左移一格。加密时把明文转成大写去掉空格和标点。假设要加密“ATTACK AT DAWN”密钥“LEMON”。密钥循环排列LEMONLEMONLE。然后逐个对应A配L查表A行L列得LT配E得XT配M得FA配O得OC配N得PA配L得LT配E得XA配M得MD配O得RA配N得NW配L得HN配E得R所以密文是LXFOPVEFRNHR。这个例子在很多密码学教材里都有你可以直接用这个结果来验证自己的手算或工具是否正确。我只提醒一件事网上能找到的“在线转换器”有些默认保留空格有些会去掉空格有些会保留大小写所以单纯对比密文时先统一格式再比较不然你可能会以为自己算错了。3.2 用Python写一个十分钟能跑通的转换器自己写转换器其实比想象中简单核心就是两个公式加密C (P K) mod 26解密P (C - K) mod 26。完整代码如下def vigenere(text, key, mode): text text.upper() key key.upper() key_len len(key) result [] key_index 0 for ch in text: if A ch Z: p ord(ch) - ord(A) k ord(key[key_index % key_len]) - ord(A) if mode encrypt: c (p k) % 26 else: c (p - k) % 26 result.append(chr(c ord(A))) key_index 1 else: result.append(ch) return .join(result) if __name__ __main__: plain ATTACK AT DAWN key LEMON cipher vigenere(plain, key, encrypt) print(cipher) print(vigenere(cipher, key, decrypt))这段代码有几个细节说一下。第一非字母字符直接保留空格、逗号、数字都不参与加密但密钥索引只在字母处递增这样解密出来能和原文对齐。第二所有输入都转成大写省去大小写处理的麻烦。如果你需要保留大小写也不是不行但那属于锦上添花核心逻辑不用改。如果你想做一个真正的“在线转换器”用Flask包一层就行。核心函数完全不用动只需要加一个页面接收请求参数把结果返回给浏览器。Flask版本如下from flask import Flask, request, jsonify app Flask(__name__) app.route(/vigenere, methods[GET]) def api(): text request.args.get(text, ) key request.args.get(key, ) mode request.args.get(mode, encrypt) if not text or not key: return jsonify({error: missing params}), 400 result vigenere(text, key, mode) return jsonify({result: result}) if __name__ __main__: app.run(debugTrue)跑起来之后浏览器访问 /vigenere?textATTACKATDAWNkeyLEMONmodeencrypt就能拿到加密结果。很多在线转换器网站背后就是这么回事把古典密码算法封装成网页接口方便大家快速验证。你完全可以把这段代码部署在本地离线使用比依赖别人的网站更踏实。3.3 给转换器加一个破解功能既然题目是“维吉尼亚密码的黄昏”我还想让你再往前走一步写一个自动破解器。网上很多转换器只做加密解密真正有破解功能的工具反而不多。我这里给一个能够自动推断密钥长度的脚本框架思路就是前面讲的重合指数。def calculate_ic(text): n len(text) if n 2: return 0 freq [0] * 26 for ch in text: if A ch Z: freq[ord(ch) - ord(A)] 1 total 0 for f in freq: total f * (f - 1) return total / (n * (n - 1)) def find_key_length(cipher, max_len20): best_len 1 best_avg_ic 0 for m in range(1, max_len 1): groups [[] for _ in range(m)] for i, ch in enumerate(cipher): if A ch Z: groups[i % m].append(ch) avg_ic sum(calculate_ic(.join(g)) for g in groups if len(g) 1) / m print(f密钥长度 {m}平均重合指数 {avg_ic:.4f}) if abs(avg_ic - 0.065) abs(best_avg_ic - 0.065): best_len m best_avg_ic avg_ic return best_len这段代码会把每个候选密钥长度的平均重合指数打出来你肉眼就能看到哪个长度最接近0.065。后面再接上频率分析还原密钥字母就能完整破译。我特意只给了前半段因为破解后半段留给读者自己动手会更有意思。你自己把频率分析补上跑通整个流程那种成就感不是拿现成工具一键出结果能比的。4. 黄昏之后从“不可破译”到现代密码学的思考维吉尼亚密码走下神坛不只是因为卡西斯基和巴贝奇的聪明本质上是因为它暴露了一个更深层的问题任何依赖固定模式哪怕模式比较复杂的算法只要密钥长度有限就存在被统计分析破解的可能。维吉尼亚密码的密钥虽然是一串字符但它是循环使用的。一旦密文长度超过密钥长度的若干倍里面就会反复出现相同的加密模式这就是它被攻克的命门。现代密码学吸取了这个教训提出了一个关键原则密钥必须足够长并且不能循环使用。如果你用一次性密码本也就是密钥和明文一样长、完全不重复、随机生成且用完即弃那确实能做到信息论层面的不可破译。4.1 维吉尼亚密码留下的遗产很多人觉得维吉尼亚密码只是历史古董学它没什么实际用处。我不这么看。它最大的价值在于提供了一个思维范式当你觉得某种加密方式安全时你要问自己它到底是在“隐藏特征”还是在“抹除特征”。凯撒密码是被频率分析干掉的因为它保留了字母频率特征维吉尼亚密码表面上抹掉了频率特征但因为密钥循环它把特征藏在了更长的周期里最后还是被统计分析挖了出来。这种“你藏得再深只要模式有规律就能被找出来”的思想至今仍然贯穿于现代密码分析中。现代密码体制强调“混淆”和“扩散”要打乱字母之间的统计关系让每一位密文都依赖大量明文位和密钥位。你看AES每一轮都在做代换和置换就是为了让输出的统计特征彻底消失。维吉尼亚密码虽然不是现代密码的直接祖先但它开启了“用数学变量控制替换方式”的思路让密码学从一门手艺活变成了可系统分析的科学。4.2 现代“不可破译”到底是什么概念维吉尼亚密码的故事还顺带引出一个很现代的问题什么是真正的不可破译密码学界有一条柯克霍夫原则系统的安全性只能依赖于密钥的保密不能依赖于算法的保密。意思是算法可以公开全世界的人都可以研究它但只要密钥够强就仍然安全。维吉尼亚密码之所以被破不是因为它算法太简单而是因为它的密钥长度太小、循环模式太明显。反观现代加密算法AES、ChaCha20这些算法完全是公开的论文随便看但人们依然认为它们安全因为密钥空间大到暴力穷举都不可能。还有一种真正意义上的“不可破译”——一次性密码本。它要求密钥长度等于明文长度、完全随机、绝不重复使用。香农在1949年给出了严格的数学证明这种方案在信息论上是绝对安全的。但它的代价也很大密钥分发和管理极其困难。你想想如果两个人想用一次性密码本通信必须先安全地交换一份和所有消息总长度一样长的随机密钥这在实际场景里基本不现实。所以维吉尼亚密码的故事最终引向的是一个冷峻的现实加密从来不是绝对的安全问题而是成本与效益的权衡问题。4.3 为什么今天还要学维吉尼亚密码我在带新人的时候总喜欢让他们从维吉尼亚密码入手哪怕他们以后要做的是AES、RSA那套现代密码。原因有三第一它是理解“频率分析”和“统计攻击”的最佳入门教材。维吉尼亚密码的破解过程每一步都清晰可见你能直观感受到统计方法的力量。第二它是CTF比赛和密码学课程里的常客。很多CTF赛题会给你一段密文告诉你这是维吉尼亚加密让你还原密钥和明文。你要是没亲手破解过光靠理论很难在赛场上快速上手。第三它是检验你对底层逻辑理解的试金石。你如果能独立写出一套维吉尼亚加密解密破解工具说明你真正掌握了替换、密钥、频率分析这些密码学核心概念之后再学现代密码会顺畅得多。在线转换器这类工具之所以流行就是因为大家想快速验证自己的手算和代码是否正确。但我一直觉得工具是拿来辅助理解的不是拿来替代思考的。你可以用在线工具核对结果但自己写一遍代码、跑一遍破解收获会大得多。5. 常见问题与避坑指南最后整理一些我经常被问到的问题以及实操中踩过的坑给你当速查表用。5.1 字母序号到底从0还是1开始这是新手最容易搞混的地方。密码学约定A0B1……Z25这样加密公式才能和mod 26无缝衔接。但有些教学材料和在线工具会用A1B2……Z26也就是直接给字母表排号。两种体系都能用但得到的结果不一样。你如果发现自己的手算结果和在线转换器不一致先别怀疑算错检查一下对方是不是用了A1体系。5.2 空格、标点和数字怎么处理大部分古典密码算法只处理字母空格和标点通常直接跳过或者原样保留。我写的代码是原样保留非字母字符这样解密之后可以完美还原原始格式。如果你在破解时发现密文里没有空格那是加密前就去掉了空格的版本解密后你还需要自己重新分词。这两种情况没有优劣之分但转换器之间的差异往往就在这里使用时要注意。5.3 密钥循环越界怎么办密钥长度只有那么几个字母明文可能有好几百个字母这时密钥要循环使用。很多人写程序时容易写错索引。正确做法是维护一个独立的key_index变量只在遇到大写字母时自增。如果你直接用明文位置i去取key[i % key_len]那遇到空格或标点时密钥索引就会错位导致解密失败。我上面的代码已经规避了这个问题但如果你从别的地方抄代码要特别注意这一点。5.4 密文太短卡西斯基测试失效怎么办卡西斯基测试依赖重复片段如果密文特别短比如只有几十个字符很可能找不到重复片段这时你就只能靠重合指数硬猜。如果密文再短一些连重合指数都不稳定那就只能穷举密钥组合或者根据场景猜测密钥单词。说到底维吉尼亚密码的安全性在短密文和长密钥面前还是有一定生存空间的但一旦密文长度超过密钥长度的二十倍基本必破。5.5 破解结果是一堆乱码哪一步出了问题你用重合指数找到了密钥长度但频率分析解出来的密钥字母不对最常见的两种原因一是这个分组的样本量太少最高频字母不一定是E的密文二是密文本身不是英文。破解维吉尼亚密码要求明文是自然语言有比较明显的字母频率特征。如果明文本来就是随机字符串那再怎么分析都还原不出来。这是古典密码的物理限制不是你的代码有问题。我在实际教人破解维吉尼亚密码的时候最后总爱说一句你亲手把“不可破译”的东西破掉一次才知道一个密码系统的自信到底应该来自哪里。维吉尼亚密码被吹了三百年最后倒在重复模式之下。今天你再去看任何一个宣称“绝对安全”的系统脑子里都会自动吊起这个历史教训所谓不可破译往往只是还没找到合适的统计方法而已。真要练手我建议你从今天开始找一本英文原著自己设个密钥加密一段再用卡西斯基加重合指数破解试试。亲手走完这两个方向你对密码学的理解会比刷十篇文章都扎实。