In: Computer Science
Try to make it as simple as you can.
You need to do some research on different types of cryptography libraries in Python. Find out how can we use cryptography libraries in Python. Write down the steps to install the cryptography library in Python. Write a small program to encrypt and decrypt a message using the Python library.
The most useful high-level secure primitive in cryptography is the Fernet implementation. Fernet is a standard for encrypting buffers in a way that follows best-practices cryptography. It is not suitable for very big files—anything in the gigabyte range and above—since it requires you to load the whole buffer that you want to encrypt or decrypt into memory at once.
Fernet supports symmetric, or secret key, cryptography: the same key is used for encryption and decryption, and therefore must be kept safe.
Generating a key is easy:
>>> k = fernet.Fernet.generate_key()
>>> type(k)
<class 'bytes'>
Those bytes can be written to a file with appropriate permissions, ideally on a secure machine.
Once you have key material, encrypting is easy as well:
>>> frn = fernet.Fernet(k)
>>> encrypted = frn.encrypt(b"x marks the spot")
>>> encrypted[:10]
b'gAAAAABb1'
You will get slightly different values if you encrypt on your machine. Not only because (I hope) you generated a different key from me, but because Fernet concatenates the value to be encrypted with some randomly generated buffer. This is one of the "best practices" I alluded to earlier: it will prevent an adversary from being able to tell which encrypted values are identical, which is sometimes an important part of an attack.
Decryption is equally simple:
>>> frn = fernet.Fernet(k)
>>> frn.decrypt(encrypted)
b'x marks the spot'
Note that this only encrypts and decrypts byte strings. In order to encrypt and decrypt text strings, they will need to be encoded and decoded, usually with UTF-8.
One of the most interesting advances in cryptography in the mid-20th century was public key cryptography. It allows the encryption key to be published while the decryption key is kept secret. It can, for example, be used to store API keys to be used by a server: the server is the only thing with access to the decryption key, but anyone can add to the store by using the public encryption key.
While cryptography does not have any public key cryptographic secure primitives, the PyNaCl library does. PyNaCl wraps and offers some nice ways to use the NaCl encryption system invented by Daniel J. Bernstein.
NaCl always encrypts and signs or decrypts and verifies signatures simultaneously. This is a way to prevent malleability-based attacks, where an adversary modifies the encrypted value.
Encryption is done with a public key, while signing is done with a secret key:
>>> from nacl.public import PrivateKey, PublicKey,
Box
>>> source = PrivateKey.generate()
>>> with open("target.pubkey", "rb") as fpin:
... target_public_key = PublicKey(fpin.read())
>>> enc_box = Box(source, target_public_key)
>>> result = enc_box.encrypt(b"x marks the spot")
>>> result[:4]
b'\xe2\x1c0\xa4'
Decryption reverses the roles: it needs the private key for decryption and the public key to verify the signature:
>>> from nacl.public import PrivateKey, PublicKey,
Box
>>> with open("source.pubkey", "rb") as fpin:
... source_public_key = PublicKey(fpin.read())
>>> with open("target.private_key", "rb") as fpin:
... target = PrivateKey(fpin.read())
>>> dec_box = Box(target, source_public_key)
>>> dec_box.decrypt(result)
b'x marks the spot'
The PocketProtector library builds on top of PyNaCl and contains a