substitution

1
2
3
4
5
6
from secret import flag
import random
s=0x1869f0
random.seed(s)
print(''.join(random.sample(flag,len(flag))))
#9lf5c7504fbea330accg{c-8d6-62e-ef}3aa-d3-34

random.sample函数
random.sample(sequence, k),从指定序列中随机获取指定长度的片断。sample函数不会修改原有序列

所以random.sample(flag,len(flag))
就会将flag随机打乱 (不是真正的随机)

这一题的random有种子,所以我们可以还原出是如何打乱的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import random
s=0x1869f0
random.seed(s)

m=[]
for i in range(0,43):
m.append(i)
m1=random.sample(m,len(m))
print(m1)

t='9lf5c7504fbea330accg{c-8d6-62e-ef}3aa-d3-34'

m2=[]
for i in range(0,43):
m2.append(i)

for i in range(0,43):
m2[m1[i]]=t[i]
print(m2)
print("".join(m2))

Easy_Feistel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import os
real_flag = 'flag{?????????????}'
fake_flag = 'flag{Miku_Miku_o~e~o_Miku_Miku_o~e~o_}'

def xor(a, b):
return ''.join(chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b))

def str_to_hex(s):
return s.encode().hex()

def swap(a):
return a[16: ] + a[ :16]

def single(m, k):
assert len(m) == 32
l = m[: 16]
r = m[16: ]
nl, nr = r, xor(k, xor(l, r))
return nl + nr

def encrypt(m, k):
for i in k:
m = single(m, i)
return swap(m)

k = []
for i in range(0, 256):
k.append(os.urandom(8).hex())

print(str_to_hex(encrypt(fake_flag[5: -1], k)))
print(str_to_hex(encrypt(real_flag[5: -1], k)))
#3f656c323c3567683e3f613d6d396a62136262205710666e29006c246f79640e
#64603b3625637e6f636d63243a2d616a3d683f6025683b66653a34773b3e3968

已知明文攻击
首先得要求出密钥k
(下面写的异或都是题目中提供的那种逐比特异或)

1
2
3
4
5
6
7
# nl=l            nr=r
# nl=r nr=l^r^k1
# nl=l^r^k1 nr=r ^ (l^r^k1) ^ k2 =l^k1^k2
# nl=l^k1^k2 nr=(l^r^k1)^(l^k1^k2) ^k3 =r^k2^k3
# nl=r^k2^k3 nr=(l^k1^k2)^(r^k2^k3)^k4=l^r^k1^k3^k4
# nl=l^r^k1^k3^k4 nr=(r^k2^k3)^(l^r^k1^k3^k4)^k5=l^k1^k2^k4^k5
#……

l和r是常量,分别是明文的左半和右半
nl和nr是变量
我现在知道明文l和r,和最后一次的nl和nr
我要还原出k1~k256

现在就看上面列的到k5的例子
我想要还原出上一步nl和nr
(上一步的nr) = nl ; (上一步的nl)=nl^nr^k5
但需要求的就是k5,然后应该怎么写?

这是我的一个疑问,我一开始以为必须要把k1~k256全部都求出来,我想的是因为Feistel解密的时候,需要把加密的密钥逆序。但是这一题密钥不需要逆序,因为这一题的F函数是异或,异或本身就是对称的,所以不需要逆序。(其实不用想太多Feistel,正常写就可以了)

所以再看上面列的到k5的例子
我们可以求出k1^k2^k4^k5k1^k3^k4
设flag密文的左半和右半分别位nl和nr
所以l=(k1^k2^k4^k5)^nr r=(k1^k3^k4)^l^nl
所以大概就是这个意思
但是不能忘记最后一步就是交换l和r

1
2
3
4
5
# nl=r            nr=l^r^k1
# nl=l^r^k1 nr=r ^ (l^r^k1) ^ k2 =l^k1^k2
# nl=l^k1^k2 nr=(l^r^k1)^(l^k1^k2) ^k3 =r^k2^k3
# nl=r^k2^k3 nr=(l^k1^k2)^(r^k2^k3)^k4=l^r^k1^k3^k4
# nl=l^r^k1^k3^k4 nr=(r^k2^k3)^(l^r^k1^k3^k4)^k5=l^k1^k2^k4^k5

发现是三个一循环
第一次nl只要r,nr有l和r
第二次nl有l和r,nr只有l
第三次nl只有l,nr只有r

所以第256是nl只要r,nr有l和r
所以就看这一个nl=r^k2^k3 nr=(l^k1^k2)^(r^k2^k3)^k4=l^r^k1^k3^k4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
from Crypto.Util.number import *

def xor(a, b):
return ''.join(chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b))

c1=0x3f656c323c3567683e3f613d6d396a62136262205710666e29006c246f79640e
c2=0x64603b3625637e6f636d63243a2d616a3d683f6025683b66653a34773b3e3968
c1=long_to_bytes(c1)
c2=long_to_bytes(c2)
m1='flag{Miku_Miku_o~e~o_Miku_Miku_o~e~o_}'
c1=c1.decode(encoding='gbk')
c2=c2.decode(encoding='utf-8')


nl=c1[:16]
nr=c1[16:]
m1=m1[5:-1]

l=m1[:16]
r=m1[16:]
temp1=xor(xor(l,r),nr)
temp2=xor(nl,r)

nl=c2[:16]
nr=c2[16:]
r=xor(nl,temp2)
l=xor(xor(nr,temp1),r)
print(l)
print(r)

最后我提交还是有点问题,但大概应该就是这么写的(我也不确定,哈)

2DES

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
from pyDes import *
import base64
import random
#from secret import flag

def pad(msg):
if len(msg)%16==0:
return msg
else:
return msg+(16-len(msg)%16)*chr(16-len(msg)%16).encode('latin-1')

def get_key():
s='0123456789abcdef'
return 2*''.join([s[random.randint(0,len(s)-1)] for _ in range(4)])

def Des_Encrypt(msg,key):

DES=des(key)

return DES.encrypt(msg)

def Des_Decrypt(cipher,key):

DES=des(key)

return DES.decrypt(cipher)


flag=b'flag{????????????????}'
hint=b'maybe_my_2DES_is_secure?'

k1=get_key()
k2=get_key()

En_hint=Des_Encrypt(Des_Encrypt(pad(hint),k1),k2)
print(base64.b64encode(En_hint))

#Lga6vE5utuDUKgcX2PMjEXD+jm3NR+HLOLaYfpsyTe4=

cipher=Des_Encrypt(Des_Encrypt(pad(flag),k1),k2)
print(base64.b64encode(cipher))
#9G3/1zcKuoFe5Hx/1uFS2x3nS90vgDPCAgsWwi37Z9pXaWKCCfkgMkGMiJ8Mjhay

已知一个明密文对,需要求出k1和k2
2重DES会有中间相遇攻击En_hint=Des_Encrypt(Des_Encrypt(pad(hint),k1),k2)
因为key的范围不是很大,所以可以爆破
我们先穷举k1,将m1用k1加密的结果都存放在一个字典中
然后再穷举k2,判断c1用k2解密的结果在不在刚才的字典中
如果在,则k1和k2就是我们要找的key