This commit is contained in:
Ryan Bakkes 2023-09-14 20:18:47 +02:00
parent 9e3661bc44
commit 23af09eeca
6 changed files with 399 additions and 0 deletions

View File

@ -0,0 +1,72 @@
#!/usr/bin/env python3
"""Asymmetric Cryptography -> Key Generation: Tutorial 1
The goal of this tutorial is to learn how to generate and use asymmetric keys.
Additionally, you will learn how to encrypt and decrypt messages using generated private and public keys.
In this implementation the message is a string converted to a byte object.
Both methods encrypt and decrypt accept two args: a message and a key to perform its operation.
Your task is to:
* locate the TODOs in this file
* complete the missing part from the code
* run the test of this tutorial located in same folder.
To test run 'Asym_t.py' in your command line
Notes:
* do not change class structure or method signature to not break unit tests
* visit this url for more information on this topic:
https://cryptography.io/en/latest/hazmat/primitives/asymmetric/rsa/
"""
from cryptography.exceptions import *
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
# TODO 1: Generate first a private key, then a public key. As a result return both values.
# Make sure you generate the keys in the correct order.
# Use recommended algorithm values where possible
# Suggested key size 2048
def generate_keys():
private = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
)
public = private.public_key()
return private, public
# TODO 2: Encrypt a passed message using the provided key
# Suggested algorithm is SHA256()
def encrypt(message, key):
try:
return key.encrypt(
message,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
except InvalidKey:
return None
# TODO 3: Decrypt a passed message using the provided key
# Make sure using the same recommended algorithm values for encryption and decryption
# Suggested algorithm is SHA256().
def decrypt(ciphertext, key):
try:
return key.decrypt(
ciphertext,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
except:
return None

View File

@ -0,0 +1,40 @@
#!/usr/bin/env python3
"""
This test case will verify if the provided solution by a student for Asym.py is correct.
"""
from Asym import *
if __name__ == '__main__':
# Generate both private en public keys for each user
alex_prv, alex_pbc = generate_keys()
mike_prv, mike_pbc = generate_keys()
rose_prv, rose_pbc = generate_keys()
# Create a message
alex_message = b'This is a message for Rose: Hi Rose'
# Encrypt and decrypt a message using a user asymmetric keys
ciphertext = encrypt(alex_message, rose_pbc)
received_message = decrypt(ciphertext, rose_prv)
# Compare sent and reveived messages before encryptions and after decryption
# to check if the proccess was applied correctly
if received_message!= None and received_message == alex_message:
print("Success: The received message is properly decrypted by Rose's Private Key.")
else:
print("Fail: The received message is not properly decrypted by Rose's Private Key.")
received_message = decrypt(ciphertext, mike_prv)
if received_message== None or received_message == alex_message:
print("Fail: The received message is None or could be decrypted by Mike's Private Key!")
else:
print("Success: The received message could not be decrypted by Mike's Private Key.")
received_message = decrypt(ciphertext, alex_pbc)
if received_message== None or received_message == alex_message:
print("Fail: The received message is None or could be decrypted by Alex's Public Key!")
else:
print("Success: The received message could not be decrypted by Alex's Public Key.")

View File

@ -0,0 +1,103 @@
#!/usr/bin/env python3
"""Asymmetric Cryptography -> Key Management: Tutorial 2
The goal of this tutorial is to learn how to load and store asymmetric keys on the disk.
In previous tutorial you have learned how to generate keys and use them directly to encrypt/decrypt a message,
but in many cases generated keys are stored on and loaded from a disk when they are needed for a specific application.
As a part of the loading and saving process keys are de-/serialized.
It is optionally possible to encrypted before saving using a password. In our example no passwords are needed.
Stored keys in the file system are encoded using PEM encapsulation format.
This format has BEGIN {format} and END {format} markers to separate keys.
Stored keys are located in a subdirectory called *storage*
Your task is to:
* locate the TODOs in this file
* complete the missing part from the code
* run the test of this tutorial located in same folder.
To test run 'Asym_t.py' in your command line
Notes:
* do not change class structure or method signature to not break unit tests
* visit these urls for more information on this topic:
https://cryptography.io/en/latest/hazmat/primitives/asymmetric/serialization/
https://docs.python.org/3/library/pickle.html
"""
# from tkinter.messagebox import NO
from cryptography.exceptions import *
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import serialization
import pickle
def generate_keys():
private_key = rsa.generate_private_key(public_exponent=65537,key_size=2048)
public_key = private_key.public_key()
return private_key, public_key
def encrypt(message, key):
try:
ciphertext = key.encrypt(message,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None))
return ciphertext
except:
return False
def decrypt(ciphertext, key):
try:
plaintext = key.decrypt(
ciphertext,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None))
return plaintext
except:
return False
# TODO 1: Store the list of keys into a given file.
# Make sure of proper PEM encoding before serialization
def save_keys(keys_file_name, keys_list):
keys_ser_list = []
for item in keys_list:
key_name, private_key, public_key = item
prv_ser = private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption()
)
pbc_ser = public_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
keys_ser_list.append((key_name, prv_ser, pbc_ser))
savefile = open(keys_file_name, "wb")
pickle.dump(keys_ser_list, savefile)
savefile.close()
# TODO2: Load all private and public keys from a given file and return those keys as a list
# Make sure of proper PEM decoding when deserializing
def load_keys(keys_file_name):
loadfile = open(keys_file_name, "rb")
keys_ser_list = pickle.load(loadfile)
loadfile.close()
keys_list = []
for item in keys_ser_list:
key_name, prv_ser, pbc_ser = item
private_key = serialization.load_pem_private_key(
prv_ser,
password=None
)
public_key = serialization.load_pem_public_key(
pbc_ser
)
keys_list.append((key_name, private_key, public_key))
return keys_list

