def _generate_data_key(self, algorithm, encryption_context=None): """Generates data key and returns plaintext and ciphertext of key. :param algorithm: Algorithm on which to base data key :type algorithm: aws_encryption_sdk.identifiers.Algorithm :param dict encryption_context: Encryption context to pass to KMS :returns: Generated data key :rtype: aws_encryption_sdk.structures.DataKey """ kms_params = { "KeyId": self._key_id, "NumberOfBytes": algorithm.kdf_input_len } if encryption_context is not None: kms_params["EncryptionContext"] = encryption_context if self.config.grant_tokens: kms_params["GrantTokens"] = self.config.grant_tokens # Catch any boto3 errors and normalize to expected EncryptKeyError try: response = self.config.client.generate_data_key(**kms_params) plaintext = response["Plaintext"] ciphertext = response["CiphertextBlob"] key_id = response["KeyId"] except (ClientError, KeyError): error_message = "Master Key {key_id} unable to generate data key".format( key_id=self._key_id) _LOGGER.exception(error_message) raise GenerateKeyError(error_message) return DataKey( key_provider=MasterKeyInfo(provider_id=self.provider_id, key_info=key_id), data_key=plaintext, encrypted_data_key=ciphertext, )
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 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: Optionally modified encryption materials. :rtype: EncryptionMaterials :raises EncryptKeyError: if unable to encrypt data key. """ # Check if generator keyring is not provided and data key is not generated if self.generator is None and encryption_materials.data_encryption_key is None: raise EncryptKeyError( "Generator keyring not provided " "and encryption materials do not already contain a plaintext data key." ) new_materials = encryption_materials # Call on_encrypt on the generator keyring if it is provided if self.generator is not None: new_materials = self.generator.on_encrypt( encryption_materials=new_materials) # Check if data key is generated if new_materials.data_encryption_key is None: raise GenerateKeyError("Unable to generate data encryption key.") # Call on_encrypt on all other keyrings for keyring in self.children: new_materials = keyring.on_encrypt( encryption_materials=new_materials) return new_materials
def _generate_data_key(self, algorithm, encryption_context=None): """Generates data key and returns plaintext and ciphertext of key. :param algorithm: Algorithm on which to base data key :type algorithm: aws_encryption_sdk.identifiers.Algorithm :param dict encryption_context: Encryption context to pass to KMS :returns: Generated data key :rtype: aws_encryption_sdk.structures.DataKey """ kms_params = self._build_generate_data_key_request( algorithm, encryption_context) # Catch any boto3 errors and normalize to expected EncryptKeyError try: response = self.config.client.generate_data_key(**kms_params) # //= compliance/framework/aws-kms/aws-kms-mrk-aware-master-key.txt#2.10 # //# The response's "Plaintext" MUST be the plaintext in the output. plaintext = response["Plaintext"] # //= compliance/framework/aws-kms/aws-kms-mrk-aware-master-key.txt#2.10 # //# The response's cipher text blob MUST be used as the returned as the # //# ciphertext for the encrypted data key in the output. ciphertext = response["CiphertextBlob"] key_id = response["KeyId"] except (ClientError, KeyError): error_message = "Master Key {key_id} unable to generate data key".format( key_id=self._key_id) _LOGGER.exception(error_message) raise GenerateKeyError(error_message) # //= compliance/framework/aws-kms/aws-kms-mrk-aware-master-key.txt#2.10 # //# The response's "KeyId" MUST be valid. # arn_from_str will error if given an invalid key ARN try: key_id_str = to_str(key_id) arn_from_str(key_id_str) except MalformedArnError: error_message = "Retrieved an unexpected KeyID in response from KMS: {key_id}".format( key_id=key_id) _LOGGER.exception(error_message) raise GenerateKeyError(error_message) return DataKey( key_provider=MasterKeyInfo(provider_id=self.provider_id, key_info=key_id), data_key=plaintext, encrypted_data_key=ciphertext, )