Assignment 1: Encryption

Summary
For this assignment, you will implement a classic (but not recommended!!) encryption technique. Classical encryption is based on the principle of substituting letters for other letters. These may be simple schemes like the ones we’ll implement in this homework or more complicated schemes such as the ones employed in the Enigma machine. The Enigma machine was used by Nazi Germany during World War II and was subsequently broken by the allies, in particular the researchers at the British Government Code and Cypher School, notably Alan Turing who led the development of the Bombe machines that were used to break the Enigma machines.
Collaboration
Each student should submit their own responses to this assignment. You may consult other students in the class as you review the course materials but you should not work together in the assignment. If you receive help from anyone (tutor or mentor), make sure to cite them. You do not need to cite course pages you were instructed to read for this assignment.

Goals for this assignment.

  • Use Scanner to create interactive programs that read user input
  • Write your own utility class
  • Practice using the String class
  • Create user-defined packages

Starter Code

Use the start-up code in the following path on MathLAN

/home/jimenezp/csc207/assignments/encryption/

Copy the Java files to your home directory.

You will be working with the Caesar Cipher class and testing program.

Encryption Preliminaries

The theory of encryption is a cornerstone of cryptography and computer security where we make our communication and/or data secure from adversaries.

Before the advent of computers, classical cryptography used various transposition and substitution ciphers to encrypt data. Here are some basic definitions you should know before proceeding.

  • A cipher is a pair of algorithms for encrypting and decrypting data.
  • Plaintext is un-encrypted data.
  • Ciphertext is encrypted data.
  • A transposition cipher creates ciphertext from plaintext by re-arranging the letters in the text in some pre-determined fashion.
  • A substitution cipher creates ciphertext from plaintext by substituting one letter for another letter.

Ciphers in classical cryptography were designed to be executed by hand with analog tools. For example, the Solitaire Cipher was designed to be hand-executed by secret agents in the field with nothing more than a deck of cards. More elaborate encryption schemes required the use of mechanical computing devices that became the forefathers of the modern-day digital computers, the Enigma machine described in the introduction being the quintessential example. However, in the age of digital computers, classical cryptography methods are no longer useful for most practical purposes because a computer can either brute-force through these encryption schemes, or otherwise greatly assist an educated individual in breaking the code.

To implement these classical cryptographic schemes, we need to understand how to map the mathematical models that underlie them into Java. Luckily this is relatively straightforward. For sake of simplicity, let’s assume that we’re only working with lowercase English letters and that each letter is assigned a number—from ‘a’ represented by 0 to ‘z’ represented by 25—called the character code of that letter. Given a single letter ch and a single letter key to encrypt the letter with:

  • To encrypt ch with key, “add” key to ch. That is, add their corresponding character codes, and the result is the character code of the corresponding encrypted letter. If you go over 25, wrap around. For example, If we encrypt c with j, then we get the letter l because the code for c is 2 and the code for j is 9. Thus, 2 + 9 = 11 which is the code for the letter l. If we encrypt x with e, then we get b because the code for x is 23 and the code for e is 4. 23 + 4 = 27 but since 27 isn’t a valid code, we wrap around and get 1 which is the code for b.
  • To decrypt ch with key, “subtract” key from ch. In the case when the difference is negative, we wrap around like with addition.

By thinking of characters as numbers, we can formalize this style of encryption as well as directly implement it in Java. With character values, encryption can be thought of the formula:

E = (ch + key) mod 26. 

Decryption is described by the formula:

D = (ch - key) mod 26. 

Mod here is almost the % operator, but not quite. The problem is that negative integers do not “wrap around” like you expect, e.g., -2 % 26 is -2 rather than 24. You will need to do a little bit of extra work to obtain the desired behavior in this case.

To get the character value of a single character, we can convert it to an integer by casting to the appropriate type:

int ch = (int) 'e'; // ch contains 101 

