def test_determine_randbytes_size_nominal_case(self): randbytes = rand_bytes_gen(47) encryption_oracle = gen_encryption_oracle(16, randbytes=randbytes) randbytes_size = determine_randbytes_size(encryption_oracle, 16) self.assertEqual(47, randbytes_size)
def break_cbc_single_blk( cipher_blk1: bytes, cipher_blk2: bytes, padding_oracle: Callable[[bytes, bytes], bool]) \ -> bytes: """ params: cipher_blk1: encrypted block prior to `cipher_blk2` or IV if `cipher_blk2` was the first encrypted block cipher_blk2: block to be decrypted padding_oracle: `valid_padding()` returns: decryption of `cipher_blk2` """ intermediate_blk2 = b'' plain_blk2 = b'' for i in range(1, 17): target_byte = i.to_bytes(1, byteorder=sys.byteorder) atk_blk_prefix = rand_bytes_gen(16 - i) atk_blk_suffix = b'' for k in range(len(intermediate_blk2)): atk_blk_suffix += xor(target_byte, get_byte_n(intermediate_blk2, k)) for j in range(256): atk_byte = j.to_bytes(1, byteorder=sys.byteorder) if valid_padding(cipher_blk2, atk_blk_prefix + atk_byte + atk_blk_suffix): break intermediate_blk2 = xor(atk_byte, target_byte) + intermediate_blk2 plain_blk2 = xor(intermediate_blk2, get_byte_n(cipher_blk1, -i)) + plain_blk2 return plain_blk2
def main(): """ decrypt contents of a file encrypted using AES-128 in ECB Mode encrypt decrypted plaintext using AES-128 in CTR Mode break CTR Mode encryption using `edit_oracle()` """ key = b"YELLOW SUBMARINE" cipher = AES.new(key, AES.MODE_ECB) ecb = ECBMode(16, cipher.encrypt, cipher.decrypt) input_filename = os.path.join(pathlib.Path(__file__).parent, "input") with open(input_filename, "r") as input_file: base64_str = input_file.read() base64_bytes = base64_str.replace('\n', '').encode("utf-8") ecb_encrypted = base64.decodebytes(base64_bytes) plaintext = ecb.decrypt(ecb_encrypted) nonce = bytes(8) unknown_key = rand_bytes_gen(16) cipher = AES.new(unknown_key, AES.MODE_ECB) ctr = CTRMode( blksize=16, encrypt_blk=cipher.encrypt, decrypt_blk=cipher.decrypt, nonce=nonce ) encrypted = ctr.encrypt(plaintext) edit_oracle = gen_edit_oracle(unknown_key, nonce) print(break_rand_access_ctr(encrypted, edit_oracle).decode())
def test_determine_randbytes_size_less_than_one_block_randbytes(self): randbytes = rand_bytes_gen(7) encryption_oracle = gen_encryption_oracle(16, randbytes=randbytes) randbytes_size = determine_randbytes_size(encryption_oracle, 16) self.assertEqual(7, randbytes_size)
def test_determine_randbytes_size_multiple_of_blksize(self): randbytes = rand_bytes_gen(32) encryption_oracle = gen_encryption_oracle(16, randbytes=randbytes) randbytes_size = determine_randbytes_size(encryption_oracle, 16) self.assertEqual(32, randbytes_size)
def test_recover_key_nominal_case(self): seed = int.from_bytes(rand_bytes_gen(1), "little") known_plaintext = b'A' * 14 ciphertext = gen_ciphertext(known_plaintext, seed) recovered_seed = recover_key(known_plaintext, ciphertext, 8) self.assertEqual(seed, recovered_seed)
def gen_ciphertext(plaintext: bytes, seed: int) -> bytes: """ params: plaintext: bytes to encrypt seed: seed to use for encryption returns: MT19937Cipher encryption of `plaintext` prepended with a random number of random bytes using a random seed of 16 bytes """ cipher = MT19937Cipher(seed) prefix = rand_bytes_gen(random.randint(1, 255)) return cipher.encrypt(prefix+plaintext)
def main(): """ append payload to message while maintaining a valid MAC """ cookie = (b"comment1=cooking%20MCs;userdata=foo;comment2=%20like%20a%20" b"pound%20of%20bacon") key = rand_bytes_gen(random.randint(0, 128)) authenticated_cookie = MAC.generate(cookie, key, SHA1) def validation_oracle(msg): return MAC.validate(msg, key, SHA1) payload = b";admin=true" attack_cookie = length_extension( authenticated_cookie, payload, validation_oracle ) assert MAC.validate(attack_cookie, key, SHA1) print(attack_cookie)
def encryption_oracle() -> Tuple[bytes, bytes]: """ params: none returns: ciphertext: one of ten plaintexts encrypted using AES-128-CBC with `iv` iv: iv used to encrypt the ciphertext """ plain_strs = ( b"MDAwMDAwTm93IHRoYXQgdGhlIHBhcnR5IGlzIGp1bXBpbmc=", b"MDAwMDAxV2l0aCB0aGUgYmFzcyBraWNrZWQgaW4gYW5kIHRoZSBWZWdhJ3MgYXJlIH" + b"B1bXBpbic=", b"MDAwMDAyUXVpY2sgdG8gdGhlIHBvaW50LCB0byB0aGUgcG9pbnQsIG5vIGZha2luZw" + b"==", b"MDAwMDAzQ29va2luZyBNQydzIGxpa2UgYSBwb3VuZCBvZiBiYWNvbg==", b"MDAwMDA0QnVybmluZyAnZW0sIGlmIHlvdSBhaW4ndCBxdWljayBhbmQgbmltYmxl", b"MDAwMDA1SSBnbyBjcmF6eSB3aGVuIEkgaGVhciBhIGN5bWJhbA==", b"MDAwMDA2QW5kIGEgaGlnaCBoYXQgd2l0aCBhIHNvdXBlZCB1cCB0ZW1wbw==", b"MDAwMDA3SSdtIG9uIGEgcm9sbCwgaXQncyB0aW1lIHRvIGdvIHNvbG8=", b"MDAwMDA4b2xsaW4nIGluIG15IGZpdmUgcG9pbnQgb2g=", b"MDAwMDA5aXRoIG15IHJhZy10b3AgZG93biBzbyBteSBoYWlyIGNhbiBibG93", ) blksize = len(CONSISTENT_KEY) plain = base64.b64decode(plain_strs[random.randint(0, len(plain_strs) - 1)]) padded = PKCS7Padding.apply(plain, blksize) cipher = AES.new(CONSISTENT_KEY, AES.MODE_ECB) iv = rand_bytes_gen(blksize) cbc = CBCMode(blksize=blksize, encrypt_blk=cipher.encrypt, decrypt_blk=cipher.decrypt, iv=iv) encrypted = cbc.encrypt(padded) return encrypted, iv
import base64 from Crypto.Cipher import AES import random import sys from typing import Callable, Tuple from set1.challenge02.fixed_xor import xor from set1.challenge07.ecb_mode import blocks from set2.challenge09.pkcs7_padding import PKCS7Padding, \ InvalidPaddingException from set2.challenge10.cbc_mode import CBCMode from set2.challenge11.rand_enc import rand_bytes_gen CONSISTENT_KEY = rand_bytes_gen(16) def encryption_oracle() -> Tuple[bytes, bytes]: """ params: none returns: ciphertext: one of ten plaintexts encrypted using AES-128-CBC with `iv` iv: iv used to encrypt the ciphertext """ plain_strs = ( b"MDAwMDAwTm93IHRoYXQgdGhlIHBhcnR5IGlzIGp1bXBpbmc=", b"MDAwMDAxV2l0aCB0aGUgYmFzcyBraWNrZWQgaW4gYW5kIHRoZSBWZWdhJ3MgYXJlIH" + b"B1bXBpbic=", b"MDAwMDAyUXVpY2sgdG8gdGhlIHBvaW50LCB0byB0aGUgcG9pbnQsIG5vIGZha2luZw" + b"==", b"MDAwMDAzQ29va2luZyBNQydzIGxpa2UgYSBwb3VuZCBvZiBiYWNvbg==",
def test_rand_bytes_gen_zero_keysize_returns_empty_bytes(self): self.assertEqual(b'', rand_bytes_gen(0))
def test_rand_bytes_gen_nominal_case(self): key = rand_bytes_gen(16) self.assertEqual(16, len(key))
def test_rand_bytes_gen_negative_keysize_returns_empty_bytes(self): self.assertEqual(b'', rand_bytes_gen(-1))
def test_break_ecb_randbytes_zero_randbytes(self): unknownstr = b"YELLOW SUBMARINEEXTRA" randbytes = rand_bytes_gen(7) encryption_oracle = gen_encryption_oracle(16, unknownstr, randbytes) self.assertEqual(unknownstr, break_ecb(encryption_oracle))
def test_break_ecb_randbytes_size_multiple_of_blksize(self): unknownstr = b"YELLOW SUBMARINEEXTRA" randbytes = rand_bytes_gen(32) encryption_oracle = gen_encryption_oracle(16, unknownstr, randbytes) self.assertEqual(unknownstr, break_ecb(encryption_oracle))
from Crypto.Cipher import AES from typing import Callable from set1.challenge02.fixed_xor import xor from set1.challenge07.ecb_mode import get_block_n from set2.challenge11.rand_enc import rand_bytes_gen from set3.challenge18.ctr_mode import CTRMode CONSISTENT_KEY = rand_bytes_gen(16) CONSISTENT_NONCE = rand_bytes_gen(8) # Copied from set2.challenge16.ctr_bitflip # Very specific use-case so I chose to copy instead of refactoring with # greater abstraction # No need to retest (Famous last words :P) # Changed to use CTRMode def gen_encryption_oracle(blksize: int = 16, prefix: bytes = None, suffix: bytes = None) \ -> Callable[[bytes], bytes]: """ params: blksize: blocksize `encryption_oracle` should use prefix: bytes to prepend to message suffix: bytes to append to message returns: `encryption_oracle` method """ if prefix is None: prefix = b"comment1=cooking%20MCs;userdata=" if suffix is None: