finished homework 2 from week 3

This commit is contained in:
“Spekulaas” 2023-09-15 10:52:49 +02:00
parent 9e8e49cfaf
commit cea43dda51
2 changed files with 169 additions and 0 deletions

View File

@ -0,0 +1,117 @@
#!/usr/bin/env python3
"""Asymmetric Cryptography -> Digital Signature: Homework
The goal of this homework is to learn how to store and load asymmetric keys of different users on a disk.
In addition, to sign and verify messages using those keys. Furthermore, it is required to encrypt keys before saving using a password.
In this implementation the passed message as an argument is a string. Proper encoding and decoding is need before usage.
When signing a message the RSA sign-function requires a specific hash like SHA256, and padding such as PSS.
RSA verify function calculates the message hash. Decrypt the signature then compares both values to verify.
Be aware that verification must use the same algorithm values as signing to correctly verify the signature.
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 'Signature_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
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
# TODO 1: Sign a passed message using a given private key
# Make sure the message is encoded correctly before signing
# Signing and verifying algorithms must be the same
def sign(message, private_key):
# Make sure the message is encoded correctly before signing
message = message.encode()
return private_key.sign(
message,
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA256()
)
# TODO 2: Verify a signature for a message using a given public key
# Make sure the message is decoded correctly before verifying
# Signing and verifying algorithms values must be the same
def verify(message, signature, public_key):
try:
message = message.encode()
public_key.verify(
signature,
message,
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA256()
)
return True
except:
return False
# TODO 3: Store the list of keys into a given file.
# In this implementation passwords are used for additional security
# Make sure of proper PEM encoding before serialization
def save_keys(keys_file_name, keys, pw):
keys_ser_list = []
print(pw)
private_key = keys[0]
public_key = keys[1]
prv_ser = private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.BestAvailableEncryption(pw.encode('utf-8'))
)
pbc_ser = public_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
keys_ser_list.append((prv_ser, pbc_ser))
savefile = open(keys_file_name, "wb")
pickle.dump(keys_ser_list, savefile)
savefile.close()
# TODO 4: Load asymmetric keys from a given file and return those keys as a tuple
# In this implementation passwords are used for additional security
# Make sure of proper PEM decoding when deserializing
def load_keys(keys_file_name, pw):
loadfile = open(keys_file_name, "rb")
keys_ser_list = pickle.load(loadfile)
loadfile.close()
prv_ser = keys_ser_list[0][0]
pbc_ser = keys_ser_list[0][1]
try:
private_key = serialization.load_pem_private_key(
prv_ser,
password=pw.encode('utf-8')
)
public_key = serialization.load_pem_public_key(
pbc_ser
)
return private_key, public_key
except:
return None, None

View File

@ -0,0 +1,52 @@
#!/usr/bin/env python3
"""
This test case will verify if the provided solution by a student for Signature_a.py is correct.
"""
from Signature import *
if __name__ == '__main__':
# Generate asymmetric keys for different users
alex_prv, alex_pbc = generate_keys()
mike_prv, mike_pbc = generate_keys()
rose_prv, rose_pbc = generate_keys()
# Use a password to secure keys during storage
pws = input("Enter a password for saving the keys: ")
save_keys('alex.keys', (alex_prv, alex_pbc), pws)
save_keys('mike.keys', (mike_prv, mike_pbc), pws)
save_keys('rose.keys', (rose_prv, rose_pbc), pws)
print('keys are successfully saved.')
alex_message = 'pay 10 euro to mike'
mike_message = 'pay 5 euro to josé'
rose_message = 'Hello, this is rose!'
# Sign each user's message with his private key
alex_signature = sign(alex_message, alex_prv)
mike_signature = sign(mike_message, mike_prv)
rose_signature = sign(rose_message, rose_prv)
# Load user's asymmetric keys from storage
pwl = input("Enter the password for loading the keys: ")
(_, alex_pbc_loaded) = load_keys('alex.keys', pwl)
(_, mike_pbc_loaded) = load_keys('mike.keys', pwl)
(_, rose_pbc_loaded) = load_keys('rose.keys', pwl)
if all([alex_pbc_loaded, mike_pbc_loaded, rose_pbc_loaded]):
# Check if each user's message can correctly be verified
for p in ['alex', 'mike', 'rose']:
r_message = input(f"What was {p}'s message? ")
(_, pbc_loaded) = load_keys(p+'.keys', pwl)
sig = globals()[p+'_signature']
correct = verify(r_message, sig, pbc_loaded)
if correct:
print('Great! You correctly entered the message.')
else:
print('Oops! The message you entered is not correct')
else:
print('Error in loading the keys')