AES notes
CBC
from Crypto.Cipher import AES
from os import urandom
from pwn import xor
p1, p2, p3, p4 = b'a'*16, b'b'*16 , b'c'*16, b'd'*16
key = urandom(16)
iv = urandom(16)
p = p1 + p2 + p3 + p4
ct = AES.new(key=key, mode=AES.MODE_CBC, iv=iv).encrypt(p)
c1, c2, c3, c4 = ct[:16], ct[16:32], ct[32:48], ct[48:]
# how does the encryption work?
def ECB_enc(x):
return AES.new(key, AES.MODE_ECB).encrypt(x)
assert c1 == ECB_enc(xor(p1, iv))
assert c2 == ECB_enc(xor(p2, c1))
assert c3 == ECB_enc(xor(p3, c2))
assert c4 == ECB_enc(xor(p4, c3))
...
# and decryption?
def ECB_dec(x):
return AES.new(key, AES.MODE_ECB).decrypt(x)
assert p1 == xor(ECB_dec(c1), iv)
assert p2 == xor(ECB_dec(c2), c1)
assert p3 == xor(ECB_dec(c3), c2)
assert p4 == xor(ECB_dec(c4), c3)
...
Padding attack
from Crypto.Util.Padding import unpad
from Crypto.Cipher import AES
from os import urandom
from pwn import xor
def oracle(iv, ct):
cipher = AES.new(KEY, AES.MODE_CBC, iv=iv)
pt = cipher.decrypt(ct)
try:
unpad(pt, 16)
return True
except:
return False
def attack(c):
r = b''
for i in reversed(range(16)):
s = bytes([16 - i] * (16 - i))
for b in range(256):
iv_ = b'\x00'*i + xor(s, bytes([b]) + r)
if oracle(iv_, c):
r = bytes([b]) + r
break
return r
plaintext = b'secret!!!!!!!!!!'
KEY = urandom(16)
iv = urandom(16)
ct = AES.new(KEY, AES.MODE_CBC, iv=iv).encrypt(plaintext)
assert attack(ct) == AES.new(KEY, AES.MODE_ECB).decrypt(ct)
print(xor(iv, attack(ct)))