# easyxor
AES 的 CBC 模式和 OFB 模式
之前赵师傅讲过 听得有点云里雾里的
现在跟着这题的 wp 顺一遍
首先 iv 与 key 是不知道的,只知道前半段密文是 OFB 模式,后半段是 CBC 模式
贴两张图
这个是 CBC 加密,我们可以知道最后一个密文的 iv 就是前一个密文
通过这个可以爆破出 key 因为我们知道 flag 最后是以}$$$$ 结尾的
这个解密图里的 iv 就是加密的 iv 密文顺序也是一样的而给的 wp 是逆序解的自己改成正序了
from Crypto.Util.number import * | |
# right shift inverse | |
def inverse_right(res, shift, bits=64): | |
tmp = res | |
for i in range(bits // shift): | |
tmp = res ^ tmp >> shift | |
return tmp | |
# right shift with mask inverse | |
def inverse_right_mask(res, shift, mask, bits=64): | |
tmp = res | |
for i in range(bits // shift): | |
tmp = res ^ tmp >> shift & mask | |
return tmp | |
# left shift inverse | |
def inverse_left(res, shift, bits=64): | |
tmp = res | |
for i in range(bits // shift): | |
tmp = res ^ tmp << shift | |
return tmp | |
# left shift with mask inverse | |
def inverse_left_mask(res, shift, mask, bits=64): | |
tmp = res | |
for i in range(bits // shift): | |
tmp = res ^ tmp << shift & mask | |
return tmp | |
def unshift(m, k, c): | |
if k < 0: | |
return inverse_right_mask(m,-k,c) | |
return inverse_left_mask(m,k,c) | |
def unconvert(m, key): | |
c_list = [0x37386180af9ae39e, 0xaf754e29895ee11a, 0x85e1a429a2b7030c, 0x964c5a89f6d3ae8c] | |
for t in range(3,-1,-1): | |
m = unshift(m, key[t], c_list[t]) | |
return m | |
def convert(m, key): | |
c_list = [0x37386180af9ae39e, 0xaf754e29895ee11a, 0x85e1a429a2b7030c, 0x964c5a89f6d3ae8c] | |
for t in range(4): | |
m = shift(m, key[t], c_list[t]) | |
return m | |
def shift(m, k, c): | |
if k < 0: | |
return m ^ m >> (-k) & c | |
return m ^ m << k & c | |
def decrypt(c, k, iv, mode='CBC'): | |
cipher=[] | |
for i in range(0,len(c),16): | |
cipher.append(int(c[i:i+16],16)) | |
groups=[] | |
if mode == 'CBC': | |
i=0 | |
for eve in ([iv]+cipher[:-1]): | |
cur_c = cipher[i] | |
cur = unconvert(cur_c, k) | |
groups.append(cur ^ eve) | |
i+=1 | |
elif mode == 'OFB': | |
last = iv | |
for eve in cipher: | |
cur_c = convert(last, k) | |
groups.append(cur_c ^ eve) | |
last = cur_c | |
else: | |
print('Not supported now!') | |
m = b'' | |
for i in groups: | |
m += long_to_bytes(i) | |
return m | |
def get_key(): | |
for a in range(-32,33): | |
for b in range(-32,33): | |
for c in range(-32,33): | |
for d in range(-32,33): | |
try: | |
plain = decrypt(c2[-16:],[a,b,c,d],c_list[-2]) | |
if(plain.endswith(b'$$$') and plain.strip(b'$').endswith(b'}')): | |
print(a,b,c,d,plain) | |
return [a,b,c,d] | |
except: | |
continue | |
cipher1='89b8aca257ee2748f030e7f6599cbe0cbb5db25db6d3990d3b752eda9689e30fa2b03ee748e0da3c989da2bba657b912' | |
flag=b'ByteCTF{' | |
m=bytes_to_long(flag) | |
c1,c2=cipher1[:len(cipher1)//2],cipher1[len(cipher1)//2:] | |
c_list = [] | |
for i in range(0,len(c2),16): | |
c_list.append(int(c2[i:i+16],16)) | |
get_key() |
然后再通过 OFB 模式得到 iv
下面是 OFB 加密和解密(好图)
我们可以知道 flag 形式为 ByteCTF {开头
刚好 8 位
这个就是 plaintext 而 ciphertext 是知道的
两个异或一下就是 key 和 iv 的加密
逆一下就能得到 iv
c_list = [] | |
for i in range(0,len(c1),16): | |
c_list.append(int(c1[i:i+16],16)) | |
E = (m ^ c_list[0]) | |
iv = unconvert(E, key) | |
#print(iv) |
最后解密
c_list = [] | |
for i in range(0,len(c1),16): | |
c_list.append(int(c1[i:i+16],16)) | |
E = (m ^ c_list[0]) | |
iv = unconvert(E, key) | |
#print(iv) | |
m1=decrypt(c1,key,iv,mode='OFB') | |
m2=decrypt(c2,key,iv) | |
print(m1+m2) |
总的代码
from Crypto.Util.number import * | |
# right shift inverse | |
def inverse_right(res, shift, bits=64): | |
tmp = res | |
for i in range(bits // shift): | |
tmp = res ^ tmp >> shift | |
return tmp | |
# right shift with mask inverse | |
def inverse_right_mask(res, shift, mask, bits=64): | |
tmp = res | |
for i in range(bits // shift): | |
tmp = res ^ tmp >> shift & mask | |
return tmp | |
# left shift inverse | |
def inverse_left(res, shift, bits=64): | |
tmp = res | |
for i in range(bits // shift): | |
tmp = res ^ tmp << shift | |
return tmp | |
# left shift with mask inverse | |
def inverse_left_mask(res, shift, mask, bits=64): | |
tmp = res | |
for i in range(bits // shift): | |
tmp = res ^ tmp << shift & mask | |
return tmp | |
def unshift(m, k, c): | |
if k < 0: | |
return inverse_right_mask(m,-k,c) | |
return inverse_left_mask(m,k,c) | |
def unconvert(m, key): | |
c_list = [0x37386180af9ae39e, 0xaf754e29895ee11a, 0x85e1a429a2b7030c, 0x964c5a89f6d3ae8c] | |
for t in range(3,-1,-1): | |
m = unshift(m, key[t], c_list[t]) | |
return m | |
def convert(m, key): | |
c_list = [0x37386180af9ae39e, 0xaf754e29895ee11a, 0x85e1a429a2b7030c, 0x964c5a89f6d3ae8c] | |
for t in range(4): | |
m = shift(m, key[t], c_list[t]) | |
return m | |
def shift(m, k, c): | |
if k < 0: | |
return m ^ m >> (-k) & c | |
return m ^ m << k & c | |
def decrypt(c, k, iv, mode='CBC'): | |
cipher=[] | |
for i in range(0,len(c),16): | |
cipher.append(int(c[i:i+16],16)) | |
groups=[] | |
if mode == 'CBC': | |
i=0 | |
for eve in ([iv]+cipher[:-1]): | |
cur_c = cipher[i] | |
cur = unconvert(cur_c, k) | |
groups.append(cur ^ eve) | |
i+=1 | |
elif mode == 'OFB': | |
last = iv | |
for eve in cipher: | |
cur_c = convert(last, k) | |
groups.append(cur_c ^ eve) | |
last = cur_c | |
else: | |
print('Not supported now!') | |
m = b'' | |
for i in groups: | |
m += long_to_bytes(i) | |
return m | |
def get_key(): | |
for a in range(-32,33): | |
for b in range(-32,33): | |
for c in range(-32,33): | |
for d in range(-32,33): | |
try: | |
plain = decrypt(c2[-16:],[a,b,c,d],c_list[-2]) | |
if(plain.endswith(b'$$$') and plain.strip(b'$').endswith(b'}')): | |
print(a,b,c,d,plain) | |
return [a,b,c,d] | |
except: | |
continue | |
cipher1='89b8aca257ee2748f030e7f6599cbe0cbb5db25db6d3990d3b752eda9689e30fa2b03ee748e0da3c989da2bba657b912' | |
flag=b'ByteCTF{' | |
m=bytes_to_long(flag) | |
c1,c2=cipher1[:len(cipher1)//2],cipher1[len(cipher1)//2:] | |
c_list = [] | |
for i in range(0,len(c2),16): | |
c_list.append(int(c2[i:i+16],16)) | |
key=[-12,26,-3,-31] | |
c_list = [] | |
for i in range(0,len(c1),16): | |
c_list.append(int(c1[i:i+16],16)) | |
E = (m ^ c_list[0]) | |
iv = unconvert(E, key) | |
#print(iv) | |
m1=decrypt(c1,key,iv,mode='OFB') | |
m2=decrypt(c2,key,iv) | |
print(m1+m2) |
好像还有点小问题,之前想通了,现在又想不通了,明天再改