A Simple Enigma Model Substitution ciphers that encode a message by substituting
ID: 3554682 • Letter: A
Question
A Simple Enigma Model
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'.
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).
For this assignment, you are to design a Java class named Enigma that simulates this three-ring
model. 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 other rotors are interchangeable, however, 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
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 that makes it simple for the user to
specify the rotor settings on an Enigma model, and encode or decode text. Once you have your
model working, test it by decoding the message OKNNWRDHGERPILRLAMFZF#FMUC using the
diagram settings.
Note: if you would like to make your own 3-ring Enigma model out of paper, download this
online form(http://www.jambe.co.nz/makeenigma.html), cut out the rings, and follow the instructions at the site.
Design and implementation guidelines:
? Javadoc comment all class files and methods
? Use validation and generate and handle exceptions as appropriate
? Structured code - use methods to eliminate redundancy and break large methods
Explanation / Answer
DO RATE if satisfied.
=================SAMPLE OUTPUT
Deocded string of OKNNWRDHGERPILRLAMFZF#FMUC is CONGRATULATIONS YOU GOT IT
____ Menu ____
v - View the Codes
i - set the inner ring Code
m - set the middle ring Code
o - set the outer ring Code
e - Encode a string
d - Decode a cipher text
t - test both encoding and decoding
q - quit
String will be converted to UPPER case by the program.
Your Choice :
t
Enter the plain text which will encoded and decoded:
THIS IS SAMPLE
Encoded string is JUYTNVQKXEAFUU
Decoded string is THIS IS SAMPLE
t
____ Menu ____
==============================
public class Enigma {
private String inn;
private String mid;
private String innR;
private String midR;
private String outR;
enum Ring {INNER, MIDDLE, OUTER};
/**
*This class will model an Enigma machine
*/
public Enigma(){
inn = "#GNUAHOVBIPWCJQXDKRYELSZFMT";
mid = "#EJOTYCHMRWAFKPUZDINSXBGLQV";
outR = "#BDFHJLNPRTVXZACEGIKMOQSUWY";
resetEnigma();
}
/**
* Sets the code for Inner rotor. Code should start with # and must contain all
* characters form A-Z in any order.
* @param code The code to set.
* @throws InvalidCharException
*/
public void setRing (Ring r, String code) throws InvalidCharException{
code = code.toUpperCase();
if( isValid(code) ){
switch( r ){
case INNER : inn = code; break;
case MIDDLE : mid = code; break;
case OUTER : outR = code; break;
}
resetEnigma();
}
else
throw new InvalidCharException("Code should start with # and should"
+ " contain each of A-Z in any order.");
}
/**
* Resets the Enigma machine. Enigma should be reset before new encoding and
* decoding can be performed.
*/
public final void resetEnigma(){
innR = inn.substring(0);
midR = mid.substring(0);
}
/**
* Encodes the @src string. If any illegal character is found an exception is thrown
* @param src The string to be encoded.
* @return Encoded string
* @throws InvalidCharException
*/
public String encodeString(String src) throws InvalidCharException{
char [] encodedChars = new char[src.length()];
src = src.toUpperCase();
resetEnigma();
for( int i=0; i<src.length(); i++){
char ch = src.charAt(i);
ch = ch==' ' ? '#' : ch; //replace <space> by '#'
if( ch =='#' || (ch>='A' && ch<='Z') ){
int indInner = innR.indexOf(ch);
char outChar = outR.charAt(indInner);
int indMiddle = midR.indexOf(outChar);
encodedChars[i] = outR.charAt(indMiddle);
rotateEnigma();
} else {
throw new InvalidCharException("Invalid Character in source string.");
}
}
return new String(encodedChars);
}
/**
* Decodes the @src string. If any illegal character is found an Exception is thrown
* @param src The string to be decoded
* @return Decoded string
* @throws InvalidCharException
*/
public String decodeString(String src) throws InvalidCharException{
char [] decodedChars = new char[ src.length()];
src = src.toUpperCase();
resetEnigma();
for( int i=0; i<src.length(); i++){
char ch = src.charAt(i);
if( ch =='#' || (ch>='A' && ch<='Z') ){
int indOuter = outR.indexOf(ch);
char midChar = midR.charAt(indOuter);
int indOuter2 = outR.indexOf(midChar);
decodedChars[i] = innR.charAt(indOuter2);
if( decodedChars[i] == '#')
decodedChars[i] = ' ';
rotateEnigma();
} else {
throw new InvalidCharException("Invalid Character in source string");
}
}
return new String(decodedChars);
}
/**
* Function to check if the code is valid cipher code. A valid cipher code starts with a '#'
* contains all characters from 'A-Z' in any order
* @param src the string to be checked for validity
* @return return true if condition is satisfied
* @throws InvalidCharException if the illegal character other than 'A-Z' or '#' is found
*/
public boolean isValid(String code){
if( code.indexOf('#') != 0 || code.length() != 27 )
return false;
for( char i='A'; i<='Z'; i++)
if( code.indexOf(i) == -1)
return false;
return true;
}
public void printCodes(){
System.out.println("The current codes are : ");
System.out.println("Outer Ring : " + outR);
System.out.println("Middle Ring: " + mid);
System.out.println("Inner Ring : " + inn);
}
private void rotateMidR(){
int l = midR.length();
midR = midR.substring(l-1, l) + midR.substring(0, l-1) ;
}
private void rotateEnigma(){
int l = innR.length();
innR = innR.substring(l-1, l) + innR.substring(0, l-1) ;
if( innR.equals(inn) )
rotateMidR();
}
/*
* Exception to handle invalid characters the code.
*/
@SuppressWarnings("serial")
class InvalidCharException extends Exception{
String msg;
InvalidCharException(){
msg = "Invalid Character found.";
}
InvalidCharException( String msg){
this.msg = msg;
}
@Override
public String toString(){
return msg;
}
}
}
//==========================CLIENTCLASS================================
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
*
*/
public class EnigmaClient {
/**
* Main function for testing
* @param argv
*/
public static void main(String [] argv){
String encoded = "OKNNWRDHGERPILRLAMFZF#FMUC";
boolean exitLoop = false;
Enigma em = new Enigma();
try {
System.out.println("Deocded string of " + encoded + " is " + em.decodeString(encoded) );
} catch (Enigma.InvalidCharException ex) {
ex.toString();
}
while( !exitLoop ){
try{
BufferedReader bufferRead = new BufferedReader(new InputStreamReader(System.in));
System.out.println("____ Menu ____ ");
System.out.println("v - View the Codes");
System.out.println("i - set the inner ring Code");
System.out.println("m - set the middle ring Code");
System.out.println("o - set the outer ring Code");
System.out.println("e - Encode a string");
System.out.println("d - Decode a cipher text");
System.out.println("t - test both encoding and decoding");
System.out.println("q - quit");
System.out.println("String will be converted to UPPER case by the program.");
System.out.println("Your Choice : ");
String s = bufferRead.readLine();
if( s.length()==0 ) continue;
switch( s.charAt(0)){
case 'v':
em.printCodes();
break;
case 'i':
case 'm':
case 'o':
System.out.println("Enter the cipher code (Should start with #): ");
System.out.println("String will be converted to UPPER case by the program.");
String code=bufferRead.readLine();
switch( s.charAt(0)){
case 'i': em.setRing(Enigma.Ring.INNER, code); break;
case 'm': em.setRing(Enigma.Ring.MIDDLE, code); break;
case 'o': em.setRing(Enigma.Ring.OUTER, code); break;
}
em.printCodes();
break;
case 'e':
System.out.println("Enter the plain text: ");
String src=bufferRead.readLine();
System.out.println("Encoded string is " + em.encodeString(src) );
break;
case 'd':
System.out.println("Enter the cipher text: ");
src=bufferRead.readLine();
System.out.println("Decoded string is " + em.decodeString(src) );
break;
case 't':
System.out.println("Enter the plain text which will encoded and decoded: ");
src=bufferRead.readLine();
String cipher = em.encodeString(src);
System.out.println("Encoded string is " + cipher );
System.out.println("Decoded string is " + em.decodeString(cipher) );
break;
case 'q':
exitLoop = true;
break;
default:
System.out.println("Invalid Input");
break;
}
System.out.println(s);
} catch(IOException e)
{
e.printStackTrace();
} catch ( Enigma.InvalidCharException ex){
System.out.println( ex + "Operation Failed");
}
}
}
}
Related Questions
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.