Otto background

Pythonic Caesar Ciphers

I was recently having a discussion with a fellow security person who stated that encryption was a ‘black art left to pure mathematicians’. And while some of it certainly is, an encryption scheme which stood up for a thousand years exists, and it can be implemented in Python.

Most folks have heard of the ‘Caesar Cipher’ (or Caesar code). The Caesar cipher uses transposition to hide its data. What that means is you move letters over by X. For example, if you had an offset of 3, the word CAT would be represented as ‘FDW’.

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
X Y Z A B C D E F G H I J K L M N O P Q R S T U V W

This method was used by Julius Caesar to send private messages back and forth. However, frequency analysis could be used to crack this cipher. In each language certain letters are most popular, such as E in the English language.

But Caesar was not defeated so easily, and so the keyed Caesar cipher was developed. A key would be something like ‘AUTOMOX’. Once added to the alphabet all unique letters are then used in the beginning, and not used again. Here, CAT is represented as ‘TAP’.

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
A U T O M O X B C D E F G H I J K L N P Q R S V W Z

With enough combination it makes it much harder to determine. Hack proof it is not, but it lasted for a long time, and is a good way to learn about keys and ciphers in Python.

Prereqs

The only external library we need to install is more_itertools. This package will allow us to get a unique list of letters from the key.

pip3 install more_itertools

 

The Program

First, let’s get the infrastructure out of the way. The code will require a key, input, and encrypt or decrypt as an option:

import argparse

import string

from  more_itertools import unique_everseen

parser = argparse.ArgumentParser(description='Caesar Cipher With Keyword')

parser.add_argument('keyword', help="Keyword or Phrase", type=str)

parser.add_argument('inputText', help="plaintext or ciphertext", type=str)

parser.add_argument('--encrypt', help="Encrypt phrase", action="store_true")

parser.add_argument('--decrypt', help="Decrypt phrase", action="store_true")

args=parser.parse_args()

 

Next, change all letters to lowercase and remove any whitespace:

def cleanup(x):

   x=x.lower()

   x=x.replace(' ', '')

   return x

 

Then, use a function that prints out the plain alphabet is necessary (we’ll need it a few times):

def plainAlpha():

   letters=[]

   for letter in string.ascii_lowercase:

       letters.append(letter)

   return letters

 

Next, use a function that will create a cipher alphabet. To do this, prepend the alphabet with unique letters in their original order from the passphrase. Then, add the remaining letters:

def createCipherAlpha(unique):

   i=len(unique)

   cipherAlpha=unique[:]

   for letter in plainAlpha():

       if letter not in unique:

           cipherAlpha.append(letter)

           i+=1

       if i == 26:

           break

   return cipherAlpha

 

Now, create a dictionary with the plaintext alphabet and the cipher alphabet, or vice versa if you are decrypting:

def createMap(key, value):

    lookupTable=dict(zip(key,value))

    return lookupTable

 

Last, create a function that creates the message using the cipher alphabet and message:

def createMessage(inputText, lookupTable):

   cipherText=""

   for letter in inputText:

       cipherText=cipherText + lookupTable[letter]

   return cipherText

 

Use some basic logic to run the program:

inputText=cleanup(args.inputText)

keyword=cleanup(args.keyword)

#Get a unique list of letters preserving order from the keyword

unique=list(unique_everseen(keyword))

#Create a cipher alphabet using the unique letters

cipherAlpha=createCipherAlpha(unique)

if args.encrypt:

   #Create a way to map plain words to cipherAlpha

   lookupTable=createMap(cipherAlpha, plainAlpha())

if args.decrypt:

   #Build an cipherAlphabet using the keyword

   lookupTable=createMap(plainAlpha(),cipherAlpha)

cipherText=createMessage(inputText, lookupTable)

print("Keyword:{}  \nUnique: {}\nOffset: {}\nOutput: {}\n".format(keyword, unique, len(unique), cipherText))

 

So, now you have the logic. Let's try it:

joes-MacBook-Pro:introcrypto joe$ ./hail.py automox --encrypt "Patch Your Shit"

Keyword:automox  

Unique: ['a', 'u', 't', 'o', 'm', 'x']

Offset: 6

Output: sachmydbuvmnc

joes-MacBook-Pro:introcrypto joe$ ./hail.py automox --decrypt sachmydbuvmnc

Keyword:automox  

Unique: ['a', 'u', 't', 'o', 'm', 'x']

Offset: 6

Output: patchyourshit

 

There you have it! A quick overview of encryption using Python. Now, don’t ask me about an elliptical curve, the math is beyond me! The whole program is included below. As usual, if you have any questions, feel free to email us: support@automox.com!

#!/usr/bin/env python3

import argparse

import string

from  more_itertools import unique_everseen

parser = argparse.ArgumentParser(description='Caesar Cipher With Keyword')

parser.add_argument('keyword', help="Keyword or Phrase", type=str)

parser.add_argument('inputText', help="plaintext or ciphertext", type=str)

parser.add_argument('--encrypt', help="Encrypt phrase", action="store_true")

parser.add_argument('--decrypt', help="Decrypt phrase", action="store_true")

args=parser.parse_args()

#cleanup keyword and input

def cleanup(x):

   x=x.lower()

   x=x.replace(' ', '')

   return x

def plainAlpha():

   letters=[]

   for letter in string.ascii_lowercase:

       letters.append(letter)

   return letters

def createCipherAlpha(unique):

   i=len(unique)

   cipherAlpha=unique[:]

   for letter in plainAlpha():

       if letter not in unique:

           cipherAlpha.append(letter)

           i+=1

       if i == 26:

           break

   return cipherAlpha

   

def createMap(key, value):

    #Create a way to map plain words to cipherAlpha

    lookupTable=dict(zip(key,value))

    return lookupTable

def createMessage(inputText, lookupTable):

   cipherText=""

   for letter in inputText:

       cipherText=cipherText + lookupTable[letter]

   return cipherText

#remove spaces and shift to lower from user input

inputText=cleanup(args.inputText)

keyword=cleanup(args.keyword)

#Get a unique list of letters preserving order from the keyword

unique=list(unique_everseen(keyword))

#Create a cipher alphabet using the unique letters

cipherAlpha=createCipherAlpha(unique)

if args.encrypt:

   #Create a way to map plain words to cipherAlpha

   lookupTable=createMap(cipherAlpha, plainAlpha())

if args.decrypt:

   #Build an cipherAlphabet using the keyword

   lookupTable=createMap(plainAlpha(),cipherAlpha)

cipherText=createMessage(inputText, lookupTable)

print("Keyword:{}  \nUnique: {}\nOffset: {}\nOutput: {}\n".format(keyword, unique, len(unique), cipherText))

 


Automox for Easy IT Operations

Automox is the cloud-native IT operations platform for modern organizations. It makes it easy to keep every endpoint automatically configured, patched, and secured – anywhere in the world. With the push of a button, IT admins can fix critical vulnerabilities faster, slash cost and complexity, and win back hours in their day. 

Grab your free trial of Automox and join thousands of companies transforming IT operations into a strategic business driver.

Dive deeper into this topic

loading...