题目给了一个.py文件和一个密文,程序如下:
[Python] 纯文本查看 复制代码 from Crypto.Cipher import AES
def dummy_key_extend(k):
assert len(k) == 4
return k * 4
def aes_duet(plain, key):
# It is so safe that I use AES twice here!
assert len(key) == 8
k1 = dummy_key_extend(key[:4])
k2 = dummy_key_extend(key[4:])
c1 = AES.new(k1, AES.MODE_ECB)
c2 = AES.new(k2, AES.MODE_ECB)
return c2.encrypt(c1.encrypt(plain))
if __name__ == '__main__':
with open('./secretkey', 'rb') as f:
key = f.read()
# To make life easier...
assert (key.encode('hex'))[0] == '0'
assert (key.encode('hex'))[-1] == '8'
plain = 'I am a piece of lovely plaintext'
with open('ciphertext', 'wb') as f:
f.write(aes_duet(plain, key))
print "I am a lovely flag: flag{ %s}" % key.encode('hex')
程序读取secretkey也就是密钥文件,然后将前四位后四位拓展到16位作为两个密钥加密两次明文,最后输出ciphertext密文文件,然而我们只有密文文件,显然就是要碰撞出密钥了。
这里出题人泄漏了hex的2位,我们只需要找到其余几位即可,然而这时候的复杂度还是不能接受(大概要有256^7),目前是不太可能算出来,不过正是由于他前后分别加密的,我们可以枚举前4位把一次加密的密文存下来然后再枚举后四位解密密文去表里查,这样复杂度就降低为256^3*32,差不多可以了。
主要代码:
[Python] 纯文本查看 复制代码 biao = {}
t=[chr(0x8),chr(0x18),chr(0x28),chr(0x38),chr(0x48),chr(0x58),chr(0x68),chr(0x78),chr(0x88),chr(0x98),chr(0xa8),chr(0xb8),chr(0xc8),chr(0xd8),chr(0xe8),chr(0xf8),]
for fst in range(16):
for a in range(256):
for b in range(256):
for c in range(256):
trypass=chr(fst)+chr(a)+chr(b)+chr(c)
trypass=dummy_key_extend(trypass)
c = AES.new(trypass, AES.MODE_ECB).encrypt('I am a piece of lovely plaintext')
biao.update({c:trypass})
print "SETP1 OK"
for ed in range(16):
for d in range(256):
for e in range(256):
for f in range(256):
trypass=chr(d)+chr(e)+chr(f)+t[ed]
trypass=dummy_key_extend(trypass)
c = AES.new(trypass, AES.MODE_ECB).decrypt(crp)
if biao.has_key(c):
key1 = biao[c]
key2 = trypass
with open('ans', 'w') as zx:
zx.write(key1)
zx.write(key2)
sys.exit(0)
不过我跑的时候发现居然Memory error内存爆了?!我可是16G的内存啊!!不过还好我可以扔到服务器上跑,搞了台20Core 64G内存的服务器,保险起见再加上100G虚拟内存走起~
半小时回来已经有输出啦(程序峰值占用近60G内存)~去重之后就是flag。出题人给的标程是要翻译为C++然后只要4G内存就能跑而且速度显然比Py快(因为py的变量无类型,存字典实际上存储的是一个巨大的结构体,有很多无用的东西)……不过鉴于反正也都算出来了,就不乱搞了,大家可以做课后练习。 |