def DecryptAES(cipher, key): """ not using the cooler equivalent inverse cause i don't want to make a different key schedule too """ if len(key) != 16: raise ValueError( "Key must be 16 bytes (for AES-128, I didn't implement others)") # get round keys round_keys = MakeRoundKeys(exp_key=KeyExpansion(key, Nk=4), rounds=11) # convert cipher to blocks cipher_blocks = [cipher[i:i + 16] for i in range(0, len(cipher), 16)] msg_blocks = [None] * len(cipher_blocks) for m in range(len(cipher_blocks)): state = cipher_blocks[m] h_state = ' '.join( [state.hex()[i:i + 2] for i in range(0, len(state.hex()), 2)]) # undo rounds 11-2 for r in range(10, 0, -1): state = AddRoundKey(state, round_keys[r]) h_state = ' '.join( [state.hex()[i:i + 2] for i in range(0, len(state.hex()), 2)]) if r != 10: state = InvMixColumns(state) h_state = ' '.join([ state.hex()[i:i + 2] for i in range(0, len(state.hex()), 2) ]) state = InvShiftRows(state) h_state = ' '.join( [state.hex()[i:i + 2] for i in range(0, len(state.hex()), 2)]) state = InvSubBytes(state) h_state = ' '.join( [state.hex()[i:i + 2] for i in range(0, len(state.hex()), 2)]) # undo round 1 state = AddRoundKey(state, round_keys[0]) h_state = ' '.join( [state.hex()[i:i + 2] for i in range(0, len(state.hex()), 2)]) msg_blocks[m] = state # unpad message return unpad(b''.join(msg_blocks))
def decrypt(self, ciphertext): # break plaintext into chunks cipher_blocks = [ ciphertext[i:i + 16] for i in range(0, len(ciphertext), 16) ] # initialize encrypted blocks msg_blocks = [None] * len(cipher_blocks) for m in range(0, len(cipher_blocks)): # use block cipher FIRST this time msg_blocks[m] = self._aes_cipher.decrypt(cipher_blocks[m]) # then xor prev CIPHERTEXT block if m == 0: msg_blocks[m] = xor(msg_blocks[m], self._iv) else: msg_blocks[m] = xor(msg_blocks[m], cipher_blocks[m - 1]) msg = unpad(b''.join(msg_blocks), 16).decode('ascii') return b''.join(msg_blocks).decode('ascii')
def decrypt(self, ciphertext): return unpad(self._aes_cipher.decrypt(ciphertext))
from s02_c09 import unpad if __name__ == '__main__': assert unpad("ICE ICE BABY\x04\x04\x04\x04") == "ICE ICE BABY" # should figure out how to unit test raised exceptions eventually unpad("ICE ICE BABY\x01\x02\x03\x04")