The Knights of Python: Ep.1.0 - Crypto - Simple File Encryption

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!

7 Likes

Challenge! Level 1 Tech Ransomware to finance the show :p

3 Likes

Good tutorial. I'm wondering is there an advantage of the Crypto library over the cryptography library?

1 Like

hmm didn't saw it first time i read this, Quick look and it looks like the cryptography is maintained more and also looks maintained more up to date.
But that doesn't say a lot.

I ended up using the cryptography library for something a while bad (python crypto was fairly new to me), but i ended up using it over the crypto one for some reason i cant remember. It was up to date and worked i think..

Last time worked on the crypto library is 2015 and i think you use python 3.5+
cryptography is the replacement and should be used instead.

But am just being careful because crypto might still be good if you use older python.
But good pointing it out.

3 Likes

I agree here is a snippet from Crytography:

Why a new crypto library for Python?

If you’ve done cryptographic work in Python before, you’ve probably seen some other libraries in Python, such as M2Crypto, PyCrypto, or PyOpenSSL. In building cryptography we wanted to address a few issues we observed in the existing libraries:

Lack of PyPy and Python 3 support.
Lack of maintenance.
Use of poor implementations of algorithms (i.e. ones with known side-channel attacks).
Lack of high level, “Cryptography for humans”, APIs.
Absence of algorithms such as AES-GCM and HKDF.
Poor introspectability, and thus poor testability.
Extremely error prone APIs, and bad defaults.

I can follow up on this using Cryptography instead, at the time I was more familiar with PyCrypto.

3 Likes