def test_unapply_whole_block_padding(self): padded = b"YELLOW\x03\x03\x03" expected_bytes = b"YELLOW" actual_bytes = PKCS7Padding.unapply(padded) self.assertEqual(expected_bytes, actual_bytes)
def test_unapply_cryptopals_case(self): padded = b"YELLOW SUBMARINE\x04\x04\x04\x04" expected_bytes = b"YELLOW SUBMARINE" actual_bytes = PKCS7Padding.unapply(padded) self.assertEqual(expected_bytes, actual_bytes)
def test_apply_bytes_size_mutliple_of_blksize_adds_extra_block(self): b = b"YELLOW" expected_padded = b"YELLOW\x03\x03\x03" actual_padded = PKCS7Padding.apply(b, 3) self.assertEqual(expected_padded, actual_padded)
def test_unapply_all_padding_returns_empty(self): padded = b"\x04\x04\x04\x04" expected_bytes = b"" actual_bytes = PKCS7Padding.unapply(padded) self.assertEqual(expected_bytes, actual_bytes)
def test_apply_empty_bytes_adds_padding(self): b = b'' expected_padded = b"\x04\x04\x04\x04" actual_padded = PKCS7Padding.apply(b, 4) self.assertEqual(expected_padded, actual_padded)
def test_apply_cryptopals_case(self): b = b"YELLOW SUBMARINE" expected_padded = b"YELLOW SUBMARINE\x04\x04\x04\x04" actual_padded = PKCS7Padding.apply(b, 20) self.assertEqual(expected_padded, actual_padded)
def encryption_oracle(b: bytes) -> bytes: """ params: b: bytes to encrypt returns: `b` encrypted using AES-128 with a random key using either ECB mode or CBC mode randomly (one in two chance) also prepends 5-10 random bytes and appends 5-10 random bytes to `b` before encryption if CBC mode is used random bytes are used for the IV """ prefix_size = random.randint(5, 10) prefix = rand_bytes_gen(prefix_size) suffix_size = random.randint(5, 10) suffix = rand_bytes_gen(suffix_size) plain = PKCS7Padding.apply(prefix+b+suffix, blksize) key = rand_bytes_gen(blksize) cipher = AES.new(key, AES.MODE_ECB) if use_ecb: # print("ECB") # for manual verification ecb = ECBMode(blksize, cipher.encrypt, cipher.decrypt) return ecb.encrypt(plain) iv = rand_bytes_gen(blksize) cbc = CBCMode( blksize=blksize, encrypt_blk=cipher.encrypt, decrypt_blk=cipher.decrypt, iv=iv ) # print("CBC") return cbc.encrypt(plain)
def encryption_oracle(b: bytes) -> bytes: """ params: b: bytes to encrypt returns: `b` encrypted using AES-128-ECB appends `unknownstr` to `b` before encrypting """ plain = PKCS7Padding.apply(b + unknownstr, blksize) cipher = AES.new(CONSISTENT_KEY, AES.MODE_ECB) ecb = ECBMode(blksize, cipher.encrypt, cipher.decrypt) return ecb.encrypt(plain)
def encrypt_profile(profile: str) -> bytes: """ params: profile: encoded profile returns: `profile` encrypted using AES-128 ECB mode with a consistent key """ blksize = 16 plain = PKCS7Padding.apply(profile.encode(), blksize) cipher = AES.new(CONSISTENT_KEY, AES.MODE_ECB) ecb = ECBMode(blksize, cipher.encrypt, cipher.decrypt) return ecb.encrypt(plain)
def decrypt_profile(encrypted: bytes) -> str: """ params: encrypted: profile encrypted using `encrypted_profile()` returns: encoded profile """ cipher = AES.new(CONSISTENT_KEY, AES.MODE_ECB) ecb = ECBMode(16, cipher.encrypt, cipher.decrypt) padded = ecb.decrypt(encrypted) return PKCS7Padding.unapply(padded).decode()
def main(): """ Already implemented `PKCS7Padding.unapply()` in set2.challenge09 Display that it solves the challenge """ b = b"ICE ICE BABY\x04\x04\x04\x04" print("PKCS7Padding.unapply(%s):" % b) print(PKCS7Padding.unapply(b)) b = b"ICE ICE BABY\x05\x05\x05\x05" print("PKCS7Padding.unapply(%s):" % b) try: PKCS7Padding.unapply(b) except (InvalidPaddingException): print("Exception raised") b = b"ICE ICE BABY\x01\x02\x03\x04" print("PKCS7Padding.unapply(%s):" % b) try: PKCS7Padding.unapply(b) except (InvalidPaddingException): print("Exception raised")
def valid_padding(encrypted: bytes, iv: bytes) -> bool: """ params: encrypted: encrypted message iv: IV used to encrypt `encrypted` returns: True if decryption of `encrypted` has valid padding False otherwise """ blksize = len(CONSISTENT_KEY) cipher = AES.new(CONSISTENT_KEY, AES.MODE_ECB) cbc = CBCMode(blksize=blksize, encrypt_blk=cipher.encrypt, decrypt_blk=cipher.decrypt, iv=iv) decrypted = cbc.decrypt(encrypted) try: PKCS7Padding.unapply(decrypted) return True except InvalidPaddingException: return False
def is_admin(encrypted: bytes, blksize: int = 16) -> bool: """ params: encrypted: message encrypted using `encryption_oracle()` blksize: blocksize used by `encryption_oracle()` returns: True if decrypted message contains ";admin=true;", False otherwise """ cipher = AES.new(CONSISTENT_KEY, AES.MODE_ECB) cbc = CBCMode(blksize=blksize, encrypt_blk=cipher.encrypt, decrypt_blk=cipher.decrypt, iv=CONSISTENT_IV) padded = cbc.decrypt(encrypted) decrypted = PKCS7Padding.unapply(padded) return b";admin=true;" in decrypted
def aes_cbc(plaintext: bytes) -> bytes: """ params: b: bytes to encrypt returns: `b` encrypted using AES-128-CBC uses key as IV """ padded = PKCS7Padding.apply(plaintext, blksize) cipher = AES.new(key, AES.MODE_ECB) cbc = CBCMode( blksize=blksize, encrypt_blk=cipher.encrypt, decrypt_blk=cipher.decrypt, iv=key, ) return cbc.encrypt(padded)
def break_cbc(encrypted: bytes, iv: bytes, padding_oracle: Callable[[bytes, bytes], bool]) \ -> bytes: """ params: encrypted: encrypted message from `encryption_oracle()` iv: IV used for encryption from `encryption_oracle()` padding_oracle: `valid_padding()` returns: decrypted bytes for `encrypted` """ decrypted = b'' prev_blk = iv for curr_blk in blocks(encrypted, 16): decrypted += break_cbc_single_blk(prev_blk, curr_blk, padding_oracle) prev_blk = curr_blk return PKCS7Padding.unapply(decrypted)
def encryption_oracle(b: bytes) -> bytes: """ params: b: bytes to encrypt returns: `b` encrypted using AES-128-CBC prepends `prefix` and appends `suffix` before encrypting """ cleaned_data = b.replace(b';', b"';'").replace(b'=', b"'='") plain = PKCS7Padding.apply(prefix + cleaned_data + suffix, blksize) cipher = AES.new(CONSISTENT_KEY, AES.MODE_ECB) cbc = CBCMode( blksize=blksize, encrypt_blk=cipher.encrypt, decrypt_blk=cipher.decrypt, iv=CONSISTENT_IV, ) return cbc.encrypt(plain)
def validate_ascii(encrypted: bytes) -> bytes: """ params: encrypted: message encrypted using `aes_cbc()` returns: decrypted bytes if they contain extended ascii characters, None otherwise """ cipher = AES.new(key, AES.MODE_ECB) cbc = CBCMode(blksize=blksize, encrypt_blk=cipher.encrypt, decrypt_blk=cipher.decrypt, iv=key) padded = cbc.decrypt(encrypted) decrypted = PKCS7Padding.unapply(padded) for c in decrypted: if c >= 128: return decrypted return None
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
def test_unapply_padding_value_larger_than_valid_raises(self): padded = b"YELLOW\x16\x16\x16" with self.assertRaises(InvalidPaddingException): PKCS7Padding.unapply(padded)
def test_unapply_padding_ending_with_zero_raises(self): padded = b"YELLOW\x00" with self.assertRaises(InvalidPaddingException): PKCS7Padding.unapply(padded)
def test_apply_negative_blksize_raises(self): b = b'YELLOW SUBMARINE' with self.assertRaises(InvalidPaddingException): PKCS7Padding.apply(b, -1)
def test_apply_blksize_over_bounds_raises(self): b = b'YELLOW SUBMARINE' with self.assertRaises(InvalidPaddingException): PKCS7Padding.apply(b, 256)
def test_apply_none_bytes_raises_typeerror(self): with self.assertRaises(TypeError): PKCS7Padding.apply(None, 1)
def test_unapply_padding_value_incosistent(self): padded = b"ICE ICE BABY\x01\x02\x03\x04" with self.assertRaises(InvalidPaddingException): PKCS7Padding.unapply(padded)
def test_unapply_padding_value_does_not_match_number_of_pads(self): padded = b"ICE ICE BABY\x05\x05\x05\x05" with self.assertRaises(InvalidPaddingException): PKCS7Padding.unapply(padded)