CTF密码学综合教学指南--第三章

第三章:古典密码学

3.1 凯撒密码(Caesar Cipher)

原理: 凯撒密码是一种最简单的替换密码,将字母表中的每字母固定偏移K个位置来实现加密。

加密公式: C = (P + K) mod 26

解密公式: P = (C - K) mod 26

其中P为明文字母的编号(A=0, B=1, ..., Z=25),C为密文字母的编号,K为偏移量。

解密方法: 由于密钥空间仅有26种可能(偏移量0-25),可以暴力枚举所有偏移量。

复制代码
# 凯撒密码暴力破解脚本

def caesar_brute_force(ciphertext):     "

""暴力枚举所有26种偏移量,打印所有可能的明文"""    

for shift in range(26):        

plaintext = ""        

for char in ciphertext:            

if char.isalpha():               

  # 确定基准字符(大写或小写)                

base = ord('A') if char.isupper() else ord('a')                

# 解密:向后偏移shift个位置                

decrypted = chr((ord(char) - base - shift) % 26 + base)                

plaintext += decrypted            

else:                

plaintext += char        

print(f"偏移量 {shift:2d}: {plaintext}") 

# 示例

ciphertext = "Fydw{Fdhvdu_Flskhu_Lv_Hdvb}"

print("=== 凯撒密码暴力破解 ===") caesar_brute_force(ciphertext)

# 偏移量 3 时得到:

Flag{Caesar_Cipher_Is_Easy}

|-------------------------------------------------------------------------------------------------------------------------|
| 💡 CTF 技巧 使用CyberChef的 ROT13 或 ROT13 Brute Force 功能可以快速尝试所有偏移。ROT13是凯撒密码偏移量为13的特例,由于26/2=13,ROT13加密和解密操作相同。 |

3.2 仿射密码(Affine Cipher)

原理: 仿射密码是凯撒密码的推广,使用线性函数进行加密。

加密: C = (a × P + b) mod 26

解密: P = a⁻¹ × (C - b) mod 26

约束条件: GCD(a, 26) = 1,即a与26互素,保证a有模逆元。

合法的 a 值: 1, 3, 5, 7, 9, 11, 15, 17, 19, 21, 23, 25(共12个)。

密钥空间:12 × 26 = 312种组合,可暴力枚举。

复制代码
def affine_decrypt(ciphertext, a, b):    

"""仿射密码解密"""    

# 计算a的模逆元    

a_inv = pow(a, -1, 26)    

plaintext = ""    

for char in ciphertext:        

if char.isalpha():            

base = ord('A') if char.isupper() else ord('a')            

c = ord(char) - base            

p = (a_inv * (c - b)) % 26            

plaintext += chr(p + base)        

else:            

plaintext += char    

return plaintext  def affine_brute_force(ciphertext):    

"""仿射密码暴力破解"""    

from math import gcd    

for a in range(1, 26):        

if gcd(a, 26) != 1:            

continue        

for b in range(26):            

result = affine_decrypt(ciphertext, a, b)            

# 检查结果中是否包含常见flag格式            

if 'flag' in result.lower() or 'ctf' in result.lower():                

print(f"a={a}, b={b}: {result}") 

# 示例

ciphertext = "Nxkq{Knnbgz_Vbiazm}" affine_brute_force(ciphertext)

# 找到合适的a和b后输出解密结果

3.3 维吉尼亚密码(Vigenère Cipher)

原理: 维吉尼亚密码是一种多表替换密码。使用一个关键词(keyword)作为密钥,关键词的每个字母决定对明文对应位置的偏移量。关键词循环使用。

加密: C_i = (P_i + K_{i mod len(K)}) mod 26

解密: P_i = (C_i - K_{i mod len(K)}) mod 26

破解方法一: Kasiski 检验法

  1. 在密文中寻找重复的字符片段(通常3个字母以上)
  2. 计算重复片段之间的间距
  3. 密钥长度很可能是这些间距的公约数
  4. 确定密钥长度后,对每组字母分别进行频率分析

破解方法二:频率分析

  1. 确定密钥长度L后,将密文按位置分为L组

  2. 每组相当于一个独立的凯撒密码

  3. 对每组进行频率分析,找出最高频字母,假设其对应英文中的'E'

  4. 由此推算每组的偏移量,组合得到完整密钥

    from collections import Counter from math import gcd from functools import reduce def kasiski_examination(ciphertext, min_len=3):

    """Kasiski检验:寻找重复片段,推测密钥长度"""

    text = ''.join(c.upper() for c in ciphertext if c.isalpha())

    distances = []

    寻找长度>=min_len的重复片段

    for length in range(min_len, len(text) // 2):

    for i in range(len(text) - length):

    pattern = text[i:i+length]

    j = text.find(pattern, i + 1)

    while j != -1:

    distances.append(j - i)

    j = text.find(pattern, j + 1)

    if not distances:

    return []

    计算所有间距的因数

    factor_count = Counter()

    for d in distances:

    for f in range(2, d + 1):

    if d % f == 0:

    factor_count[f] += 1

    返回最可能的密钥长度

    return factor_count.most_common(5) def vigenere_decrypt(ciphertext, key):

    """维吉尼亚密码解密"""

    key = key.upper()

    plaintext = ""

    key_idx = 0

    for char in ciphertext:

    if char.isalpha():

    base = ord('A') if char.isupper() else ord('a')

    shift = ord(key[key_idx % len(key)]) - ord('A')

    decrypted = chr((ord(char) - base - shift) % 26 + base)

    plaintext += decrypted

    key_idx += 1

    else:

    plaintext += char

    return plaintext def frequency_analysis_crack(ciphertext, key_length):

    """通过频率分析破解维吉尼亚密码"""

    text = ''.join(c.upper() for c in ciphertext if c.isalpha())

    key = ""

    for i in range(key_length):

    提取第i组字母

    group = text[i::key_length]

    统计频率

    freq = Counter(group)

    假设最高频字母对应'E'(编号4)

    most_common = freq.most_common(1)[0][0]

    shift = (ord(most_common) - ord('E')) % 26

    key += chr(shift + ord('A'))

    return key

    示例用法

    ciphertext = "Lxfopv ef rnhr" key = "KEY" print(vigenere_decrypt(ciphertext, key))

3.4 栅栏密码(Rail Fence Cipher)

原理: 将明文按照锯齿形(zigzag)排列到指定行数的"栅栏"上,然后按行读取得到密文。

示例: 明文 "WEAREDISCOVERED",栅栏数为3:
W . . . E . . . S . . . E . . . E . R . D . S . O . R . D . . . A . . . I . . . V . . . . 密文:WESE ERDSORD AIVO (按行读取拼接)

复制代码
def rail_fence_decrypt(ciphertext, num_rails):    

"""栅栏密码解密"""    

if num_rails <= data-id="367" 1:        

return ciphertext     

n = len(ciphertext)    

# 构建栅栏模式,确定每个位置属于哪一行    

pattern = []    

for i in range(n):        

cycle = 2 * (num_rails - 1)        

pos = i % cycle        

row = pos if pos < num_rails else cycle - pos        

pattern.append(row)     

# 计算每行的字符数    

row_lengths = [0] * num_rails    

for r in pattern:        

row_lengths[r] += 1     

# 将密文分配到各行    

rows = []    

idx = 0    

for length in row_lengths:        

rows.append(list(ciphertext[idx:idx+length]))        

idx += length     

# 按模式重建明文    

row_indices = [0] * num_rails    

plaintext = ""    

for r in pattern:        

plaintext += rows[r][row_indices[r]]        

row_indices[r] += 1     

return plaintext 

# 暴力尝试不同栅栏数 def rail_fence_brute_force(ciphertext, max_rails=20):     """暴力尝试所有可能的栅栏数"""    

for rails in range(2, min(max_rails, len(ciphertext))):        

result = rail_fence_decrypt(ciphertext, rails)        

print(f"栅栏数 {rails}: {result}") 

# 示例

cipher = "WECRLTEERDSOEEFEAOC" rail_fence_brute_force(cipher, 10)

3.5 培根密码(Bacon's Cipher)

原理: 由弗朗西斯·培根发明,使用5位二进制编码(A和B的组合)来表示字母。

字母 编码 字母 编码 字母 编码
A/a AAAAA J/i ABAAA S BAAAB
B AAAAB K ABAAB T BAABA
C AAABA L ABABA U/V BAABB
D AAABB M ABABB W BABAA
E AABAA N ABBAA X BABAB
F AABAB O ABBAB Y BABBA
G AABBA P ABBBA Z BABBB
H AABBB Q ABBBB
I/J ABAAA R BAAAA

隐写形式: 在CTF中常见用大小写字母(小写=A,大写=B)或两种不同字体来编码。

  1. 大小写混合 :例如 baCoN -> aabab (小写=a, 大写=b)

  2. AB字符混合 :例如 aabab (直接包含A/B或a/b字符)

    import re

    class BaconCipher:
    """
    培根密码解密工具
    支持标准24字母表 (I/J, U/V 合并)
    """

    复制代码
     # 标准培根密码表 (I=J, U=V)
     # 注意:有些变体表会将 I/J 分开,U/V 分开,若解密乱码可尝试调整此处
     BACON_DICT = {
         'AAAAA': 'A', 'AAAAB': 'B', 'AAABA': 'C', 'AAABB': 'D', 'AABAA': 'E',
         'AABAB': 'F', 'AABBA': 'G', 'AABBB': 'H', 'ABAAA': 'I', 'ABAAB': 'K', # I 对应 J
         'ABABA': 'L', 'ABABB': 'M', 'ABBAA': 'N', 'ABBAB': 'O', 'ABBBA': 'P',
         'ABBBB': 'Q', 'BAAAA': 'R', 'BAAAB': 'S', 'BAABA': 'T', 'BAABB': 'U', # U 对应 V
         'BABAA': 'W', 'BABAB': 'X', 'BABBA': 'Y', 'BABBB': 'Z'
     }
    
     @staticmethod
     def decode(text, mode='case'):
         """
         解密培根密码
         
         参数:
             text (str): 密文
             mode (str): 解密模式
                        'case' - 大小写模式 (小写=a, 大写=b)
                        'char' - 字符模式 (a=A, b=B)
         
         返回:
             str: 解密后的明文
         """
         # 1. 预处理:提取有效字符并转换为统一的 A/B 序列
         ab_sequence = ""
         
         if mode == 'case':
             # 大小写模式:通常小写代表a,大写代表b (反之亦可,视题目而定)
             # 这里假设:小写->A, 大写->B
             for char in text:
                 if char.islower():
                     ab_sequence += 'A'
                 elif char.isupper():
                     ab_sequence += 'B'
                     
         elif mode == 'char':
             # 字符模式:直接查找 a/A 和 b/B
             # 统一转为大写方便处理
             clean_text = text.upper()
             for char in clean_text:
                 if char == 'A':
                     ab_sequence += 'A'
                 elif char == 'B':
                     ab_sequence += 'B'
                 # 忽略其他字符
             
         else:
             return "错误:未知的解密模式"
    
         # 2. 检查长度是否合法 (必须是5的倍数)
         if len(ab_sequence) % 5 != 0:
             print(f"警告:提取的序列长度为 {len(ab_sequence)},不是5的倍数,末尾多余字符将被忽略。")
    
         # 3. 每5位一组进行查表解密
         result = ""
         for i in range(0, len(ab_sequence), 5):
             # 截取5个字符
             chunk = ab_sequence[i:i+5]
             
             # 如果不足5个字符(也就是最后剩下的),则跳出
             if len(chunk) < 5:
                 break
                 
             # 查表
             letter = BaconCipher.BACON_DICT.get(chunk, '?')
             result += letter
             
         return result

    ==========================================

    使用示例

    ==========================================

    if name == "main":
    solver = BaconCipher()

    复制代码
     # 场景1:大小写混合 (CTF常见形式)
     # 密文示例:baCoNBacoN... (小写=a, 大写=b)
     cipher_case = "baCoNBacoNbaconbACoNbacOnbAconBacOnbacoNbaconbacOnbACOnbACoN"
     print(f"--- 场景1: 大小写模式 ---")
     print(f"密文: {cipher_case}")
     print(f"明文: {solver.decode(cipher_case, mode='case')}")
     print()
    
     # 场景2:AB字符混合
     # 密文示例:AABBABABAA...
     cipher_char = "AABBABABAAABBBABABBAAAAAAABBABAABBA"
     print(f"--- 场景2: AB字符模式 ---")
     print(f"密文: {cipher_char}")
     print(f"明文: {solver.decode(cipher_char, mode='char')}")

3.6 其他古典密码简介

Playfair 密码: 使用一个5×5的字母矩阵(I和J合并),明文两两分组,根据字母在矩阵中的位置关系进行替换。规则:同行取右边、同列取下方、不同行列取对角。

Polybius 方阵密码: 使用5×5方阵,每个字母用其行列坐标表示。如A=11, B=12, ..., Z=55。

Atbash 密码: 字母表反转替换。A↔Z, B↔Y, C↔X, ..., M↔N。可看作凯撒密码的特殊形式。

复制代码
class AtbashCipher:
    """
    Atbash (埃特巴什码) 加解密工具
    原理:字母表倒序映射 (A<->Z, B<->Y, ...)
    特性:加密和解密使用同一算法 (自反性)
    """
    
    # 定义希伯来字母表范围 (可选,用于处理特殊题目)
    HEBREW_ALEPH = ord('א')
    HEBREW_TAV = ord('ת')

    @staticmethod
    def process(text):
        """
        执行 Atbash 变换 (加/解密)
        
        参数:
            text (str): 输入字符串
            
        返回:
            str: 变换后的字符串
        """
        result = ""
        
        for char in text:
            # 1. 处理大写英文字母 (A-Z)
            if 'A' <= char <= 'Z':
                # 公式:Cipher = (25 - (Plain - A)) + A
                # 简化为:Z - Plain + A
                result += chr(ord('Z') - (ord(char) - ord('A')))
            
            # 2. 处理小写英文字母 (a-z)
            elif 'a' <= char <= 'z':
                result += chr(ord('z') - (ord(char) - ord('a')))
            
            # 3. 处理希伯来字母 (可选扩展)
            # 范围:א (Aleph) 到 ת (Tav)
            elif AtbashCipher.HEBREW_ALEPH <= ord(char) <= AtbashCipher.HEBREW_TAV:
                result += chr(AtbashCipher.HEBREW_TAV - (ord(char) - AtbashCipher.HEBREW_ALEPH))
            
            # 4. 其他字符保持不变 (数字、标点、空格)
            else:
                result += char
                
        return result

    @staticmethod
    def solve_ctf_challenge(ciphertext):
        """
        专门用于 CTF 的快捷方法
        通常 CTF 题目只需要处理英文部分
        """
        return AtbashCipher.process(ciphertext)

# ==========================================
# 使用示例
# ==========================================
if __name__ == "__main__":
    solver = AtbashCipher()
    
    # 场景1:标准英文句子
    text1 = "the quick brown fox jumps over the lazy dog"
    print(f"--- 场景1: 英文句子 ---")
    print(f"原文: {text1}")
    print(f"密文: {solver.process(text1)}")
    print(f"回解密: {solver.process(solver.process(text1))}") # 验证自反性
    print()

    # 场景2:CTF Flag 格式
    # 假设题目给出 flag{...} 的变体,或者全大写的密文
    cipher_flag = "uozt{Zgyzhv_xlwv_uiln_xguhsld}" 
    print(f"--- 场景2: CTF Flag ---")
    print(f"密文: {cipher_flag}")
    print(f"明文: {solver.solve_ctf_challenge(cipher_flag)}")
    # 预期输出: flag{Atbash_is_very_easy_to_break} (仅为示例推测)
    print()

    # 场景3:混合字符
    text3 = "Hello World! 123"
    print(f"--- 场景3: 混合字符 ---")
    print(f"原文: {text3}")
    print(f"密文: {solver.process(text3)}")

ROT13 凯撒密码偏移量为13的特例。由于英文字母共26个,ROT13加密两次回到原文,即加密和解密操作相同。

猪圈密码( Pigpen Cipher ): 一种图形替换密码,每个字母对应一个由线段和点组成的独特图形。需要查阅对应的图形映射表进行解密。在CTF中,通常以图片形式出题。

3.7 综合实战案例

|-------------------------------------------------------------------------------|
| 📋 题目 你截获了以下密文:Gur synt vf: synt{pynffvpny_pelcgb_vf_sha} 请分析密码类型并破解。 |

解题思路:

  1. 观察特征: 密文保留了空格和标点,字母被替换但结构不变,长度与原文一致------这是一种单表替换密码

  2. 关键线索: "synt" 出现两次,且前面有 "synt vf:" 的模式,很像 "flag is: flag{...}"

  3. 验证: s→f (偏移13), y→l (偏移13), n→a (偏移13), t→g (偏移13) --- 偏移量恒为13

  4. 确认: 这是ROT13加密

    import codecs
    import string

    class ROT13Solver:
    """
    ROT13 加解密工具
    原理:凯撒密码的特例,位移量为 13
    特性:自反性 (ROT13(ROT13(x)) = x)
    """

    复制代码
     @staticmethod
     def solve_standard(text):
         """
         方法一:使用 codecs 标准库 (推荐,最稳健)
         适用于:绝大多数 CTF 题目
         """
         return codecs.decode(text, 'rot_13')
    
     @staticmethod
     def solve_manual(text):
         """
         方法二:手动实现 (理解原理)
         适用于:不允许使用标准库的受限环境或学习目的
         """
         result = ""
         for char in text:
             if char.islower():
                 # 小写字母处理:(当前索引 + 13) % 26
                 result += chr((ord(char) - ord('a') + 13) % 26 + ord('a'))
             elif char.isupper():
                 # 大写字母处理
                 result += chr((ord(char) - ord('A') + 13) % 26 + ord('A'))
             else:
                 # 非字母字符保持不变 (数字、标点、花括号等)
                 result += char
         return result
    
     @staticmethod
     def solve_translate(text):
         """
         方法三:字符串映射 (高性能)
         适用于:需要处理超大文本或追求极致速度的场景
         """
         # 构建转换表:ABCDEFGHIJKLMNOPQRSTUVWXYZ -> NOPQRSTUVWXYZABCDEFGHIJKLM
         trans_table = str.maketrans(
             "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
             "NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm"
         )
         return text.translate(trans_table)
    
     @staticmethod
     def extract_flag(ciphertext):
         """
         CTF 专用:尝试解密并提取 Flag
         """
         plaintext = ROT13Solver.solve_standard(ciphertext)
         if "flag{" in plaintext:
             # 简单提取 flag{...} 内容
             start = plaintext.find("flag{")
             end = plaintext.find("}", start)
             if end != -1:
                 return plaintext[start:end+1]
         return plaintext

    ==========================================

    使用示例

    ==========================================

    if name == "main":
    solver = ROT13Solver()

    复制代码
     # 场景1:基础解密 (你的原始代码场景)
     ciphertext = "Gur synt vf: synt{pynffvpny_pelcgb_vf_sha}"
     print(f"--- 场景1: 基础解密 ---")
     print(f"密文: {ciphertext}")
     print(f"解密: {solver.solve_standard(ciphertext)}")
     # 输出: The flag is: flag{classical_crypto_is_fun}
     print()
    
     # 场景2:验证自反性 (加密=解密)
     original = "Hello CTF"
     encrypted = solver.solve_standard(original)
     decrypted = solver.solve_standard(encrypted)
     print(f"--- 场景2: 自反性验证 ---")
     print(f"原文: {original}")
     print(f"加密: {encrypted}") # Uryyb PSG
     print(f"解密: {decrypted}") # Hello CTF
     print()
    
     # 场景3:CTF Flag 提取
     messy_text = "Uryyb Jbeyq! Gur synt vf synt{ebg13_vf_fvzcyr}."
     flag = solver.extract_flag(messy_text)
     print(f"--- 场景3: Flag 提取 ---")
     print(f"杂讯文本: {messy_text}")
     print(f"提取结果: {flag}")
相关推荐
NGSI vimp1 小时前
Java进阶——如何查看Java字节码
java·开发语言
其实防守也摸鱼1 小时前
CTF密码学综合教学指南--第四章
网络·笔记·安全·网络安全·密码学·ctf
DevilSeagull2 小时前
电脑上安装的服务会自动消失? 推荐项目: localhostSCmanager. 更好管理你的服务!
测试工具·安全·react·vite·localhost·hono·trpc
A7bert7772 小时前
【YOLOv8pose部署至RDK X5】模型训练→转换bin→Sunrise 5部署
c++·python·深度学习·yolo·目标检测
草履虫君2 小时前
VMware 虚拟机网络性能优化指南:从 11 秒到 4 秒的完整调优实践
服务器·网络·经验分享·性能优化
We་ct2 小时前
深度剖析浏览器跨域问题
开发语言·前端·浏览器·跨域·cors·同源·浏览器跨域
skywalk81633 小时前
在考虑双轨制,即在中文语法的基础上,加上数学公式的支持,这样像很多计算将更加简单方便,就像现在的小学数学课本里面一样,比如:定x=2*x + 1
开发语言
@insist1233 小时前
信息安全-防火墙技术演进全景:从代理NAT 到下一代及专项防火墙
网络·安全·web安全·软考·信息安全工程师·软件水平考试
小书房3 小时前
Kotlin的by
android·开发语言·kotlin·委托·by