CTF密码学实战:Python实现埃特巴什码的加密与解密

📅 发布时间:2026/7/15 22:49:58 👁️ 浏览次数:
CTF密码学实战:Python实现埃特巴什码的加密与解密
1. 从零认识埃特巴什码CTF里最“懒”的古典密码大家好我是老陈一个在CTF密码学和AI领域摸爬滚打了十多年的老兵。今天咱们来聊一个在CTF密码学题目里出场率极高但原理又简单到让人会心一笑的古典密码——埃特巴什码。如果你刚接触CTF或者对密码学有点兴趣但又被各种复杂算法吓到那埃特巴什码绝对是你的完美起点。埃特巴什码到底是什么用一句话概括它就是字母表的“镜像对称”替换。想象一下你把26个英文字母从A到Z写在一张纸条上然后捏住纸条的两端把它对折。A和Z贴在一起B和Y贴在一起C和X贴在一起……以此类推。加密和解密就是按照这个“谁和谁是一对”的规则把字母换成它的“镜像伴侣”。我当年第一次在CTF比赛里遇到它题目给了一段像乱码的字符串gsv jfrxp yildm ulc qfnkh levi gsv ozab wlt。当时我试了凯撒密码、栅栏密码折腾了半天没头绪。后来灵光一闪把每个字母“倒过来”映射瞬间就得到了那句著名的测试句the quick brown fox jumps over the lazy dog。那种“原来如此”的顿悟感至今记忆犹新。埃特巴什码的魅力就在于此它不靠复杂的数学运算纯粹是一种巧妙的对称思维。为什么说它“懒”呢因为它的加密和解密过程完全一样。对一段文本用埃特巴什规则处理一次得到密文再用同样的规则处理一次密文就变回明文。这种特性在密码学里称为“自反性”或“对合性”。你不需要记两套规则一套就够了。在CTF实战中这个特性非常有用。当你怀疑一段密文可能是埃特巴什码时根本不用纠结这是加密还是解密直接拿同一段代码跑一遍如果是立马现原形。那么埃特巴什码在CTF里通常怎么出现呢根据我这十年的“踩坑”经验主要有三种姿势单独出现作为一道独立的入门题直接给一段密文让你还原。这种题就是送分考察你是否知道这个密码的存在。组合出现作为“套娃”的一部分。比如题目先给一段Base64编码解码后得到一串看起来还是乱码的字母这时候再尝试埃特巴什码才能拿到真正的Flag。这是CTF出题人最喜欢的套路之一。变形或部分应用只对字符串中的字母部分进行埃特巴什替换而数字、符号、花括号{}Flag的常见格式保持不变。这需要你在写代码时做好字符类型的判断。接下来我们就用Python这把“瑞士军刀”亲手实现这个有趣的密码并看看如何在CTF实战中运用它。2. 手把手用Python实现埃特巴什码的核心算法理解了原理动手实现就是水到渠成。我们用Python来写不仅因为它是CTF脚本小子的最爱更因为它语法简洁能让我们专注于逻辑本身。我会给出两种不同思路的实现从最直观的到最高效的并解释其中的“坑”和技巧。2.1 方法一字典映射法最直观这是最符合人类思维的方式我先告诉电脑A对应ZB对应Y……建立一个“密码本”字典然后查表替换。def atbash_cipher_dict(text): 使用字典映射实现埃特巴什码加密/解密。 参数 text: 待处理的字符串 返回: 处理后的字符串 # 构建映射字典 # 大写字母映射 upper_map {} # 小写字母映射 lower_map {} # 利用循环和ASCII码构建映射关系 for i in range(26): plain_upper chr(ord(A) i) # 从A开始的大写字母 cipher_upper chr(ord(Z) - i) # 对应的镜像大写字母 upper_map[plain_upper] cipher_upper plain_lower chr(ord(a) i) # 从a开始的小写字母 cipher_lower chr(ord(z) - i) # 对应的镜像小写字母 lower_map[plain_lower] cipher_lower result [] for char in text: if char in upper_map: # 如果是大写字母查大写映射表 result.append(upper_map[char]) elif char in lower_map: # 如果是小写字母查小写映射表 result.append(lower_map[char]) else: # 非字母字符如数字、空格、标点、CTF flag中的花括号{}原样保留 result.append(char) return .join(result) # 测试一下 test_text Hello CTF{Atbash_Is_Fun} encrypted atbash_cipher_dict(test_text) print(f原文: {test_text}) print(f密文: {encrypted}) print(f再次处理密文应还原: {atbash_cipher_dict(encrypted)})运行上面的代码你会看到输出原文: Hello CTF{Atbash_Is_Fun} 密文: Svool XGU{Zgyzhs_Rh_Ufm} 再次处理密文应还原: Hello CTF{Atbash_Is_Fun}代码解读与踩坑点大小写分离这是第一个坑。‘A’的镜像是‘Z’但‘a’的镜像是‘z’。我们必须区分大小写建立两个映射字典否则会得到错误结果。非字母保留这是CTF实战中的关键。Flag的格式通常是flag{...}或CTF{...}那些花括号{和}绝对不能被加密必须原样保留。我们的if-else逻辑确保了这一点。使用列表拼接在循环中我们使用result.append()而不是直接用字符串的运算符。对于较长的文本前者的效率更高。自反性验证最后一行代码验证了“自反性”对密文再次加密果然变回了原文。字典法的优点是极其清晰一看就懂。但它的效率不是最高的因为每个字符都要进行两次字典查找char in map。对于CTF题目那点长度完全够用但如果我们追求极致可以看看更数学化的方法。2.2 方法二数学公式法最高效埃特巴什码的映射关系其实可以用一个简单的数学公式来描述对于一个偏移量为base的字母‘A’或‘a’其镜像位置 (base 25) - (当前字母ASCII码 - base)2 * base 25 - 当前字母ASCII码。观察一下ord(A) ord(Z) 155ord(a) ord(z) 219。所以镜像字母的ASCII码 155 - 原大写字母ASCII码或219 - 原小写字母ASCII码。def atbash_cipher_math(text): 使用数学计算实现埃特巴什码加密/解密。更高效。 参数 text: 待处理的字符串 返回: 处理后的字符串 result [] for char in text: ascii_val ord(char) if A char Z: # 大写字母A(65) Z(90) 155 result.append(chr(155 - ascii_val)) elif a char z: # 小写字母a(97) z(122) 219 result.append(chr(219 - ascii_val)) else: # 非字母字符原样保留 result.append(char) return .join(result) # 测试结果应该和字典法一模一样 print(atbash_cipher_math(Hello CTF{Atbash_Is_Fun}))代码解读与优势效率提升避免了字典的创建和查找开销直接进行计算。对于超长文本虽然CTF不常见这种方法更快。逻辑紧凑利用ASCII码的连续性‘A’到‘Z’‘a’到‘z’是连续的和对称性用减法一步完成映射。边界清晰if A char Z这种判断方式非常Pythonic清晰表达了字符范围。在实际写CTF脚本时我更喜欢用第二种方法因为它写起来快跑起来也快。你可以把它封装成一个函数随时调用。2.3 方法三使用str.maketrans和str.translate最PythonicPython的字符串内置方法提供了终极简洁的方案def atbash_cipher_translate(text): 使用str.maketrans和str.translate实现代码最简洁。 # 创建映射表 # 生成正序和倒序的字母表 original_upper ABCDEFGHIJKLMNOPQRSTUVWXYZ reversed_upper ZYXWVUTSRQPONMLKJIHGFEDCBA original_lower abcdefghijklmnopqrstuvwxyz reversed_lower zyxwvutsrqponmlkjihgfedcba # 创建转换表 translation_table str.maketrans(original_upper original_lower, reversed_upper reversed_lower) # 应用转换 return text.translate(translation_table) # 测试 print(atbash_cipher_translate(The Quick Brown Fox jumps over 123!))一句话解释str.maketrans生成一个翻译表str.translate根据这个表批量替换字符串中的字符。这是处理这类简单替换密码的“王牌”方法一行核心代码搞定而且底层用C实现速度极快。三种方法怎么选学习理解用字典法一步步看清映射关系。比赛实战用数学公式法或translate法写得快跑得快。代码优雅毫无疑问是translate法。3. CTF实战演练识别与破解埃特巴什码光会写代码不够关键是要在题目里认出它来。埃特巴什码的密文有一些可识别的特征结合Python脚本我们可以快速定位。3.1 密文特征与肉眼识别技巧拿到一段疑似古典密码的密文先问自己几个问题是否只包含字母埃特巴什码通常只转换字母保留数字、标点和特殊符号如{}_!?。如果一段“乱码”里混杂着明显的数字和符号它很可能被某种编码如Base64处理过或者埃特巴什只是其中一步。有没有“镜像”单词这是最直接的线索。尝试念一下密文。埃特巴什码处理英文后会产生很多以不常见字母如Z, X, V, J开头或结尾的“伪单词”。比如gsvthe的加密、jfrxpquick的加密、yildmbrown的加密。如果你发现密文单词里z,x,v,j等字母异常多而e,t,a,o等常见元音很少就要高度怀疑。试试“首尾字母”猜测在CTF的Flag中开头经常是flag或ctf。flag的埃特巴什码是oztzctf的埃特巴什码是xgu。如果你在密文开头看到oztz{或xgu{那基本可以实锤了。实战案例1基础识别假设题目给出一段密文Dsviv ziv hlfixgzuv. Z XZKRGFWV ULI GSV YVZIGS.观察全是字母和空格、句点。单词Z很显眼它很可能是A的镜像因为A-Z。GSV出现了两次它很可能是THE的镜像T-G, H-S, E-V。用我们的Python函数跑一下立刻得到Where are solutions. A COMPUTER FOR THE BETTER.这很可能就是提示信息。3.2 编写自动化识别与破解脚本在CTF比赛中时间就是分数。我们不能只靠肉眼。我们可以写一个脚本尝试多种古典密码其中就包括埃特巴什码。import string def try_common_ciphers(ciphertext): 尝试几种常见古典密码解密包括埃特巴什。 返回一个可能的结果列表。 results [] # 1. 尝试埃特巴什码 atbash_result atbash_cipher_math(ciphertext) # 简单启发式判断如果解密后包含常见英文单词片段则可能性高 common_words [the, and, flag, ctf, is, in, to, of] score sum(1 for word in common_words if word in atbash_result.lower()) results.append((Atbash, atbash_result, score)) # 2. 可以继续添加其他密码的尝试例如凯撒密码爆破 # ... (此处省略凯撒密码的尝试代码) # 按“得分”排序得分高的更像英文的排前面 results.sort(keylambda x: x[2], reverseTrue) return results # 使用示例 cipher_from_ctf Gsv jfrxp yildm ulc qfnkh levi gsv ozab wlt. oztz{svool_dliow} possible_solutions try_common_ciphers(cipher_from_ctf) print(可能的解密结果按可能性排序) for cipher_name, plaintext, score in possible_solutions[:3]: # 只看前三个 print(f[{cipher_name}] - {plaintext} (得分: {score}))这个脚本会输出埃特巴什码的解密结果并且因为解密文中包含“the”、“gsv”原文的“the”被加密为“gsv”解密后变回“the”等大量英文单词所以得分会很高排在前面。这样我们就能快速锁定埃特巴什码就是正解。3.3 处理混合编码与“套娃”题CTF出题人不会让你轻松过关。埃特巴什码常常和其他编码方式组合形成“套娃”。经典解题步骤观察密文看结尾是否有Base64特征是否全是十六进制字符Hex特征是否有%URL编码特征。从外到内剥离像剥洋葱一样从最外层的编码开始解。尝试埃特巴什当解码出一段看起来是字母组合但又不是正常单词的文本时马上尝试埃特巴什码。让我们模拟一个经典题型题目给出VU9aVFNaU1pYR1VSSE1SWFY解题脚本import base64 def solve_ctf_challenge(cipher): print(f原始密文: {cipher}) # 第1步观察有尝试Base64解码 try: step1 base64.b64decode(cipher).decode(ascii) print(fBase64解码后: {step1}) except: step1 cipher print(不是标准Base64或解码失败。) # 第2步Base64解码后得到纯英文大写字符串尝试埃特巴什 if step1.isalpha() and step1.isupper(): step2 atbash_cipher_math(step1) print(f应用Atbash后: {step2}) # 通常flag会是小写我们转为小写看看 flag_candidate step2.lower() print(fFlag候选: {flag_candidate}) # 检查是否符合常见flag格式 if flag_candidate.startswith(flag) or ctf in flag_candidate: print(f✅ 发现疑似Flag: {flag_candidate}) return flag_candidate else: print(解码后文本不符合埃特巴什码常见特征需尝试其他方法。) return None # 运行解题 cipher_text VU9aVFNaU1pYR1VSSE1SWFY solve_ctf_challenge(cipher_text)运行后你会看到输出原始密文: VU9aVFNaU1pYR1VSSE1SWFY Base64解码后: UOZTSZSZXGURHMRXV 应用Atbash后: FLAGHAHACTFISNICE Flag候选: flaghahactfisnice ✅ 发现疑似Flag: flaghahactfisnice看这就是一个标准的“Base64 埃特巴什”套娃题。我们的脚本自动化完成了识别和解码流程。4. 深入原理与变种不止于26个字母掌握了基础玩法我们来看看埃特巴什码的“七十二变”。理解这些变种能帮助你在CTF中应对那些不按常理出牌的题目。4.1 数学本质与自反性证明埃特巴什码的数学核心是一个对合函数。什么叫对合就是函数自己和自己复合后得到恒等映射f(f(x)) x。我们用数学公式来表达对于单个字母的映射 设字母在字母表中的位置索引为i(A0, B1, ..., Z25)。 加密/解密函数E(i) 25 - i。 验证自反性E(E(i)) 25 - (25 - i) i。完美在编程中我们用的155 - ord(A)和219 - ord(a)正是这个公式在ASCII码体系下的体现。因为ord(Z) ord(A) 25所以ord(A) ord(Z) 2*ord(A) 25 155。4.2 扩展与变种真正的CTF题目不会总是用标准的26字母英文字母表。1. 自定义字母表比如题目可能只用字母表的前N个字母或者使用自定义的符号序列。def custom_atbash(text, alphabet): 对任意自定义字母表进行Atbash变换。 参数: text: 待处理文本 alphabet: 字母表字符串如ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 n len(alphabet) # 创建映射字典首尾对称 mapping {} for i in range(n): src alphabet[i] dst alphabet[n-1-i] mapping[src] dst # 同时建立反向映射方便加解密同一函数 mapping[dst] src result [] for char in text: result.append(mapping.get(char, char)) # 找不到的字符原样保留 return .join(result) # 示例对数字0-9也进行Atbash alphabet_full ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 test_str FLAG123 encrypted custom_atbash(test_str, alphabet_full) print(f自定义字母表加密 {test_str}: {encrypted}) print(f解密: {custom_atbash(encrypted, alphabet_full)})输出可能是FLAG123-UOZT876取决于字母表顺序。这要求你从题目描述或上下文推断出正确的字母表。2. 仅对部分字符应用有时出题人只对单词中的元音或辅音进行埃特巴什替换。这就需要我们仔细分析替换规则。写脚本时核心逻辑不变只是修改字符判断条件。3. 数字埃特巴什完全可以将规则应用到数字上0-9, 1-8, 2-7, 3-6, 4-5。def atbash_numbers(text): 对字符串中的数字进行Atbash变换0-9, 1-8, ... digit_map str.maketrans(0123456789, 9876543210) return text.translate(digit_map) print(atbash_numbers(Answer is 12345)) # 输出: Answer is 876544.3 安全性探讨为什么它不安全埃特巴什码在现代密码学视角下是完全不安全的。原因如下密钥空间极小它的“密钥”就是那个固定的、唯一的映射关系。攻击者连试都不用试只有一种可能。保留统计特征它没有改变原文字母的频率分布。英文中最常见的字母是e加密后对应的是v。那么在密文中v就会是最常见的字母。攻击者通过频率分析很容易猜出映射关系。无扩散性明文中的一个微小变化只会导致密文中对应位置的一个变化不会影响其他部分。所以埃特巴什码绝不能用于任何真正的信息安全目的。它的价值在于教学、趣味谜题以及CTF中作为一道“开胃菜”或者复杂编码链中的一环。5. 打造你的CTF密码工具箱模块化与实战技巧在真实的CTF比赛或日常练习中效率至关重要。我们应该把常用的密码函数包括埃特巴什码封装成随时可调用的工具。5.1 创建可复用的Python模块我习惯创建一个名为crypto_utils.py的文件里面存放各种密码函数# crypto_utils.py CTF密码学常用工具函数库 作者你的名字 def atbash(text): 埃特巴什码加密/解密。 result [] for ch in text: if A ch Z: result.append(chr(155 - ord(ch))) elif a ch z: result.append(chr(219 - ord(ch))) else: result.append(ch) return .join(result) def rot13(text): ROT13加密/解密。 # ... 实现代码 pass def caesar_bruteforce(ciphertext): 凯撒密码爆破返回所有25种可能。 # ... 实现代码 pass def detect_simple_substitution(ciphertext): 尝试识别简单替换密码包括埃特巴什。 # 可以在这里集成我们之前写的try_common_ciphers逻辑 pass # ... 其他函数如base64解码、hex解码、摩斯电码等然后在解题脚本中直接导入使用from crypto_utils import atbash, caesar_bruteforce import base64 cipher VU9aVFNaU1pYR1VSSE1SWFY step1 base64.b64decode(cipher).decode() flag atbash(step1) print(fFlag: {flag.lower()})5.2 集成到命令行工具更进一步我们可以做一个命令行工具像使用grep或cat一样使用它# atbash_cli.py import argparse import sys def main(): parser argparse.ArgumentParser(description埃特巴什码命令行工具 - CTF助手) parser.add_argument(text, nargs?, help要处理的文本。如果未提供则从标准输入读取。) parser.add_argument(-f, --file, help从文件中读取文本) parser.add_argument(-o, --output, help将结果输出到文件) args parser.parse_args() # 获取输入文本 input_text if args.file: try: with open(args.file, r, encodingutf-8) as f: input_text f.read() except FileNotFoundError: print(f错误文件 {args.file} 未找到。, filesys.stderr) sys.exit(1) elif args.text: input_text args.text else: # 从标准输入读取 input_text sys.stdin.read().strip() if not input_text: print(错误未提供输入文本。, filesys.stderr) parser.print_help() sys.exit(1) # 处理加密/解密相同 result atbash(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 atbash_cli.py Gsv jfrxp yildm # 从文件读取 python atbash_cli.py -f cipher.txt # 管道操作 echo UOZTSZSZXGURHMRXV | python atbash_cli.py5.3 应对CTF比赛的实战策略优先尝试遇到一段由字母组成的密文且长度适中可以第一时间用埃特巴什码试一下。成本极低一键运行。组合思维如果埃特巴什单独解不出有意义的内容别放弃。想想是不是Base64/Hex/URL编码 埃特巴什或者埃特巴什 凯撒。写一个自动化的解码流水线脚本。注意格式CTF的Flag有固定格式如flag{...}、CTF{...}、SECCON{...}等。解密后首先检查输出是否符合这些格式这能帮你快速判断方向是否正确。利用在线工具但别依赖有很多在线埃特巴什加解密网站。在紧急或验证思路时可以用但比赛网络可能不稳定或者题目环境是离线的。所以自己本地有一个可靠的脚本库是硬道理。埃特巴什码就像密码世界里的“Hello World”它简单但蕴含着对称和映射的核心思想。通过亲手实现它你不仅掌握了一个CTF考点更迈出了理解更复杂加密算法如仿射密码、维吉尼亚密码的第一步。下次在CTF赛场上看到一段奇怪的字母不妨先试试把它“倒过来”看看也许Flag就在眼前。