古典密码学实验:从凯撒到维吉尼亚的算法实现与密码分析实战

📅 2026/7/6 9:48:20
古典密码学实验:从凯撒到维吉尼亚的算法实现与密码分析实战
1. 项目概述为什么今天还要研究古典密码如果你对信息安全、密码学或者计算机历史感兴趣你大概率听说过凯撒密码、维吉尼亚密码这些名字。它们出现在各种侦探小说、电影和入门课程里常常被贴上“简单”、“过时”、“已被破解”的标签。那么一个很自然的问题就来了在量子计算和高级加密标准AES大行其道的今天我们为什么还要花时间去写一份关于古典密码学的实验报告去深入了解这些“老古董”呢这个问题的答案恰恰是古典密码学实验的核心价值所在。它不是一个简单的“历史回顾”作业而是一次对现代密码学思维方式的“寻根之旅”。古典密码学特别是从凯撒到维吉尼亚再到普莱费尔这一系列密码清晰地展示了密码学发展的几个关键脉络从依赖算法保密如凯撒的位移规则到引入密钥如维吉尼亚的密钥词再到对明文结构进行复杂变换如普莱费尔的双字母替换。每一次演进都是对前一种密码脆弱性的直接回应。通过亲手实现这些密码的加解密过程并对其进行频率分析等攻击你能够最直观地理解什么是“唯密文攻击”、“已知明文攻击”以及“密钥空间”的大小如何直接影响密码的安全性。这些概念是现代密码学的基石而古典密码学实验就是搭建这些基石最生动、最没有技术门槛的沙盘。因此这份实验报告的目标绝不仅仅是让你学会把“HELLO”变成“KHOOR”。它的深层目标是让你像一名密码分析者一样思考。你需要理解每种密码的设计哲学亲手验证它的强度并最终明白它为何会被淘汰。这个过程对于培养严谨的工程思维和安全意识至关重要。接下来我将以一个资深从业者的视角带你拆解这份实验报告的核心环节分享从设计到实现再到分析的全流程干货与避坑经验。2. 实验整体设计与核心思路拆解一份有价值的古典密码学实验报告其结构应该反映密码学研究的完整闭环理解、实现、攻击、反思。它不应该是一堆代码的堆砌而是一份有逻辑、有分析的技术文档。2.1 实验目标的层次化设定首先我们需要明确实验的不同层次目标这决定了报告的深度。基础目标必做实现3-4种具有代表性的古典密码算法完成准确的加密和解密功能。这是技术实现的基本功。通常的选择组合是单表替换密码凯撒密码、多表替换密码维吉尼亚密码、置换密码栅栏密码以及一个稍复杂的多图替换密码普莱费尔密码。这个组合覆盖了古典密码的主要类型。进阶目标核心价值对实现的密码进行密码分析。这是实验的灵魂。你需要使用频率分析、重合指数法等方法尝试在仅知道密文和加密算法但不知道密钥的情况下破解它。例如对凯撒密码进行穷举攻击对维吉尼亚密码进行卡西斯基试验确定密钥长度再进行频率分析猜解密钥。拓展目标体现思考对比分析不同密码的优缺点并尝试进行简单的融合与改进。例如思考“先使用栅栏密码置换再用维吉尼亚密码加密”这样的复合密码是否能提升安全性为什么这能体现你对密码学原理的融会贯通。2.2 技术选型与工具准备对于古典密码实验技术栈的选择以“轻量、直观、便于展示过程”为原则。编程语言首选Python这是毫无争议的选择。原因有三一是语法简洁能让你聚焦于算法逻辑而非语言细节二是字符串处理能力强大古典密码操作的核心就是字符串和列表三是有丰富的库支持可视化如matplotlib画频率分布图和数据分析。关键工具库collections.Counter: 用于统计字母频率是频率分析的神器。string模块方便地获取string.ascii_uppercase大写字母表等常量。matplotlib: 用于绘制字母频率分布直方图让分析结果一目了然。环境与数据准备一份纯英文的经典文本作为测试数据例如《双城记》的开篇段落。避免使用现代网络用语或包含太多特殊符号的文本以保证频率分析的有效性。文本需要预先处理转换为大写、去除所有非字母字符如空格、标点。注意文本预处理是第一个容易踩坑的地方。很多同学在加密时忽略了去除空格和标点导致解密时出现混乱。务必保证加解密双方的预处理规则完全一致。一个健壮的程序应该在加密函数入口处就完成文本清洗。3. 核心算法实现与实操要点这里我们以维吉尼亚密码和普莱费尔密码为例深入其实现细节。凯撒密码过于简单我们将重点放在其破解上。3.1 维吉尼亚密码从实现到安全边界维吉尼亚密码是多表替换的典范其安全性在数百年内被称为“不可破译的密码”。1. 加密/解密算法实现要点核心公式是C_i (P_i K_i) mod 26和P_i (C_i - K_i) mod 26。其中P_i,C_i,K_i分别是明文、密文、密钥字母在字母表中的序号A0, B1...。def vigenere_encrypt(plaintext, key): # 预处理转大写去除非字母字符 plaintext .join(filter(str.isalpha, plaintext.upper())) key key.upper() ciphertext [] key_length len(key) for i, char in enumerate(plaintext): p ord(char) - ord(A) k ord(key[i % key_length]) - ord(A) # 循环使用密钥 c (p k) % 26 ciphertext.append(chr(c ord(A))) return .join(ciphertext) def vigenere_decrypt(ciphertext, key): # 解密是加密的逆过程 key key.upper() plaintext [] key_length len(key) for i, char in enumerate(ciphertext): c ord(char) - ord(A) k ord(key[i % key_length]) - ord(A) p (c - k) % 26 # 注意这里是减法 plaintext.append(chr(p ord(A))) return .join(plaintext)2. 实操心得与坑点密钥处理务必确保密钥也经过大写化和去除非字母字符处理。密钥“hello world”应该被处理为“HELLOWORLD”。负数取模在解密运算(c - k) % 26中当c-k为负数时Python的取模运算会自动得到正确结果如-3 % 26 23这很方便。但如果你用其他语言可能需要手动加26再取模。输出格式为了方便阅读和后续分析加密后的密文可以按固定长度如5个一组分组输出但这不影响算法本身。3.2 普莱费尔密码二维变换的优雅与繁琐普莱费尔密码基于一个5x5的密钥方格I和J通常合并为一格对明文成对加密能很好地抵抗简单的频率分析。1. 密钥方格构建这是最易出错的一步。规则是使用密钥词去除重复字母填充方格开头再用剩余字母表顺序填充。def create_playfair_square(key): key key.upper().replace(J, I) # 合并I/J key .join(sorted(set(key), keykey.index)) # 去重并保持顺序 alphabet ABCDEFGHIKLMNOPQRSTUVWXYZ # 注意没有J # 将密钥词和字母表合并并去重 square_string key .join([c for c in alphabet if c not in key]) # 转换为5x5列表 square [list(square_string[i:i5]) for i in range(0, 25, 5)] return square2. 明文预处理规则这是普莱费尔密码最繁琐但也最关键的部分规则必须严格执行。将明文转换为大写去除非字母字符合并I/J。将明文两两分组。若一组内两个字母相同则在第一个字母后插入一个预先约定的填充字母如‘X’然后将原第二个字母与下一个字母重新分组。例如“BALLOON”会先被分成 BA LL OO N。LL和OO都是重复对需要处理。处理后会变成 BA LX LO OX N。最后一个单字母‘N’需要补一个填充字母如‘X’变成‘NX’。实操踩坑记录很多人在实现分组逻辑时使用简单的for i in range(0, len(text), 2)循环这无法动态处理插入‘X’后索引的变化。正确做法是使用while循环或递归逐个字符处理动态构建分组列表。3. 加密规则实现对于一对字母(a,b)在方格中定位其行(row_a, col_a)和(row_b, col_b)。同行各取右边的字母循环。同列各取下边的字母循环。其他取对方所在列的自己行字母即矩形的另外两个角。解密规则是加密的逆过程同行取左同列取上。提示在编写定位函数时可以建立一个字母到坐标(row, col)的字典映射这样在加密每一对字母时可以快速O(1)时间定位而不是每次遍历整个5x5方格。4. 密码分析实战从黑盒到破解实现加密是“造锁”而密码分析是“开锁”。这部分是实验报告最出彩的地方。4.1 凯撒密码的穷举与频率分析凯撒密码的密钥空间只有25种可能位移1-25位。破解它最直接的方法是穷举攻击也叫暴力破解。但如何让机器自动判断哪一种是正确的明文呢这就需要引入频率分析。步骤穷举生成所有25种可能的解密结果。评分对每一种可能的结果计算其字母频率分布与标准英文文本字母频率分布的吻合程度。标准频率参考大约是E(12.7%), T(9.1%), A(8.2%), O(7.5%), I(7.0%), N(6.7%), S(6.3%)...计算吻合度常用卡方检验或简单的欧氏距离。这里可以用一个简单的方法计算每个字母在解密文本中的频率与标准频率的绝对差值之和差值最小的那个最有可能是正确明文。def break_caesar(ciphertext): standard_freq {E: 12.7, T: 9.1, ...} # 简化的标准频率表 best_shift 0 best_score float(inf) all_plaintexts [] for shift in range(26): plaintext caesar_decrypt(ciphertext, shift) # 假设有解密函数 # 计算该明文的字母频率 freq calculate_frequency(plaintext) # 计算与标准频率的差异分数欧氏距离 score sum((freq.get(chr(i65), 0) - standard_freq.get(chr(i65), 0))**2 for i in range(26)) all_plaintexts.append((shift, plaintext, score)) if score best_score: best_score score best_shift shift # 按分数排序输出最可能的几个结果 all_plaintexts.sort(keylambda x: x[2]) return all_plaintexts[:5] # 返回前5个最可能的结果4.2 维吉尼亚密码的破解卡西斯基试验与交互式分析破解维吉尼亚密码是古典密码分析的王冠。它无法完全自动化需要人的判断介入这个过程非常能锻炼分析能力。第一步卡西斯基试验确定密钥长度原理在密文中寻找重复出现的片段长度通常3。这些重复很可能是因为明文中相同的单词或短语被密钥中相同的部分加密所致。计算这些重复片段起始位置之间的距离这些距离的最大公约数GCD很可能就是密钥的长度。操作流程编写程序在密文中找出所有长度为3及以上的重复序列及其位置。计算每对重复序列的间距。对所有间距求最大公约数。如果GCD是1可能需要观察间距是否有共同的因子如3, 6, 9的共同因子是3。得到一个或几个可能的密钥长度候选如 3, 6, 9。第二步按密钥长度分组建模假设密钥长度为key_len那么将密文每key_len个字母为一组分成key_len个集合集合1: 第1, 1key_len, 12*key_len, ... 个字母集合2: 第2, 2key_len, 22*key_len, ... 个字母...集合key_len: 第key_len, 2key_len, 3key_len, ... 个字母关键洞察每个集合中的字母都是由密钥的同一个字母即密钥流中固定位置的那个字母加密的。因此每个集合本质上都是一个单表替换密码具体来说是凯撒密码第三步对每个集合进行频率分析现在对上面分好的每一个集合单独进行类似于破解凯撒密码的频率分析。目标是猜出加密该集合的那个密钥字母的位移量。例如对集合1进行频率分析发现其频率分布与标准英文字母频率分布偏移了4位即‘E’对应‘I’那么密钥的第一个字母就可能是E - I即位移量为(‘I’ - ‘A’) - (‘E’ - ‘A’) 4对应的密钥字母是E因为A4E。但这里有个陷阱频率最高的字母不一定是‘E’也可能是‘T’或其他。所以程序应该输出每个集合最可能的几个位移量候选。第四步组合与验证将每个集合分析出的最可能的密钥字母候选组合起来就得到了几个可能的密钥词。例如假设密钥长度是3分析结果可能是集合1候选:[‘K’, ‘E’, ‘A’]集合2候选:[‘I’, ‘N’, ‘G’]集合3候选:[‘N’, ‘D’, ‘X’]那么最可能的密钥就是第一个候选的组合KIN。用这个密钥去解密密文看得到的明文是否是有意义的英文。如果不是尝试其他候选组合如KND,EIN,ENG等。这个过程通常需要人工查看解密结果来判断。实操心得维吉尼亚密码的破解无法保证100%自动化成功尤其是当密文较短时。你的实验报告价值就在于清晰展示这个分析流程包括卡西斯基试验找到的重复序列、间距计算、GCD推导、分组频率分析图表以及最后基于候选密钥的解密结果对比。即使最终没有猜出完全正确的密钥只要流程正确、分析到位并讨论了失败原因如密文太短、明文非常规这份报告依然极具价值。5. 实验报告撰写与深度思考代码和破解过程是血肉而报告的文字分析是灵魂。一份优秀的报告需要展现你的思考。5.1 结果对比分析与可视化不要只扔出一堆数字和文本。用图表说话。频率分布对比图用matplotlib绘制标准英文频率、明文频率、密文频率对于单表替换的并列条形图。对于维吉尼亚密码绘制每个分组的频率分布图。这能直观展示加密如何打乱频率以及分析如何将其还原。安全性对比表格制作一个表格从多个维度对比你实现的几种密码。密码类型密钥空间抵抗频率分析能力主要攻击方法破解难度主观凯撒密码极小 (25)无穷举攻击、频率分析极低维吉尼亚密码较大 (26^k, k为密钥长)强长密钥下卡西斯基试验、分组频率分析中等需交互普莱费尔密码大 (密钥方格排列)较强破坏双字母频率已知明文攻击、选择明文攻击较高栅栏密码小 (与栏数有关)无穷举所有栏数、结合语言特征低5.2 常见问题与排查技巧实录在实验过程中你一定会遇到各种问题。把这些问题和解决方法记录下来就是宝贵的经验。问题1普莱费尔密码解密后出现乱码或‘X’过多。排查99%的原因出在加密时的明文预处理规则和解密后的后处理规则不匹配。解决确保加密时插入填充字母‘X’的规则处理重复字母和单字母被严格执行。解密后需要识别并移除这些填充的‘X’。但要注意不能简单删除所有‘X’因为原文可能就有‘X’。通常规则是如果解密后的明文对是(a, X)且a与前一个字母相同或处于末尾则这个X很可能是填充的可以移除。这是一个需要精细处理的逻辑。问题2维吉尼亚密码破解时卡西斯基试验找不到重复片段或GCD为1。原因密文长度不足或者明文本身重复模式少或者密钥很长。应对尝试更长的重复片段长度比如找长度为4或5的重复。手动观察间距即使GCD是1如果间距多次出现如6, 9, 12那么密钥长度很可能是3。尝试假设密钥长度直接假设密钥长度为2,3,4,5,6...进行分组频率分析看哪个长度下分组的频率分布最像单表替换即峰值明显。在报告中诚实说明分析失败的原因本身就是有价值的结论体现了维吉尼亚密码在短密文下的相对安全性。问题3频率分析对某些文本不准确。原因标准频率是基于大规模通用英文文本的。如果你的测试文本是特定领域的如科技文献包含大量“computer”、“algorithm”其字母频率如‘C’ ‘G’ ‘M’会偏离标准。改进可以在报告中讨论这一点。甚至可以尝试用你的测试明文本身建立一个“本地”频率表然后用这个表去分析其密文效果可能会更好。这引出了“已知明文攻击”的概念。5.3 从古典到现代的思维延伸在报告的总结部分避免空泛地说“古典密码不安全现代密码安全”。应该进行有深度的关联思考。混淆与扩散香农提出的这两个概念在古典密码中已有雏形。替换如维吉尼亚实现了“混淆”让密钥与密文的关系变得复杂置换如栅栏实现了“扩散”将明文一位的影响扩散到密文多位。现代分组密码如AES是这两种操作的复杂、多轮组合。密钥与算法分离凯撒密码的安全依赖于算法位移3保密这是大忌。维吉尼亚密码将安全性转移到了密钥上即使算法公开只要密钥够长且随机依然安全。这奠定了现代密码学的柯克霍夫原则密码系统的安全性应仅依赖于密钥的保密而不依赖于算法的保密。计算安全性与理论安全性古典密码的破解往往只需要纸笔和统计如维吉尼亚密码属于计算安全性范畴。而现代密码学追求在计算复杂度上不可行如大数分解难题并且有像一次一密这样的理论绝对安全的密码前提是密钥真随机、长度不小于明文、只用一次。你可以思考维吉尼亚密码如果密钥是真正随机、长度等于明文、且只用一次它是不是就变成一次一密了这其中的差别和实际限制是什么通过这样一层层的剖析你的实验报告就从一个简单的编程作业升华为一次对密码学核心思想的深入探索。这份报告的价值不在于你复原了几个古老的玩具而在于你通过亲手触摸这些“化石”理解了现代密码学大厦赖以矗立的地基是如何一块块垒起来的。这才是“古典密码学实验”真正的艺术与实践所在。