Skip to content

chore(examples): Added raw RSA/AES keyring multithreaded examples #694

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 27 commits into from
Aug 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
86f4332
mplv2
lucasmcdonald3 May 20, 2024
4ce31f6
Merge branch 'mpl-reviewed' into lucmcdon/mpl-v2
lucasmcdonald3 May 20, 2024
cb80152
cleanup
lucasmcdonald3 May 20, 2024
efe2d1d
isort
lucasmcdonald3 May 20, 2024
dd285f6
win
lucasmcdonald3 May 22, 2024
bf1a15f
debug win import
lucasmcdonald3 May 22, 2024
2144b14
debug win import
lucasmcdonald3 May 22, 2024
a83ab6d
actual v2
lucasmcdonald3 May 22, 2024
3b5157d
add
lucasmcdonald3 Jun 27, 2024
1591bdf
refactoring and fixes
RitvikKapila Jun 28, 2024
e75fe70
chore: performance tests for ESDK-python (#680)
RitvikKapila Jun 5, 2024
5ea31f5
chore(performance_tests): added hierarchy keyring and caching cmm tes…
RitvikKapila Jun 7, 2024
f45e641
chore(migration examples): added KMS, raw AES and raw RSA keyring/MKP…
RitvikKapila Jun 13, 2024
dca6fdd
chore(custom_cmm_example.py): added test for custom_cmm_example.py (#…
RitvikKapila Jun 26, 2024
23084a0
chore(MPL): Update README and primary pydocs (#658)
lucasmcdonald3 Jul 30, 2024
a8fb0ed
chore: Change MPL branch, remove PYTHONPATH workarounds (#683)
lucasmcdonald3 Aug 5, 2024
42c2aea
Merge branch 'mpl-reviewed' into threaded-tests
lucasmcdonald3 Aug 6, 2024
233faa7
Update src/aws_encryption_sdk/streaming_client.py
lucasmcdonald3 Aug 6, 2024
48a67f5
cleanup
lucasmcdonald3 Aug 6, 2024
4228c92
cleanup
lucasmcdonald3 Aug 7, 2024
fa2d084
cleanup
lucasmcdonald3 Aug 7, 2024
512eb7c
cleanup
lucasmcdonald3 Aug 7, 2024
0c0b7d9
cleanup
lucasmcdonald3 Aug 7, 2024
1d063de
cleanup
lucasmcdonald3 Aug 7, 2024
56937f0
fix
lucasmcdonald3 Aug 7, 2024
7cd9713
clean
lucasmcdonald3 Aug 7, 2024
0650844
fix
lucasmcdonald3 Aug 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions examples/src/multithreading/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
"""init file for multi-threading examples."""
import time

from aws_cryptographic_materialproviders.mpl.references import IKeyring
from typing import Dict # noqa pylint: disable=wrong-import-order

import aws_encryption_sdk


def encrypt_and_decrypt_with_keyring(
plaintext_data: bytes,
keyring: IKeyring,
client: aws_encryption_sdk.EncryptionSDKClient
):
"""Demonstrate how to encrypt and decrypt plaintext data using a keyring.

Usage: encrypt_and_decrypt_with_keyring(plaintext_data, keyring, client)
:param plaintext_data: plaintext data you want to encrypt
:type: bytes
:param keyring: Keyring to use for encryption.
:type keyring: IKeyring
:param client: The Encryption SDK client to use for encryption.
:type client: aws_encryption_sdk.EncryptionSDKClient
:return: encrypted and decrypted (cycled) plaintext data
:rtype: bytes
"""
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",
}

ciphertext_data, _ = client.encrypt(
source=plaintext_data,
keyring=keyring,
encryption_context=encryption_context
)

decrypted_plaintext_data, _ = client.decrypt(
source=ciphertext_data,
keyring=keyring
)

return decrypted_plaintext_data


def run_encrypt_and_decrypt_with_keyring_for_duration_seconds(
plaintext_data: bytes,
keyring: IKeyring,
client: aws_encryption_sdk.EncryptionSDKClient,
duration: int = 2
):
"""Helper function to repeatedly run an encrypt and decrypt cycle for 'duration' seconds."""
time_end = time.time() + duration

while time.time() < time_end:
decrypted_plaintext_data = encrypt_and_decrypt_with_keyring(plaintext_data, keyring, client)
assert decrypted_plaintext_data == plaintext_data, \
"Decrypted plaintext should be identical to the original plaintext. Invalid decryption"
38 changes: 38 additions & 0 deletions examples/src/multithreading/raw_aes_keyring.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
"""This file contains methods to use for testing multi-threading for Raw AES keyring."""

import secrets

from aws_cryptographic_materialproviders.mpl import AwsCryptographicMaterialProviders
from aws_cryptographic_materialproviders.mpl.config import MaterialProvidersConfig
from aws_cryptographic_materialproviders.mpl.models import AesWrappingAlg, CreateRawAesKeyringInput
from aws_cryptographic_materialproviders.mpl.references import IKeyring


def create_keyring():
"""Demonstrate how to create a Raw AES keyring.

Usage: create_keyring()
"""
key_name_space = "Some managed raw keys"
key_name = "My 256-bit AES wrapping key"

static_key = secrets.token_bytes(32)

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
)

keyring: IKeyring = mat_prov.create_raw_aes_keyring(
input=keyring_input
)

return keyring
66 changes: 66 additions & 0 deletions examples/src/multithreading/raw_rsa_keyring.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
"""This file contains methods to use for testing multi-threading for Raw RSA keyring."""
from aws_cryptographic_materialproviders.mpl import AwsCryptographicMaterialProviders
from aws_cryptographic_materialproviders.mpl.config import MaterialProvidersConfig
from aws_cryptographic_materialproviders.mpl.models import CreateRawRsaKeyringInput, PaddingScheme
from aws_cryptographic_materialproviders.mpl.references import IKeyring
from cryptography.hazmat.backends import default_backend as crypto_default_backend
from cryptography.hazmat.primitives import serialization as crypto_serialization
from cryptography.hazmat.primitives.asymmetric import rsa


def generate_rsa_keys():
"""Generates a 4096-bit RSA public and private key pair

Usage: generate_rsa_keys()
"""
ssh_rsa_exponent = 65537
bit_strength = 4096
key = rsa.generate_private_key(
backend=crypto_default_backend(),
public_exponent=ssh_rsa_exponent,
key_size=bit_strength
)

# This example choses a particular type of encoding, format and encryption_algorithm
# Users can choose the PublicFormat, PrivateFormat and encryption_algorithm that align most
# with their use-cases
public_key = key.public_key().public_bytes(
encoding=crypto_serialization.Encoding.PEM,
format=crypto_serialization.PublicFormat.SubjectPublicKeyInfo
)
private_key = key.private_bytes(
encoding=crypto_serialization.Encoding.PEM,
format=crypto_serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=crypto_serialization.NoEncryption()
)

return public_key, private_key


def create_keyring(public_key, private_key):
"""Demonstrate how to create a Raw RSA keyring using the key pair.

Usage: create_keyring(public_key, private_key)
"""
key_name_space = "Some managed raw keys"
key_name = "My 4096-bit RSA wrapping key"

mat_prov: AwsCryptographicMaterialProviders = AwsCryptographicMaterialProviders(
config=MaterialProvidersConfig()
)

keyring_input: CreateRawRsaKeyringInput = CreateRawRsaKeyringInput(
key_namespace=key_name_space,
key_name=key_name,
padding_scheme=PaddingScheme.OAEP_SHA256_MGF1,
public_key=public_key,
private_key=private_key
)

keyring: IKeyring = mat_prov.create_raw_rsa_keyring(
input=keyring_input
)

return keyring
3 changes: 3 additions & 0 deletions examples/test/multithreading/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
"""Stub module indicator to make linter configuration simpler."""
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
"""Test suite for the Raw AES keyring example with multi-threading."""
from concurrent.futures import ThreadPoolExecutor, as_completed

import pytest
# pylint and isort disagree about where this goes; listen to isort
from typing import Optional # pylint: disable=wrong-import-order

import aws_encryption_sdk
from aws_encryption_sdk import CommitmentPolicy

from ...src.multithreading import run_encrypt_and_decrypt_with_keyring_for_duration_seconds
from ...src.multithreading.raw_aes_keyring import create_keyring

pytestmark = [pytest.mark.examples]


def encrypt_and_decrypt_with_keyring_multithreaded_helper(n_threads=64, duration=60):
"""Encrypt and decrypt using a keyring for fixed n_threads and duration."""
keyring = create_keyring()
plaintext_data = b"Hello World"
client = aws_encryption_sdk.EncryptionSDKClient(
commitment_policy=CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT
)

with ThreadPoolExecutor(max_workers=n_threads) as executor:
thread_futures = {executor.submit(run_encrypt_and_decrypt_with_keyring_for_duration_seconds,
plaintext_data=plaintext_data,
keyring=keyring,
client=client,
duration=duration): i for i in range(n_threads)}

for future in as_completed(thread_futures):
future.result()


def test_encrypt_and_decrypt_with_keyring_multithreaded(
n_threads_list: Optional[list] = None,
duration_list: Optional[list] = None,
):
"""Test function for multi-threaded encrypt and decrypt using a keyring for different n_threads and duration."""
# Set defaults if no value is provided
if n_threads_list is None:
n_threads_list = [1, 4, 16, 64]
if duration_list is None:
duration_list = [2, 10, 60]
for n in n_threads_list:
for d in duration_list:
encrypt_and_decrypt_with_keyring_multithreaded_helper(n_threads=n, duration=d)
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
"""Test suite for the Raw RSA keyring example with multi-threading."""
from concurrent.futures import ThreadPoolExecutor, as_completed

import pytest
# pylint and isort disagree about where this goes; listen to isort
from typing import Optional # pylint: disable=wrong-import-order

import aws_encryption_sdk
from aws_encryption_sdk import CommitmentPolicy

from ...src.multithreading import run_encrypt_and_decrypt_with_keyring_for_duration_seconds
from ...src.multithreading.raw_rsa_keyring import create_keyring, generate_rsa_keys

pytestmark = [pytest.mark.examples]


def encrypt_and_decrypt_with_keyring_multithreaded_helper(n_threads=64, duration=60):
"""Encrypt and decrypt using a keyring for fixed n_threads and duration."""
public_key, private_key = generate_rsa_keys()
keyring = create_keyring(public_key=public_key, private_key=private_key)
plaintext_data = b"Hello World"
client = aws_encryption_sdk.EncryptionSDKClient(
commitment_policy=CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT
)

with ThreadPoolExecutor(max_workers=n_threads) as executor:
thread_futures = {executor.submit(run_encrypt_and_decrypt_with_keyring_for_duration_seconds,
plaintext_data=plaintext_data,
keyring=keyring,
client=client,
duration=duration): i for i in range(n_threads)}

for future in as_completed(thread_futures):
future.result()


def test_encrypt_and_decrypt_with_keyring_multithreaded(
n_threads_list: Optional[list] = None,
duration_list: Optional[list] = None,
):
"""Test function for multi-threaded encrypt and decrypt using a keyring for different n_threads and duration."""
# Set defaults if no value is provided
if n_threads_list is None:
n_threads_list = [1, 4, 16, 64]
if duration_list is None:
duration_list = [2, 10, 60]
for n in n_threads_list:
for d in duration_list:
encrypt_and_decrypt_with_keyring_multithreaded_helper(n_threads=n, duration=d)
Loading