块密码 AES
跟着blog系统地学习一遍
ECB模式
ECB模式首先将明文分块 然后用相同的加密方式和密钥进行加密
因此相同的明文在不同次的加密后是一样的
注意: plaintext和key都必须是16的倍数
SWPU2020 ECB
chall.py
from Crypto.Cipher import AES
import os
BLOCKSIZE = 16
flag = os.environ['FLAG']
def pad(data):
pad_len = BLOCKSIZE - (len(data) % BLOCKSIZE) if len(data) % BLOCKSIZE != 0 else 0
return data + chr(pad_len) * pad_len
def unpad(data):
num = ord(data[-1])
return data[:-num]
def enc(data,key):
cipher = AES.new(key,AES.MODE_ECB)
encrypt = cipher.encrypt(pad(data))
return encrypt
def dec(data,key):
try:
cipher = AES.new(key,AES.MODE_ECB)
encrypt = cipher.decrypt(data)
return unpad(encrypt)
except:
exit()
def task():
try:
key = os.urandom(16)
while True:
plaintext = raw_input("Amazing function: ").decode('hex')
yusa = plaintext+flag
print (enc(yusa,key).encode('hex'))
except Exception as e:
print (str(e))
exit()
if __name__ == "__main__":
task()
(...
CBC模式
与ECB不同的是这里每个明文组与前一个密文组xor后再进行ECB的加密模式
每个明文组长度要是128bit的整数倍
简单原理练习
from Crypto.Cipher import AES
import os
iv = os.urandom(16)
key = os.urandom(16)
my_aes = AES.new(key, AES.MODE_CBC, iv)
flag = open('flag.txt', 'rb').read()
flag += (16 - len(flag) % 16) * b'\x00'
c = my_aes.encrypt(flag)
print(list(c), list(iv), list(key))
'''
[137, 163, 60, 145, 236, 127, 76, 5, 212, 171, 46, 211, 161, 172, 41, 198, 117, 247, 140, 226, 169, 248, 208, 245, 214, 44, 180, 9, 170, 59, 205, 234]
[138, 237, 90, 59, 60, 190, 103, 179, 137, 128, 10, 206, 237, 10, 183, 174]
[170, 90, 227, 119, 123, 155, 185, 38, 148, 37, 159, 42, 221, 36, 2, 57]
'''
这里只需要将c,iv,key转成byte即可
同时注意AES.new(key,MODE,iv)参数的顺序
from Crypto.Cipher import AES
from Crypto.Util.number import *
c = [137, 163, 60, 145, 236, 127, 76, 5, 212, 171, 46, 211, 161, 172, 41, 198, 117, 247, 140, 226, 169, 248, 208, 245, 214, 44, 180, 9, 170, 59, 205, 234]
iv = [138, 237, 90, 59, 60, 190, 103, 179, 137, 128, 10, 206, 237, 10, 183, 174]
key = [170, 90, 227, 119, 123, 155, 185, 38, 148, 37, 159, 42, 221, 36, 2, 57]
C = b''
for i in c:
C += long_to_bytes(i)
IV = b''
for i in iv:
IV += long_to_bytes(i)
KEY = b''
for i in key:
KEY += long_to_bytes(i)
aes = AES.new(KEY,AES.MODE_CBC,IV)
print(aes.decrypt(C).decode())
# flag{E@SY_AAAAaaaaa33333s}
[HNCTF 2022 WEEK3]AES
chall.py
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'
"""
重点是要看到key = next
这里
那么我们从最后往前推的话 每次的key就是前一密文块 这样除了初始key不知道没办法还原第一个密文块以外 其余的都能还原
from Crypto.Cipher import AES
from Crypto.Util.number import *
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'
ct = [ct[i:i+16] for i in range(0,len(ct),16)]
flag = ''
for i in range(len(ct)-1,0,-1):
key = ct[i-1]
aes = AES.new(key,AES.MODE_ECB)
flag = aes.decrypt(ct[i]).decode()+flag
print(flag)
# 45e4-11ed-bba0-28d0eab06969}NSSCTF{07104f28-45e4-11ed-bba0-28d0eab06969}NSSCTF{07104f28-45e4-11ed-bba0-28d0eab06969}
安洵杯2020 easyaes
chall.py
#!/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 再根据已经告诉的最后密文块向前还原IV
from Crypto.Cipher import AES
import binascii
from Crypto.Util.number import *
from pwn import xor
hint = 56631233292325412205528754798133970783633216936302049893130220461139160682777
enc = b'3c976c92aff4095a23e885b195077b66'
enc = binascii.unhexlify(enc)
# 先恢复key
hint = long_to_bytes(hint)
print(hint)
key = bytes_to_long(hint[16:])^bytes_to_long(hint[:16])
print(long_to_bytes(key))
key = b'd0g3{welcomeyou}'
msg = b'Welcome to this competition, I hope you can have fun today!!!!!!'
msg = [msg[i:i+16] for i in range(0,len(msg),16)]
def decrypt(msg):
ebc = AES.new(key,AES.MODE_ECB)
return ebc.decrypt(msg)
c3 = xor(decrypt(enc),msg[3])
c2 = xor(decrypt(c3),msg[2])
c1 = xor(decrypt(c2),msg[1])
c0 = xor(decrypt(c1),msg[0])
iv = c0
print(b'd0g3{'+iv+b'}')
本质是要弄清楚CBC比ECB就多了层xor(ct[i-1],pt[i])然后就跟ECB一模一样
还有关于hexify
这里不清楚到底告诉的几个密文块可以输出len(binascii.unhexlify(enc))
发现长度为16 刚好128bit 所以告诉的是最后一个密文块
CTR模式
在CTR模式中关键是这个计数器
它是由IV经过一定规则生成的一段数据 长度与数据块相等
COUNTER通过ECB加密后得到一个COUNTER的密文,再和明文1进行异或得到密文1。在加密结束后COUNTER的值加1,然后再次用ECB加密,依次加密
其实就是在ECB模式基础上进一步复杂化xor
例题
from Crypto.Util.number import *
from Crypto.Cipher import AES
from Crypto.Util import Counter
from hashlib import sha256
from secret import flag
import os
def padding(msg):
return msg + os.urandom(16 - len(msg) % 16)
msg = b"where is the flag? Key in my Heart/Counter!!!!"
key = b"I w0nder how????"
assert len(msg) == 46
assert len(key) == 16
enc_key = os.urandom(16)
initial_value = bytes_to_long(enc_key)
hash = sha256(str(initial_value).encode()).hexdigest()
aes = AES.new(enc_key, AES.MODE_ECB)
enc_flag = aes.encrypt(padding(flag))
ctr = Counter.new(AES.block_size * 8, initial_value=initial_value)
aes = AES.new(key, counter=ctr, mode=AES.MODE_CTR)
enc = aes.encrypt(msg)
print("enc = {}".format(enc[-16:]))
print("enc_flag = {}".format(enc_flag))
print("hash = {}".format(hash))
'''
enc = b'\xbe\x9bd\xc6\xd4=\x8c\xe4\x95bi\xbc\xe01\x0e\xb8'
enc_flag = b'\xb2\x97\x83\x1dB\x13\x9b\xc2\x97\x9a\xa6+M\x19\xd74\xd2-\xc0\xb6\xba\xe8ZE\x0b:\x14\xed\xec!\xa1\x92\xdfZ\xb0\xbd\xb4M\xb1\x14\xea\xd8\xee\xbf\x83\x16g\xfa'
hash = efb07225b3f1993113e104757210261083c79de50f577b3f0564368ee7b25eeb
'''
这里要先弄清楚CTR的工作流程
由于这里msg是46bytes 会被分成3组 : 16,16,14
由原理图 CTR->CTR+1->CTR+2 也就是说最后的CTR和初始CTR差值为2
那么我们就先想办法获得LAST_CTR
由原理图: 最后一组14bytes(pad后16bytes)与(CTR+2)xor后得到了enc
那么我们将msg[-14:]与enc[-14:] xor就能得到LAST_CTR的前14bytes
剩下的2bytes爆破一下 利用hash进行check即可
注意aes = AES.new(key, counter=ctr, mode=AES.MODE_CTR)
这里生成的时候用的key 所以CTR在INITIAL_VALUE的基础上以这个key作了一次ECB
from Crypto.Cipher import AES
from tqdm import *
import binascii
from Crypto.Util.number import *
from pwn import xor
from hashlib import *
msg = b"where is the flag? Key in my Heart/Counter!!!!"
key = b"I w0nder how????"
enc = b'\xbe\x9bd\xc6\xd4=\x8c\xe4\x95bi\xbc\xe01\x0e\xb8'
enc_flag = b'\xb2\x97\x83\x1dB\x13\x9b\xc2\x97\x9a\xa6+M\x19\xd74\xd2-\xc0\xb6\xba\xe8ZE\x0b:\x14\xed\xec!\xa1\x92\xdfZ\xb0\xbd\xb4M\xb1\x14\xea\xd8\xee\xbf\x83\x16g\xfa'
hash = 'efb07225b3f1993113e104757210261083c79de50f577b3f0564368ee7b25eeb'
last_CTR = xor(msg[-14:],enc[-14:]) # 得到最后CTR的前14个字节
# 爆破剩下两个字节
for bit in trange(2**8,2**16):
CTR = last_CTR + long_to_bytes(bit)
ecb = AES.new(key,AES.MODE_ECB)
CTR = ecb.decrypt(CTR)
INIT_CTR = bytes_to_long(CTR)-2
_hash = sha256(str(INIT_CTR).encode()).hexdigest()
if hash == _hash:
enc_key = long_to_bytes(INIT_CTR)
aes = AES.new(enc_key,AES.MODE_ECB)
print(aes.decrypt(enc_flag))