Import libraries and generate public and private keys


In [1]:
import hashlib
import json
from collections import OrderedDict
from Crypto.PublicKey import RSA
from Crypto import Random
from pprint import pprint

# Generate an RSA of 2048 bits
random_generator = Random.new().read

# Alice RSA keys
alice_private_key = RSA.generate(2048, random_generator)
alice_public_key_pem = alice_private_key.publickey().exportKey(format='PEM')

# Bob RSA keys
bob_private_key = RSA.generate(2048, random_generator)
bob_public_key_pem = bob_private_key.publickey().exportKey(format='PEM')

Sample Signing Examples


In [2]:
# Create a very big string to sign using alice's private key
a_test_message = b'A short message'
a_large_message = b'aa' * 10000000

# This works on a smaller message without hashing but doesn't work as well on a large message
# alice_sign_msg = alice_private_key.sign(a_large_message, K=None)

# A better option is to hash the message and then sign it using Alice's private key
hash_message = hashlib.sha256(a_large_message).digest()
print(hash_message)

# Now sign this message using Alice's private key
alice_sign_msg = alice_private_key.sign(hash_message, K=None)

# Now verify the message using Alice's public key (assume from another user)
import_alice_public_key = RSA.importKey(alice_public_key_pem)
print(import_alice_public_key.verify(hash_message, alice_sign_msg)) # Evaluates to True

# Now lets try and evaluate it importing Bob's public key
import_bob_public_key = RSA.importKey(bob_public_key_pem)
print(import_bob_public_key.verify(hash_message, alice_sign_msg)) # Evaluates to False

# Also try a different message against the one received
a_dif_test_message = b'An incorrect short message'
hash_dif_message = hashlib.sha256(a_dif_test_message).digest()
print(import_alice_public_key.verify(hash_dif_message, alice_sign_msg)) # Evaluates to False


b'\xad\xed\x0e\xa9\xb4\xd0e\x89\xb1=\x00\xba\xb4\x83\xfa\xf4y\xd6\x1e\xd5\xde!\xf1v\n\xa7\x01\x8a(\xe30\xe5'
True
False
False

A simple Blockchain example

Merged with the work provided by Kevin


In [3]:
# Generate a simple transaction for Alice, assumming she has Bob's public key
transaction = {
    'from_pk' : alice_public_key_pem,
    'to_pk': bob_public_key_pem,
    'cc_amount': 50
}

# Hash and generate signature using the sender's private key
hash_transaction = hashlib.sha256(bytes(str(transaction), encoding="UTF-8")).hexdigest()
signature = alice_private_key.sign(bytes(str(hash_transaction), encoding="UTF-8"), K = None)

# Add signature to the transaction message
transaction['signature'] = signature

## Send your transaction...

# Pretend it has been sent
received_transaction = transaction

# Extract the signature
received_signature = transaction['signature']

# Remove signature from the transaction and get hash
del received_transaction['signature']
hash_received_transaction = hashlib.sha256(bytes(str(received_transaction), encoding="UTF-8")).hexdigest()

public_key = RSA.importKey(transaction['from_pk'])

# Check if the signature matches
signature_check = public_key.verify(bytes(str(hash_received_transaction), encoding="UTF-8"), received_signature)

if signature_check:
    print("The sender is who they claim to be.")
else:
    print("The sender is not who you think it is.")


The sender is who they claim to be.

In [ ]: