def test_aes_encrypt(self, mock_func): aes = AESCrypto() for item in AES_CBC_TEST_VECTORS: key = item['key'].decode('hex') iv = item['iv'].decode('hex') plain_text = item['plaintext'].decode('hex') expected_cipher_text = item['ciphertext'].decode('hex') mock_func.return_value = iv encrypted_with_iv_and_pad = aes.encrypt(key=key, data=plain_text) # Remove IV encrypted = encrypted_with_iv_and_pad[len(iv):] # Unpad encrypted = encrypted[:-len(plain_text)] self.assertEqual(encrypted, expected_cipher_text) # Also test round-trip decrypted = aes.decrypt(key=key, data=encrypted_with_iv_and_pad) self.assertEqual(decrypted, plain_text)
class HybridCryptoEncrypter(HybridCryptoMixin): """ Class which provides functionality for encrypting data using hybrid cryptosystem. """ def __init__(self, keys_path): """ :param keys_path: Path to the directory containg public keys. :type keys_path: ``str`` """ if not os.path.exists(keys_path): raise ValueError('Directory with public keys doesnt exist') self._keys_path = keys_path self._keyczar = Encrypter.Read(self._keys_path) self._aes = AESCrypto() def encrypt(self, data): """ Encrypt provided data. """ if len(data) > self.long_message_threshold: cipher_text = self._encrypt_long_message(data=data) else: cipher_text = self._encrypt_short_message(data=data) return cipher_text def _encrypt_short_message(self, data): """ Encrypt a short message using public-key cryptography. :param data: Data to encrypt. :type data: ``str`` """ header = 'hpkc' data = str(data) if len(data) > self.long_message_threshold: raise ValueError('Data is too long and cant be encrypted using ' 'PKC') cipher_text = header + self._keyczar.Encrypt(data) return cipher_text def _encrypt_long_message(self, data): """ Encrypt a long message using hybrid cryptography. Data is encrypted using the following approach: 1. Generate fresh symmetric AES key for the data encapsulation scheme 2. Encrypt provided data using data encapsulation scheme 3. Encrypt generates AES key using key encapsulation scheme (PKC) 4. Assemble a final message - header + pkc_encrypted_aes_key + delimiter + aes_encrypted_data :param data: Data to encrypt. :type data: ``str`` """ header = 'haes' # Generate a fresh symmetric key for the data encapsulation scheme aes_key = RandBytes(n=self.aes_key_size) aes_key = str(aes_key) # Encrypt message using data encapsulation scheme (AES) aes_cipher_text = self._aes.encrypt(key=aes_key, data=data) aes_cipher_text = Base64WSEncode(aes_cipher_text) # Encrypt AES key using key encapsulation scheme key_cipher_text = self._keyczar.Encrypt(aes_key) # Assemble a final message parts = [header, key_cipher_text, self.delimiter, aes_cipher_text] msg_cipher_text = ''.join(parts) return msg_cipher_text def _aes_encrypt(self, key, data): header = 'paes' cipher_text = self._aes.encrypt(key=key, data=data) msg_cipher_text = header + cipher_text return msg_cipher_text