古典密码系统
古典密码系统
本文适合
已经能识别基础编码,准备处理 Caesar、Vigenere、替换、栅栏和列置换题的新手。学完你能:根据字符分布、明文格式和密钥空间,选择枚举、频率分析、已知明文或置换搜索来还原古典密码。
一句话判断
古典密码题通常不是靠大数或现代算法,而是靠小密钥空间、语言统计、已知明文 flag{ 和排列规律把明文还原出来。
题目中常见信号
可能方向:Caesar、Atbash、替换
可能方向:单表替换或 Vigenere
可能方向:Vigenere 周期密钥
可能方向:栅栏、列置换、矩阵置换
可能方向:古典密码优先
可能方向:用 flag{ 做 crib 推密钥
核心概念
替换类密码改变字符,不改变位置;置换类密码改变位置,不改变字符;Vigenere 则把多个 Caesar 按周期组合起来。判断方向时先看“字符频率是否被保留”和“字符顺序是否被打乱”,这比直接开工具更稳。
古典密码的优势是密钥空间小。Caesar 只有 26 种,栅栏层数通常不大,列置换短密钥可以枚举。S 级做法是先估算搜索空间,再写脚本枚举并用 flag 格式或语言得分筛选。
最小分析流程
- 清理输入:保留原文,同时记录是否只含字母、数字、空格或符号。
- 看字符集合:是否是字母表内替换,是否需要先 Base64/Hex 解码。
- 用已知前缀:尝试
flag{、ctf{、题目名关键字反推移位或密钥。 - 对小密钥空间直接枚举,输出候选前 80 字符。
- 对替换题做频率分析,对 Vigenere 先估计密钥长度。
- 对置换题枚举行数、列数、栅栏数或列顺序。
最小验证示例
import string
ct = "iodj{fodvvlfdo_flskhu}"
abc = string.ascii_lowercase
for shift in range(26):
pt = ""
for ch in ct:
if ch in abc:
pt += abc[(abc.index(ch) - shift) % 26]
else:
pt += ch
if "flag{" in pt or "ctf{" in pt or "{" in pt:
print(shift, pt)如果某个 shift 输出 flag{...},就不是“碰巧跑出一句话”,而是已知 flag 格式验证了 Caesar 假设。
常见利用 / 解题路线
路线总览:
- Caesar/ROT:26 种枚举,优先看
flag{、英文单词和题目名。 - Vigenere:Kasiski 或重合指数估计密钥长度,再按列做 Caesar 频率分析。
- 单表替换:先用 ETAOIN 频率和常见词猜映射,再迭代修正。
- 栅栏/列置换:枚举层数、列数或短 key 排列,筛选可读输出。
- 已知明文攻击:用
cipher[i] - plain[i]推 Caesar/Vigenere 密钥片段。
常见失败原因
排查动作:检查是否 Atbash、ROT47、大小写混合或先做了编码
排查动作:尝试多个候选长度,不只依赖一个重复片段
排查动作:密文太短时改用已知明文和题目提示
排查动作:检查是否加密/解密方向写反,是否保留了空格和标点
排查动作:检查是否还套了一层逆序、Base64 或大小写变换
迷你案例
密文:
iodj{fdhvdu_lv_wrr_hdvb}枚举 Caesar 时 shift 3 得到:
flag{caesar_is_too_easy}判断链条是:全小写字母和 {} 保留 -> 替换类优先 -> Caesar 密钥空间只有 26 -> 枚举命中 flag 格式。WP 中要写出枚举脚本和命中的 shift,而不是只写“凯撒解密”。