Skip to content

Commit 5d698db

Browse files
committed
chore: updated and refactored raw rsa keyring example
1 parent 59faa8c commit 5d698db

File tree

2 files changed

+115
-35
lines changed

2 files changed

+115
-35
lines changed

examples/src/keyrings/raw_rsa_keyring_example.py

Lines changed: 75 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,18 @@
1717
1. Ciphertext and plaintext data are not the same
1818
2. Encryption context is correct in the decrypted message header
1919
3. Decrypted plaintext value matches EXAMPLE_DATA
20-
4. After verifying that the encrypt and decrypt works, this example also demonstrates
21-
that the original ciphertext should not be decrypted using a new Raw RSA keyring generated by
22-
another user, let's say Bob (Points 9 and 10).
20+
4. The original ciphertext is not decryptable using a keyring with a different RSA key pair
2321
These sanity checks are for demonstration in the example only. You do not need these in your code.
2422
2523
A Raw RSA keyring that encrypts and decrypts must include an asymmetric public key and private
2624
key pair. However, you can encrypt data with a Raw RSA keyring that has only a public key,
27-
and you can decrypt data with a Raw RSA keyring that has only a private key. You can include
28-
any Raw RSA keyring in a multi-keyring. If you configure a Raw RSA keyring with a public and
29-
private key, be sure that they are part of the same key pair. Some language implementations
30-
of the AWS Encryption SDK will not construct a Raw RSA keyring with keys from different pairs.
31-
Others rely on you to verify that your keys are from the same key pair.
25+
and you can decrypt data with a Raw RSA keyring that has only a private key. This example requires
26+
the user to either provide both private and public keys, or not provide any keys and the example
27+
generates both to test encryption and decryption. If you configure a Raw RSA keyring with a
28+
public and private key, be sure that they are part of the same key pair. Some language
29+
implementations of the AWS Encryption SDK will not construct a Raw RSA keyring with keys
30+
from different pairs. Others rely on you to verify that your keys are from the same key pair.
31+
You can include any Raw RSA keyring in a multi-keyring.
3232
3333
For more information on how to use Raw RSA keyrings, see
3434
https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/use-raw-rsa-keyring.html
@@ -58,20 +58,31 @@
5858
EXAMPLE_DATA: bytes = b"Hello World"
5959

6060

61-
def generate_rsa_keyring():
62-
"""Generates new public and private keys to create a Raw RSA keyring and
63-
then generates the keyring
61+
def should_generate_new_rsa_key_pair(public_key, private_key):
62+
"""Returns True if user doesn't provide keys, and we need to generate them and
63+
returns False if the user has already provided both public and private keys
64+
Raises an AssertionError if the user only provides one of private_key and public_key
6465
65-
Usage: generate_rsa_keyring()
66+
Usage: should_generate_new_rsa_key_pair(public_key, private_key)
6667
"""
67-
# 1. The key namespace and key name are defined by you.
68-
# and are used by the Raw RSA keyring
69-
# For more information, see
70-
# https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/use-raw-rsa-keyring.html
71-
key_name_space = "Some managed raw keys"
72-
key_name = "My 4096-bit RSA wrapping key"
68+
# If only one of public_key and private_key is provided, raise an Assertion Error
69+
if (public_key and not private_key) or (not public_key and private_key):
70+
raise AssertionError("Either both public and private keys should be provided! Or no keys \
71+
should be provided and the example can create the keys for you!")
72+
73+
# If no keys are provided, we should generate a new rsa key pair, so return True
74+
if not public_key and not private_key:
75+
return True
76+
77+
# If both keys are already provided, return False
78+
return False
79+
7380

74-
# 2. Generate a 4096-bit RSA key to use with your keyring.
81+
def generate_rsa_keys():
82+
"""Generates a 4096-bit RSA public and private key pair
83+
84+
Usage: generate_rsa_keys()
85+
"""
7586
ssh_rsa_exponent = 65537
7687
bit_strength = 4096
7788
key = rsa.generate_private_key(
@@ -81,19 +92,34 @@ def generate_rsa_keyring():
8192
)
8293

8394
# This example choses a particular type of encoding, format and encryption_algorithm
84-
# Users can choose the PrivateFormat, PublicFormat and encryption_algorithm that align most
95+
# Users can choose the PublicFormat, PrivateFormat and encryption_algorithm that align most
8596
# with their use-cases
97+
public_key = key.public_key().public_bytes(
98+
encoding=crypto_serialization.Encoding.PEM,
99+
format=crypto_serialization.PublicFormat.SubjectPublicKeyInfo
100+
)
86101
private_key = key.private_bytes(
87102
encoding=crypto_serialization.Encoding.PEM,
88103
format=crypto_serialization.PrivateFormat.TraditionalOpenSSL,
89104
encryption_algorithm=crypto_serialization.NoEncryption()
90105
)
91-
public_key = key.public_key().public_bytes(
92-
encoding=crypto_serialization.Encoding.PEM,
93-
format=crypto_serialization.PublicFormat.SubjectPublicKeyInfo
94-
)
95106

96-
# 3. Create a Raw RSA keyring
107+
return public_key, private_key
108+
109+
110+
def create_rsa_keyring(public_key, private_key):
111+
"""Create a Raw RSA keyring using the key pair
112+
113+
Usage: create_rsa_keyring(public_key, private_key)
114+
"""
115+
# 1. The key namespace and key name are defined by you.
116+
# and are used by the Raw RSA keyring
117+
# For more information, see
118+
# https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/use-raw-rsa-keyring.html
119+
key_name_space = "Some managed raw keys"
120+
key_name = "My 4096-bit RSA wrapping key"
121+
122+
# 2. Create a Raw RSA keyring
97123
mat_prov: AwsCryptographicMaterialProviders = AwsCryptographicMaterialProviders(
98124
config=MaterialProvidersConfig()
99125
)
@@ -113,10 +139,12 @@ def generate_rsa_keyring():
113139
return raw_rsa_keyring
114140

115141

116-
def encrypt_and_decrypt_with_keyring():
117-
"""Demonstrate an encrypt/decrypt cycle using a Raw RSA keyring.
142+
def encrypt_and_decrypt_with_keyring(public_key=None, private_key=None):
143+
"""Demonstrate an encrypt/decrypt cycle using a Raw RSA keyring
144+
with user defined keys. If no keys are present, generate new RSA
145+
public and private keys and use them to create a Raw RSA keyring
118146
119-
Usage: encrypt_and_decrypt_with_keyring()
147+
Usage: encrypt_and_decrypt_with_keyring(public_key, private_key)
120148
"""
121149
# 1. Instantiate the encryption SDK client.
122150
# This builds the client with the REQUIRE_ENCRYPT_REQUIRE_DECRYPT commitment policy,
@@ -142,7 +170,18 @@ def encrypt_and_decrypt_with_keyring():
142170
}
143171

