def on_encrypt(self, encryption_materials): # type: (EncryptionMaterials) -> EncryptionMaterials trace_info = MasterKeyInfo(provider_id=KEY_NAMESPACE, key_info=self._key_id) new_materials = encryption_materials try: if new_materials.data_encryption_key is None: plaintext_key, encrypted_key = _do_aws_kms_generate_data_key( client_supplier=self._client_supplier, key_name=self._key_id, encryption_context=new_materials.encryption_context, algorithm=new_materials.algorithm, grant_tokens=self._grant_tokens, ) new_materials = new_materials.with_data_encryption_key( data_encryption_key=plaintext_key, keyring_trace=KeyringTrace(wrapping_key=trace_info, flags=_GENERATE_FLAGS), ) else: encrypted_key = _do_aws_kms_encrypt( client_supplier=self._client_supplier, key_name=self._key_id, plaintext_data_key=new_materials.data_encryption_key, encryption_context=new_materials.encryption_context, grant_tokens=self._grant_tokens, ) except Exception: # pylint: disable=broad-except # We intentionally WANT to catch all exceptions here message = "Unable to generate or encrypt data key using {}".format(trace_info) _LOGGER.exception(message) raise EncryptKeyError(message) return new_materials.with_encrypted_data_key( encrypted_data_key=encrypted_key, keyring_trace=KeyringTrace(wrapping_key=trace_info, flags=_ENCRYPT_FLAGS) )
def _try_aws_kms_decrypt(client_supplier, decryption_materials, grant_tokens, encrypted_data_key): # type: (ClientSupplierType, DecryptionMaterials, Iterable[str], EncryptedDataKey) -> DecryptionMaterials """Attempt to call ``kms:Decrypt`` and return the resulting plaintext data key. Any errors encountered are caught and logged. .. versionadded:: 1.5.0 """ try: plaintext_key = _do_aws_kms_decrypt( client_supplier=client_supplier, key_name=encrypted_data_key.key_provider.key_info.decode("utf-8"), encrypted_data_key=encrypted_data_key, encryption_context=decryption_materials.encryption_context, grant_tokens=grant_tokens, ) except Exception: # pylint: disable=broad-except # We intentionally WANT to catch all exceptions here _LOGGER.exception("Unable to decrypt encrypted data key from %s", encrypted_data_key.key_provider) return decryption_materials return decryption_materials.with_data_encryption_key( data_encryption_key=plaintext_key, keyring_trace=KeyringTrace(wrapping_key=encrypted_data_key.key_provider, flags=_DECRYPT_FLAGS), )
def _generate_data_key( encryption_materials, # type: EncryptionMaterials key_provider, # type: MasterKeyInfo ): # type: (...) -> EncryptionMaterials """Generates plaintext data key for the keyring. :param EncryptionMaterials encryption_materials: Encryption materials for the keyring to modify. :param MasterKeyInfo key_provider: Information about the key in the keyring. :rtype: EncryptionMaterials :returns: Encryption materials containing a data encryption key """ # Check if encryption materials contain data encryption key if encryption_materials.data_encryption_key is not None: raise TypeError("Data encryption key already exists.") # Generate data key try: plaintext_data_key = os.urandom( encryption_materials.algorithm.kdf_input_len) except Exception: # pylint: disable=broad-except error_message = "Unable to generate data encryption key." _LOGGER.exception(error_message) raise GenerateKeyError("Unable to generate data encryption key.") # Create a keyring trace keyring_trace = KeyringTrace(wrapping_key=key_provider, flags={KeyringTraceFlag.GENERATED_DATA_KEY}) # plaintext_data_key to RawDataKey data_encryption_key = RawDataKey(key_provider=key_provider, data_key=plaintext_data_key) return encryption_materials.with_data_encryption_key( data_encryption_key=data_encryption_key, keyring_trace=keyring_trace)
def get_encryption_materials_with_encrypted_data_key(): return EncryptionMaterials( algorithm=AlgorithmSuite.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, data_encryption_key=RawDataKey( key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_EXISTING_KEY_ID), data_key= b'*!\xa1"^-(\xf3\x105\x05i@B\xc2\xa2\xb7\xdd\xd5\xd5\xa9\xddm\xfae\xa8\\$\xf9d\x1e(', ), encrypted_data_keys=[ EncryptedDataKey( key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_EXISTING_KEY_ID), encrypted_data_key= b"\xde^\x97\x7f\x84\xe9\x9e\x98\xd0\xe2\xf8\xd5\xcb\xe9\x7f.}\x87\x16,\x11n#\xc8p" b"\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\x07FzE\xde", ) ], encryption_context=_ENCRYPTION_CONTEXT, signing_key=_SIGNING_KEY, keyring_trace=[ KeyringTrace( wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_EXISTING_KEY_ID), flags={ KeyringTraceFlag.GENERATED_DATA_KEY, KeyringTraceFlag.ENCRYPTED_DATA_KEY }, ) ], )
def sample_encryption_materials(): return [ EncryptionMaterials( algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, encryption_context=_ENCRYPTION_CONTEXT, signing_key=_SIGNING_KEY, ), EncryptionMaterials( algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, data_encryption_key=RawDataKey( key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), data_key= b'*!\xa1"^-(\xf3\x105\x05i@B\xc2\xa2\xb7\xdd\xd5\xd5\xa9\xddm\xfae\xa8\\$\xf9d\x1e(', ), encryption_context=_ENCRYPTION_CONTEXT, signing_key=_SIGNING_KEY, keyring_trace=[ KeyringTrace( wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), flags={KeyringTraceFlag.GENERATED_DATA_KEY}, ) ], ), ]
def on_decrypt(self, decryption_materials, encrypted_data_keys): # type: (DecryptionMaterials, Iterable[EncryptedDataKey]) -> DecryptionMaterials """Attempt to decrypt the encrypted data keys. :param DecryptionMaterials decryption_materials: Decryption materials for keyring to modify. :param encrypted_data_keys: List of encrypted data keys. :type: List[EncryptedDataKey] :returns: Decryption materials that MAY include a plaintext data key :rtype: DecryptionMaterials """ new_materials = decryption_materials if new_materials.data_encryption_key is not None: return new_materials if self._private_wrapping_key is None: return new_materials # Decrypt data key for key in encrypted_data_keys: if key.key_provider != self._key_provider: continue # Wrapped EncryptedDataKey to deserialized EncryptedData encrypted_wrapped_key = deserialize_wrapped_key( wrapping_algorithm=self._wrapping_algorithm, wrapping_key_id=self.key_name, wrapped_encrypted_key=key) try: plaintext_data_key = self._private_wrapping_key.decrypt( ciphertext=encrypted_wrapped_key.ciphertext, padding=self._wrapping_algorithm.padding) except Exception: # pylint: disable=broad-except error_message = "Raw RSA Keyring unable to decrypt data key" _LOGGER.exception(error_message) # The Raw RSA keyring MUST evaluate every encrypted data key # until it either succeeds or runs out of encrypted data keys. continue # Create a keyring trace keyring_trace = KeyringTrace( wrapping_key=self._key_provider, flags={KeyringTraceFlag.DECRYPTED_DATA_KEY}) # Update decryption materials data_encryption_key = RawDataKey(key_provider=self._key_provider, data_key=plaintext_data_key) return new_materials.with_data_encryption_key( data_encryption_key=data_encryption_key, keyring_trace=keyring_trace) return new_materials
def on_encrypt(self, encryption_materials): # type: (EncryptionMaterials) -> EncryptionMaterials """Generate a data key using generator keyring and encrypt it using any available wrapping key in any child keyring. :param EncryptionMaterials encryption_materials: Encryption materials for keyring to modify. :returns: Encryption materials containing data key and encrypted data key :rtype: EncryptionMaterials """ new_materials = encryption_materials if new_materials.data_encryption_key is None: new_materials = _generate_data_key( encryption_materials=new_materials, key_provider=self._key_provider) if self._public_wrapping_key is None: # This should be impossible, but just in case, give a useful error message. raise EncryptKeyError( "Raw RSA keyring unable to encrypt data key: no public key available" ) try: # Encrypt data key encrypted_wrapped_key = EncryptedData( iv=None, ciphertext=self._public_wrapping_key.encrypt( plaintext=new_materials.data_encryption_key.data_key, padding=self._wrapping_algorithm.padding, ), tag=None, ) # EncryptedData to EncryptedDataKey encrypted_data_key = serialize_wrapped_key( key_provider=self._key_provider, wrapping_algorithm=self._wrapping_algorithm, wrapping_key_id=self.key_name, encrypted_wrapped_key=encrypted_wrapped_key, ) except Exception: # pylint: disable=broad-except error_message = "Raw RSA keyring unable to encrypt data key" _LOGGER.exception(error_message) raise EncryptKeyError(error_message) # Update Keyring Trace keyring_trace = KeyringTrace( wrapping_key=self._key_provider, flags={KeyringTraceFlag.ENCRYPTED_DATA_KEY}) # Add encrypted data key to encryption_materials return new_materials.with_encrypted_data_key( encrypted_data_key=encrypted_data_key, keyring_trace=keyring_trace)
def on_encrypt(self, encryption_materials): # type: (EncryptionMaterials) -> EncryptionMaterials if encryption_materials.data_encryption_key is None: key_provider = MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID) data_encryption_key = RawDataKey( key_provider=key_provider, data_key=os.urandom( encryption_materials.algorithm.kdf_input_len)) encryption_materials = encryption_materials.with_data_encryption_key( data_encryption_key=data_encryption_key, keyring_trace=KeyringTrace( wrapping_key=key_provider, flags={KeyringTraceFlag.GENERATED_DATA_KEY}), ) return encryption_materials
def on_encrypt(self, encryption_materials): # type: (EncryptionMaterials) -> EncryptionMaterials """Generate a data key if not present and encrypt it using any available wrapping key :param EncryptionMaterials encryption_materials: Encryption materials for the keyring to modify :returns: Encryption materials containing data key and encrypted data key :rtype: EncryptionMaterials """ new_materials = encryption_materials if new_materials.data_encryption_key is None: # Get encryption materials with a new data key. new_materials = _generate_data_key( encryption_materials=new_materials, key_provider=self._key_provider) try: # Encrypt data key encrypted_wrapped_key = self._wrapping_key_structure.encrypt( plaintext_data_key=new_materials.data_encryption_key.data_key, encryption_context=new_materials.encryption_context, ) # EncryptedData to EncryptedDataKey encrypted_data_key = serialize_wrapped_key( key_provider=self._key_provider, wrapping_algorithm=self._wrapping_algorithm, wrapping_key_id=self.key_name, encrypted_wrapped_key=encrypted_wrapped_key, ) except Exception: # pylint: disable=broad-except error_message = "Raw AES keyring unable to encrypt data key" _LOGGER.exception(error_message) raise EncryptKeyError(error_message) # Update Keyring Trace keyring_trace = KeyringTrace( wrapping_key=self._key_provider, flags={ KeyringTraceFlag.ENCRYPTED_DATA_KEY, KeyringTraceFlag.SIGNED_ENCRYPTION_CONTEXT }, ) return new_materials.with_encrypted_data_key( encrypted_data_key=encrypted_data_key, keyring_trace=keyring_trace)
def get_decryption_materials_with_data_encryption_key(): return DecryptionMaterials( algorithm=AlgorithmSuite.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, data_encryption_key=RawDataKey( key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_EXISTING_KEY_ID), data_key= b'*!\xa1"^-(\xf3\x105\x05i@B\xc2\xa2\xb7\xdd\xd5\xd5\xa9\xddm\xfae\xa8\\$\xf9d\x1e(', ), encryption_context=_ENCRYPTION_CONTEXT, verification_key=b"ex_verification_key", keyring_trace=[ KeyringTrace( wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_EXISTING_KEY_ID), flags={KeyringTraceFlag.DECRYPTED_DATA_KEY}, ) ], )
_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY = EncryptionMaterials( algorithm=ALGORITHM, encryption_context=_ENCRYPTION_CONTEXT) _ENCRYPTION_MATERIALS_WITH_DATA_KEY = EncryptionMaterials( algorithm=ALGORITHM, data_encryption_key=RawDataKey( key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), data_key= b'*!\xa1"^-(\xf3\x105\x05i@B\xc2\xa2\xb7\xdd\xd5\xd5\xa9\xddm\xfae\xa8\\$\xf9d\x1e(', ), encryption_context=_ENCRYPTION_CONTEXT, keyring_trace=[ KeyringTrace( wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), flags={KeyringTraceFlag.GENERATED_DATA_KEY}, ) ], ) _MULTI_KEYRING_WITH_GENERATOR_AND_CHILDREN = MultiKeyring( generator=RawAESKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_key=_WRAPPING_KEY_AES, ), children=[ RawRSAKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID,
def on_decrypt(self, decryption_materials, encrypted_data_keys): # type: (DecryptionMaterials, Iterable[EncryptedDataKey]) -> DecryptionMaterials """Attempt to decrypt the encrypted data keys. :param DecryptionMaterials decryption_materials: Decryption materials for the keyring to modify :param List[EncryptedDataKey] encrypted_data_keys: List of encrypted data keys :returns: Decryption materials that MAY include a plaintext data key :rtype: DecryptionMaterials """ new_materials = decryption_materials if new_materials.data_encryption_key is not None: return new_materials # Decrypt data key expected_key_info_len = len( self._key_info_prefix) + self._wrapping_algorithm.algorithm.iv_len for key in encrypted_data_keys: if (key.key_provider.provider_id != self._key_provider.provider_id or len(key.key_provider.key_info) != expected_key_info_len or not key.key_provider.key_info.startswith( self._key_info_prefix)): continue # Wrapped EncryptedDataKey to deserialized EncryptedData encrypted_wrapped_key = deserialize_wrapped_key( wrapping_algorithm=self._wrapping_algorithm, wrapping_key_id=self.key_name, wrapped_encrypted_key=key) # EncryptedData to raw key string try: plaintext_data_key = self._wrapping_key_structure.decrypt( encrypted_wrapped_data_key=encrypted_wrapped_key, encryption_context=new_materials.encryption_context, ) except Exception: # pylint: disable=broad-except # We intentionally WANT to catch all exceptions here error_message = "Raw AES Keyring unable to decrypt data key" _LOGGER.exception(error_message) # The Raw AES keyring MUST evaluate every encrypted data key # until it either succeeds or runs out of encrypted data keys. continue # Create a keyring trace keyring_trace = KeyringTrace( wrapping_key=self._key_provider, flags={ KeyringTraceFlag.DECRYPTED_DATA_KEY, KeyringTraceFlag.VERIFIED_ENCRYPTION_CONTEXT }, ) # Update decryption materials data_encryption_key = RawDataKey(key_provider=self._key_provider, data_key=plaintext_data_key) return new_materials.with_data_encryption_key( data_encryption_key=data_encryption_key, keyring_trace=keyring_trace) return new_materials