#! /usr/bin/env python from Crypto.Util.number import bytes_to_long, long_to_bytes from random import randint, getrandbits
defshift(m, k, c): if k < 0: return m ^ m >> (-k) & c return m ^ m << k & c
defconvert(m, key): c_list = [0x37386180af9ae39e, 0xaf754e29895ee11a, 0x85e1a429a2b7030c, 0x964c5a89f6d3ae8c] for t inrange(4): m = shift(m, key[t], c_list[t]) return m
defencrypt(m, k, iv, mode='CBC'): assertlen(m) % 8 == 0 num = len(m) // 8 groups = [] for i inrange(num): groups.append(bytes_to_long(m[i * 8: (i + 1) * 8])) last = iv cipher = [] if mode == 'CBC': for eve in groups: cur = eve ^ last cur_c = convert(cur, k) cipher.append(cur_c) last = cur_c elif mode == 'OFB': for eve in groups: cur_c = convert(last, k) cipher.append(cur_c ^ eve) last = cur_c else: print'Not supported now!' return''.join([hex(eve)[2:].strip('L').rjust(16, '0') for eve in cipher])
if __name__ == '__main__': from secret import flag iflen(flag) % 8 != 0: flag += '$' * (8 - len(flag) % 8) length = len(flag) num = length // 8 keys = [randint(-32, 32) for _ inrange(4)] IV = getrandbits(64) front = flag[:length // 2] back = flag[length // 2:] cipher1 = encrypt(front, keys, IV, mode='OFB') cipher2 = encrypt(back, keys, IV) print cipher1 + cipher2 #89b8aca257ee2748f030e7f6599cbe0cbb5db25db6d3990d3b752eda9689e30fa2b03ee748e0da3c989da2bba657b912
题目分析
将flag分为两段,前半段采用OFB加密,后半段采用CBC加密
OFB解密
将前半段flag又进行切分,将其8位分为一组,存到group数组中。
1 2 3 4 5 6
#主要加密代码 elif mode == 'OFB': for eve in groups: cur_c = convert(last, k) cipher.append(cur_c ^ eve) last = cur_c
#OFB解密 #! /usr/bin/env python from Crypto.Util.number import bytes_to_long, long_to_bytes from random import randint, getrandbits
defshift(m, k, c): if k < 0: return m ^ m >> (-k) & c return m ^ m << k & c
defconvert(m, key): c_list = [ 0x37386180AF9AE39E, 0xAF754E29895EE11A, 0x85E1A429A2B7030C, 0x964C5A89F6D3AE8C, ] for t inrange(4): m = shift(m, key[t], c_list[t]) return m defcheck(s): c=1 for i in s: if32<=i<=127: continue else: c=0 break return c c = "89b8aca257ee2748f030e7f6599cbe0cbb5db25db6d3990d3b752eda9689e30fa2b03ee748e0da3c989da2bba657b912" c=c[:len(c)//2] cipher = [] for i inrange(len(c)//16): cipher.append(int(c[i*16:(i+1)*16],16)) flag = b'ByteCTF{' m0 = bytes_to_long(flag) m_m = m0 ^ cipher[0] for a inrange(-32,32): for b inrange(-32,32): for c inrange(-32,32): for d inrange(-32,32): keys=[a,b,c,d] m_m1=convert(m_m,keys) m1=long_to_bytes((m_m1^cipher[1])) if check(m1): m_m2 = convert(m_m1, keys) m2 = long_to_bytes((m_m2 ^ cipher[2])) if check(m2): flag+=m1 flag+=m2 print(flag) print(a,b,c,d) #b'ByteCTF{5831a241s-f30980' #keys:-12 26 -3 -31
defshift(m, k, c): if k < 0: return m ^ m >> (-k) & c return m ^ m << k & c
推理过程
这里我们举例k>0时的情况。(k<0同理)
m和c都是64位,k是-32~32的10进制数。
1、m << k相当于在m后补k位0,得到的新数我们称为a,a=m <<
k。
2、令b = a &
c,由于a是64+k位,c是64位,所以b是64位,并且b的后k位都是0。
3、令x = m ^
b,x则是shift加密之后的值,x也是64位,并且x的后k位是与m的后k位相同的,与0异或得本身。
我们走完了一遍shift加密,得到的结论是,密文的位数同样是64,并且密文的后k位与明文相同。
分析unshift
1 2 3 4 5 6 7 8 9 10
defunshift(m, k, c, bits=64): tmp = m if k < 0: for i inrange(bits // (-k)): tmp = m ^ tmp >> (-k) & c else: for i inrange(bits // k): tmp = m ^ tmp << k & c assert shift(tmp, k, c) == m return tmp
from Crypto.Util.number import bytes_to_long, long_to_bytes from random import randint, getrandbits defshift(m, k, c): if k < 0: return m ^ m >> (-k) & c return m ^ m << k & c defunconvert(m, key): tmp = m c_list = [0x37386180af9ae39e, 0xaf754e29895ee11a, 0x85e1a429a2b7030c, 0x964c5a89f6d3ae8c] for t inrange(3,-1,-1): m = unshift(m, key[t], c_list[t]) return m defunshift(m, k, c, bits=64): tmp = m if k < 0: for i inrange(bits // (-k)): tmp = m ^ tmp >> (-k) & c else: for i inrange(bits // k):
tmp = m ^ tmp << k & c assert shift(tmp, k, c) == m return tmp
keys=[-12,26,-3,-31] c_list = [0x37386180af9ae39e, 0xaf754e29895ee11a, 0x85e1a429a2b7030c, 0x964c5a89f6d3ae8c] flag=b'ByteCTF{' flag=bytes_to_long(flag) iv=16476971533267772345 c = "89b8aca257ee2748f030e7f6599cbe0cbb5db25db6d3990d3b752eda9689e30fa2b03ee748e0da3c989da2bba657b912" c=c[len(c)//2:] cipher = [] for i inrange(len(c)//16): cipher.append(int(c[i*16:(i+1)*16],16)) group=[]