class AESModeOfOperationCBC(AESBlockModeOfOperation): '''AES Cipher-Block Chaining Mode of Operation. o The Initialization Vector (IV) o Block-cipher, so data must be padded to 16 byte boundaries o An incorrect initialization vector will only cause the first block to be corrupt; all other blocks will be intact o A corrupt bit in the cipher text will cause a block to be corrupted, and the next block to be inverted, but all other blocks will be intact. Security Notes: o This method (and CTR) ARE recommended. Also see: o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher-block_chaining_.28CBC.29 o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.2''' name = "Cipher-Block Chaining (CBC)" def __init__(self, key, iv = None): if iv is None: self._last_cipherblock = [ 0 ] * 16 elif len(iv) != 16: raise ValueError('initialization vector must be 16 bytes') else: self._last_cipherblock = _string_to_bytes(iv) AESBlockModeOfOperation.__init__(self, key) def encrypt(self, plaintext): if len(plaintext) != 16: raise ValueError('plaintext block must be 16 bytes') plaintext = _string_to_bytes(plaintext) precipherblock = [ (p ^ l) for (p, l) in zip(plaintext, self._last_cipherblock) ] self._last_cipherblock = self._aes.encrypt(precipherblock) return _bytes_to_string(self._last_cipherblock) def decrypt(self, ciphertext): if len(ciphertext) != 16: raise ValueError('ciphertext block must be 16 bytes') cipherblock = _string_to_bytes(ciphertext) plaintext = [ (p ^ l) for (p, l) in zip(self._aes.decrypt(cipherblock), self._last_cipherblock) ] self._last_cipherblock = cipherblock return _bytes_to_string(plaintext)