finished homework 2 from week 3
This commit is contained in:
parent
9e8e49cfaf
commit
cea43dda51
@ -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
|
||||||
|
|
@ -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')
|
Loading…
x
Reference in New Issue
Block a user