144172
# 3. Create a Raw RSA keyring
145-
raw_rsa_keyring = generate_rsa_keyring()
173+
174+
# Check if we need to generate an RSA key pair
175+
should_generate_new_rsa_key_pair_bool = \
176+
should_generate_new_rsa_key_pair(public_key=public_key, private_key=private_key)
177+
178+
# If user doesn't provide the keys, that is, if should_generate_new_rsa_key_pair_bool is True
179+
# generate a new RSA public and private key pair
180+
if should_generate_new_rsa_key_pair_bool:
181+
public_key, private_key = generate_rsa_keys()
182+
183+
# Create the keyring
184+
raw_rsa_keyring = create_rsa_keyring(public_key=public_key, private_key=private_key)
146185

147186
# 4. Encrypt the data for the encryptionContext
148187
ciphertext, _ = client.encrypt(
@@ -176,12 +215,16 @@ def encrypt_and_decrypt_with_keyring():
176215
# decryption of the original ciphertext is not possible with a different keyring (Bob's)
177216
# (This is an example for demonstration; you do not need to do this in your own code.)
178217

179-
# 9. Generate a new Raw RSA keyring for Bob
180-
raw_rsa_keyring_bob = generate_rsa_keyring()
218+
# 9. Create a new Raw RSA keyring for Bob
219+
# Generate new keys
220+
public_key_bob, private_key_bob = generate_rsa_keys()
221+
222+
# Create the keyring
223+
raw_rsa_keyring_bob = create_rsa_keyring(public_key=public_key_bob, private_key=private_key_bob)
181224

182225
# 10. Test decrypt for the original ciphertext using raw_rsa_keyring_bob
183226
try:
184-
plaintext_bytes_bob, dec_header_bob = client.decrypt(
227+
plaintext_bytes_bob, _ = client.decrypt(
185228
source=ciphertext,
186229
keyring=raw_rsa_keyring_bob
187230
)

examples/test/keyrings/test_i_raw_rsa_keyring_example.py

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,48 @@
33
"""Test suite for the Raw RSA keyring example."""
44
import pytest
55

6-
from ...src.keyrings.raw_rsa_keyring_example import encrypt_and_decrypt_with_keyring
6+
from ...src.keyrings.raw_rsa_keyring_example import encrypt_and_decrypt_with_keyring, generate_rsa_keys
77

88
pytestmark = [pytest.mark.examples]
99

1010

11-
def test_encrypt_and_decrypt_with_keyring():
12-
"""Test function for encrypt and decrypt using the Raw RSA Keyring example."""
11+
def test_encrypt_and_decrypt_with_keyring_without_user_defined_keys():
12+
"""Test function for encrypt and decrypt using the Raw RSA Keyring example
13+
where user doesn't provide the public and private keys"""
1314
encrypt_and_decrypt_with_keyring()
15+
16+
17+
def test_encrypt_and_decrypt_with_keyring_with_user_defined_keys():
18+
"""Test function for encrypt and decrypt using the Raw RSA Keyring example
19+
where user provides the public and private keys. To test this, we create the
20+
keys using the generate_rsa_keys function"""
21+
user_public_key, user_private_key = generate_rsa_keys()
22+
encrypt_and_decrypt_with_keyring(public_key=user_public_key, private_key=user_private_key)
23+
24+
25+
def test_encrypt_and_decrypt_fails_if_user_provides_only_public_key():
26+
"""Test function for encrypt and decrypt using the Raw RSA Keyring example
27+
where user provides only the public key. The program should throw an Assertion error
28+
as this example requires the user to either provide both private and public keys to
29+
test both encryption and decryption, or not provide any keys and the example generates both"""
30+
user_public_key, user_private_key = generate_rsa_keys()
31+
try:
32+
encrypt_and_decrypt_with_keyring(public_key=user_public_key)
33+
34+
raise AssertionError("encrypt_and_decrypt_with_keyring should raise an error")
35+
except AssertionError:
36+
pass
37+
38+
39+
def test_encrypt_and_decrypt_fails_if_user_provides_only_private_key():
40+
"""Test function for encrypt and decrypt using the Raw RSA Keyring example
41+
where user provides only the private key. The program should throw an Assertion error
42+
as this example requires the user to either provide both private and public keys to
43+
test both encryption and decryption, or not provide any keys and the example generates both"""
44+
user_public_key, user_private_key = generate_rsa_keys()
45+
try:
46+
encrypt_and_decrypt_with_keyring(private_key=user_private_key)
47+
48+
raise AssertionError("encrypt_and_decrypt_with_keyring should raise an error")
49+
except AssertionError:
50+
pass

0 commit comments

Comments
 (0)