Question

In: Computer Science

BACKGROUND Substitution ciphers that encode a message by substituting one character for another go back at...

BACKGROUND

Substitution ciphers that encode a message by substituting one character for another go back at least as far as Julius Caesar, who used a rotating character scheme to encode military orders. This simple type of encryption is vulnerable to statistical attacks, however, as anyone who has solved CRYPTOGRAM puzzles can attest. In World War II, the Nazi military employed an encryption scheme that addressed this weakness of simple substitution ciphers. This scheme, implemented by typewriter-sized devices known as Enigma machines, gave the Nazis a tactical advantage that greatly contributed to their early success in the war. In fact, the eventual breaking of this coding scheme by researchers at Bletchley Park, England (including Alan Turing) is hailed as one of the turning points of the war.

Enigma machines used interchangeable rotors that could be placed in different orientations to obtain different substitution patterns. More significantly, the rotors rotated after each character was encoded, changing the substitution pattern and making the code very difficult to break. The behavior of the rotating rotors can be modeled, in a simplified form, by a device consisting of labeled, concentric rings. For example, the model below has three rings labeled with the letters of the alphabet and '#' (representing a space).

To encrypt a character using this model, find the character on the inner rotor (i.e., the inside ring) and note the character aligned with it on the outer rotor (i.e., the outside ring), then find that character on the middle rotor (i.e., the middle ring) and output the one aligned with it on the outer rotor. After a character is encrypted, turn the inner rotor clockwise one step. Whenever the inner rotor returns to its original orientation, the middle rotor turns once in lock-step, just like the odometer in a car.

For example, in this configuration the character 'A' would be encrypted as 'N', since 'A' on the inner rotor is aligned with 'H' on the outer rotor, and 'H' on the middle rotor is aligned with 'N' on the outer rotor. After performing this encryption, the inner rotor is rotated clockwise, so the letter 'A' would next be encrypted as 'D'.