However, we said that the character code for e is 4. What is going on here? It turns out that we assign character codes to not just lowercase letters but to all possible letters. Imagine putting all the possible letters on a line. The lowercase letters occupy indices 97 through 122 on that line:

 int ch1 = (int) 'a'; // ch1 contains 97
 int ch2 = (int) 'z'; // ch2 contains 122 

To “re-base” these numbers at index zero, we simply need to subtract the character value of a.

 int base = (int) 'a';
 int b1 = 'a' - base; // b1 contains 0
 int b2 = 'z' - base; // b2 contains 25 

When we want to get a letter back given a computed character value in the range 0-25, we simply reverse the process by adding back in (int) ‘a’ and then casting back to char.

int result = 22; 
char ch = (char)(result + base); // ch contains w 

The Caesar Cipher

With the fundamentals of manipulating characters-as-numbers out of the way, we will now implement a number of classic ciphers based off these cryptographic principles. First, we will implement the Caesar Cipher, so named after Julius Caesar who used this encryption for his own private correspondence.

In terms of the formula described above, the key we use to add and subtract to each character is constant. That is, for any message, we pick a particular value n and encrypt a message with:

E = (ch + n) mod 26 

And we decrypt a message with

D = (ch - n) mod 26 

For example, say we want to encrypt the message hello, we would pick a key n, say n = 11. Then, to encode the message, we calculate:

 'h' + 11 = 7 + 11 = 18 = 's'
 'e' + 11 = 4 + 11 = 15 = 'p'
 'l' + 11 = 11 + 11 = 22 = 'w'
 'l' + 11 = 11 + 11 = 22 = 'w'
 'o' + 11 = 14 + 11 = 25 = 'z' 

To decrypt the message, we subtract the key rather than add it:

 's' - 11 = 18 - 11 = 7
 'p' - 11 = 15 - 11 = 4
 'w' - 11 = 22 - 11 = 11
 'w' - 11 = 22 - 11 = 11
 'z' - 11 = 25 - 11 = 14 

Your task is to write a program in a class called CaesarCipher that encodes and decodes messages using the Caesar cipher as described above. Because there are only 26 letters in the English alphabet, rather than shifting according to a user-defined value, we can simply show the user the result of applying all 26 possible shifts!

Here are some example executions of the program you should create.

 $ java CaesarCipherTester
 This program encrypts and decrypts messages using the Caesar Cipher.
 Would you like to encode or decode a message? encode
 Enter the string to encode: helloworld
 n = 0: helloworld
 n = 1: ifmmpxpsme
 n = 2: jgnnqyqtnf
 n = 3: khoorzruog
 n = 4: lippsasvph
 n = 5: mjqqtbtwqi
 n = 6: nkrrucuxrj
 n = 7: olssvdvysk
 n = 8: pmttwewztl
 n = 9: qnuuxfxaum
 n = 10: rovvygybvn
 n = 11: spwwzhzcwo
 n = 12: tqxxaiadxp
 n = 13: uryybjbeyq
 n = 14: vszzckcfzr
 n = 15: wtaadldgas
 n = 16: xubbemehbt
 n = 17: yvccfnficu
 n = 18: zwddgogjdv
 n = 19: axeehphkew
 n = 20: byffiqilfx
 n = 21: czggjrjmgy
 n = 22: dahhksknhz
 n = 23: ebiiltloia
 n = 24: fcjjmumpjb
 n = 25: gdkknvnqkc

 $ java CaesarCipherTester
 This program encrypts and decrypts messages using the Caesar Cipher.
 Would you like to encode or decode a message? decode
 Enter the string to decode: dahhksknhz
 n = 0: dahhksknhz
 n = 1: czggjrjmgy
 n = 2: byffiqilfx
 n = 3: axeehphkew
 n = 4: zwddgogjdv
 n = 5: yvccfnficu
 n = 6: xubbemehbt
 n = 7: wtaadldgas
 n = 8: vszzckcfzr
 n = 9: uryybjbeyq
 n = 10: tqxxaiadxp
 n = 11: spwwzhzcwo
 n = 12: rovvygybvn
 n = 13: qnuuxfxaum
 n = 14: pmttwewztl
 n = 15: olssvdvysk
 n = 16: nkrrucuxrj
 n = 17: mjqqtbtwqi
 n = 18: lippsasvph
 n = 19: khoorzruog
 n = 20: jgnnqyqtnf
 n = 21: ifmmpxpsme
 n = 22: helloworld
 n = 23: gdkknvnqkc
 n = 24: fcjjmumpjb
 n = 25: ebiiltloia
 

