1. 项目概述为什么现在还要学古典密码最近看到不少朋友在讨论信息安全尤其是家里有孩子报了相关专业的总有人问“学这个后不后悔”。我的看法是信息安全从来都不是一个“过时”的领域它的核心是攻防对抗的思维而这种思维最好的启蒙恰恰是那些被我们称为“古典密码”的东西。用Python来实现它们不是一个怀旧游戏而是一次绝佳的思维训练。它能让你亲手触摸到密码学的“骨骼”——那些关于替换、移位、统计和密钥的基础概念这些概念在现代的AES、RSA等算法中依然以更复杂的形式存在。当你用几十行Python代码实现一个凯撒密码并尝试去破解它时你实际上就在经历一次完整的安全评估理解算法、寻找弱点、实施攻击。这个过程比直接调用一个cryptography库里的AES.encrypt()要有价值得多。后者让你成为一个“使用者”而前者让你开始像一个“设计者”或“分析者”一样思考。这也是为什么在CTF夺旗赛中古典密码的嵌套、与隐写术的结合比如热词里提到的gfsj1127-【catcat】这类题目一直是常客它考察的正是这种基础的、灵活的密码学直觉。所以这个项目适合谁如果你是信息安全的新手正在为“网络与信息安全管理员”或“软考信息安全工程师”考试打基础这里的数学原理和编程实践能帮你夯实“信息安全数学基础”。如果你是Python初学者刚刚配好vscode python环境或者用anaconda配好了环境正愁没地方练手那么从古典密码入手既能熟悉python基础语法、python collections等模块又能做出有实际反馈加解密文本的小项目成就感十足。甚至当你能把脚本python打包成exe发给朋友玩时学习的乐趣就又上了一个台阶。2. 古典密码的核心思想与Python映射古典密码虽然形式多样但核心思想可以归结为两大流派替换和置换也叫移位。理解这两点就握住了打开古典密码大门的钥匙。2.1 替换密码字符的一对一映射替换密码的核心是建立一个映射表将明文中的每个字符替换为另一个字符。最著名的就是凯撒密码它是一种特殊的替换密码——等距移位替换。为什么是等距移位在古罗马时代这种规则简单到可以用心算或简单的物理工具如密码棒实现易于加密和解密双方记忆和操作。它的安全性完全依赖于密钥移位数字的保密。在Python中我们可以用字符的ASCII码或自定义字母表索引来实现这种映射。注意古典密码通常只考虑字母忽略大小写和标点。这是为了简化模型专注于密码算法本身。在实际编程中我们需要先对输入文本进行预处理如统一转为大写过滤非字母字符。2.2 置换密码字符位置的重新排列置换密码不改变字符本身而是打乱字符的顺序。比如栅栏密码把明文按一定规则写成多行再按列读取生成密文。为什么改变位置也能加密这破坏了明文语言的统计特性如单词间隔、常见字母组合和可读性。对于短文本单纯的置换可能效果不明显但结合替换或其他操作就能显著增加复杂度。在Python中这通常涉及到对字符串进行切片、重组和矩阵变换操作。这两种思想是现代密码学的基石。例如著名的AES算法中就包含了替换S盒和置换行移位、列混淆的多轮操作。我们从古典密码学起就是在理解这些基本操作的原始形态。3. 核心密码算法Python实现与详解下面我们将用Python逐一实现几个最具代表性的古典密码。我会提供可直接运行的代码并详细解释每一行代码背后的意图和密码学原理。3.1 凯撒密码密码学的“Hello World”凯撒密码是移位密码的代表。其加密过程是将明文字母按字母表顺序向后移动一个固定数值密钥解密则反向移动。核心Python实现def caesar_cipher(text, shift, modeencrypt): 实现凯撒密码的加密和解密。 参数: text: 待处理的字符串 shift: 移位值密钥 mode: encrypt 或 decrypt 返回: 处理后的字符串 result [] # 预处理只处理字母统一转为大写以便于计算 processed_text text.upper() for char in processed_text: if char.isalpha(): # 核心计算找到字符在A-Z(0-25)中的位置 base ord(A) char_index ord(char) - base if mode encrypt: new_index (char_index shift) % 26 # 加密正向移位 else: # decrypt new_index (char_index - shift) % 26 # 解密反向移位 new_char chr(base new_index) result.append(new_char) else: # 非字母字符原样保留可根据需求修改如过滤掉 result.append(char) return .join(result) # 示例使用 plaintext HELLO SECURITY key 3 ciphertext caesar_cipher(plaintext, key, encrypt) print(f明文: {plaintext}) print(f密文: {ciphertext}) print(f解密: {caesar_cipher(ciphertext, key, decrypt)})代码与原理拆解char.isalpha(): 这个判断至关重要。古典密码模型通常只针对字母表忽略数字和标点。这既是历史习惯也简化了我们的算法焦点。ord(char) - ord(A): 这是将字符映射为0-25数字的核心。ord()函数获取字符的Unicode码点A-Z是连续的65-90相减后正好得到字母表索引。(char_index ± shift) % 26: 这是算法的数学核心。取模运算% 26确保了移位是循环的例如Z后移1位回到A。这体现了密码算法中的“封闭性”要求。为什么模数是26这是由英文字母表的长度决定的。如果你要处理包含数字的更大字符集模数就需要相应改变。实操心得在测试时尝试shift值为26。你会发现密文和明文一样因为移动一整圈回到了原点。这说明密钥空间其实只有0-25共26种非常脆弱。对于包含空格和标点的句子上述代码会保留它们。这在某些CTF题中可能是提示但在严格的古典密码分析中通常先会去除这些干扰项。你可以修改代码在预处理步骤中用filter函数只保留字母。3.2 仿射密码凯撒密码的升级版仿射密码是凯撒密码的推广它用了两个密钥a和b加密公式为E(x) (a * x b) mod 26。其中x是字母索引0-25a必须与26互质即gcd(a, 26) 1。为什么要求a与26互质这是为了确保加密函数是一个“双射”即每个明文字母唯一对应一个密文字母并且可以解密。如果a和26不互质比如a2那么加密E(0)0, E(13)0两个不同的明文A和N都加密成了A解密时就无法确定原文是什么了。Python实现def gcd(a, b): 计算最大公约数用于检查密钥a是否合法 while b ! 0: a, b b, a % b return a def mod_inverse(a, m): 求模逆元。即寻找一个整数 a_inv使得 (a * a_inv) % m 1。 这是解密所必需的。 for x in range(1, m): if (a * x) % m 1: return x return None # 如果不存在逆元 def affine_cipher(text, a, b, modeencrypt): 实现仿射密码。 参数: a: 乘法密钥必须与26互质 b: 加法密钥 # 1. 密钥有效性检查 if gcd(a, 26) ! 1: raise ValueError(f密钥a{a}无效必须与26互质。) result [] processed_text text.upper() for char in processed_text: if char.isalpha(): base ord(A) x ord(char) - base if mode encrypt: # 加密: E(x) (a*x b) mod 26 y (a * x b) % 26 else: # 解密: D(y) a_inv * (y - b) mod 26 a_inv mod_inverse(a, 26) if a_inv is None: raise ValueError(f密钥a{a}的模26逆元不存在无法解密。) y (a_inv * (x - b)) % 26 result.append(chr(base y)) else: result.append(char) return .join(result) # 示例使用a5, b8 (因为gcd(5,26)1) plaintext AFFINE CIPHER a, b 5, 8 ciphertext affine_cipher(plaintext, a, b, encrypt) print(f仿射加密 ({a},{b}): {ciphertext}) print(f仿射解密: {affine_cipher(ciphertext, a, b, decrypt)})算法深度解析密钥空间扩大凯撒密码只有26种可能b0-25a固定为1。仿射密码中a有φ(26)12种选择与26互质的数b有26种所以总密钥数为12*26312种。虽然依然很小但已是凯撒的12倍。模逆元计算解密的关键是找到a在模26下的逆元a_inv。我们用了最简单的遍历法从1到25尝试。对于小模数这没问题但对于大质数模数如RSA中就需要用扩展欧几里得算法来高效计算。这里手动实现一次对理解公钥密码学的底层原理非常有帮助。错误处理代码中加入了密钥检查当用户输入无效的a时如a2会立即抛出错误。这在构建健壮的密码工具时是必要的。3.3 维吉尼亚密码多表替换的里程碑维吉尼亚密码通过使用一个关键词实现多个凯撒密码的轮换使用极大增强了抗频率分析的能力。关键词KEY会重复使用每个字母对应一个移位量A0, B1, ..., Z25。Python实现def vigenere_cipher(text, keyword, modeencrypt): 实现维吉尼亚密码。 参数: keyword: 密钥词仅包含字母。 result [] # 预处理统一大写并过滤非字母字符但保留其位置用于还原这里简单处理仅加密字母 processed_text text.upper() keyword keyword.upper().replace( , ) key_length len(keyword) key_indices [ord(k) - ord(A) for k in keyword] # 预计算密钥字母的移位值 non_alpha_count 0 # 用于记录非字母字符以便密钥索引对齐 for i, char in enumerate(processed_text): if char.isalpha(): # 计算当前使用的密钥字母索引 key_index (i - non_alpha_count) % key_length shift key_indices[key_index] base ord(A) char_index ord(char) - base if mode encrypt: new_index (char_index shift) % 26 else: new_index (char_index - shift) % 26 result.append(chr(base new_index)) else: # 非字母字符原样输出并且需要记录以免打乱密钥流同步 result.append(char) non_alpha_count 1 return .join(result) # 示例 plaintext ATTACK AT DAWN keyword LEMON ciphertext vigenere_cipher(plaintext, keyword, encrypt) print(f维吉尼亚加密 (密钥:{keyword}): {ciphertext}) print(f维吉尼亚解密: {vigenere_cipher(ciphertext, keyword, decrypt)})为什么维吉尼亚更安全凯撒密码中一个字母永远被加密成同一个字母单表替换。在英文中E的出现频率最高那么密文里出现频率最高的字母很可能就对应E。维吉尼亚密码中明文的同一个字母如果对应的密钥字母不同会被加密成不同的密文字母。例如用密钥KEY加密HELLO第一个L对应密钥E(移位4)第二个L对应密钥Y(移位24)结果不同。这破坏了单字母频率统计破解难度直线上升。实操中的关键细节密钥流同步代码中(i - non_alpha_count) % key_length是精髓。它确保了密钥字母只对明文字母进行移位跳过空格、标点等非字母字符。如果简单按字符位置i % key_length取密钥遇到空格时密钥流就会“错位”导致解密失败。这是很多初学者容易忽略的坑。密钥管理维吉尼亚的安全性很大程度上依赖于密钥的长度和随机性。一个短且常见的关键词如“KEY”、“SECRET”很容易被猜出或通过卡西斯基试验破解。3.4 栅栏密码典型的置换密码栅栏密码将明文按“之”字形排列然后按行读取形成密文。例如深度为3的栅栏密码将明文HELLOWORLD写成H O L E L W R D L O按行读取HOLELWRDLO。Python实现def rail_fence_cipher(text, rails, modeencrypt): 实现栅栏密码。 参数: rails: 栅栏的层数深度 if rails 2: return text if mode encrypt: # 创建rails个空字符串模拟栅栏 fence [] * rails rail 0 direction 1 # 1表示向下-1表示向上 for char in text: fence[rail] char # 到达顶部或底部时转向 if rail 0: direction 1 elif rail rails - 1: direction -1 rail direction return .join(fence) else: # 解密稍复杂需要先重建栅栏的“形状” length len(text) # 创建一个二维列表模拟空栅栏 fence [[ for _ in range(length)] for __ in range(rails)] # 标记出栅栏的路径位置放置*号占位 rail 0 direction 1 for i in range(length): fence[rail][i] * if rail 0: direction 1 elif rail rails - 1: direction -1 rail direction # 将密文字母按行填充到*号位置 index 0 for r in range(rails): for c in range(length): if fence[r][c] * and index length: fence[r][c] text[index] index 1 # 按照加密时的路径读取明文 result [] rail 0 direction 1 for i in range(length): result.append(fence[rail][i]) if rail 0: direction 1 elif rail rails - 1: direction -1 rail direction return .join(result) # 示例 plaintext HELLOWORLD rails 3 ciphertext rail_fence_cipher(plaintext, rails, encrypt) print(f栅栏加密 (深度{rails}): {ciphertext}) print(f栅栏解密: {rail_fence_cipher(ciphertext, rails, decrypt)})置换密码的特点与局限不改变字符密文和明文由完全相同的字母组成只是顺序变了。这对于非常短的文本可能加密效果不明显。密钥是栅栏深度密钥空间很小通常从2到文本长度的一半。可以通过暴力枚举所有可能的深度来破解。常与其他密码结合正因为其弱点明显在CTF或实际古典密码应用中栅栏密码很少单独使用。它常作为一层“混淆”手段与替换密码如凯撒、维吉尼亚嵌套使用增加分析难度。这就是热词中提到的“嵌套”玩法。4. 从实现到破解古典密码分析实战只会加密不算真正理解。密码学的另一半是密码分析即如何在不知道密钥的情况下破解密文。我们用Python来实现两种经典的攻击方法。4.1 凯撒密码的暴力破解与频率分析由于凯撒密码只有26种可能的密钥最直接的方法就是暴力枚举所有偏移量然后人工观察哪个结果是有意义的英文。但我们可以用频率分析来让程序自动做出最佳猜测。英文单字母频率统计近似E: 12.7%, T: 9.1%, A: 8.2%, O: 7.5%, I: 7.0%, N: 6.7%, ...Python实现智能破解def frequency_analysis(text): 统计文本中字母频率返回一个字典 text text.upper() letter_count {chr(i): 0 for i in range(ord(A), ord(Z)1)} total_letters 0 for char in text: if char in letter_count: letter_count[char] 1 total_letters 1 if total_letters 0: return {} # 计算频率百分比 frequency {k: (v / total_letters) * 100 for k, v in letter_count.items()} return frequency def caesar_break(ciphertext): 尝试破解凯撒密码。 步骤1. 暴力枚举所有26种移位。2. 对每个结果计算频率并与英文字母标准频率做相关性比较。 # 英文字母标准频率按E,T,A,O,I,N,S...顺序的百分比 english_freq [ 12.70, 9.06, 8.17, 7.51, 6.97, 6.75, 6.33, 6.09, 5.99, 4.25, 4.03, 2.78, 2.76, 2.41, 2.36, 2.23, 2.02, 1.97, 1.93, 1.49, 1.39, 0.98, 0.77, 0.15, 0.15, 0.10 ] # 对应A-Z best_shift 0 best_correlation -1 possible_plaintexts [] for shift in range(26): # 用当前shift尝试解密 decrypted caesar_cipher(ciphertext, shift, decrypt) # 计算解密文本的字母频率 freq frequency_analysis(decrypted) if not freq: continue # 将频率字典按字母表顺序转为列表 freq_list [freq.get(chr(ord(A)i), 0) for i in range(26)] # 计算与标准频率的相关系数皮尔逊积矩相关系数的简化版 # 这里用点积作为相关性的简单度量 correlation sum(f * e for f, e in zip(freq_list, english_freq)) possible_plaintexts.append((decrypted, shift, correlation)) if correlation best_correlation: best_correlation correlation best_shift shift # 按相关性排序输出最有可能的前3个结果 possible_plaintexts.sort(keylambda x: x[2], reverseTrue) print(最有可能的破解结果按频率匹配度排序:) for i, (text, shift, corr) in enumerate(possible_plaintexts[:3]): print(f 尝试 {i1}: Shift{shift:2d}, 匹配度{corr:.2f}, 明文预览: {text[:50]}...) return caesar_cipher(ciphertext, best_shift, decrypt) # 测试破解 ciphertext caesar_cipher(The quick brown fox jumps over the lazy dog, 17, encrypt) print(f待破解密文: {ciphertext}) plaintext_guessed caesar_break(ciphertext) print(f\n程序推荐的最可能明文: {plaintext_guessed})破解原理与注意事项频率分析的有效性这种方法依赖于密文足够长以体现英文的统计特征。如果密文只有几个单词频率可能失真程序可能会给出错误的最佳猜测。这时就需要结合暴力枚举的结果人工判断。相关系数简化我们用了简单的点积来代替复杂的相关系数计算因为目的是比较相对大小而非绝对值。在实际更严谨的工具中会使用卡方检验或更精确的相关系数。非字母处理我们的frequency_analysis函数只统计字母忽略了空格和标点。这在实际中是合理的因为古典密码分析通常先处理纯字母文本。4.2 维吉尼亚密码的卡西斯基试验思路完全破解维吉尼亚密码要复杂得多但其中一个关键步骤是确定密钥长度卡西斯基试验是经典方法。其核心思想是在密文中寻找重复出现的片段这些片段可能对应明文中相同的单词如“THE”、“AND”而它们之间的距离很可能是密钥长度的倍数。Python实现密钥长度推测def kasiski_examination(ciphertext, seq_len3): 卡西斯基试验寻找重复序列计算其间距的公约数以推测密钥长度。 参数: seq_len: 要寻找的重复序列的最小长度通常为3 ciphertext .join(filter(str.isalpha, ciphertext.upper())) # 取纯字母密文 n len(ciphertext) # 步骤1找出所有重复序列及其位置 seq_positions {} for i in range(n - seq_len 1): seq ciphertext[i:iseq_len] if seq not in seq_positions: seq_positions[seq] [] seq_positions[seq].append(i) # 只保留出现超过1次的序列 repeating_seqs {seq: pos for seq, pos in seq_positions.items() if len(pos) 1} if not repeating_seqs: print(未找到足够长的重复序列卡西斯基试验可能不适用。) return [] print(f找到的重复序列长度{seq_len}及位置:) for seq, pos in repeating_seqs.items(): print(f {seq}: {pos}) # 步骤2计算重复序列间距 distances [] for seq, positions in repeating_seqs.items(): for i in range(len(positions)): for j in range(i1, len(positions)): dist positions[j] - positions[i] distances.append(dist) print(f 序列 {seq} 间距: {dist}) # 步骤3对所有间距求最大公约数或公约数推测密钥长度 from math import gcd from functools import reduce if distances: # 计算所有间距的最大公约数 overall_gcd reduce(gcd, distances) print(f\n所有间距的最大公约数 (GCD): {overall_gcd}) # 密钥长度可能是GCD的因子 possible_lengths [] for l in range(2, min(overall_gcd, 20) 1): # 假设密钥长度不超过20 if overall_gcd % l 0: possible_lengths.append(l) print(f推测的可能密钥长度 (GCD的因子): {possible_lengths}) return possible_lengths else: return [] # 测试使用一个较长的、有重复单词的明文加密后测试 plain_test THIS IS A SECRET MESSAGE THAT CONTAINS THE WORD SECRET TWICE FOR TESTING SECRET key_test KEY cipher_test vigenere_cipher(plain_test, key_test, encrypt).replace( , ) print(f测试密文: {cipher_test[:50]}...) possible_lengths kasiski_examination(cipher_test, 3)卡西斯基试验的局限性需要足够长的密文密文太短重复序列可能只是随机巧合或者根本不存在。明文需有重复词汇如果明文本身用词高度随机没有像“THE”、“AND”、“SECRET”这样的常见词重复这个方法就失效了。结果是指示性的它给出的是密钥长度的可能值因子还需要结合弗里德曼试验利用重合指数来进一步确认最可能的长度。一旦确定了密钥长度L维吉尼亚密码就被分解成了L个独立的凯撒密码。你可以将密文按每第L个字母分组对每个分组单独进行频率分析破解出密钥的每一个字母最终拼出完整密钥。这个过程虽然繁琐但用Python自动化是完全可行的这留给你作为扩展练习。5. 工程化与扩展打造你的古典密码工具箱当我们把几个密码算法都实现后就可以考虑把它们“工程化”做成一个更实用、更健壮的工具甚至图形界面。5.1 构建一个命令行工具我们可以用Python的argparse库创建一个命令行程序支持多种密码算法。import argparse def main(): parser argparse.ArgumentParser(description古典密码加密/解密工具箱) parser.add_argument(mode, choices[encrypt, decrypt, break], help操作模式) parser.add_argument(cipher, choices[caesar, affine, vigenere, railfence], help密码类型) parser.add_argument(-t, --text, help直接输入的文本) parser.add_argument(-f, --file, help从文件读取文本) parser.add_argument(-k, --key, help密钥对于凯撒是数字仿射是a,b维吉尼亚是单词栅栏是深度) parser.add_argument(-o, --output, help输出到文件) args parser.parse_args() # 获取输入文本 if args.text: input_text args.text elif args.file: with open(args.file, r, encodingutf-8) as f: input_text f.read() else: print(错误请通过 -t 或 -f 提供输入文本。) return # 根据密码类型和模式调用相应的函数 result if args.cipher caesar: if args.mode in [encrypt, decrypt]: if not args.key: print(错误凯撒密码需要 -k KEY整数) return shift int(args.key) result caesar_cipher(input_text, shift, args.mode) elif args.mode break: result caesar_break(input_text) # ... 其他密码类型的处理逻辑仿射、维吉尼亚、栅栏 # 输出结果 if args.output: with open(args.output, w, encodingutf-8) as f: f.write(result) print(f结果已写入文件: {args.output}) else: print(结果:) print(result) if __name__ __main__: main()这样你就可以在终端里像这样使用python cipher_tool.py encrypt caesar -t HELLO -k 5。5.2 密码嵌套与CTF实战技巧在CTF比赛中古典密码常常不是单独出现的。热词中提到的gfsj1127-【catcat】 简单隐写加古典密码嵌套就是一个典型例子。解题思路通常是观察与识别首先看题目给的文件或字符串。可能是二进制文件、图片隐写、或者一段看起来像Base64但解码后乱码的文本。尝试常见编码如果密文由A-Za-z0-9/组成先尝试Base64解码。如果由0-9a-f组成可能是十六进制。如果只有字母可能是凯撒、仿射、维吉尼亚或Atbash字母表反转等。统计特征分析对纯字母密文计算字母频率。如果频率分布非常不均匀像英文可能是单表替换如凯撒、仿射。如果频率分布非常平坦接近平均可能是多表替换如维吉尼亚或已进行过置换。工具暴力尝试对于凯撒、栅栏等密钥空间小的直接写脚本或在线工具暴力枚举所有可能。嵌套破解如果一层解密后得到的结果还是乱码但看起来有规律比如变成了另一种编码格式就要考虑嵌套。例如“Base64解码 → 得到十六进制字符串 → 十六进制转文本 → 得到维吉尼亚密文 → 破解维吉尼亚”。结合上下文题目描述、文件名、标签如gfsj1127有时就是密钥或提示。一个模拟嵌套的例子import base64 # 模拟一个嵌套加密流程 plain_secret FLAG{Classical_Cipher_Is_Fun} # 第一层栅栏密码 (深度4) layer1 rail_fence_cipher(plain_secret, 4, encrypt) # 第二层凯撒密码 (移位7) layer2 caesar_cipher(layer1, 7, encrypt) # 第三层Base64编码使其看起来像一堆乱码 final_cipher base64.b64encode(layer2.encode()).decode() print(f最终密文 (Base64): {final_cipher}) # 破解思路逆向 # 1. Base64解码 decoded base64.b64decode(final_cipher).decode() print(fBase64解码后: {decoded}) # 2. 凯撒暴力破解已知是古典密码可尝试 for shift in range(26): attempt caesar_cipher(decoded, shift, decrypt) # 通过肉眼或程序判断是否有“FLAG{”字样 if FLAG{ in attempt: print(f找到可能的凯撒偏移: {shift}, 文本: {attempt}) # 3. 对结果尝试不同深度的栅栏解密 for depth in range(2, 10): final_attempt rail_fence_cipher(attempt, depth, decrypt) if FLAG{ in final_attempt: print(f 成功栅栏深度: {depth}, 最终明文: {final_attempt}) break5.3 避免的坑与最佳实践在实现和使用这些密码时有一些坑需要避开字符集问题我们的示例默认处理A-Z。如果文本包含小写字母、数字、中文或特殊符号需要明确处理策略。是忽略、保留还是扩展算法在CTF中出题人有时会利用这一点设置陷阱。密钥输入验证对于仿射密码必须检查a是否与26互质。对于维吉尼亚密码密钥词不应为空且最好只包含字母。在图形界面或Web应用中前端和后端都要做验证。性能考虑对于极长的文本如整本书我们的字符串拼接result char方式效率较低。更高效的做法是使用列表append最后.join(list)正如我在代码中所做。代码可读性密码学代码涉及数学务必写清楚注释尤其是模运算和索引计算部分。变量名使用plaintext、ciphertext、shift、key等有意义的名称。不要用于真实加密务必记住所有这些古典密码都绝对不安全不能用于保护任何真实的敏感信息。它们只有教学、历史研究和CTF娱乐价值。真正的系统应该使用经过严格认证的现代密码库如Python的cryptography模块。最后学习古典密码的Python实现就像学习武术的套路。套路本身不能直接用于实战但它训练了你的基本功、协调性和对力量的理解。当你未来学习AES的S盒、RSA的模幂运算、椭圆曲线的点加时你会感谢今天亲手实现凯撒移位和模逆元的经历。它让你对“加密”和“解密”这一对互逆操作有了最直观和本质的把握。