-
Notifications
You must be signed in to change notification settings - Fork 86
/
Copy pathfile_streaming_example.py
139 lines (119 loc) · 6.33 KB
/
file_streaming_example.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
"""
This example demonstrates file streaming for encryption and decryption.
File streaming is useful when the plaintext or ciphertext file/data is too large to load into
memory. Therefore, the AWS Encryption SDK allows users to stream the data, instead of loading it
all at once in memory. In this example, we demonstrate file streaming for encryption and decryption
using a Raw AES keyring. However, you can use any keyring with streaming.
This example creates a Raw AES Keyring and then encrypts an input stream from the file
`plaintext_filename` with an encryption context to an output (encrypted) file `ciphertext_filename`.
It then decrypts the ciphertext from `ciphertext_filename` to a new file `decrypted_filename`.
This example also includes some sanity checks for demonstration:
1. Ciphertext and plaintext data are not the same
2. Decrypted plaintext value matches EXAMPLE_DATA
These sanity checks are for demonstration in the example only. You do not need these in your code.
For more information on how to use Raw AES keyrings, see
https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/use-raw-aes-keyring.html
See raw_aes_keyring_example.py in the same directory for another raw AES keyring example
in the AWS Encryption SDK for Python.
"""
import filecmp
import secrets
from aws_cryptographic_material_providers.mpl import AwsCryptographicMaterialProviders
from aws_cryptographic_material_providers.mpl.config import MaterialProvidersConfig
from aws_cryptographic_material_providers.mpl.models import AesWrappingAlg, CreateRawAesKeyringInput
from aws_cryptographic_material_providers.mpl.references import IKeyring
from typing import Dict # noqa pylint: disable=wrong-import-order
import aws_encryption_sdk
from aws_encryption_sdk import CommitmentPolicy
def encrypt_and_decrypt_with_keyring(
plaintext_filename: str,
ciphertext_filename: str,
decrypted_filename: str
):
"""Demonstrate a streaming encrypt/decrypt cycle.
Usage: encrypt_and_decrypt_with_keyring(plaintext_filename
ciphertext_filename
decrypted_filename)
:param plaintext_filename: filename of the plaintext data
:type plaintext_filename: string
:param ciphertext_filename: filename of the ciphertext data
:type ciphertext_filename: string
:param decrypted_filename: filename of the decrypted data
:type decrypted_filename: string
"""
# 1. Instantiate the encryption SDK client.
# This builds the client with the REQUIRE_ENCRYPT_REQUIRE_DECRYPT commitment policy,
# which enforces that this client only encrypts using committing algorithm suites and enforces
# that this client will only decrypt encrypted messages that were created with a committing
# algorithm suite.
# This is the default commitment policy if you were to build the client as
# `client = aws_encryption_sdk.EncryptionSDKClient()`.
client = aws_encryption_sdk.EncryptionSDKClient(
commitment_policy=CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT
)
# 2. The key namespace and key name are defined by you.
# and are used by the Raw AES keyring to determine
# whether it should attempt to decrypt an encrypted data key.
# For more information, see
# https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/use-raw-aes-keyring.html
key_name_space = "Some managed raw keys"
key_name = "My 256-bit AES wrapping key"
# 3. Create encryption context.
# Remember that your encryption context is NOT SECRET.
# For more information, see
# https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context
encryption_context: Dict[str, str] = {
"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",
}
# 4. Generate a 256-bit AES key to use with your keyring.
# In practice, you should get this key from a secure key management system such as an HSM.
# Here, the input to secrets.token_bytes() = 32 bytes = 256 bits
static_key = secrets.token_bytes(32)
# 5. Create a Raw AES keyring
# We choose to use a raw AES keyring, but any keyring can be used with streaming.
mat_prov: AwsCryptographicMaterialProviders = AwsCryptographicMaterialProviders(
config=MaterialProvidersConfig()
)
keyring_input: CreateRawAesKeyringInput = CreateRawAesKeyringInput(
key_namespace=key_name_space,
key_name=key_name,
wrapping_key=static_key,
wrapping_alg=AesWrappingAlg.ALG_AES256_GCM_IV12_TAG16
)
raw_aes_keyring: IKeyring = mat_prov.create_raw_aes_keyring(
input=keyring_input
)
# 6. Encrypt the data stream with the encryptionContext
with open(plaintext_filename, 'rb') as pt_file, open(ciphertext_filename, 'wb') as ct_file:
with client.stream(
mode='e',
source=pt_file,
keyring=raw_aes_keyring,
encryption_context=encryption_context
) as encryptor:
for chunk in encryptor:
ct_file.write(chunk)
# 7. Demonstrate that the ciphertext and plaintext are different.
# (This is an example for demonstration; you do not need to do this in your own code.)
assert not filecmp.cmp(plaintext_filename, ciphertext_filename), \
"Ciphertext and plaintext data are the same. Invalid encryption"
# 8. Decrypt your encrypted data stream using the same keyring you used on encrypt.
with open(ciphertext_filename, 'rb') as ct_file, open(decrypted_filename, 'wb') as pt_file:
with client.stream(
mode='d',
source=ct_file,
keyring=raw_aes_keyring,
encryption_context=encryption_context
) as decryptor:
for chunk in decryptor:
pt_file.write(chunk)
# 10. Demonstrate that the decrypted plaintext is identical to the original plaintext.
# (This is an example for demonstration; you do not need to do this in your own code.)
assert filecmp.cmp(plaintext_filename, decrypted_filename), \
"Decrypted plaintext should be identical to the original plaintext. Invalid decryption"