Coding Supply

Everything a Programmer Needs

  • Programming Monitors
  • Learn Programming
  • Programming Laptops
  • Start a Programming Blog
  • Blog
Learn Simple Encryption in Ruby

Updated: September 26, 2018 Leave a Comment

Learn Simple Encryption in Ruby

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.

Related posts:

What's the difference between PL/SQL and SQL?

Filed Under: Learn Programming Tagged With: encryption, ruby

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Search codingSupply

Categories

  • Career
  • Learn Programming
  • Productivity
  • Programming Gear
  • Programming Languages
  • Students
best-keyboards-for-programming

Best Keyboard for Programming [2021 Update]

A computer programmers most important tool (besides our glorious minds, of course) is the keyboard. A keyboard is vessel in which you turn the solutions to problems into code, and thus it’s vitally important that every developer has a keyboard they feel awesome with. But a keyboard is just a keyboard, right? No way! Keyboards […]

starting programming blog

How to Start a Programming Blog in 2021

If you’re looking to make the most out of your programming career, making a name for yourself is the best way to open up countless opportunities. The best way to do this is by starting your very own programming blog. Certainly not every programmerneeds to do this in order to have a great career, but […]

best headphones programming

Best Headphones for Programming in 2021

Any experienced programmer can tell you that achieving a flow state while coding is one of the most fulfilling professional you can hope to have. Entering the “flow state” can be described as when you become engrossed in your work, and your coding flows effortlessly. In these flow states, it’s possible to be extremely productive and […]

Copyright © 2023 Coding Supply · Amazon Affiliate Disclosure