The purpose for the Knights of Python series is to provide a challenge to those who are ready to make the jump from the fundamentals (some of you are pro's already) and into some code and projects. Beginners are welcome since we are a community, but the Noobs series will not go away, and more Ep.'s will come soon with more code samples & community challenges.
We begin the Intermediate to Advanced section of the Python series with one of my
favorite topics, Crypto !
The Python Crypto modules contains several cryptographic modules implementing various algorithms and protocols. Subpackages include :
Crypto.Cipher
Secret-key (AES, DES, ARC4) and public-key encryption (RSA PKCS#1) algorithms
Crypto.Hash
Hashing algorithms (MD5, SHA, HMAC)
Crypto.Protocol
Cryptographic protocols (Chaffing, all-or-nothing transform, key derivation
functions). This package does not contain any network protocols.
Crypto.PublicKey
Public-key encryption and signature algorithms (RSA, DSA)
Crypto.Signature
Public-key signature algorithms (RSA PKCS#1)
Crypto.Util
Various useful modules and functions (long-to-string conversion, random number
generation, number theoretic functions)
2 things we need to clear up before we get started: Symmetric- and Asymmetric-key
Symmetric-key algorithms are algorithms for cryptography that use the same cryptographic keys for both encryption of plaintext and decryption of ciphertext. The keys may be identical or there may be a simple transformation to go between the two keys. The keys, in practice, represent a shared secret between two or more parties that can be used to maintain a private information link.[2] This requirement that both parties have access to the secret key is one of the main drawbacks of symmetric key encryption, in comparison to public-key encryption (also known as asymmetric key encryption)
Asymmetric cryptography, is any cryptographic system that uses pairs of keys: public keys which may be disseminated widely, and private keys which are known only to the owner. This accomplishes two functions: authentication, which is when the public key is used to verify that a holder of the paired private key sent the message, and encryption, whereby only the holder of the paired private key can decrypt the message encrypted with the public key.
We will be covering Crypto.Cipher.AES
in our file simple encryptor below.
There is literally a ton of information online about these two, another type of Cryptography we will touch on is called Hashing !
Hash functions take arbitrary binary strings as input, and produce a random-like output
of fixed size that is dependent on the input; it should be practically infeasible to derive the original input data given only the hash function's output. In other words, the hash function is one-way.
Again, A ton of information and discussion can be had for these two topics, but for the code sample below, We will cover
Crypto.Hash.SHA256
We are Knights of Python, although I know some of the Noobs will curiously wander to this section, so don't be afraid to ask questions if you have any.
Q: So what do I need to get started?
A: Install the Crypto package by using pip install Crypto
On Linux, you might need python-devel packages and other tools to properly install this. I am on Fedora 24 at the moment, I needed the python-devel
, redhat-rpm-config
, also the python3-gmpy2
but not all to sure if it was necessary since I had this from a previous install.
So here is the code sample below:
import os
from getpass import getpass
from Crypto.Hash import SHA256
from Crypto.Cipher import AES
from Crypto import Random
def encrypt(key, filename):
chunksize = 64*1024
outputfile = 'encrypt.'+ filename
filesize = str(os.path.getsize(filename)).zfill(16)
IV = Random.new().read(16)
encryptor = AES.new(key, AES.MODE_CBC, IV)
with open(filename, 'rb') as infile:
with open(outputfile, 'wb') as outfile:
outfile.write(filesize.encode('UTF-8'))
outfile.write(IV)
while True:
chunk = infile.read(chunksize)
if len(chunk) == 0:
break
elif len(chunk) % 16 != 0:
chunk += b' ' * (16 - (len(chunk) % 16))
outfile.write(encryptor.encrypt(chunk))
def decrypt(key, filename):
chunksize = 64*1024
outputfile = filename[8:]
with open(filename, 'rb') as infile:
filesize = int(infile.read(16))
IV = infile.read(16)
decryptor = AES.new(key, AES.MODE_CBC, IV)
with open(outputfile, 'wb') as outfile:
while True:
chunk = infile.read(chunksize)
if len(chunk) == 0:
break
outfile.write(decryptor.decrypt(chunk))
outfile.truncate(filesize)
def getkey(password):
hashme = SHA256.new(password.encode('UTF-8'))
return hashme.digest()
def Main():
Question = input('Encrypt or Decrypt? E | D: ')
if Question == 'E':
filename = input('Please enter filename: ')
password = getpass()
encrypt(getkey(password), filename)
print('Complete!')
elif Question == 'D':
filename = input('Please enter filename: ')
password = getpass()
decrypt(getkey(password), filename)
print('Complete!')
else:
print('Please enter a valid option...')
if __name__ == '__main__':
Main()
Save the code as EncryptMe.py and you can run the code from the terminal python3 EncryptMe.py
The file you are going to encrypt has to be in the same directory you save the program. so keep that in mind. We will add functionality to the code as we move on.
If you have questions pertaining to certain things in this piece of code, please post it in the comments section. There are several modules in use here and a couple you might not be familiar with.
Code Challenge
Let's add some functionality to the program. Currently it only encrypts files and the password is not limited to any number of characters. So on to the Challenge !
1. add the ability to encrypt Directories
2. make the password at least 8 characters long
3. The Question
variable does not receive lowercase input, How would you fix that?
So Get to Code Code_Warriors!