Generate public and private keys using RSA of 2048 bits for the key size

Possible python libraries to use:

  • pycrypto
  • rsa
  • ...

In [1]:
# This method uses the 'pycrypto' package
# Import all the packages needed for this notebook
from Crypto.PublicKey import RSA
from Crypto import Random
import hashlib

In [2]:
# Generate an RSA of 2048 bits
random_generator = Random.new().read
private_key = RSA.generate(2048, random_generator)
public_key = private_key.publickey()

# Test the encryption and decrytion process
message = b'Super secret message'

# Encrypt with the public key
crypt_msg = public_key.encrypt(message, K=None)
print(crypt_msg)

# Now decrypt using the private key
decrypt_msg = private_key.decrypt(crypt_msg)
print(decrypt_msg)


('\x03\x98\xda\xaf!\xf7#U\xc3N\x8eF\xeco\xbc\xfd7\xfc\xf5\x7f*\x80\xb4\x99~B\xe4O\xbf\xc9\xa1{<o\x99\xa2\xe9\x05d\xc0\x92!\x9f\x14\x14Z\x8e@\x95\xac\xcf\xd0\xc8\x11P\xf8\xb1\x10x\xe6H\xd1k:\x92}2\xaa\nnJ\x91 G.N\x1fW\xc5\xd0\xa1\xf8DcA\r\x88\xd8\x1a\xc8\xe8x8\xc4"\xfb:\xb4\xe4\t_C\xe4d\xdb\xbb\xbc5\xdc\xe9[\xbb\x8f\x85=\xb1\x93M\xde#rG\xee\x91\xa6\x11b2b,\x0f]\x06\xa4\xa1\xcbW\x11\xa3p\x99-Sb\xb1\x14\x0ey\xd1\xccg\x0by\xd8YlsI\x1dB\x84{Q,\xe8\x15\xcf\\\x86\xb7\x15\x82\x92\xbb\xde\x14\xa7Q\xb2-\xd8H\xa9\xae\xbdE\xc1\x1a\xd5\x0c?\x14S\xf8\x01\x16\xd4\xeeU\xf8\xd1\xed\xc5\xad\x87\x8f\x86I\x14\xd0\xe8\xda\x88\xf7\x898\xf31\xa3\xe3\xff/M\xa0\xe2\xbf\x04\x9f\t\x0eQ\x88\x1e\x12-\xcfm\x16\x8f\x8e\xb0\xcc\xf5\x86}\x07\xfe\xc0\xf2\xb5\x07T\xee\xf1\x12+',)
Super secret message

Read and write to PEM formatted text


In [3]:
# Print the public and private keys to console in PEM format  

# Print private key
print(private_key.exportKey(format='PEM'))

print('\n')

# Print public key
print(public_key.exportKey(format='PEM'))


