finished tutorials
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives import hashes
|
||||
|
||||
class CBlock:
|
||||
|
||||
data = None
|
||||
previousHash = None
|
||||
previousBlock = None
|
||||
def __init__(self, data, previousBlock):
|
||||
self.data = data
|
||||
self.previousBlock = previousBlock
|
||||
if previousBlock != None:
|
||||
self.previousHash = previousBlock.computeHash()
|
||||
|
||||
def computeHash(self):
|
||||
digest = hashes.Hash(hashes.SHA256(), backend=default_backend())
|
||||
digest.update(bytes(str(self.data),'utf8'))
|
||||
digest.update(bytes(str(self.previousHash),'utf8'))
|
||||
return digest.finalize()
|
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Transactions -> Ledger (Transaction Blockchain): Tutorial 1
|
||||
|
||||
The goal of this tutorial is to learn how custom data structures can be de-/serialized
|
||||
before storage and transference. In addition, you will learn how an application will fail
|
||||
if serialization is not applied before storing an object in a file.
|
||||
Any data structure needs to be serialized as a byte stream before storing it
|
||||
in a file or transferring it through the network. Pickle module supports such an operation.
|
||||
However, it has limited support for data structures to be serialized automatically.
|
||||
Custom data structures such as asymmetric keys and transactions are not supported natively.
|
||||
They need to be serialized before storage. Pickle will throw an exception if it
|
||||
does not support the data structure. Some third-party modules such as Cryptography provide
|
||||
such serialization functions. Only some objects are needed for storage or transference
|
||||
should be serialized. For instance, we might need only to serialize public keys and
|
||||
leave private keys not serialized. Depending on your implementation scenario,
|
||||
you might also check JSON serialization functions.
|
||||
|
||||
Many serialization formats support multiple different types of asymmetric keys
|
||||
and will return an instance of the appropriate type. You should check that
|
||||
the returned key matches the type your application expects when using these methods.
|
||||
|
||||
In this scenario we generate a asymmetric keys. Use the private to sign a message.
|
||||
Your task is to de-/serialize public key of alex before storing to and when loading from a file.
|
||||
|
||||
Your task is to:
|
||||
* locate the TODOs in this file
|
||||
* complete the missing part from the code
|
||||
* run the test of this exercise located in same folder.
|
||||
|
||||
To test run 'KeyFile_test_a.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/serialization/
|
||||
https://cryptography.io/en/latest/hazmat/primitives/asymmetric/serialization/#cryptography.hazmat.primitives.serialization.load_pem_public_key
|
||||
"""
|
||||
from Signature import *
|
||||
from Transaction import *
|
||||
import pickle
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
alex_prv, alex_pbc = generate_keys()
|
||||
|
||||
sample_message = b'a test message'
|
||||
sig = sign(sample_message, alex_prv)
|
||||
print(verify(sample_message, sig, alex_pbc))
|
||||
|
||||
savefile = open("key.dat", "wb")
|
||||
|
||||
# TODO 1: Serialize the public key to bytes
|
||||
# Use PEM encoding
|
||||
|
||||
pickle.dump(alex_pbc, savefile)
|
||||
savefile.close()
|
||||
|
||||
|
||||
loadfile = open("key.dat", "rb")
|
||||
new_pbc = pickle.load(loadfile)
|
||||
|
||||
# TODO 2: Deserialize a public key from PEM encoded data
|
||||
# Load using one of the function that supports asymmetric public key-loading
|
||||
|
||||
|
||||
loadfile.close()
|
||||
print(verify(sample_message, sig, new_pbc))
|
@@ -0,0 +1,35 @@
|
||||
from cryptography.exceptions import *
|
||||
from cryptography.hazmat.primitives.asymmetric import rsa
|
||||
from cryptography.hazmat.primitives import hashes
|
||||
from cryptography.hazmat.primitives.asymmetric import padding
|
||||
|
||||
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 sign(message, private_key):
|
||||
message = bytes(str(message), 'utf-8')
|
||||
signature = private_key.sign(
|
||||
message,
|
||||
padding.PSS(mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.MAX_LENGTH),
|
||||
hashes.SHA256()
|
||||
)
|
||||
return signature
|
||||
|
||||
def verify(message, signature, public_key):
|
||||
message = bytes(str(message), 'utf-8')
|
||||
try:
|
||||
public_key.verify(
|
||||
signature,
|
||||
message,
|
||||
padding.PSS(mgf=padding.MGF1(hashes.SHA256()),
|
||||
salt_length=padding.PSS.MAX_LENGTH),
|
||||
hashes.SHA256()
|
||||
)
|
||||
return True
|
||||
except InvalidSignature:
|
||||
return False
|
||||
except:
|
||||
print("Error executing 'public_key.verify'")
|
||||
return False
|
@@ -0,0 +1,66 @@
|
||||
from Signature import *
|
||||
|
||||
class Tx:
|
||||
inputs = None
|
||||
outputs =None
|
||||
sigs = None
|
||||
reqd = None
|
||||
def __init__(self):
|
||||
self.inputs = []
|
||||
self.outputs = []
|
||||
self.sigs = []
|
||||
self.reqd = []
|
||||
|
||||
def add_input(self, from_addr, amount):
|
||||
self.inputs.append((from_addr, amount))
|
||||
|
||||
def add_output(self, to_addr, amount):
|
||||
self.outputs.append((to_addr, amount))
|
||||
|
||||
def add_reqd(self, addr):
|
||||
self.reqd.append(addr)
|
||||
|
||||
def sign(self, private):
|
||||
message = self.__gather()
|
||||
newsig = sign(message, private)
|
||||
self.sigs.append(newsig)
|
||||
|
||||
def is_valid(self):
|
||||
total_in = 0
|
||||
total_out = 0
|
||||
message = self.__gather()
|
||||
for addr,amount in self.inputs:
|
||||
found = False
|
||||
for s in self.sigs:
|
||||
if verify(message, s, addr):
|
||||
found = True
|
||||
if not found:
|
||||
# print ("No good sig found for " + str(message))
|
||||
return False
|
||||
if amount < 0:
|
||||
return False
|
||||
total_in = total_in + amount
|
||||
for addr in self.reqd:
|
||||
found = False
|
||||
for s in self.sigs:
|
||||
if verify(message, s, addr):
|
||||
found = True
|
||||
if not found:
|
||||
return False
|
||||
for addr,amount in self.outputs:
|
||||
if amount < 0:
|
||||
return False
|
||||
total_out = total_out + amount
|
||||
|
||||
if total_out > total_in:
|
||||
# print("Outputs exceed inputs")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def __gather(self):
|
||||
data=[]
|
||||
data.append(self.inputs)
|
||||
data.append(self.outputs)
|
||||
data.append(self.reqd)
|
||||
return data
|
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Transactions -> Ledger (Transaction Blockchain): Tutorial 1
|
||||
|
||||
The goal of this tutorial is to learn how custom data structures can be de-/serialized
|
||||
before storage and transference. In addition, you will learn how an application will fail
|
||||
if serialization is not applied before storing an object in a file.
|
||||
Any data structure needs to be serialized as a byte stream before storing it
|
||||
in a file or transferring it through the network. Pickle module supports such an operation.
|
||||
However, it has limited support for data structures to be serialized automatically.
|
||||
Custom data structures such as asymmetric keys and transactions are not supported natively.
|
||||
They need to be serialized before storage. Pickle will throw an exception if it
|
||||
does not support the data structure. Some third-party modules such as Cryptography provide
|
||||
such serialization functions. Only some objects are needed for storage or transference
|
||||
should be serialized. For instance, we might need only to serialize public keys and
|
||||
leave private keys not serialized. Depending on your implementation scenario,
|
||||
you might also check JSON serialization functions.
|
||||
|
||||
In this scenario we try to store a custom data structure into a file without serialization.
|
||||
Pickle will fail to store the byte stream into the file as it does not recognize the object.
|
||||
Your task is to try different Pickle.dump() calls and check the output.
|
||||
|
||||
Your task is to:
|
||||
* locate the TODOs in this file
|
||||
* complete the missing part from the code
|
||||
* run the test of this exercise located in same folder.
|
||||
|
||||
To test run 'TxFile_test_a.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/serialization/
|
||||
https://cryptography.io/en/latest/hazmat/primitives/asymmetric/serialization/#cryptography.hazmat.primitives.serialization.load_pem_public_key
|
||||
"""
|
||||
from Signature import *
|
||||
from Transaction import *
|
||||
import pickle
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
# Generating asymmetric keys for multiple users
|
||||
alex_prv, alex_pbc = generate_keys()
|
||||
mike_prv, mike_pbc = generate_keys()
|
||||
rose_prv, rose_pbc = generate_keys()
|
||||
mara_prv, mara_pbc = generate_keys()
|
||||
|
||||
# Creating a transaction from alex to mike and signing it with alex private key
|
||||
Tx1 = Tx()
|
||||
Tx1.add_input(alex_pbc, 1)
|
||||
Tx1.add_output(mike_pbc, 1)
|
||||
Tx1.sign(alex_prv)
|
||||
|
||||
# Checking the validity of this transaction
|
||||
if Tx1.is_valid():
|
||||
print("Success! Tx is valid")
|
||||
else:
|
||||
print("Fail! Tx is invalid")
|
||||
|
||||
# Opening a file to store a transaction data
|
||||
savefile = open("tx.dat", "wb")
|
||||
|
||||
# TODO 1: Try different dump() calls by uncommenting it
|
||||
# Make sure you uncomment other dump calls before trying a new one
|
||||
# Application should stop here as it fails to serialize our custom data structure (transaction)
|
||||
pickle.dump(Tx1, savefile)
|
||||
# pickle.dump(Tx1.inputs[0][0], savefile)
|
||||
# pickle.dump(alex_pbc, savefile)
|
||||
|
||||
savefile.close()
|
||||
|
||||
loadfile = open("tx.dat", "rb")
|
||||
newTx = pickle.load(loadfile)
|
||||
|
||||
if newTx.is_valid():
|
||||
print("Sucess! Loaded tx is valid")
|
||||
loadfile.close()
|
Reference in New Issue
Block a user