一文打通DES算法以及在ctf中的运用!【附2023NepCTF simpleDES巨细题解(1)

本文深入探讨了DES(数据加密标准)算法,包括48位到56位的转换、子密钥生成过程,并展示了如何在ctf(Capture The Flag)挑战中应用DES。文中通过实例解释了如何利用泄露的最后一轮子密钥推导所有子密钥,进而解密获取原始密钥。此外,还讨论了逆向工程子密钥、PC1和PC2盒的使用,以及S盒和IP、EP、P函数在DES加密解密过程中的作用。
摘要由CSDN通过智能技术生成

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,
32, 0, 40, 8, 48, 16, 56, 24]]

return cipher

def bitxor(plain1: List[int], plain2: List[List[int]]) -> List[int]:
return [int(i) for i in bin(int(‘’.join(str(i) for i in plain1),2)^int(‘’.join(str(i) for i in plain2),2))[2:].zfill(64)]

#key的字母表为abcdefghijklmnopqrstuvwsyz
from secret import flag, key

t=[]
z=[[0]*64]
#对key中的每一位进行循环操作 将该为转为二进制 前置0进行填充到8位
#然后map应用于迭代对象(这里是一个字符串)中的每个元素,将每个二进制位字符转换为整数 然后放到列表里
#reduce(add, …):这是 functools 模块中的 reduce() 函数,用于将一个二进制位的整数列表合并为一个整数,通过逐步应用 add 函数来实现。
key = reduce(add, [list(map(int, bin(key_byte)[2:].zfill(8))) for key_byte in key])
#对flag进行分段加密 0,1,2 相当于进行了3次的des操作
for i in range(0,3):
#仿照key的方法 提取flag的前8位字符
pt = reduce(add, [list(map(int, bin(flag_byte)[2:].zfill(8))) for flag_byte in flag[ 8*i:8*(i+1) ]])
#进行des的加密操作 待加密对象是pt 传入所有子密钥 注意原始的key第一次是key本身 往后则需要与上一次的明文进行异或
#输入时64bits的盒 每一次des输出的ct也是64bits
ct = encrypt(pt, get_sub_key(bitxor(z[i],key)))
#z保存明文
z.append(pt)
#t保存每次des加密的结果
t += ct
print(t)

‘’’
i=0情况下的LL,Rr
LL= [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
Rr= [0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0]
t=[0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0]
‘’’

参考文章:子密钥的逆推:https://www.freebuf.com/news/topnews/219723.html

出题师傅的思路:

image-20230813201601281

解第一段(i=0):

通过泄露的最后一轮的C16和D16推出一组子密钥

通过已知的一组子密钥进入到guess_allsbkey函数中获得所有子密钥 并记录下C1和D1

将所有子密钥倒序进行des原始的enc加密操作中进行解密

from base64 import b64decode
from itertools import product
from DES import * # https://github.com/soreatu/Cryptography/blob/master/DES.py 自行导入
from typing import List
from Crypto.Util.number import *

guess_8bit = list(product(range(2), repeat=8))
#这是在PC2盒中没出现的位置数
not_in_PC2 = [9,18,22,25,35,38,43,54]

def re_PC2(sbkey):

48-bit -> 56-bit

res = [‘*’]*56 #这样不确定的位置更明确一点
for i in range(len(sbkey)):
#这里之所以减1是因为在置换的时候我们是从第一位开始回推CD 但在列表中是从第0位开始的
#但这个地方有个小困惑 就是这个DES加密是出题师傅自己写的 我们发现__pc2盒相比于我们调用库里的PC-2要减了1
#现在明白了 出题师傅构造的盒的位数采用的是列表中的思维 直接从0开始计数
#所以可以写为res[__pc2[i]] = sbkey[i] 就不用再减1了 道理是一样的 还要修改一下上面的not_in_PC2列表
res[PC_2_table[i]-1] = sbkey[i]
#sbkey的长度只有48 所以存在8bit不确定的位置
return res # ok

#对这8bit进行猜测 也就是不在PC2的数值对应的位置
def guess_CiDi16(sbkey, t):
res = re_PC2(sbkey)
for i in range(8):
#填充爆破未知位 其中guess_8bit包含256种8位二进制的全部组合
res[not_in_PC2[i]-1] = g

  • 21
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值