-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA1hMZdpNU9otxPGI0C3P0Uv2tSp9MU3WAEx2VvRMcjyVaxa8V
lwLbsgW48j2udsH8j/lKqVCR8sMIg9nHUNef+U7sM503Xer++nqxgYXSMXzyn6/h
Lp73GgKfyll6JMcEwmdK996mzewGP+/lKFkqf9GkxGG8Qx5dblG0+/65kSPUviz4
OK0UaugVaCojuU5h83hYa0t8d8zl8u0qb+z9COLUFmEN0PvKOrXXjA8nsmrQxnI0
Lt5ScDCrcXhOTE6oXgy4sWheRye/ma1TO9+LGPlvKrkqpLoETm+6OkkjGcLlAyXs
qxK5d9CwIIBYkhYj0j3EqajOZCGyjyF4gymOdQIDAQABAoIBAQCus1mFXgjpRrS7
TX0hl5hdHe6MxmF4fpxtfShU68LTwu1IBHE/ErMNngPnlJTLD9Y3/H6EnF7u2WEa
kOBKxh0kTNcP7A5iE8PPz88KX5ZAkrJBxTukW1BWpquWa9z1JIFq0PbqP4aq6CHV
jcXaXqIDO6gWJ5iGwcIHpKBpQeBYY4I7dwH7h799KuK5hjzlcZBZwHSAAnmT8I45
spg6i4ktbujweQigQpvk29/dTfH3DRI7EWbfciK8a116zxMaIuK4xmeQ5Z1+kQ7l
/LEt3Czmb/WEJZpj347zMy1P1sVvql+tsm5fPQ5ZySNMWf8XuCUV/Kh7vfVu5Y6a
wnbkCEJhAoGBAOcXgmvfsriuXU2rm+/eTr/b+ixhkHpBmD2qg6LXPBcKreDXOZun
0yffyz+R30r/mzjTemJe3FV63YryKCBo3PsEGUQofrznkdciGY7j6Z09tGQOdPmY
g6pcdrYt3z85KvSQGXWG+LoYSiL62RyUOB5DA34OpmahFhibFXnZOx55AoGBAO0m
CR59DQLyMWV4nD6M2JhMBEzN/BRHb8trer9Pucdg1WnNqO+9YOKc0ab1WUFLAl0C
7GYsRNE6+AKkhXV+l1Q3sCn8xA3OssTTezTPmWawxAHgaiCagy5vvAD3Quql8dHc
5zJkpD7DLfm7mcSBhUtGdDIgbFwlRUDQ+unHEkDdAoGBAM0Qw59ORp4zvIAsBJh6
wY7nebzgZwDWLG6sXVune59Gzr1yv6As8Oe1Y/rpSyiWYfuvTi701rjT6rxd3tXD
uDTXkkQ1WyHurDAoBl4SSUBLfUQ8v/itKkmG+6D2W+ESrdeP98efGiCpZUBdMUR3
EsVn2jWGcosn7x+unwQdjKShAoGAa3/uak+tckRvd9vwl7opBQCQgnBtcJPhbYjP
H6H4SRTwKQH9Lo/eN1t2/gQB7cMe0yLcHoS6vU3J1wjVJqm314lW5fGavdeQ2gAz
vYDNvOssLt2XvifMh2RHCPkM8GlA8Sz98K4Gdhzr3mTYE2fTEIhja8We2TZb6kHR
O9/tulECgYBnlfXNXA2tcs45CxHvxD8IGeNEVTc+dezkYh2IKcI9aPCcALaBdBQn
iIGrCqEQGrhjwbTl+tj4sNTppqxHGOAKJBaCALLBDKjSHQ/EbcqE84dl9sgrwIHj
em8Zc8osq7YizSi5BY03WH7gssgyV/O7pNbkh8kB9+9PZ/CLQBANRg==
-----END RSA PRIVATE KEY-----


-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1hMZdpNU9otxPGI0C3P0
Uv2tSp9MU3WAEx2VvRMcjyVaxa8VlwLbsgW48j2udsH8j/lKqVCR8sMIg9nHUNef
+U7sM503Xer++nqxgYXSMXzyn6/hLp73GgKfyll6JMcEwmdK996mzewGP+/lKFkq
f9GkxGG8Qx5dblG0+/65kSPUviz4OK0UaugVaCojuU5h83hYa0t8d8zl8u0qb+z9
COLUFmEN0PvKOrXXjA8nsmrQxnI0Lt5ScDCrcXhOTE6oXgy4sWheRye/ma1TO9+L
GPlvKrkqpLoETm+6OkkjGcLlAyXsqxK5d9CwIIBYkhYj0j3EqajOZCGyjyF4gymO
dQIDAQAB
-----END PUBLIC KEY-----

Build typical transaction object

