[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 AES
import os
import gmpy2
from flag import FLAG
from Crypto.Util.number import *

def main():
key=os.urandom(2)*16#32
iv=os.urandom(16)#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 AES

xor = 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'))
#actf{W0W_y0u_can_so1v3_AES_now!}

注意到使用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
#!/usr/bin/python
from Crypto.Cipher import AES
import binascii
from Crypto.Util.number import bytes_to_long
from flag import flag
from key import key

iv = 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))
#7d3424647d3424647d3424647d34246419044357064341081e5b4901045b5119

hint1='7d3424647d3424647d3424647d342464'
xor='19044357064341081e5b4901045b5119'
key=long_to_bytes(int(hint1,16)^int(xor,16))
#b'd0g3{welcomeyou}'

后面进行CBC,我们已知最后一个块加密后的密文,可以一步一步反推出iv得到flag:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from Crypto.Cipher import AES
from Crypto.Util.strxor import strxor
from 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 base64
from Crypto.Cipher import AES
from flag import getflag
iv = '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)
#data=862EoKZMO3sqpNlzyvIW5G/8MFeAI/zgGXcgi5eNOL8=

pad函数给不满足块加密的部分用空格补足,可以忽略,这题初始化向量和key都给了,给的data是base64格式,直接解就行:

1
2
3
4
5
6
7
8
9
10
11
from Crypto.Cipher import AES
import base64

iv = 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
#!/usr/bin/python2.7
# -*- coding: utf-8 -*-

from Crypto.Cipher import AES
from Crypto.Random import random
from Crypto.Util.number import long_to_bytes

def 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 AES

with 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 AES
from Crypto.Util.Padding import pad, unpad
from os import urandom
from flag import flag

def 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"flag = {flag}")
# print(f"key = {key}")
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 AES

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'
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))