$ java CaesarCipher
 This program encrypts and decrypts messages using the Caesar Cipher.
 Would you like to encode or decode a message? booboo
 Valid options are "encode" or "decode" 

Note how the program operates:

  1. The CaesarCipher program first describes what it does.
  2. It prompts the user, asking whether the user wants to encode or decode a message.
  3. If the user does not respond with either encode or decode, the program displays the valid options to the user (as shown above) and then exits.
  4. Otherwise, the program prompts the user for the string to either encode or decode.
  5. Finally, the program displays all 26 possible ways of encoding or decoding that string.

Your program must follow this format exactly and produce identical output to the sample execution above.

Here are some assumptions you can make about the user input to simplify the problem:

  • The user must enter exactly encode or decode as the first input to the program. If the user enters any other string, the program displays the valid options and then exits.
  • The string the user provides to be encoded or decoded must consist of only lowercase characters. In particular, the string should not contain any whitespace.

For this program, you will need to use a handful of String methods and constructors:

  • s.charAt(n) retrieves the character at the nth index of string s.
  • s.toCharArray() creates a character array (i.e., a value of type char[]) containing the characters of string s.
  • s.length() returns the number of characters in the string s.
  • new String(arr) creates a new string from the given character array arr.

Also, to retrieve input from user, you will need to use the Scanner class. To use the Scanner, you must first import it from the java.util package as shown below:

import java.util.Scanner;

Then, you can instantiate a Scanner that is attached to the keyboard (i.e., standard input). You can query the Scanner for a line of input with the nextLine() method:

 Scanner in = new Scanner(System.in);
 String response = in.nextLine(); 

Finally, create a package for your classes, called “ciphers”

Submission Guidelines

This assignment must be done individually, and you may NOT work with another student!! If you need help, contact your course mentor or instructor. Your work should be your own; remember to include your Academic Honesty Statement at the beginning of your program (Client App or Tester). If you ask your course mentor for help, you must include him in the list of sources consulted!

You will submit your source files (.java) files but NOT your compiled code. You should also include a file that describes how to compile your program files (yes, it will be very short in this instance). You must remember to compress the folder that contains your source (but NOT binary) files before you submit them to Gradescope (.tar.gz as practiced in the first lab).

Grading

You must submit this assignment via Gradescope and include an Academic Honesty Statement at the beginning of one of your .java files (main program). Your program must compile and run in the MathLAN environment for it to be graded. Neither the instructor nor the graders will make corrections to your program since the submission must be your own, individual work. If your program does not compile will not receive a grade.

This assignment is worth up to 25 points, based on the following criteria:

Good practices – Documentation

  • [2 point] Program gives an introductory message regarding the program’s purpose.
  • [2 point] Well documented code, use header comments, comments to describe methods and parts of the code as you consider appropriate.

Meet Requirement specification

  • [2 points] Program requests the operation mode (encrypt vs. decrypt) and accepts the appropriate string input.
  • [2 points] Program prompts the user for the string to encode or decode and accepts the input.
  • [5 points] Program converts the plain text string to characters, converts each character, and assembles a new string.
  • [5 points] Program creates the table for all possible encryption/decription keys (n).
  • [3 points] Program output in testing matches the example given exactly.
  • [1 point] All required files are correct and included in the submission.
  • [1 point] Classes are part of a package.

Handling errors

  • [2 point] If the user does not enter the appropriate response, the program gives an error message and terminates gracefully.