substitution 1 2 3 4 5 6 from secret import flagimport random s=0x1869f0 random.seed(s)print ('' .join(random.sample(flag,len (flag))))
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 + nrdef 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)))
已知明文攻击 首先得要求出密钥k (下面写的异或都是题目中提供的那种逐比特异或)
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^k5
和k1^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 =0 x3 f656 c323 c3567683 e3 f613 d6 d396 a62136262205710666 e29006 c246 f79640 ec2 =0 x64603 b3625637 e6 f636 d63243 a2 d616 a3 d683 f6025683 b66653 a34773 b3 e3968 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 base64import randomdef 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)) cipher=Des_Encrypt(Des_Encrypt(pad(flag),k1),k2)print (base64.b64encode(cipher))
已知一个明密文对,需要求出k1和k2 2重DES会有中间相遇攻击En_hint=Des_Encrypt(Des_Encrypt(pad(hint),k1),k2)
因为key的范围不是很大,所以可以爆破 我们先穷举k1,将m1用k1加密的结果都存放在一个字典中 然后再穷举k2,判断c1用k2解密的结果在不在刚才的字典中 如果在,则k1和k2就是我们要找的key