Skip to content

Commit f1fca97

Browse files
committed
chore(migration examples): added KMS, raw AES and raw RSA keyring/MKP examples
1 parent ebbc26b commit f1fca97

9 files changed

+970
-1
lines changed
Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
"""
4+
This is a migration example for moving to the AWS KMS Keyring from AWS KMS master key provider (MKP)
5+
6+
The AWS KMS keyring uses symmetric encryption KMS keys to generate, encrypt and
7+
decrypt data keys. This example defines classes for KMS Keyring and KMS MKP and
8+
then encrypts a custom input EXAMPLE_DATA with an encryption context using both
9+
the keyring and MKP. The example then decrypts the ciphertext using both keyring and MKPs.
10+
This example also includes some sanity checks for demonstration:
11+
1. Decryption of these ciphertexts encrypted using keyring and MKP
12+
is possible using both KMS keyring and KMS MKP
13+
2. Both decrypted plaintexts are same and match EXAMPLE_DATA
14+
These sanity checks are for demonstration in the example only. You do not need these in your code.
15+
16+
Note: The ciphertexts obtained by encrypting EXAMPLE_DATA using keyring and MKP are not
17+
the same because the ESDK generates different data keys each time for encryption of the data.
18+
But both ciphertexts when decrypted using keyring and MKP should give the same plaintext result.
19+
20+
For more information on how to use KMS keyrings, see
21+
https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/use-kms-keyring.html
22+
"""
23+
24+
import boto3
25+
from aws_cryptographic_materialproviders.mpl import AwsCryptographicMaterialProviders
26+
from aws_cryptographic_materialproviders.mpl.config import MaterialProvidersConfig
27+
from aws_cryptographic_materialproviders.mpl.models import CreateAwsKmsKeyringInput
28+
from aws_cryptographic_materialproviders.mpl.references import IKeyring
29+
from typing import Dict # noqa pylint: disable=wrong-import-order
30+
31+
import aws_encryption_sdk
32+
33+
EXAMPLE_DATA: bytes = b"Hello World"
34+
35+
DEFAULT_ENCRYPTION_CONTEXT : Dict[str, str] = {
36+
"encryption": "context",
37+
"is not": "secret",
38+
"but adds": "useful metadata",
39+
"that can help you": "be confident that",
40+
"the data you are handling": "is what you think it is",
41+
}
42+
43+
44+
class AwsKmsKeyring():
45+
"""Class for creating a KMS Keyring and using it for encryption and decryption"""
46+
47+
@staticmethod
48+
def create_kms_client(aws_region="us-west-2"):
49+
"""Create an AWS KMS client.
50+
51+
Usage: create_kms_client(aws_region)
52+
:param aws_region: AWS region to use for KMS client.
53+
:type aws_region: string
54+
"""
55+
# Create a boto3 client for KMS.
56+
kms_client = boto3.client('kms', region_name=aws_region)
57+
58+
return kms_client
59+
60+
@staticmethod
61+
def create_keyring(
62+
kms_key_id: str
63+
):
64+
"""Demonstrate how to create an AWS KMS keyring.
65+
66+
Usage: create_keyring(kms_key_id)
67+
:param kms_key_id: KMS Key identifier for the KMS key you want to use.
68+
:type kms_key_id: string
69+
70+
For more information on KMS Key identifiers, see
71+
https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#key-id
72+
"""
73+
# Create a boto3 client for KMS.
74+
kms_client = AwsKmsKeyring.create_kms_client()
75+
76+
# Create a KMS keyring
77+
mat_prov: AwsCryptographicMaterialProviders = AwsCryptographicMaterialProviders(
78+
config=MaterialProvidersConfig()
79+
)
80+
81+
keyring_input: CreateAwsKmsKeyringInput = CreateAwsKmsKeyringInput(
82+
kms_key_id=kms_key_id,
83+
kms_client=kms_client
84+
)
85+
86+
keyring: IKeyring = mat_prov.create_aws_kms_keyring(
87+
input=keyring_input
88+
)
89+
90+
return keyring
91+
92+
@staticmethod
93+
def encrypt_using_keyring(
94+
plaintext_data: bytes,
95+
keyring: IKeyring
96+
):
97+
"""Demonstrate how to encrypt plaintext data using an AWS KMS keyring.
98+
99+
Usage: encrypt_using_keyring(plaintext_data, keyring)
100+
:param plaintext_data: plaintext data you want to encrypt
101+
:type: bytes
102+
:param keyring: Keyring to use for encryption.
103+
:type keyring: IKeyring
104+
"""
105+
client = aws_encryption_sdk.EncryptionSDKClient()
106+
107+
ciphertext_data, _ = client.encrypt(
108+
source=plaintext_data,
109+
keyring=keyring,
110+
encryption_context=DEFAULT_ENCRYPTION_CONTEXT
111+
)
112+
113+
return ciphertext_data
114+
115+
@staticmethod
116+
def decrypt_using_keyring(
117+
ciphertext_data: bytes,
118+
keyring: IKeyring
119+
):
120+
"""Demonstrate how to decrypt ciphertext data using an AWS KMS keyring.
121+
122+
Usage: decrypt_using_keyring(ciphertext_data, keyring)
123+
:param ciphertext_data: ciphertext data you want to decrypt
124+
:type: bytes
125+
:param keyring: Keyring to use for decryption.
126+
:type keyring: IKeyring
127+
"""
128+
client = aws_encryption_sdk.EncryptionSDKClient()
129+
130+
decrypted_plaintext_data, _ = client.decrypt(
131+
source=ciphertext_data,
132+
keyring=keyring
133+
)
134+
135+
return decrypted_plaintext_data
136+
137+
138+
class AwsKmsMasterKeyProvider():
139+
"""Class for creating a KMS MKP and using it for encryption and decryption"""
140+
141+
@staticmethod
142+
def create_key_provider(
143+
kms_key_id: str
144+
):
145+
"""Demonstrate how to create an AWS KMS master key provider.
146+
147+
Usage: create_key_provider(kms_key_id)
148+
:param kms_key_id: KMS Key identifier for the KMS key you want to use.
149+
:type kms_key_id: string
150+
151+
For more information on KMS Key identifiers, see
152+
https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#key-id
153+
"""
154+
# Create a KMS master key provider.
155+
key_provider = aws_encryption_sdk.StrictAwsKmsMasterKeyProvider(key_ids=[
156+
kms_key_id,
157+
])
158+
159+
return key_provider
160+
161+
@staticmethod
162+
def encrypt_using_key_provider(
163+
plaintext_data: bytes,
164+
key_provider: aws_encryption_sdk.key_providers.base.MasterKeyProvider
165+
):
166+
"""Demonstrate how to encrypt plaintext data using an AWS KMS master key provider.
167+
168+
Usage: encrypt_using_key_provider(plaintext_data, key_provider)
169+
:param plaintext_data: plaintext data you want to encrypt
170+
:type: bytes
171+
:param key_provider: Master key provider to use for encryption.
172+
:type key_provider: aws_encryption_sdk.key_providers.base.MasterKeyProvider
173+
"""
174+
client = aws_encryption_sdk.EncryptionSDKClient()
175+
176+
ciphertext_data, _ = client.encrypt(
177+
source=plaintext_data,
178+
key_provider=key_provider,
179+
encryption_context=DEFAULT_ENCRYPTION_CONTEXT
180+
)
181+
182+
return ciphertext_data
183+
184+
@staticmethod
185+
def decrypt_using_key_provider(
186+
ciphertext_data: bytes,
187+
key_provider: aws_encryption_sdk.key_providers.base.MasterKeyProvider
188+
):
189+
"""Demonstrate how to decrypt ciphertext data using an AWS KMS master key provider.
190+
191+
Usage: decrypt_using_key_provider(ciphertext_data, key_provider)
192+
:param ciphertext_data: ciphertext data you want to decrypt
193+
:type: bytes
194+
:param key_provider: Master key provider to use for decryption.
195+
:type key_provider: aws_encryption_sdk.key_providers.base.MasterKeyProvider
196+
"""
197+
client = aws_encryption_sdk.EncryptionSDKClient()
198+
199+
decrypted_plaintext_data, _ = client.decrypt(
200+
source=ciphertext_data,
201+
key_provider=key_provider
202+
)
203+
204+
return decrypted_plaintext_data
205+
206+
207+
def migration_to_aws_kms_keyring_from_aws_kms_master_key_provider(
208+
kms_key_id: str
209+
):
210+
"""Demonstrate a migration example for moving from an AWS KMS keyring to AWS KMS MKP.
211+
212+
Usage: migration_to_aws_kms_keyring_from_aws_kms_master_key_provider(kms_key_id)
213+
:param kms_key_id: KMS Key identifier for the KMS key you want to use for encryption and
214+
decryption of your data keys.
215+
:type kms_key_id: string
216+
217+
For more information on KMS Key identifiers, see
218+
https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#key-id
219+
"""
220+
221+
# 1a. Create a AWS KMS Keyring
222+
aws_kms_keyring = AwsKmsKeyring.create_keyring(kms_key_id=kms_key_id)
223+
224+
# 1b. Create a AWS KMS Master Key Provider
225+
aws_kms_master_key_provider = AwsKmsMasterKeyProvider.create_key_provider(kms_key_id=kms_key_id)
226+
227+
# 2a. Encrypt EXAMPLE_DATA using AWS KMS Keyring
228+
ciphertext_keyring = AwsKmsKeyring.encrypt_using_keyring(
229+
plaintext_data=EXAMPLE_DATA,
230+
keyring=aws_kms_keyring
231+
)
232+
233+
# 2b. Encrypt EXAMPLE_DATA using AWS KMS Master Key Provider
234+
ciphertext_mkp = AwsKmsMasterKeyProvider.encrypt_using_key_provider(
235+
plaintext_data=EXAMPLE_DATA,
236+
key_provider=aws_kms_master_key_provider
237+
)
238+
239+
# Note: The ciphertexts obtained by encrypting EXAMPLE_DATA using keyring and MKP
240+
# (that is ciphertext_keyring and ciphertext_mkp) are not the same because the ESDK
241+
# generates different data keys each time for encryption of the data. But both
242+
# ciphertexts when decrypted using keyring and MKP should give the same plaintext result.
243+
244+
# 3. Decrypt the ciphertext_keyring using both the keyring and MKP and ensure the
245+
# resulting plaintext is the same and also equal to EXAMPLE_DATA
246+
decrypted_ciphertext_keyring_using_keyring = AwsKmsKeyring.decrypt_using_keyring(
247+
ciphertext_data=ciphertext_keyring,
248+
keyring=aws_kms_keyring
249+
)
250+
251+
decrypted_ciphertext_keyring_using_mkp = AwsKmsMasterKeyProvider.decrypt_using_key_provider(
252+
ciphertext_data=ciphertext_keyring,
253+
key_provider=aws_kms_master_key_provider
254+
)
255+
256+
assert decrypted_ciphertext_keyring_using_keyring == decrypted_ciphertext_keyring_using_mkp \
257+
and decrypted_ciphertext_keyring_using_keyring == EXAMPLE_DATA, \
258+
"Decrypted outputs using keyring and master key provider are not the same"
259+
260+
# 4. Decrypt the ciphertext_mkp using both the keyring and MKP and ensure the
261+
# resulting plaintext is the same and also equal to EXAMPLE_DATA
262+
decrypted_ciphertext_mkp_using_keyring = AwsKmsKeyring.decrypt_using_keyring(
263+
ciphertext_data=ciphertext_mkp,
264+
keyring=aws_kms_keyring
265+
)
266+
267+
decrypted_ciphertext_mkp_using_mkp = AwsKmsMasterKeyProvider.decrypt_using_key_provider(
268+
ciphertext_data=ciphertext_mkp,
269+
key_provider=aws_kms_master_key_provider
270+
)
271+
272+
assert decrypted_ciphertext_mkp_using_keyring == decrypted_ciphertext_mkp_using_mkp \
273+
and decrypted_ciphertext_mkp_using_keyring == EXAMPLE_DATA, \
274+
"Decrypted outputs using keyring and master key provider are not the same"

0 commit comments

Comments
 (0)