A transaction should have the following properties:

  1. The owners public key and private key (Alice's public key, for example.
  2. Another users public key, so that they can send encrypted messages

In [13]:
"""
Similate a basic transaction
1.  Create digital wallet objects for Alice and Bob.
2.  Create private and digital keys for these wallets
3.  Send Bob's public key in 'PEM' format to Alice
4.  Alice then encrypt's a message using Bob's public key
5.  Alice sends encrypted message to Bob
6.  Bob receives message and decrypts message using his private key
"""

class DigitalWallet(object):
    def __init__(self, name):
                
        # Owner of the wallet
        self._name = name
        
        # Generate RSA keys on object creation
        private_key, public_key = self.__generate_RSA_keys(2048)
        
        # Objects RSA keys
        self._private_key = private_key # This should never be sent out
        self._public_keys = {self._name: public_key} 
        
    def __generate_RSA_keys(self, num_bits):
        # Keys that are generated when the digital wallet is created
        random_generator = Random.new().read
        private_key = RSA.generate(2048, random_generator)
        public_key = private_key.publickey()
        return private_key, public_key
    
    def send_public_keys(self):
        # Public key can be sent to others for message encryption
        return {self._name: self._public_keys[self._name].exportKey(format='PEM')}
    
    def receive_public_key(self, key_dict):
        # Recieve a public key from another person
        for key, val in key_dict.items():
            public_key = RSA.importKey(val)
            self._public_keys[key] = public_key
        
    def send_encrypted_message(self, to_user, message):
        # Encrypt with the public key and return to user
        return self._public_keys[to_user].encrypt(message, K=None)
    
    def receive_encrypted_message(self, encrypted_message):
        decoded_message = self._private_key.decrypt(encrypted_message)
        print(decoded_message)
        
    
# Build wallets for Alice and Bob
alice_wallet = DigitalWallet(name='Alice')
bob_wallet = DigitalWallet(name='Bob')

# Receive a public key from Bob
bob_public_key = bob_wallet.send_public_keys()
alice_wallet.receive_public_key(bob_public_key)

# Send an encrypted message to Bob that only Bob can decrypt
bob_encrypted_message = alice_wallet.send_encrypted_message('Bob', b'Secret message for bob')

# Receive the encrypted message
bob_wallet.receive_encrypted_message(bob_encrypted_message)


Secret message for bob

Examples of hashing

Use hashlib at: https://docs.python.org/3/library/hashlib.html

Thought I would add in some use cases of where you would use hashing


In [7]:
import hashlib

### An example of creating a password, storing this hashed value and validating future logins

# Create a new password, hash it and store it in a database 
new_password = b'Super_secret_password'
hashed_new_password = hashlib.sha256(new_password) 
hex_new_password = hashed_new_password.hexdigest() # Export this as a hexadecimal value (store this in a database)
print('New password hex: \t{0}'.format(hex_new_password))

# Now a user wants to log in using this password
# We validate whether the password is correct by hashing it and comparing it against the value in the database
# First try an incorrect password
bad_password = b'Wr0ngPassword'
hashed_bad_password = hashlib.sha256(bad_password)
hex_bad_password = hashed_bad_password.hexdigest() 
print('Bad password hex: \t{0}'.format(hex_bad_password))

# Now attempt to compare
if hex_new_password == hex_bad_password:
    print("Successfully logged in!\n")
else:
    print("Login failed!\n")

# Now do correct password validation    
correct_password = b'Super_secret_password'
hashed_correct_password = hashlib.sha256(correct_password)
hex_correct_password = hashed_correct_password.hexdigest() 
print('Correct password hex: \t{0}'.format(hex_correct_password))

# Now attempt to compare
if hex_new_password == hex_correct_password:
    print("Successfully logged in!\n")
else:
    print("Login failed!\n")


New password hex: 	598d162b9ac3d2170f68a435ae2540935d3b19c86929bd2b6320cb42e338ba3f
Bad password hex: 	5815400171596b064a68519d6b935561e7eac65159e5fa4805f34236b8b3a870
Login failed!

Correct password hex: 	598d162b9ac3d2170f68a435ae2540935d3b19c86929bd2b6320cb42e338ba3f
Successfully logged in!


In [28]:
### This doesn't quite work just yet.

# You can also hash objects
hashed_alice_wallet = hashlib.sha256(bytes(alice_wallet))
print('Hashed version of alice_wallet: \t{0}'.format(hashed_alice_wallet.hexdigest()))
hashed_bob_wallet = hashlib.sha256(bytes(bob_wallet))
print('Hashed version of bob_wallet: \t\t{0}'.format(hashed_bob_wallet.hexdigest()))

# Create a new version of bob_wallet
new_bob_wallet = DigitalWallet(name='Bob')
hashed_new_bob_wallet = hashlib.sha256(bytes(new_bob_wallet))
print('Hashed version of new_bob_wallet: \t\t{0}'.format(hashed_new_bob_wallet.hexdigest()))


Hashed version of alice_wallet: 	0a51170fc2a1d15e8c5d485070f1fbc69d9c39f5c5b346c49c50520cb6f77409
Hashed version of bob_wallet: 		c344c87f05e1b13ee2531749742deb19e9ec870c7f1997821dc21e029a994d4b
Hashed version of new_bob_wallet: 		6693e368a0f3c19682e72d61cd6ac341a27624815b704f4c0436a6348bce1c10