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))
 

About Automox

Facing growing threats and a rapidly expanding attack surface, understaffed and alert-fatigued organizations need more efficient ways to eliminate their exposure to vulnerabilities. Automox is a modern cyber hygiene platform that closes the aperture of attack by more than 80% with just half the effort of traditional solutions.

Cloud-native and globally available, Automox enforces OS & third-party patch management, security configurations, and custom scripting across Windows, Mac, and Linux from a single intuitive console. IT and SecOps can quickly gain control and share visibility of on-prem, remote and virtual endpoints without the need to deploy costly infrastructure.

Experience modern, cloud-native patch management today with a 15-day free trial of Automox and start recapturing more than half the time you're currently spending on managing your attack surface. Automox dramatically reduces corporate risk while raising operational efficiency to deliver best-in-class security outcomes, faster and with fewer resources.

More posts like this:

Cybersecurity
# of endpoints

15-day free trial. No credit card required.

By submitting this form you agree to our terms of service.

Already have an account?