cbc_padding_oracle.py (2193B)
1 from Crypto.Cipher import AES 2 from Crypto import Random 3 from Crypto.Random import random 4 5 key = Random.new().read(AES.block_size) 6 iv = Random.new().read(AES.block_size) 7 8 def encryption_oracle(): 9 with open('files/17.txt') as f: 10 plaintext = f.read().splitlines()[random.randint(0, 9)] 11 12 pad_len = AES.block_size - (len(plaintext) % AES.block_size) 13 return iv + AES.new(key, AES.MODE_CBC, iv).encrypt(plaintext + ''.join([chr(pad_len) for i in range(pad_len)])) 14 15 def pkcs7_padding_validation(msg, strip_mode): 16 len_pad = ord(msg[len(msg) - 1]) 17 18 if len_pad == 0 or len_pad > AES.block_size: 19 return False if not strip_mode else "" 20 21 for c in msg[len(msg) - len_pad:]: 22 if c != chr(len_pad): 23 return False if not strip_mode else "" 24 25 return True if not strip_mode else msg[:len(msg) - len_pad] 26 27 def padding_oracle(ciphertext): 28 return pkcs7_padding_validation(AES.new(key, AES.MODE_CBC, iv).decrypt(ciphertext), False) 29 30 ciphertext = encryption_oracle() 31 plaintext = "" 32 33 for b_idx in reversed(range((len(ciphertext) / AES.block_size) - 1)): 34 blocks = [ciphertext[i : i + AES.block_size] for i in range(0, len(ciphertext), AES.block_size)] 35 block = list(blocks[b_idx]) 36 padding = [] 37 38 for i in range(AES.block_size): 39 guessed_byte = block[AES.block_size - i - 1] 40 found = False 41 42 for c in range(256): 43 if chr(c) != guessed_byte: 44 block[AES.block_size - i - 1] = chr(c) 45 blocks[b_idx] = ''.join(block) 46 47 if padding_oracle(''.join(blocks[:b_idx + 2])): 48 plaintext += chr(c ^ ord(guessed_byte) ^ (i + 1)) 49 padding.append(c) 50 51 for p in range(i + 1): 52 block[AES.block_size - p - 1] = chr(padding[p] ^ (p + 1) ^ (i + 2)) 53 54 found = True 55 break 56 57 if not found: 58 plaintext += chr(i + 1) 59 padding.append(ord(guessed_byte)) 60 61 for p in range(i + 1): 62 block[AES.block_size - p - 1] = chr(padding[p] ^ (p + 1) ^ (i + 2)) 63 64 print pkcs7_padding_validation(plaintext[::-1], True).decode("base64")