8
8
LocalCryptoMaterialsCache ,
9
9
StrictAwsKmsMasterKeyProvider ,
10
10
)
11
-
12
11
from aws_lambda_powertools .utilities .data_masking .provider import BaseProvider
13
12
from aws_lambda_powertools .shared .user_agent import register_feature_to_botocore_session
14
13
15
14
15
+ class ContextMismatchError (Exception ):
16
+ def __init__ (self , key ):
17
+ super ().__init__ (f"Encryption Context does not match expected value for key: { key } " )
18
+ self .key = key
19
+
20
+
16
21
class SingletonMeta (type ):
17
22
"""Metaclass to cache class instances to optimize encryption"""
18
23
@@ -32,27 +37,70 @@ def __call__(cls, *args, **provider_options):
32
37
33
38
34
39
class AwsEncryptionSdkProvider (BaseProvider ):
35
- cache = LocalCryptoMaterialsCache (CACHE_CAPACITY )
40
+ """
41
+ The AwsEncryptionSdkProvider is to be used as a Provider for the Datamasking class.
42
+ Example:
43
+ >>> data_masker = DataMasking(provider=AwsEncryptionSdkProvider(keys=[keyARN1, keyARN2,...,]))
44
+ >>> encrypted_data = data_masker.encrypt("a string")
45
+ "encrptedBase64String"
46
+ >>> decrypted_data = data_masker.decrypt(encrypted_data)
47
+ "a string"
48
+ """
49
+
36
50
session = botocore .session .Session ()
37
51
register_feature_to_botocore_session (session , "data-masking" )
38
52
39
- def __init__ (self , keys : List [str ], client : Optional [EncryptionSDKClient ] = None ):
53
+ def __init__ (
54
+ self ,
55
+ keys : List [str ],
56
+ client : Optional [EncryptionSDKClient ] = None ,
57
+ local_cache_capacity : Optional [int ] = CACHE_CAPACITY ,
58
+ max_cache_age_seconds : Optional [float ] = MAX_ENTRY_AGE_SECONDS ,
59
+ max_messages : Optional [int ] = MAX_MESSAGES ,
60
+ ):
40
61
self .client = client or EncryptionSDKClient ()
41
62
self .keys = keys
63
+ self .cache = LocalCryptoMaterialsCache (local_cache_capacity )
42
64
self .key_provider = StrictAwsKmsMasterKeyProvider (key_ids = self .keys , botocore_session = self .session )
43
65
self .cache_cmm = CachingCryptoMaterialsManager (
44
66
master_key_provider = self .key_provider ,
45
67
cache = self .cache ,
46
- max_age = MAX_ENTRY_AGE_SECONDS ,
47
- max_messages_encrypted = MAX_MESSAGES ,
68
+ max_age = max_cache_age_seconds ,
69
+ max_messages_encrypted = max_messages ,
48
70
)
49
71
50
72
def encrypt (self , data : Union [bytes , str ], ** provider_options ) -> str :
73
+ """
74
+ Encrypt data using the AwsEncryptionSdkProvider.
75
+
76
+ Parameters:
77
+ - data (Union[bytes, str]):
78
+ The data to be encrypted.
79
+ - provider_options:
80
+ Additional options for the aws_encryption_sdk.EncryptionSDKClient
81
+
82
+ Returns:
83
+ - ciphertext (str):
84
+ The encrypted data, as a base64-encoded string.
85
+ """
51
86
ciphertext , _ = self .client .encrypt (source = data , materials_manager = self .cache_cmm , ** provider_options )
52
87
ciphertext = base64 .b64encode (ciphertext ).decode ()
53
88
return ciphertext
54
89
55
90
def decrypt (self , data : str , ** provider_options ) -> bytes :
91
+ """
92
+ Decrypt data using AwsEncryptionSdkProvider.
93
+
94
+ Parameters:
95
+ - data (Union[bytes, str]):
96
+ The encrypted data, as a base64-encoded string.
97
+ - provider_options:
98
+ Additional options for the aws_encryption_sdk.EncryptionSDKClient
99
+
100
+ Returns:
101
+ - ciphertext (bytes):
102
+ The decrypted data in bytes
103
+ """
56
104
ciphertext_decoded = base64 .b64decode (data )
57
105
58
106
expected_context = provider_options .pop ("encryption_context" , {})
@@ -63,6 +111,6 @@ def decrypt(self, data: str, **provider_options) -> bytes:
63
111
64
112
for key , value in expected_context .items ():
65
113
if decryptor_header .encryption_context .get (key ) != value :
66
- raise ValueError ( f"Encryption Context does not match expected value for key: { key } " )
114
+ raise ContextMismatchError ( key )
67
115
68
116
return ciphertext
0 commit comments