As long as there has been civilization and written language, there has been a need for encryption. Encryption is basically the act of disguising your message so that (hopefully) only the intended recipient can read it.
While you likely associate encryption with internet protocols and WiFi passwords today, there’s a very long and interesting history of encryption dating back to ancient times. I recently read a fascinating history of cryptography called The Code Book by Simon Singh.
While the book is a bit dated in terms of modern cryptography (it was published in 2000, so don’t expect anything about blockchain), it’s still a fantastic read that I would recommend to any programmer.
Coding a Caesar Shift
The most basic and ancient example of cryptography is the “Caesar Cipher“, or “Caesar Shift”. You’ve probably created your own Caesar Cipher as a kid without even knowing the name or history of it. The basics of it are this
- Write out the message you’d like to encrypt (“HELLO”).
- Select a “secret number” (for example, 4).
- Replace every letter in your message to the letter that’s 4 spaces ahead in the alphabet (A becomes E, B becomes F, etc)
- Send the encrypted message to the recipient (“LIPPS”)
This will encrypt your message into a seemingly random looking set of characters that can’t be easily read by the human eye without deciphering it by reversing the shift using the secret number. While this level of encryption could be useful back in Ancient Rome, especially with illiterate messengers, this encryption obviously has a lot of shortcomings.
- Only 25 possible “secret numbers” means the code can be broken through brute force pretty quickly even without a computer.
- Doing a straight “substitution” encryption gives hints as to what certain characters are. For example, my encryption message has two P’s repeating, so if you think my message is in English you have a good idea it may very well represent O, E, L, etc but not A, I, Q, etc.
Nevertheless, this is a pretty fun programming exercise to create a simple Caesar Cipher. I’m going to do it below in Ruby, and here are my design specs –
- Input parameters are a phrase and a number to shift
- Output the encrypted message, removing all spaces/non-alpha characters
- Accept negative shift numbers as well as numbers of any size (which would just loop the alphabet again)
Caesar Shift in Ruby – Tests and Code
Here’s a look at my test cases written in Rspec. Can you write a solution that passes these tests?
require_relative "caesar_cipher" describe CaesarCipher do cc = CaesarCipher.new cc.input = "The Scarecrow Walks at Midnight" it "should remove non-alpha and make uppercase" do cc.shift(0) expect(cc.output).to eq "THESCARECROWWALKSATMIDNIGHT" end it "should shift letters forward by 1" do cc.shift(1) expect(cc.output).to eq "UIFTDBSFDSPXXBMLTBUNJEOJHIU" end it "should handle shift greater than alphabet length" do cc.shift(27) expect(cc.output).to eq "UIFTDBSFDSPXXBMLTBUNJEOJHIU" end it "should shift letters backwards by 1" do cc.shift(-1) expect(cc.output).to eq "SGDRBZQDBQNVVZKJRZSLHCMHFGS" end it "should handle negative shift greater than alphabet length" do cc.shift(-27) expect(cc.output).to eq "SGDRBZQDBQNVVZKJRZSLHCMHFGS" end end
Here’s the result! What did you come up with?
class CaesarCipher attr_accessor :input attr_reader :output ALPHA = ("A".."Z").to_a def initialize #set our encryption alphabet by default @encrypt_alpha = ALPHA end def shift(shift = 1) if @input.nil? @output = 'input not set!' exit end #get our secret message and split into an array plain_text = @input.upcase.split('') #create our array for the encrypted text encrypted_text =  plain_text.each do |a| index = @encrypt_alpha.index(a) #get the index number for this letter, a = 1, etc #strip out any non alphanumeric if index.nil? next end new_index = index + shift #cases where our shift put us out of bounds of the alphabet if new_index.abs > @encrypt_alpha.length - 1 if new_index > 0 #subtract length to account for large shifts or shifts at the end of the alphabet while new_index > @encrypt_alpha.length - 1 new_index -= @encrypt_alpha.length end else #add for negative cases while new_index.abs > @encrypt_alpha.length - 1 new_index += @encrypt_alpha.length end end end encrypted_text << @encrypt_alpha[new_index] end @output = encrypted_text.join end end
The obvious weakness with this encryption is there are only 25 possible “keys” for decryption. You could easily cycle through all possibilities quickly since the alphabet remains in the same order, so this simple encryption is easily cracked even without a computer. Let’s take a look on how we can greatly expand the number of keys to make a simple encryption system much more secure.
A More Secure Encryption Method
The reason why the caesar shift is so weak is that the alphabet remains in the same order, only the starting position changes and it can only change 25 times. But what if we jumbled the order of the alphabet as well? Given 26 letters, there are over 400 septillion (400,000,000,000,000,000,000,000,000) possible keys! This is a giant leap forward for security, especially in the pre-computer days.
The only drawback to this idea of making a substitution cipher by jumbling the whole alphabet is you need both parties to either a.) remember the arrangement of all 26 characters or b.) keep the key written down somewhere which could be stolen or secretly copied.
One way to overcome that without greatly diminishing our possible keys is by using a keyword cipher. The way this works is my recipient and I agree on a keyword or phrase as the basis of our cipher. For my example let’s say we choose “Wild Hoggies”. This phrase builds our cipher alphabet using the following steps
- This phrase will begin our alphabet
- Skip any repeated letters
- Fill in the rest of the alphabet with the remaining letters, A through Z, skipping any that already exist
So our encrypted alphabet becomes W I L D H O G E S A B C F J K M N P Q R T U V X Y Z.
We’re still using a simple substitution cipher where one letter converts to one other letter, both my recipient and I can easily remember how to build our secret alphabet, but the possibilities are greatly expanded as we can use a secret phrase or word of any length.
Our new test and code to accomplish this could look like this-
require_relative "caesar_cipher" describe CaesarCipher do cc = CaesarCipher.new cc.input = "The Scarecrow Walks at Midnight" it "should encrypt our phrase using a keyword" do cc.keyword_cipher("WILDHOGGIES") expect(cc.output).to eq "UEHILJTHLTFAAJCOIJUPBDQBGEU" end end class CaesarCipher attr_accessor :input attr_reader :output ALPHA = ("A".."Z").to_a def initialize #set our encryption alphabet by default @encrypt_alpha = ALPHA end def keyword_cipher(keyword = "WILDHOGGIES") @encrypt_alpha = keyword.upcase.scan /\w/ #strips out duplicates in our keyword, adds in letters from the alphabet #that are not yet in the array to build our new caesar alphabet ALPHA.each do |a| @encrypt_alpha |= [ a ] end #get our secret message and split into an array plain_text = @input.upcase.gsub(/[^A-Z]/, '').split('') #create our array for the encrypted text encrypted_text =  plain_text.each do |a| index = @encrypt_alpha.index(a) encrypted_text << ALPHA[index] end @output = encrypted_text.join end end
There you have it! An easy way to enhance some basic encryption without requiring great memory or tools at our disposal.