View File

@ -0,0 +1,50 @@
#!/usr/bin/env python3
"""
This test case will verify if the provided solution by a student for Asym.py is correct.
"""
from Asym import *
if __name__ == '__main__':
# Create an empty list
keys_list = []
# Generate asymmetric keys for several users
# Save all keys to the list
alex_prv, alex_pbc = generate_keys()
keys_list.append(('alex', alex_prv, alex_pbc))
mike_prv, mike_pbc = generate_keys()
keys_list.append(('mike', mike_prv, mike_pbc))
rose_prv, rose_pbc = generate_keys()
keys_list.append(('rose', rose_prv, rose_pbc))
mara_prv, mara_pbc = generate_keys()
keys_list.append(('mara', mara_prv, mara_pbc))
john_prv, john_pbc = generate_keys()
keys_list.append(('john', john_prv, john_pbc))
lily_prv, lily_pbc = generate_keys()
keys_list.append(('lily', lily_prv, lily_pbc))
# Specify the file name for key storage
keys_file_name = 'samples.keys'
# Save keys to the file
save_keys(keys_file_name, keys_list)
# Load keys
loaded_keys = load_keys(keys_file_name)
plain_message = b'This is a test message!'
# Test if a message can be encrypted/decrypted using asymmetric key combination of each user
for item in loaded_keys:
key_name, prv_key, pbc_key = item
ciphertext = encrypt(plain_message, pbc_key)
decrypted_message = decrypt(ciphertext, prv_key)
if decrypted_message == plain_message:
print(f'Success: The message is correctly encrypted and decrypted by {key_name}')
else:
print(f'Fail: The message could not be decrypted by {key_name}')

View File

@ -0,0 +1,104 @@
#!/usr/bin/env python3
"""Asymmetric Cryptography -> Message Receive: Tutorial 3
The goal of this tutorial is to learn how to read a decrypted message from a file.
In previous tutorial you have learned how to store and load asymmetric keys.
When a user receives a messages it is normally encrypted.
To simplify the implementation we assume the received encrypted message is stored in
a file called *message_test.enc*. Asymmetric keys are stored in the file *samples_test.keys*.
Your task is to:
* locate the TODOs in this file
* complete the missing part from the code
* run the test of this tutorial located in same folder.
To test run 'Asym_t.py' in your command line
Notes:
* do not change class structure or method signature to not break unit tests
* visit this url for more information on this topic:
https://cryptography.io/en/latest/hazmat/primitives/asymmetric/rsa/
"""
# from tkinter.messagebox import NO
from cryptography.exceptions import *
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import serialization
import pickle
def generate_keys():
private_key = rsa.generate_private_key(public_exponent=65537,key_size=2048)
public_key = private_key.public_key()
return private_key, public_key
def encrypt(message, key):
try:
ciphertext = key.encrypt(message,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None))
return ciphertext
except:
return False
def decrypt(ciphertext, key):
try:
plaintext = key.decrypt(
ciphertext,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None))
return plaintext
except:
return False
def save_keys(keys_file_name, keys_list):
keys_ser_list = []
for item in keys_list:
key_name, private_key, public_key = item
prv_ser = private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption()
)
pbc_ser = public_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
keys_ser_list.append((key_name, prv_ser, pbc_ser))
savefile = open(keys_file_name, "wb")
pickle.dump(keys_ser_list, savefile)
savefile.close()
def load_keys(keys_file_name):
loadfile = open(keys_file_name, "rb")
keys_list_ser = pickle.load(loadfile)
loadfile.close()
keys_list = []
for item in keys_list_ser:
key_name, private_key_ser, public_key_ser = item
private_key = serialization.load_pem_private_key(private_key_ser,password=None)
public_key = serialization.load_pem_public_key(public_key_ser)
keys_list.append((key_name, private_key, public_key))
return keys_list
# TODO 1: Load message from a given file and return it
# Make sure of passing proper arguments to open a file in read mode
def load_message(file_name):
load_file = open(file_name, "rb")
message_list = pickle.load(load_file)
load_file.close()
for item in message_list:
message = item
print(message)
return None

View File

@ -0,0 +1,30 @@
#!/usr/bin/env python3
"""
This test case will verify if the provided solution by a student for Asym.py is correct.
"""
from Asym import *
if __name__ == '__main__':
# Specify file name for key storage
keys_file_name = 'samples_test.keys'
# Specify file name where the encrypted message is located
message_file_name = 'message_test.enc'
# Load encrypted message from the file
received_message = load_message(message_file_name)
# Load existing asymmetric keys
loaded_keys = load_keys(keys_file_name)
found = False
# Try to decrypt the loaded message using every existing private key
# Print the result of each decryption attempt
for item in loaded_keys:
key_name, prv_key, _ = item
decrypted_message = decrypt(received_message, prv_key)
if decrypted_message:
print(f'Sucecss: The message is decoded by {key_name}: "{str(decrypted_message,"utf-8")}"')
found = True
if not found:
print('Fail: The message could not be successfully decoded.')