[ACTF新生赛2020]crypto-aes 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 from Crypto.Cipher import AESimport osimport gmpy2from flag import FLAGfrom Crypto.Util.number import *def main (): key=os.urandom(2 )*16 iv=os.urandom(16 ) print (bytes_to_long(key)^bytes_to_long(iv)) aes=AES.new(key,AES.MODE_CBC,iv) enc_flag = aes.encrypt(FLAG) print (enc_flag) if __name__=="__main__" : main() ''' 91144196586662942563895769614300232343026691029427747065707381728622849079757 b'\x8c-\xcd\xde\xa7\xe9\x7f.b\x8aKs\xf1\xba\xc75\xc4d\x13\x07\xac\xa4&\xd6\x91\xfe\xf3\x14\x10|\xf8p' '''
题目用了CBC模式进行加密,iv为16位,key是由2位的随机字节乘16得到的32位key。
我们得到的数据为key和iv异或后得到的,由于key32位,iv只有16位,所以key的前16位没有变化,而且前后16位都是一样的。我们可以使用前半截和后半截异或,得到iv,key就是前半段乘2,进而就能破解这道AES:
1 2 3 4 5 6 7 8 9 10 11 12 from Crypto.Util.number import *from Crypto.Cipher import AESxor = 91144196586662942563895769614300232343026691029427747065707381728622849079757 enflag = b'\x8c-\xcd\xde\xa7\xe9\x7f.b\x8aKs\xf1\xba\xc75\xc4d\x13\x07\xac\xa4&\xd6\x91\xfe\xf3\x14\x10|\xf8p' XOR = long_to_bytes(xor) iv = long_to_bytes(bytes_to_long(XOR[:16 ]) ^ bytes_to_long(XOR[16 :])) key = XOR[:16 ]*2 aes = AES.new(key, AES.MODE_CBC, iv) print (aes.decrypt(enflag).decode('utf-8' ))
注意到使用AES加解密时,需要的key、iv和flag都需要为字节格式。
[安洵杯 2020]easyaes 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 from Crypto.Cipher import AESimport binasciifrom Crypto.Util.number import bytes_to_longfrom flag import flagfrom key import keyiv = flag.strip(b'd0g3{' ).strip(b'}' ) LENGTH = len (key) assert LENGTH == 16 hint = os.urandom(4 ) * 8 print (bytes_to_long(hint)^bytes_to_long(key))msg = b'Welcome to this competition, I hope you can have fun today!!!!!!' def encrypto (message ): aes = AES.new(key,AES.MODE_CBC,iv) return aes.encrypt(message) print (binascii.hexlify(encrypto(msg))[-32 :])''' 56631233292325412205528754798133970783633216936302049893130220461139160682777 b'3c976c92aff4095a23e885b195077b66' '''
这道题未知key,给的数值为hint和key异或后的结果,但是key为16位,hint为4位一循环的32位字符串。可以通过异或得到key:
1 2 3 4 5 6 7 8 9 from Crypto.Util.number import *print (hex (56631233292325412205528754798133970783633216936302049893130220461139160682777 ))hint1='7d3424647d3424647d3424647d342464' xor='19044357064341081e5b4901045b5119' key=long_to_bytes(int (hint1,16 )^int (xor,16 ))
后面进行CBC,我们已知最后一个块加密后的密文,可以一步一步反推出iv得到flag:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from Crypto.Cipher import AESfrom Crypto.Util.strxor import strxorfrom Crypto.Util.number import *hint1='7d3424647d3424647d3424647d342464' xor='19044357064341081e5b4901045b5119' key=long_to_bytes(int (hint1,16 )^int (xor,16 )) msg = b'Welcome to this competition, I hope you can have fun today!!!!!!' plain=[msg[k:k+16 ]for k in range (0 ,len (msg),16 )] plain.reverse() IV = long_to_bytes(int ('3c976c92aff4095a23e885b195077b66' ,16 )) aes = AES.new(key,AES.MODE_ECB) for i in plain: IV=strxor(aes.decrypt(IV),i) print (b'd0g3{' +IV+b'}' )
在进行解密的时候,未知本轮的iv值,只需要解密到CBC异或后但还未经key块加密的密文即可,所以只需要得到ECB模式解密后的结果,然后再进行异或得到本轮iv值,循环往复,最终就能得到最开始的iv值了。
[SWPUCTF 2022 新生赛]AES 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import base64from Crypto.Cipher import AESfrom flag import getflagiv = '1229002635654321' key = 'nssctfneedcrypto' data = getflag() def pad (data ): pad_data = data for i in range (0 , 16 - len (data)): pad_data = pad_data + ' ' return pad_data def AES_en (key, data ): if len (data) < 16 : data = pad(data) AES_obj = AES.new(key.encode("utf-8" ), AES.MODE_CBC, iv.encode("utf-8" )) AES_en_str = AES_obj.encrypt(data.encode("utf-8" )) AES_en_str = base64.b64encode(AES_en_str) return AES_en_str.decode("utf-8" ) data = AES_en(key, data) print (data)
pad函数给不满足块加密的部分用空格补足,可以忽略,这题初始化向量和key都给了,给的data是base64格式,直接解就行:
1 2 3 4 5 6 7 8 9 10 11 from Crypto.Cipher import AESimport base64iv = b'1229002635654321' key = b'nssctfneedcrypto' data='862EoKZMO3sqpNlzyvIW5G/8MFeAI/zgGXcgi5eNOL8=' data=base64.b64decode(data) cipher=AES.new(key,AES.MODE_CBC,iv) flag=cipher.decrypt(data) print (flag)
[AFCTF 2018]MyOwnCBC 题目描述:
CBC什么东西呀?不就是把上一轮加密的影响扩散到下一轮嘛 它写的CBC一点都不正宗 我这样写肯定也行的! 大概吧?
代码:
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 from Crypto.Cipher import AESfrom Crypto.Random import randomfrom Crypto.Util.number import long_to_bytesdef MyOwnCBC (key, plain ): if len (key)!=32 : return "error!" cipher_txt = b"" cipher_arr = [] cipher = AES.new(key, AES.MODE_ECB, "" ) plain = [plain[i:i+32 ] for i in range (0 , len (plain), 32 )] print plain cipher_arr.append(cipher.encrypt(plain[0 ])) cipher_txt += cipher_arr[0 ] for i in range (1 , len (plain)): cipher = AES.new(cipher_arr[i-1 ], AES.MODE_ECB, "" ) cipher_arr.append(cipher.encrypt(plain[i])) cipher_txt += cipher_arr[i] return cipher_txt key = random.getrandbits(256 ) key = long_to_bytes(key) s = "" with open ("flag.txt" ,"r" ) as f: s = f.read() f.close() with open ("flag_cipher" ,"wb" ) as f: f.write(MyOwnCBC(key, s)) f.close()
读完一遍代码,发现了一些奇怪的事情:
这个所谓的CBC加密,其实只是长得像CBC的ECB模式加密,而且很容易被破解,他把key进行第一次加密之后,将第一轮的密文直接作为了第二轮加密的key,如此往复。
还原明文也非常简单,把给的密文分组后反向用ECB模式解密即可,每组key是上一组的密文。
当然,由于我们实际上还是不知道key,所以第一组密文是破解不了的,不过flag不在这里,就无所谓了。
1 2 3 4 5 6 7 8 9 10 11 from Crypto.Cipher import AESwith open ("flag_cipher" ,'rb' ) as f: f=f.read() list =[f[i:i+32 ] for i in range (0 ,len (f),32 )] plain=[] for i in range (len (list )-1 ,0 ,-1 ): cipher = AES.new(list [i-1 ], AES.MODE_ECB) plain.append(cipher.decrypt(list [i])) for i in range (len (plain),0 ,-1 ): print (plain[i-1 ].decode('utf-8' ),end='' )
[HNCTF 2022 WEEK3]AES 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 from Crypto.Cipher import AESfrom Crypto.Util.Padding import pad, unpadfrom os import urandomfrom flag import flagdef cbc_encrypt (msg: bytes ): msg = pad(msg, 16 ) msg = [msg[i:i+16 ] for i in range (0 , len (msg), 16 )] key = urandom(16 ) out = [] for block in msg: cipher = AES.new(key, AES.MODE_ECB) next = cipher.encrypt(block) out.append(next ) key = next out = b"" .join(out) return key, out def main (): key, ct = cbc_encrypt(flag*3 ) print (f"ct = {ct} " ) if __name__ == "__main__" : main() ct = b'\x179\xb8l\x97\xbew\xc2\xd5f~\x8e\xdc\xf2\x9b\xabR\xa9a\xd2\xf4\xde\xd6|\xd1\x9f\xe9q\x1d\xfcm\xfbj\xe9\x9e\xab\xf5fL\xb3\xb5_\xa5\x16\x8e\x7f\x9fV`\x8b\x16\xa1\xa6)\x08\x97\x91\xbd3\x1d\xeb\\\x86\xa2\xd6\x94>\xf3\xfdt\xd9\x14\xf3\xfc\xe2\x02\xd6\xc4\xcfq"\x1a\x14~2]4\x9f\xc9\x88\xf8\x12\xb6\xa2\xd7\xec\x0b\x7f\xd4d\xdc\xc6\xb4]\x10u\xc6f\x97m\xccA\x82\x02\xa5gh\x85\x85Wz\xd9.\xff\x9bx\x99J\x0e\x86\x16\x90\xad\x1e\x17\x86\x95\xb8S\x17\xea\x93v\xd0'
读完题发现和MyOwnCBC一样的原理,还是反着解密就出了:
1 2 3 4 5 6 7 8 9 10 11 from Crypto.Cipher import AESct = b'\x179\xb8l\x97\xbew\xc2\xd5f~\x8e\xdc\xf2\x9b\xabR\xa9a\xd2\xf4\xde\xd6|\xd1\x9f\xe9q\x1d\xfcm\xfbj\xe9\x9e\xab\xf5fL\xb3\xb5_\xa5\x16\x8e\x7f\x9fV`\x8b\x16\xa1\xa6)\x08\x97\x91\xbd3\x1d\xeb\\\x86\xa2\xd6\x94>\xf3\xfdt\xd9\x14\xf3\xfc\xe2\x02\xd6\xc4\xcfq"\x1a\x14~2]4\x9f\xc9\x88\xf8\x12\xb6\xa2\xd7\xec\x0b\x7f\xd4d\xdc\xc6\xb4]\x10u\xc6f\x97m\xccA\x82\x02\xa5gh\x85\x85Wz\xd9.\xff\x9bx\x99J\x0e\x86\x16\x90\xad\x1e\x17\x86\x95\xb8S\x17\xea\x93v\xd0' cipher = [ct[i:i+16 ] for i in range (len (ct)-16 , -1 , -16 )] plain=[] for i in range (len (cipher)-1 ): key=cipher[i+1 ] aes=AES.new(key, AES.MODE_ECB) plain.append(aes.decrypt(cipher[i]).decode()) plain=[plain[i] for i in range (len (plain)-1 , -1 , -1 )] print ('' .join(i for i in plain))