def test_raw_master_key_decrypts_what_raw_keyring_encrypts( encryption_materials_samples): test_raw_rsa_keyring = RawRSAKeyring.from_pem_encoding( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=_WRAPPING_ALGORITHM, private_encoded_key=_PRIVATE_WRAPPING_KEY_PEM, public_encoded_key=_PUBLIC_WRAPPING_KEY_PEM, ) # Creating an instance of a raw master key test_raw_master_key = RawMasterKey( key_id=_KEY_ID, provider_id=_PROVIDER_ID, wrapping_key=WrappingKey( wrapping_algorithm=_WRAPPING_ALGORITHM, wrapping_key=_PRIVATE_WRAPPING_KEY_PEM, wrapping_key_type=EncryptionKeyType.PRIVATE, ), ) # Call on_encrypt function for the keyring encryption_materials = test_raw_rsa_keyring.on_encrypt( encryption_materials=encryption_materials_samples) # Check if plaintext data key encrypted by raw keyring is decrypted by raw master key raw_mkp_decrypted_data_key = test_raw_master_key.decrypt_data_key_from_list( encrypted_data_keys=encryption_materials._encrypted_data_keys, algorithm=encryption_materials.algorithm, encryption_context=encryption_materials.encryption_context, ).data_key assert encryption_materials.data_encryption_key.data_key == raw_mkp_decrypted_data_key
def raw_rsa_mkps_from_keyring(keyring): # type: (RawRSAKeyring) -> (MasterKeyProvider, MasterKeyProvider) """Constructs a private and public raw RSA MKP using the private key in the raw RSA keyring.""" private_key = keyring._private_wrapping_key private_pem = private_key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption(), ) public_pem = private_key.public_key().public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo) private_key_mkp = RawMasterKey( provider_id=keyring.key_namespace, key_id=keyring.key_name, wrapping_key=WrappingKey( wrapping_algorithm=keyring._wrapping_algorithm, wrapping_key=private_pem, wrapping_key_type=EncryptionKeyType.PRIVATE, ), ) public_key_mkp = RawMasterKey( provider_id=keyring.key_namespace, key_id=keyring.key_name, wrapping_key=WrappingKey( wrapping_algorithm=keyring._wrapping_algorithm, wrapping_key=public_pem, wrapping_key_type=EncryptionKeyType.PUBLIC, ), ) return private_key_mkp, public_key_mkp
def test_raw_master_key_decrypts_what_raw_keyring_encrypts( encryption_materials_samples): # Initializing attributes key_namespace = _PROVIDER_ID key_name = _KEY_ID # Creating an instance of a raw AES keyring test_raw_aes_keyring = RawAESKeyring( key_namespace=key_namespace, key_name=key_name, wrapping_key=_WRAPPING_KEY, ) # Creating an instance of a raw master key test_raw_master_key = RawMasterKey( key_id=test_raw_aes_keyring.key_name, provider_id=test_raw_aes_keyring.key_namespace, wrapping_key=test_raw_aes_keyring._wrapping_key_structure, ) # Encrypt using raw AES keyring encryption_materials = test_raw_aes_keyring.on_encrypt( encryption_materials=encryption_materials_samples) # Check if plaintext data key encrypted by raw keyring is decrypted by raw master key raw_mkp_decrypted_data_key = test_raw_master_key.decrypt_data_key_from_list( encrypted_data_keys=encryption_materials._encrypted_data_keys, algorithm=encryption_materials.algorithm, encryption_context=encryption_materials.encryption_context, ).data_key assert encryption_materials.data_encryption_key.data_key == raw_mkp_decrypted_data_key
def test_owns_data_key_owned_symmetric(self, mock_prefix): self.mock_wrapping_key.wrapping_algorithm = WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING test_master_key = RawMasterKey( key_id=VALUES['wrapped_keys']['raw']['key_info'], provider_id=VALUES['provider_id'], wrapping_key=self.mock_wrapping_key) assert test_master_key.owns_data_key( data_key=DataKey(key_provider=MasterKeyInfo( provider_id=VALUES['provider_id'], key_info=VALUES['wrapped_keys']['serialized']['key_info']), encrypted_data_key=VALUES['encrypted_data_key'], data_key=VALUES['data_key']))
def test_owns_data_key_not_owned_asymmetric_checking_symmetric(self): self.mock_wrapping_key.wrapping_algorithm = WrappingAlgorithm.RSA_OAEP_SHA1_MGF1 test_master_key = RawMasterKey( key_id=VALUES['wrapped_keys']['raw']['key_info'], provider_id=VALUES['provider_id'], wrapping_key=self.mock_wrapping_key) assert not test_master_key.owns_data_key( data_key=DataKey(key_provider=MasterKeyInfo( provider_id=VALUES['provider_id'], key_info=VALUES['wrapped_keys']['serialized']['key_info']), encrypted_data_key=VALUES['encrypted_data_key'], data_key=VALUES['data_key']))
def test_owns_data_key_not_owned_asymmetric_checking_symmetric(self): self.mock_wrapping_key.wrapping_algorithm = WrappingAlgorithm.RSA_OAEP_SHA1_MGF1 test_master_key = RawMasterKey( key_id=VALUES["wrapped_keys"]["raw"]["key_info"], provider_id=VALUES["provider_id"], wrapping_key=self.mock_wrapping_key, ) assert not test_master_key.owns_data_key(data_key=DataKey( key_provider=MasterKeyInfo(provider_id=VALUES["provider_id"], key_info=VALUES["wrapped_keys"] ["serialized"]["key_info"]), encrypted_data_key=VALUES["encrypted_data_key"], data_key=VALUES["data_key"], ))
def test_owns_data_key_owned_symmetric(self, mock_prefix): self.mock_wrapping_key.wrapping_algorithm = WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING test_master_key = RawMasterKey( key_id=VALUES["wrapped_keys"]["raw"]["key_info"], provider_id=VALUES["provider_id"], wrapping_key=self.mock_wrapping_key, ) assert test_master_key.owns_data_key(data_key=DataKey( key_provider=MasterKeyInfo(provider_id=VALUES["provider_id"], key_info=VALUES["wrapped_keys"] ["serialized"]["key_info"]), encrypted_data_key=VALUES["encrypted_data_key"], data_key=VALUES["data_key"], ))
def test_init(self): test = RawMasterKey( key_id=VALUES["wrapped_keys"]["raw"]["key_info"], provider_id=VALUES["provider_id"], wrapping_key=self.mock_wrapping_key, ) assert test.provider_id == VALUES["provider_id"]
def test_decrypt_data_key(self, mock_wrapped_deserialize): test_master_key = RawMasterKey( key_id=VALUES['wrapped_keys']['raw']['key_info'], provider_id=VALUES['provider_id'], wrapping_key=self.mock_wrapping_key) test = test_master_key._decrypt_data_key( encrypted_data_key=self.mock_encrypted_data_key, algorithm=self.mock_algorithm, encryption_context=sentinel.encryption_context) mock_wrapped_deserialize.assert_called_once_with( wrapping_algorithm=self.mock_wrapping_algorithm, wrapping_key_id=VALUES['wrapped_keys']['raw']['key_info'], wrapped_encrypted_key=self.mock_encrypted_data_key) self.mock_wrapping_key.decrypt.assert_called_once_with( encrypted_wrapped_data_key=sentinel.encrypted_wrapped_key, encryption_context=sentinel.encryption_context) assert test == self.mock_data_key
def test_generate_data_key(self, mock_encrypt_data_key, mock_urandom, mock_key_len_check): mock_urandom.return_value = VALUES['data_key'] mock_encrypt_data_key.return_value = self.mock_encrypted_data_key test_master_key = RawMasterKey( key_id=VALUES['wrapped_keys']['raw']['key_info'], provider_id=VALUES['provider_id'], wrapping_key=self.mock_wrapping_key) test = test_master_key.generate_data_key( algorithm=self.mock_algorithm, encryption_context=VALUES['encryption_context']) mock_urandom.assert_called_once_with(sentinel.kdf_input_len) mock_encrypt_data_key.assert_called_once_with( data_key=RawDataKey(key_provider=test_master_key.key_provider, data_key=VALUES['data_key']), algorithm=self.mock_algorithm, encryption_context=VALUES['encryption_context']) assert test == self.mock_data_key
def test_encrypt_data_key(self, mock_wrapped_serialize): test_master_key = RawMasterKey( key_id=VALUES['wrapped_keys']['raw']['key_info'], provider_id=VALUES['provider_id'], wrapping_key=self.mock_wrapping_key) test = test_master_key._encrypt_data_key( data_key=self.mock_data_key, algorithm=sentinel.algorithm, encryption_context=sentinel.encryption_context) self.mock_wrapping_key.encrypt.assert_called_once_with( plaintext_data_key=VALUES['data_key'], encryption_context=sentinel.encryption_context) mock_wrapped_serialize.assert_called_once_with( key_provider=test_master_key.key_provider, wrapping_algorithm=self.mock_wrapping_algorithm, wrapping_key_id=VALUES['wrapped_keys']['raw']['key_info'], encrypted_wrapped_key=sentinel.encrypted_data) assert test is sentinel.wrapped_key
def test_raw_keyring_decrypts_what_raw_master_key_encrypts( encryption_materials_samples): # Create instance of raw master key test_raw_master_key = RawMasterKey( key_id=_KEY_ID, provider_id=_PROVIDER_ID, wrapping_key=WrappingKey( wrapping_algorithm=_WRAPPING_ALGORITHM, wrapping_key=_PRIVATE_WRAPPING_KEY_PEM, wrapping_key_type=EncryptionKeyType.PRIVATE, ), ) test_raw_rsa_keyring = RawRSAKeyring.from_pem_encoding( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=_WRAPPING_ALGORITHM, private_encoded_key=_PRIVATE_WRAPPING_KEY_PEM, public_encoded_key=_PUBLIC_WRAPPING_KEY_PEM, ) raw_mkp_generated_data_key = test_raw_master_key.generate_data_key( algorithm=encryption_materials_samples.algorithm, encryption_context=encryption_materials_samples.encryption_context, ) raw_mkp_encrypted_data_key = test_raw_master_key.encrypt_data_key( data_key=raw_mkp_generated_data_key, algorithm=encryption_materials_samples.algorithm, encryption_context=encryption_materials_samples.encryption_context, ) decryption_materials = test_raw_rsa_keyring.on_decrypt( decryption_materials=DecryptionMaterials( algorithm=encryption_materials_samples.algorithm, encryption_context=encryption_materials_samples.encryption_context, verification_key=b"ex_verification_key", ), encrypted_data_keys=[raw_mkp_encrypted_data_key], ) assert raw_mkp_generated_data_key.data_key == decryption_materials.data_encryption_key.data_key
def test_key_info_prefix_vectors(wrapping_algorithm): assert (serialize_raw_master_key_prefix(raw_master_key=RawMasterKey( provider_id=_PROVIDER_ID, key_id=_KEY_ID, wrapping_key=WrappingKey( wrapping_algorithm=wrapping_algorithm, wrapping_key=_WRAPPING_KEY, wrapping_key_type=EncryptionKeyType.SYMMETRIC, ), )) == _KEY_ID + b"\x00\x00\x00\x80\x00\x00\x00\x0c")
def test_generate_data_key(self, mock_encrypt_data_key, mock_urandom, mock_key_len_check): mock_urandom.return_value = VALUES["data_key"] mock_encrypt_data_key.return_value = self.mock_encrypted_data_key test_master_key = RawMasterKey( key_id=VALUES["wrapped_keys"]["raw"]["key_info"], provider_id=VALUES["provider_id"], wrapping_key=self.mock_wrapping_key, ) test = test_master_key.generate_data_key( algorithm=self.mock_algorithm, encryption_context=VALUES["encryption_context"]) mock_urandom.assert_called_once_with(sentinel.kdf_input_len) mock_encrypt_data_key.assert_called_once_with( data_key=RawDataKey(key_provider=test_master_key.key_provider, data_key=VALUES["data_key"]), algorithm=self.mock_algorithm, encryption_context=VALUES["encryption_context"], ) assert test == self.mock_data_key
def test_encrypt_data_key(self, mock_wrapped_serialize): test_master_key = RawMasterKey( key_id=VALUES["wrapped_keys"]["raw"]["key_info"], provider_id=VALUES["provider_id"], wrapping_key=self.mock_wrapping_key, ) test = test_master_key._encrypt_data_key( data_key=self.mock_data_key, algorithm=sentinel.algorithm, encryption_context=sentinel.encryption_context) self.mock_wrapping_key.encrypt.assert_called_once_with( plaintext_data_key=VALUES["data_key"], encryption_context=sentinel.encryption_context) mock_wrapped_serialize.assert_called_once_with( key_provider=test_master_key.key_provider, wrapping_algorithm=self.mock_wrapping_algorithm, wrapping_key_id=VALUES["wrapped_keys"]["raw"]["key_info"], encrypted_wrapped_key=sentinel.encrypted_data, ) assert test is sentinel.wrapped_key
def test_raw_keyring_decrypts_what_raw_master_key_encrypts( encryption_materials_samples): # Initializing attributes key_namespace = _PROVIDER_ID key_name = _KEY_ID # Creating an instance of a raw AES keyring test_raw_aes_keyring = RawAESKeyring( key_namespace=key_namespace, key_name=key_name, wrapping_key=_WRAPPING_KEY, ) # Creating an instance of a raw master key test_raw_master_key = RawMasterKey( key_id=test_raw_aes_keyring.key_name, provider_id=test_raw_aes_keyring.key_namespace, wrapping_key=test_raw_aes_keyring._wrapping_key_structure, ) if encryption_materials_samples.data_encryption_key is None: return raw_master_key_encrypted_data_key = test_raw_master_key.encrypt_data_key( data_key=encryption_materials_samples.data_encryption_key, algorithm=encryption_materials_samples.algorithm, encryption_context=encryption_materials_samples.encryption_context, ) # Check if plaintext data key encrypted by raw master key is decrypted by raw keyring raw_aes_keyring_decrypted_data_key = test_raw_aes_keyring.on_decrypt( decryption_materials=DecryptionMaterials( algorithm=encryption_materials_samples.algorithm, encryption_context=encryption_materials_samples.encryption_context, verification_key=b"ex_verification_key", ), encrypted_data_keys=[raw_master_key_encrypted_data_key], ).data_encryption_key.data_key assert encryption_materials_samples.data_encryption_key.data_key == raw_aes_keyring_decrypted_data_key
def ephemeral_raw_rsa_master_key(size=4096): # type: (int) -> RawMasterKey key_bytes = _generate_rsa_key_bytes(size) return RawMasterKey( provider_id="fake", key_id="rsa-{}".format(size).encode("utf-8"), wrapping_key=WrappingKey( wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, wrapping_key=key_bytes, wrapping_key_type=EncryptionKeyType.PRIVATE, ), )
def _get_key_info_prefix(key_namespace, key_name, wrapping_key): # type: (str, bytes, WrappingKey) -> six.binary_type """Helper function to get key info prefix :param str key_namespace: String defining the keyring. :param bytes key_name: Key ID :param WrappingKey wrapping_key: Encryption key with which to wrap plaintext data key. :return: Serialized key_info prefix :rtype: bytes """ key_info_prefix = serialize_raw_master_key_prefix( RawMasterKey(provider_id=key_namespace, key_id=key_name, wrapping_key=wrapping_key)) return key_info_prefix
def _raw_master_key_from_spec(self, key_spec): # type: (KeySpec) -> RawMasterKey """Build a raw master key using this specification. :param KeySpec key_spec: Key specification to use with this master key :return: Raw master key based on this specification :rtype: RawMasterKey :raises TypeError: if this is not a raw master key specification """ if not self.type_name == "raw": raise TypeError("This is not a raw master key") wrapping_key = self._wrapping_key(key_spec) key_id = self._raw_key_id() return RawMasterKey(provider_id=self.provider_id, key_id=key_id, wrapping_key=wrapping_key)
def _keys_to_mkp(keys): if len(keys) > 1: return RawMultiMKP(valid_key_ids=[key["key_id"] for key in keys]) _key = keys[0] return RawMasterKey( provider_id=_PROVIDER_ID, key_id=_key["key_id"], wrapping_key=WrappingKey( wrapping_algorithm=WrappingAlgorithm. AES_256_GCM_IV12_TAG16_NO_PADDING, wrapping_key=_key["wrapping_key"], wrapping_key_type=EncryptionKeyType.SYMMETRIC, ), )
def ephemeral_raw_aes_master_key( wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, key=None): # type: (WrappingAlgorithm, Optional[bytes]) -> RawMasterKey key_length = wrapping_algorithm.algorithm.data_key_len if key is None: key = os.urandom(key_length) return RawMasterKey( provider_id="fake", key_id="aes-{}".format(key_length * 8).encode("utf-8"), wrapping_key=WrappingKey( wrapping_algorithm=wrapping_algorithm, wrapping_key=key, wrapping_key_type=EncryptionKeyType.SYMMETRIC, ), )
def run(source_plaintext): # type: (bytes) -> None """Demonstrate an encrypt/decrypt cycle using a raw AES master key. :param bytes source_plaintext: Plaintext to encrypt """ # Prepare your encryption context. # https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context encryption_context = { "encryption": "context", "is not": "secret", "but adds": "useful metadata", "that can help you": "be confident that", "the data you are handling": "is what you think it is", } # Choose the wrapping algorithm for your master key to use. wrapping_algorithm = WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING # Generate an AES key to use with your master key. # The key size depends on the wrapping algorithm. # # In practice, you should get this key from a secure key management system such as an HSM. key = os.urandom(wrapping_algorithm.algorithm.kdf_input_len) # Create the master key that determines how your data keys are protected. master_key = RawMasterKey( # The provider ID and key ID are defined by you # and are used by the raw AES master key # to determine whether it should attempt to decrypt # an encrypted data key. provider_id= "some managed raw keys", # provider ID corresponds to key namespace for keyrings key_id= b"my AES wrapping key", # key ID corresponds to key name for keyrings wrapping_key=WrappingKey( wrapping_algorithm=wrapping_algorithm, wrapping_key_type=EncryptionKeyType.SYMMETRIC, wrapping_key=key, ), ) # Encrypt your plaintext data. ciphertext, _encrypt_header = aws_encryption_sdk.encrypt( source=source_plaintext, encryption_context=encryption_context, key_provider=master_key) # Demonstrate that the ciphertext and plaintext are different. assert ciphertext != source_plaintext # Decrypt your encrypted data using the same master key you used on encrypt. # # You do not need to specify the encryption context on decrypt # because the header of the encrypted message includes the encryption context. decrypted, decrypt_header = aws_encryption_sdk.decrypt( source=ciphertext, key_provider=master_key) # Demonstrate that the decrypted plaintext is identical to the original plaintext. assert decrypted == source_plaintext # Verify that the encryption context used in the decrypt operation includes # the encryption context that you specified when encrypting. # The AWS Encryption SDK can add pairs, so don't require an exact match. # # In production, always use a meaningful encryption context. assert set(encryption_context.items()) <= set( decrypt_header.encryption_context.items())
def test_init(self): test = RawMasterKey(key_id=VALUES['wrapped_keys']['raw']['key_info'], provider_id=VALUES['provider_id'], wrapping_key=self.mock_wrapping_key) assert test.provider_id == VALUES['provider_id']
def run(aws_kms_cmk, source_plaintext): # type: (str, bytes) -> None """Demonstrate configuring a master key provider to use an AWS KMS CMK and an RSA wrapping key. :param str aws_kms_cmk: The ARN of an AWS KMS CMK that protects data keys :param bytes source_plaintext: Plaintext to encrypt """ # Prepare your encryption context. # Remember that your encryption context is NOT SECRET. # https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context encryption_context = { "encryption": "context", "is not": "secret", "but adds": "useful metadata", "that can help you": "be confident that", "the data you are handling": "is what you think it is", } # Generate an RSA private key to use with your master key. # In practice, you should get this key from a secure key management system such as an HSM. # # The National Institute of Standards and Technology (NIST) recommends a minimum of 2048-bit keys for RSA. # https://www.nist.gov/publications/transitioning-use-cryptographic-algorithms-and-key-lengths # # Why did we use this public exponent? # https://crypto.stanford.edu/~dabo/pubs/papers/RSA-survey.pdf private_key = rsa.generate_private_key(public_exponent=65537, key_size=4096, backend=default_backend()) # Serialize the RSA private key to PEM encoding. # This or DER encoding is likely to be what you get from your key management system in practice. private_key_pem = private_key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption(), ) # Collect the public key from the private key. public_key = private_key.public_key() # Serialize the RSA public key to PEM encoding. # This or DER encoding is likely to be what you get from your key management system in practice. public_key_pem = public_key.public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo, ) # Create the encrypt master key that only has access to the public key. escrow_encrypt_master_key = RawMasterKey( # The provider ID and key ID are defined by you # and are used by the raw RSA master key # to determine whether it should attempt to decrypt # an encrypted data key. provider_id= "some managed raw keys", # provider ID corresponds to key namespace for keyrings key_id= b"my RSA wrapping key", # key ID corresponds to key name for keyrings wrapping_key=WrappingKey( wrapping_key=public_key_pem, wrapping_key_type=EncryptionKeyType.PUBLIC, # The wrapping algorithm tells the raw RSA master key # how to use your wrapping key to encrypt data keys. # # We recommend using RSA_OAEP_SHA256_MGF1. # You should not use RSA_PKCS1 unless you require it for backwards compatibility. wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, ), ) # Create the decrypt master key that has access to the private key. escrow_decrypt_master_key = RawMasterKey( # The key namespace and key name MUST match the encrypt master key. provider_id= "some managed raw keys", # provider ID corresponds to key namespace for keyrings key_id= b"my RSA wrapping key", # key ID corresponds to key name for keyrings wrapping_key=WrappingKey( wrapping_key=private_key_pem, wrapping_key_type=EncryptionKeyType.PRIVATE, # The wrapping algorithm MUST match the encrypt master key. wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, ), ) # Create the AWS KMS master key that you will use for decryption during normal operations. kms_master_key = KMSMasterKeyProvider(key_ids=[aws_kms_cmk]) # Add the escrow encrypt master key to the AWS KMS master key. kms_master_key.add_master_key_provider(escrow_encrypt_master_key) # Encrypt your plaintext data using the combined master keys. ciphertext, encrypt_header = aws_encryption_sdk.encrypt( source=source_plaintext, encryption_context=encryption_context, key_provider=kms_master_key) # Verify that the header contains the expected number of encrypted data keys (EDKs). # It should contain one EDK for AWS KMS and one for the escrow key. assert len(encrypt_header.encrypted_data_keys) == 2 # Demonstrate that the ciphertext and plaintext are different. assert ciphertext != source_plaintext # Decrypt your encrypted data separately using the AWS KMS master key and the escrow decrypt master key. # # You do not need to specify the encryption context on decrypt # because the header of the encrypted message includes the encryption context. decrypted_kms, decrypt_header_kms = aws_encryption_sdk.decrypt( source=ciphertext, key_provider=kms_master_key) decrypted_escrow, decrypt_header_escrow = aws_encryption_sdk.decrypt( source=ciphertext, key_provider=escrow_decrypt_master_key) # Demonstrate that the decrypted plaintext is identical to the original plaintext. assert decrypted_kms == source_plaintext assert decrypted_escrow == source_plaintext # Verify that the encryption context used in the decrypt operation includes # the encryption context that you specified when encrypting. # The AWS Encryption SDK can add pairs, so don't require an exact match. # # In production, always use a meaningful encryption context. assert set(encryption_context.items()) <= set( decrypt_header_kms.encryption_context.items()) assert set(encryption_context.items()) <= set( decrypt_header_escrow.encryption_context.items())
def run(source_plaintext): # type: (bytes) -> None """Demonstrate an encrypt/decrypt cycle using a raw RSA master key loaded from a PEM-encoded key. :param bytes source_plaintext: Plaintext to encrypt """ # Prepare your encryption context. # Remember that your encryption context is NOT SECRET. # https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context encryption_context = { "encryption": "context", "is not": "secret", "but adds": "useful metadata", "that can help you": "be confident that", "the data you are handling": "is what you think it is", } # Generate an RSA private key to use with your master key. # In practice, you should get this key from a secure key management system such as an HSM. # # The National Institute of Standards and Technology (NIST) recommends a minimum of 2048-bit keys for RSA. # https://www.nist.gov/publications/transitioning-use-cryptographic-algorithms-and-key-lengths # # Why did we use this public exponent? # https://crypto.stanford.edu/~dabo/pubs/papers/RSA-survey.pdf private_key = rsa.generate_private_key(public_exponent=65537, key_size=4096, backend=default_backend()) # Serialize the RSA private key to PEM encoding. # This or DER encoding is likely to be what you get from your key management system in practice. private_key_pem = private_key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption(), ) # Create the master key that determines how your data keys are protected. # # WrappingKey can only load PEM-encoded keys. master_key = RawMasterKey( # The provider ID and key ID are defined by you # and are used by the raw RSA master key # to determine whether it should attempt to decrypt # an encrypted data key. provider_id= "some managed raw keys", # provider ID corresponds to key namespace for keyrings key_id= b"my RSA wrapping key", # key ID corresponds to key name for keyrings wrapping_key=WrappingKey( wrapping_key=private_key_pem, wrapping_key_type=EncryptionKeyType.PRIVATE, # The wrapping algorithm tells the raw RSA master key # how to use your wrapping key to encrypt data keys. # # We recommend using RSA_OAEP_SHA256_MGF1. # You should not use RSA_PKCS1 unless you require it for backwards compatibility. wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, ), ) # Encrypt your plaintext data. ciphertext, _encrypt_header = aws_encryption_sdk.encrypt( source=source_plaintext, encryption_context=encryption_context, key_provider=master_key) # Demonstrate that the ciphertext and plaintext are different. assert ciphertext != source_plaintext # Decrypt your encrypted data using the same master key you used on encrypt. # # You do not need to specify the encryption context on decrypt # because the header of the encrypted message includes the encryption context. decrypted, decrypt_header = aws_encryption_sdk.decrypt( source=ciphertext, key_provider=master_key) # Demonstrate that the decrypted plaintext is identical to the original plaintext. assert decrypted == source_plaintext # Verify that the encryption context used in the decrypt operation includes # the encryption context that you specified when encrypting. # The AWS Encryption SDK can add pairs, so don't require an exact match. # # In production, always use a meaningful encryption context. assert set(encryption_context.items()) <= set( decrypt_header.encryption_context.items())