从CTF题解到实战:手把手教你用Python复现DES算法(附完整代码)
从CTF题解到实战:手把手教你用Python复现DES算法(附完整代码)
在CTF竞赛中,DES算法经常作为密码学挑战的核心考点出现。许多参赛者能够通过工具快速解密,却对算法内部机制一知半解。本文将带你从CTF解题的逆向思维转向正向实现,用Python完整复现DES算法,真正掌握这一经典对称加密技术的精髓。
1. DES算法核心架构解析
DES(Data Encryption Standard)是一种分组加密算法,采用64位分组长度和56位密钥长度。其核心架构包含三个关键阶段:
- 初始置换(IP):对64位明文进行位重排
- 16轮Feistel网络:算法的核心加密流程
- 最终置换(FP):逆初始置换,产生密文
Feistel网络结构是DES的精妙之处,它通过以下数学表达式定义每一轮操作:
Ln = Rn-1 Rn = Ln-1 ⊕ f(Rn-1, Kn)其中f函数包含扩展置换、密钥异或、S盒替换和P盒置换四个步骤。
提示:Feistel结构的设计使得加密和解密过程完全对称,只需反转子密钥顺序即可实现解密。
2. 子密钥生成系统实现
DES的子密钥生成是一个独立且精巧的系统,其流程如下:
- PC-1置换:64位密钥→56位
- 分裂为C0/D0:各28位
- 循环左移:根据轮数进行1或2位左移
- PC-2置换:56位→48位子密钥
用Python实现的关键代码如下:
def generate_subkeys(key): # PC-1置换(64位→56位) pc1 = [57,49,41,33,25,17,9,1,58,50,42,34,26,18, 10,2,59,51,43,35,27,19,11,3,60,52,44,36, 63,55,47,39,31,23,15,7,62,54,46,38,30,22, 14,6,61,53,45,37,29,21,13,5,28,20,12,4] key_pc1 = [key[i-1] for i in pc1] # 分裂为C0和D0 C = key_pc1[:28] D = key_pc1[28:] subkeys = [] shifts = [1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1] for shift in shifts: # 循环左移 C = C[shift:] + C[:shift] D = D[shift:] + D[:shift] # PC-2置换(56位→48位) pc2 = [14,17,11,24,1,5,3,28,15,6,21,10, 23,19,12,4,26,8,16,7,27,20,13,2, 41,52,31,37,47,55,30,40,51,45,33,48, 44,49,39,56,34,53,46,42,50,36,29,32] combined = C + D subkey = [combined[i-1] for i in pc2] subkeys.append(subkey) return subkeys3. 加密核心函数实现
f函数是DES加密的核心,其处理流程如下表所示:
| 步骤 | 操作 | 位数变化 | 关键功能 |
|---|---|---|---|
| 1 | 扩展置换(E) | 32→48位 | 将右半部分扩展 |
| 2 | 密钥异或 | 48位 | 与子密钥按位异或 |
| 3 | S盒替换 | 48→32位 | 6位输入→4位输出 |
| 4 | P盒置换 | 32位 | 位重排增加扩散性 |
完整实现代码如下:
def f_function(R, subkey): # 扩展置换E E = [32,1,2,3,4,5,4,5,6,7,8,9, 8,9,10,11,12,13,12,13,14,15,16,17, 16,17,18,19,20,21,20,21,22,23,24,25, 24,25,26,27,28,29,28,29,30,31,32,1] expanded = [R[i-1] for i in E] # 与子密钥异或 xor_result = [e ^ k for e,k in zip(expanded, subkey)] # S盒替换(8个S盒,每个6位输入→4位输出) s_boxes = [...] output = [] for i in range(8): block = xor_result[i*6:(i+1)*6] row = (block[0] << 1) + block[5] col = (block[1] << 3) + (block[2] << 2) + (block[3] << 1) + block[4] val = s_boxes[i][row][col] output += [int(b) for b in format(val, '04b')] # P盒置换 P = [16,7,20,21,29,12,28,17,1,15,23,26,5,18,31,10, 2,8,24,14,32,27,3,9,19,13,30,6,22,11,4,25] return [output[i-1] for i in P]4. 完整DES加密流程实现
将各个模块组合起来,实现完整的DES加密流程:
def des_encrypt(plaintext, key): # 初始置换IP IP = [58,50,42,34,26,18,10,2,60,52,44,36,28,20,12,4, 62,54,46,38,30,22,14,6,64,56,48,40,32,24,16,8, 57,49,41,33,25,17,9,1,59,51,43,35,27,19,11,3, 61,53,45,37,29,21,13,5,63,55,47,39,31,23,15,7] permuted = [plaintext[i-1] for i in IP] # 生成16轮子密钥 subkeys = generate_subkeys(key) # 初始左右分组 L = permuted[:32] R = permuted[32:] # 16轮Feistel网络 for i in range(16): new_L = R new_R = [l ^ f for l,f in zip(L, f_function(R, subkeys[i]))] L, R = new_L, new_R # 最终置换FP FP = [40,8,48,16,56,24,64,32,39,7,47,15,55,23,63,31, 38,6,46,14,54,22,62,30,37,5,45,13,53,21,61,29, 36,4,44,12,52,20,60,28,35,3,43,11,51,19,59,27, 34,2,42,10,50,18,58,26,33,1,41,9,49,17,57,25] ciphertext = [R+L][i-1] for i in FP] return ciphertext5. 实战验证与CTF应用
为了验证我们的实现是否正确,可以与标准库(如pycryptodome)的结果进行对比:
from Crypto.Cipher import DES import binascii def test_implementation(): # 测试向量 plaintext = b"12345678" key = b"abcdefgh" # 标准库加密 cipher = DES.new(key, DES.MODE_ECB) std_ciphertext = cipher.encrypt(plaintext) # 我们的实现 plain_bits = [int(b) for b in ''.join(format(c, '08b') for c in plaintext)] key_bits = [int(b) for b in ''.join(format(c, '08b') for c in key)] our_ciphertext = des_encrypt(plain_bits, key_bits) our_bytes = bytes(int(''.join(map(str, our_ciphertext[i:i+8])), 2) for i in range(0, 64, 8)) # 对比结果 assert binascii.hexlify(std_ciphertext) == binascii.hexlify(our_bytes) print("DES实现验证通过!")在CTF竞赛中,DES相关题目通常考察以下知识点:
- 弱密钥识别(当所有子密钥相同时)
- 已知明文攻击(当可以获取部分明文-密文对时)
- 中间相遇攻击(针对双重DES)
- 子密钥逆推(如NepCTF中的simpleDES题目)
通过亲手实现DES算法,你不仅能更轻松解决这类CTF挑战,还能深入理解现代分组加密算法的设计精髓。当遇到加密相关的漏洞分析或安全审计任务时,这种底层实现经验将变得尤为宝贵。