1 Adopted from Nifty Assignments - SIGCSE 2009 (http://nifty.stanford.edu/2009/reed-enigma/)

In other words, the rings are used in the following order: InnerOuterMiddleOuter. Note that decrypting a message requires following the same steps, only in reverse (i.e., find the character on the outer rotor, note the character aligned with it on the middle rotor, find that character on the outer rotor, then output the character aligned with it on the inner rotor). In short: OuterMiddleOuterInner.

ASSIGNMENT DESCRIPTION

For this assignment, you are to design and implement a Java class named Enigma that simulates this three-ring model of an Enigma machine. You may assume that all Enigma models have the same outer rotor, as shown in the above diagram. That is, the outer rotor consists of the 26 capital letters and the '#' symbol (representing a space) in the following clockwise order: #BDFHJLNPRTVXZACEGIKMOQSUWY. Since the middle and inner rotors are interchangeable, their contents and alignment relative to the outer rotor must be specified when constructing an Enigma model. For example, the initial settings of the inner and middle rotors in the above diagram are #GNUAHOVBIPWCJQXDKRYELSZFMT and #EJOTYCHMRWAFKPUZDINSXBGLQV, respectively. Using an Enigma object, it should be possible to both encode and decode text messages, with the appropriate rotation of the rotors occurring after each character encoding/decoding.

You should also design and implement a client program. For users who do not want to specify their own rotor settings, have a “default” option that uses the setting shown in the diagram. In addition, create an option that makes it simple for the user to specify the rotor settings on an Enigma model, and encode or decode text.

SPECIFIC TASKS

Using the outlines provided as a starting point:

 Complete all method stubs in the Enigma class (Enigma.java). You are welcome to add additional methods as needed to facilitate procedural decomposition

 Implement a user-friendly client program (EnigmaClient.java)

 Provide user instructions fully explaining how to use your program for making your

program user-friendly

 Fully demonstrate the proper functioning of your program by providing samples

input/output
Design and implementation guidelines:

 Javadoc comment all class files and methods

 Handle exceptions as appropriate and include @throws documentation in Javadoc

comments

 Structured code - use methods to eliminate redundancy and break large methods into

smaller, logical sub problems

ENIGMA CLASS OUTLINE

This Enigma class outline contain method “stubs” along with commented descriptions of what each method should do. You need to write the actual methods, with the appropriate inputs and outputs. An example of a method stub is provided below:

This method stub tells you that the method takes a String as input and returns a Boolean value. The comments provided in the method stub list some hints on how the String should be validated. You need to write the method and the Javadoc comment. You should also comment your code using line comments as you see fit.

WHAT TO SUBMIT

You will need to submit the following files:

 Your Enigma.java file

 Your EnigmaClient.java file

 A text document showing how you tested your program (include screen shots or copy and

paste sample output). Include a “Reflections” section in this text document that discusses any difficulties you had with the assignment, what you learned, what you found interesting, etc.

PLEASE MAKE SURE THE JAVA FILES YOU SUBMIT COMPILE AND RUN EVEN IF YOU ARE NOT ABLE TO FINISH THE PROGRAM COMPLETELY AND/OR CORRECTLY.

Sample output is provided below. You do not have to recreate this format exactly, but your program should have similar behavior.

SAMPLE PROGRAM OUTPUT

1. Upon running the program:

2. After first user selection:

3. After second user selection:
NOTE: You do not have to keep printing out rotor settings, but you may find this feature helpful when you are trying to write the encryption and decryption methods.

Solutions

Expert Solution

EnigmaClient.java

import java.util.*; // scanner
import java.io.*;

public class EnigmaClient {
   public static void main(String[] args) {
    
      giveIntro();
      Scanner console = new Scanner(System.in); // user input
      Enigma input = rotorSettings(console);
      codeMessage(console, input);
   }

   // method to give introduction to user
   public static void giveIntro() {
      System.out.println("Welcome to Enigma!");
      System.out.println("This program will help you encode or decode ");
      System.out.println("messages using an Enigma three-ring model.");
      System.out.println();
      System.out.println("Please select from the menu below:");
      System.out.println("   1. Use default rotor setings");
      System.out.println("   2. Input custom rotor settings");
      System.out.print("Selection: ");
   }

   // takes in scanner and uses user input to determind which rotor settings they want
   // returns an Enigma object with desired rotor settings
   public static Enigma rotorSettings(Scanner console) {   
      int select = console.nextInt();
      System.out.println();
      if (select == 1){
         System.out.println("Using default settings.");
         System.out.println("The Enigma model will use the following settings:");
         System.out.println("       Outer ring: #BDFHJLNPRTVXZACEGIKMOQSUWY");
         System.out.println("       Middle ring: #EJOTYCHMRWAFKPUZDINSXBGLQV");
         System.out.println("       Inner ring: #GNUAHOVBIPWCJQXDKRYELSZFMT");
         System.out.println();
         Enigma input = new Enigma();
         return input;
      } else {
         System.out.println("Using user settings.");
         System.out.println("The outer ring is: #BDFHJLNPRTVXZACEGIKMOQSUWY");
         System.out.print("Please input middle ring: ");
         String middle = console.next();
         System.out.print("Please input inner ring: ");
         String inner = console.next();
         System.out.println();
         Enigma input = new Enigma(middle, inner);
         return input;
      }
   }

   // takes in scanner and the enigma object
   // Asks to encrypt or decrypt than calls Enigma e=methods to complete
   public static void codeMessage(Scanner console, Enigma input) {
      System.out.println("Would you like to:");
      System.out.println("   1. Encript");
      System.out.println("   2. Decript");
      System.out.println("   3. Run Default Example");
      System.out.print("Selection: ");
      int selection = console.nextInt();
      System.out.println();
      if(selection == 1) {
         System.out.println("What message do you want to encrypt?");
         console.nextLine();
         System.out.println("Your encrypted code is: " + input.encrypt(console.nextLine()));
      } else if (selection == 2) {
         System.out.println("What message do you want to decrypt?");
         System.out.println("Your message is: " + input.decrypt(console.next()));
      } else {
         String example = "Computer Programing is Lots of Fun";
         System.out.println("You have chosen to use the default string: " + example);
         String encrypted = input.encrypt(example);
         System.out.println("After encrypting, your code is: " + encrypted);
         System.out.println("If we decrypt this code we get back to: " + input.decrypt(encrypted));
      }
   }
}

Enigma.java

import java.util.*;
import java.io.*;

public class Enigma {
  
   public static final String outerRotor = "#BDFHJLNPRTVXZACEGIKMOQSUWY";
   //required instance members go here
   //for example, all three rotors are declared here
   //instance member to keep count to move middle rotor
   private String middleRotor;
   private String innerRotor;
   private int counter;
   private String encryptedMessage = "";
   private String decryptedMessage = "";
         
   //default constructor - constructs enigma machine as shown in spec
   public Enigma(){
      middleRotor = "#EJOTYCHMRWAFKPUZDINSXBGLQV";
      innerRotor = "#GNUAHOVBIPWCJQXDKRYELSZFMT";
   }

   // non-default constructor - constructs machine with user specified inner and middle rotors
   // calls isRotorValid method to make sure rotors meet requirements
   public Enigma(String s1, String s2){
      if(isRotorValid(s1)){
         this.middleRotor = s1;
      }
      if(isRotorValid(s2)){
         this.innerRotor = s2;
      }
   }
  
   //verify that rotStr is exactly 27 chars long
   //verify that all chars from english alphbet occur only once
   //verify that rotor starts with a # char
   // throws exepetion or returns fale if these arent met
   private boolean isRotorValid (String rotStr){
      for(int i = 0; i < rotStr.length(); i++) {
         for(int j = 0; j < rotStr.length(); j++) {
            if(rotStr.charAt(i) == rotStr.charAt(j)) {
               return false;
            }
         }
      }
      if(rotStr.length() != 27 || rotStr.charAt(0) != '#') {
         throw new IndexOutOfBoundsException();
      }
      return true;          
   }
  
   // This takes in the message from the user and encypts it.
   // forloop runs through every character and calls encodeChar method to encypt it
   // rotates the rotors clockwise
   public String encrypt (String message){
      message = message.toUpperCase();
      for(int i = 0; i < message.length(); i++){          
         encryptedMessage += encodeChar(message.charAt(i));
         rotateClockwise();
      }
      reset();
      return encryptedMessage;
   }
  
   // This takes in the message from the user that needs to be decripted.
   // forloop runs through every character and calls decode method to decode it
   // With the examples provided in the assignment rotateAntiClockwise doesnt work
   // So I rotated it clockwise. returns decrypted new message
   public String decrypt (String message){
      for(int i = 0; i < message.length(); i++){          
         decryptedMessage += decodeChar(message.charAt(i));
         rotateClockwise();
      }
      reset();
      return decryptedMessage;
   }

   // this finds the code character for ch (as per spec)
   // takes in character from message and returns encrypted version
   private char encodeChar (char ch){
      if (ch == ' '){
         ch = '#';
      }
      char c = outerRotor.charAt(innerRotor.indexOf(ch));
      ch = outerRotor.charAt(middleRotor.indexOf(c));
      return ch;
   }
  
   // this finds the original character for the code ch (as per spec)
   // Takes in character from message and returns the decoded version
   private char decodeChar (char ch){
      char c = middleRotor.charAt(outerRotor.indexOf(ch));
      ch = innerRotor.charAt(outerRotor.indexOf(c));
      if (ch == '#'){
         return ' ';
      }
      return ch;
   }
  
   // rotates the clockwise and once inner makes full loop middle rotates once
   private void rotateClockwise(){
      innerRotor = innerRotor.charAt(innerRotor.length() - 1) + innerRotor.substring(0, innerRotor.length() - 1);
         counter ++;
      if (counter % 27 == 0) {
         middleRotor = middleRotor.charAt(middleRotor.length() - 1) + middleRotor.substring(0, middleRotor.length() - 1);
      }
   }
  
   // rotates inner counter clockwise and than middle once the inner is back at end point
   private void rotateAntiClockwise(){
      innerRotor = innerRotor.substring(1) + innerRotor.charAt(0);
      if (innerRotor.charAt(26) == '#') {
         middleRotor = middleRotor.substring(1) + middleRotor.charAt(0);
      }
   }
  
   // resets to align all # chars on all rotors (returns rotors to initial configuration)
   // by rotating clockwise until it's back at starting position
   public void reset (){
      while(innerRotor.charAt(0) != '#') {
         rotateClockwise();
      }
      while(middleRotor.charAt(0) != '#') {
         rotateClockwise();
      }
      counter = 0;
   }
}



Related Solutions

ADVERTISEMENT
ADVERTISEMENT
ADVERTISEMENT