Skip to content

Instantly share code, notes, and snippets.

@mikeecb mikeecb/cryptopals_1_16.py Secret
Created May 13, 2017

Embed
What would you like to do?
Cryptopals Set 1 Exercise 16
from Crypto.Cipher import AES
from random import randint
def xor(b1, b2):
b = bytearray(len(b1))
for i in range(len(b1)):
b[i] = b1[i] ^ b2[i]
return b
def random_key(length):
key = bytearray(length)
for i in range(length):
key[i] = chr(randint(0, 255))
return key
def pad_pkcs7(buffer, block_size):
if len(buffer) % block_size:
padding = (len(buffer) / block_size + 1) * block_size - len(buffer)
else:
padding = 0
# Padding size must be less than a byte
assert 0 <= padding <= 255
new_buffer = bytearray()
new_buffer[:] = buffer
new_buffer += bytearray([chr(padding)] * padding)
return new_buffer
def unpad_pkcs7(buffer):
padding = buffer[-1]
for i in range(len(buffer)-1, len(buffer)-padding, -1):
if buffer[i] != buffer[-1]:
return buffer
new_buffer = bytearray()
new_buffer[:] = buffer[:-padding]
return new_buffer
def aes_128_ecb_enc(buffer, key):
obj = AES.new(key, AES.MODE_ECB)
return bytearray(obj.encrypt(bytes(buffer)))
def aes_128_ecb_dec(buffer, key):
obj = AES.new(key, AES.MODE_ECB)
return bytearray(obj.decrypt(bytes(buffer)))
def aes_128_cbc_enc(buffer, key, iv):
plaintext = pad_pkcs7(buffer, AES.block_size)
ciphertext = bytearray(len(plaintext))
prev_block = iv
for i in range(0, len(plaintext), AES.block_size):
ciphertext[i: i + AES.block_size] = aes_128_ecb_enc(
xor(plaintext[i: i + AES.block_size], prev_block),
key,
)
prev_block = ciphertext[i: i + AES.block_size]
return ciphertext
def aes_128_cbc_dec(ciphertext, key, iv):
plaintext = bytearray(len(ciphertext))
prev_block = iv
for i in range(0, len(ciphertext), AES.block_size):
plaintext[i: i + AES.block_size] = xor(
aes_128_ecb_dec(bytes(ciphertext[i: i + AES.block_size]), key),
prev_block
)
prev_block = ciphertext[i: i + AES.block_size]
return unpad_pkcs7(plaintext)
key = bytes(random_key(AES.block_size))
iv = bytearray(random_key(AES.block_size))
def encryption_oracle(input_data):
input_data = input_data.replace(';','%3b').replace('=','%3d')
plaintext = bytearray(
"comment1=cooking%20MCs;userdata=" +
input_data +
";comment2=%20like%20a%20pound%20of%20bacon"
)
return aes_128_cbc_enc(plaintext, key, iv)
def is_admin(enc_data):
plaintext = aes_128_cbc_dec(enc_data, key, iv)
return ";admin=true;" in plaintext
def crack():
first_block = bytearray('A' * AES.block_size)
second_block = bytearray("AadminAtrueA")
plaintext = first_block + second_block
ciphertext = encryption_oracle(plaintext)
# We 'know' the prefix is two blocks long
offset = 32
# Change the first byte in first_block 'A' so we change the first byte in
# second_block to be ';'
ciphertext[offset] = bytes(
xor(
bytearray(chr(ciphertext[offset])),
xor(bytearray("A"), bytearray(";"))
)
)
# Change the 7th byte in first_block 'A' so we change the first byte in
# second_block to be '='
ciphertext[offset + 6] = bytes(
xor(
bytearray(chr(ciphertext[offset + 6])),
xor(bytearray("A"), bytearray("="))
)
)
# Change the 12th byte in first_block 'A' so we change the first byte in
# second_block to be ';'
ciphertext[offset + 11] = bytes(
xor(
bytearray(chr(ciphertext[offset + 11])),
xor(bytearray("A"), bytearray(";"))
)
)
return is_admin(ciphertext)
crack()
# True
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.