## Exercise: Encrypt and Decrypt Data

While Bitcoin doesn't actually encrypt any data, it relies upon public and private keys pairs. Working with Bitcoin requires familiarity with these keys and the best way to get familiar with technology is to use it! In this exercise, we'll generate a key pair and use those keys to encrypt and decrypt data with a bit of Python.

In this lesson we'll use Python to learn how to generate a key pair and then how to use that key pair to encrypt and decrypt data.

Again, Bitcoin doesn't encrypt any data, all blockchain data is public. What we are learning here is how to work with public key cryptography which is heavily used in Bitcoin.

For this example we'll use a Python cryptography library called pycryptodomex. Bitcoin uses elliptic curve cryptography and more specifically, the SECP256k1 curve. We'll introduce you to those functions in the next unit.

First let's install the pycryptodomex package.

pip3 install pycryptodome

Then import the functions we need.

from Crypto.Cipher import PKCS1_OAEP
from Crypto.PublicKey import RSA
from binascii import hexlify

Now let's create a secret message to encrypt.

message = b'I love cryptography!'

Before we can encrypt we'll need a key pair. We'll first generate a private key, and then derive the public key from the private key. There are a number of different options for key generation here, but we'll go with a key length of 1024 bits.

private_key = RSA.generate(1024)
public_key = private_key.publickey()

We can also print these objects out at this point to be sure they are what we are expecting, which is "class 'Crypto.PublicKey.RSA.RsaKey'".

print(type(private_key), type(public_key))

Now we'll convert our keys to strings, save them in.pem files and take a look at them.

private_pem = private_key.export_key().decode()
public_pem = public_key.export_key().decode()

Be sure that they are now strings.

print(type(private_pem), type(public_pem))

And save the strings to.pem files

with open('private.pem', 'w') as pr:
pr.write(private_pem)
with open('public.pem', 'w') as pu:
pu.write(public_pem)


And print it out.

print('private.pem:')
with open('private.pem', 'r') as f:
print(f.read())

print('public.pem:')
with open('public.pem', 'r') as f:
print(f.read())

Now let's convert these key files back into RSA key objects, and do some encrypting.

pr_key = RSA.import_key(open('private.pem', 'r').read())
pu_key = RSA.import_key(open('public.pem', 'r').read())

And again, let's check on it.

print(type(pr_key), type(pu_key))

And now, the encryption! Remember data is encrypted with a public key and decrypted with the corresponding private key.

Encrypt.

cipher = PKCS1_OAEP.new(key=pu_key)
cipher_text = cipher.encrypt(message)

And have a look.

print(cipher_text)

We'll now use our private key to decrypt the message back to its original form.

decrypt = PKCS1_OAEP.new(key=pr_key)
decrypted_message = decrypt.decrypt(cipher_text)

And check if it worked!

print(decrypted_message)

If you see your original message, congrats, you completed the first exercise. You're done!

print('Done!')