ASCII and Other Simple Ciphers

The simple ciphers we examine in this tutorial are called monoalphabetic substitution ciphers, where one character always maps to some other letter in the adjusted alphabet. 

In addition to the Caesar cipher, you will see names like Atbash, Affine, Beaufort, Hill, and others.  Here, you can experiment with Atbash, mixed alphabet, and a very useful variation on the Caesar shift cipher that uses ASCII characters.  

ASCII Shift Cipher

The Caesar cipher works well as an introduction to ciphers, but it’s not overly practical.  With only 25 keys and every word separated by a space, it’s definitely one of the easiest ciphers to crack.  The Caesar cipher is also not a very good fit for encrypting radio data since CAPS LOCK letters with no other characters or spaces would make a script to send an encrypted version of this dictionary really difficult:

{'start' : 3, 'after' : 'Liftoff! '}

The ASCII Shift Cipher works on all printable characters, including spaces, so that dictionary string would be no problem to encrypt and decrypt with ASCII Shift.  Although it’s still considered very weak in the encryption world, 93 different keys is still more secure than 25.

Example script: ascii_shift_cipher

  • Enter and save ascii_shift_cipher, then flash it into the micro:bit.
# ascii_shift_cipher
 
from microbit import *
 
''' Function converts plaintext to ciphertext using key '''
 
def ascii_shift(key, text):
    result = ""
    for letter in text:
        ascii = ( ord(letter) + key - 32 ) % 94 + 32
        result = result + chr(ascii)
    return result
 
''' Script starts from here... '''
 
sleep(1000)
 
while True:
    text = input("Enter key: ")
    key = int(text)
 
    text = input("Enter printable character(s): ")
 
    result = ascii_shift(key, text)
    
    print("result:", result)
    print()
  • Open the terminal and follow the prompts.  Valid keys are from -93 to 93.
  • Try encrypting Cases, spaces , and punctuation! with the key set to 5.
  • Try decrypting Hfxjx1%xufhjx1%uzshyzfynts& with the key set to -5.
  • Try encrypting and decrypting a string like: {'start' : 3, 'after' : 'Liftoff! '}

How It Works: ascii_shift_cipher

Assuming you are just making use of the function, all your script has to do to encrypt some text is this:

    result = ascii_shift(key, text)

Like the caesar function, ascii_shift also has arguments for a key and text parameters that accept strings.  Unlike the caesar function, the string you pass to text can contain all printable characters including spaces, digits, punctuation, and other keyboard symbols.  The ascii_shift function also has a for letter in text loop that does the shift operation on each character and adds it to a result string, which was declared as an empty string variable before the loop.

def ascii_shift(key, text):
    result = ""
    for letter in text:
        ascii = ( ord(letter) + key - 32 ) % 94 + 32
        result = result + chr(ascii)
    return result

Inside that function, the main difference is this statement:

        ascii = ( ord(letter) - 32 + key ) % 94 + 32

That single statement does the same job as these five:

        ascii = ord(letter)

        ascii = ascii – 32

        ascii = ascii + key

        ascii = ascii % 94

        ascii = ascii + 32

Unlike the Caesar cipher, which started with characters indexed as 0…25, the printable ASCII characters are in a range of 32…126.  The modulus operator trick doesn’t work right if your alphabet doesn’t start with an index of 0.  So, it has to subtract 32 before ascii = ascii % 94, then add 32 afterwards.  Here is a breakdown of each step:

  1. Get the letter’s ASCII value with ascii = ord(letter)
  2. Subtract 32 to shift the index from 32…126 to 0…93 with ascii = ascii - 32.  
  3. Add the key with ascii = ascii + key.
  4. Circular shift any index values above 93 around to continue from zero with ascii = ascii % 94.
  5. Make sure the result goes back to the 32…126 range with ascii = ascii + 32.