2015-02-04 20:51:31 +01:00
package de.vanitasvitae.enigmandroid ;
/ * *
* Enigma - machine
2015-03-14 00:29:43 +01:00
* Copyright ( C ) 2015 Paul Schaub
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License along
with this program ; if not , write to the Free Software Foundation , Inc . ,
51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
2015-02-18 21:51:40 +01:00
* @author vanitasvitae
2015-02-04 20:51:31 +01:00
* /
2015-02-18 21:51:40 +01:00
public class Enigma
2015-02-04 20:51:31 +01:00
{
2015-02-18 21:51:40 +01:00
private Plugboard plugboard ;
2015-02-04 20:51:31 +01:00
2015-02-11 20:56:43 +01:00
//Slots for the rotors
2015-02-18 21:51:40 +01:00
private Rotor r1 ;
private Rotor r2 ;
private Rotor r3 ;
2015-02-11 20:56:43 +01:00
//Slot for the reflector
2015-02-18 21:51:40 +01:00
private Rotor reflector ;
2015-02-24 23:36:24 +01:00
private boolean prefAnomaly ; //Do you want to simulate the anomaly?
private boolean anomaly ; //Is it time to spin twice?
2015-02-18 21:51:40 +01:00
//Standard configuration (rotors 1-3, reflector B, all three rotors set to position 1, rings too)
public static final int [ ] STANDARD_CONFIGURATION = { 1 , 2 , 3 , 2 , 1 , 1 , 1 , 0 , 0 , 0 } ;
2015-02-04 20:51:31 +01:00
2015-02-18 21:51:40 +01:00
/ * *
2015-02-11 20:56:43 +01:00
* Create new Enigma with given configuration .
* If pbconf = = null no plugs will be set ( no scrambling in the plugboard ) .
* If conf = = null the enigma will be set to STANDARD_CONFIGURATION .
2015-02-18 21:51:40 +01:00
*
* @param pbconf two - dimensional array containing the chars symbolizing plugs that need to be switched over .
* @param conf configuration of the enigma ( a , b , c , d , e , f , g - a - c rotors , d reflector , e - g positions of the rotors )
* /
public Enigma ( char [ ] [ ] pbconf , int [ ] conf ) throws Plugboard . PlugAlreadyUsedException
{
if ( conf ! = null ) setConfiguration ( conf ) ;
else setConfiguration ( Enigma . STANDARD_CONFIGURATION ) ;
2015-02-04 20:51:31 +01:00
this . setPlugboard ( pbconf ) ;
2015-02-18 21:51:40 +01:00
}
2015-02-04 20:51:31 +01:00
2015-02-18 21:51:40 +01:00
/ * *
* Encrypt / Decrypt a given String
*
* @param w Text to decrypt / encrypt
* @return encrypted / decrypted string
* /
public String encrypt ( String w )
{
2015-02-11 20:56:43 +01:00
//output string
2015-02-18 21:51:40 +01:00
String c = " " ;
//for each char x in k
for ( int i = 0 ; i < w . length ( ) ; i + + )
{
char x = w . charAt ( i ) ;
2015-02-11 20:56:43 +01:00
//encrypt char
2015-02-18 21:51:40 +01:00
c = c + this . encryptChar ( x ) ;
}
2015-02-11 20:56:43 +01:00
//return en-/decrypted string
2015-02-18 21:51:40 +01:00
return c ;
}
2015-02-04 20:51:31 +01:00
2015-02-18 21:51:40 +01:00
/ * *
* Perform crypto on char .
* Beforehand rotate rotors . Also implement the rotor anomaly .
*
* @param k input char
* @return output char
* /
public char encryptChar ( char k )
{
//Rotate rotors
r1 . incrementCounter ( ) ;
2015-02-24 23:36:24 +01:00
if ( r1 . isAtTurnoverPosition ( ) | | ( this . anomaly & & prefAnomaly ) )
2015-02-17 01:07:33 +01:00
{
2015-02-04 20:51:31 +01:00
r2 . incrementCounter ( ) ;
2015-02-17 01:07:33 +01:00
//Handle Anomaly
2015-02-18 21:51:40 +01:00
this . anomaly = r2 . doubleTurnAnomaly ( ) ;
2015-02-17 01:07:33 +01:00
if ( r2 . isAtTurnoverPosition ( ) )
{
2015-02-04 20:51:31 +01:00
r3 . incrementCounter ( ) ;
}
}
2015-02-18 21:51:40 +01:00
int x = ( int ) k ;
x = x - 65 ; //Remove Unicode Offset (A=65 in Unicode.)
2015-02-04 20:51:31 +01:00
2015-02-18 21:51:40 +01:00
//Encryption
//forward direction
x = plugboard . encrypt ( x ) ;
x = ( x + r1 . getCounter ( ) ) % 26 ;
x = r1 . encryptForward ( x ) ;
x = ( x + r2 . getCounter ( ) - r1 . getCounter ( ) ) % 26 ;
x = r2 . encryptForward ( x ) ;
x = ( x + r3 . getCounter ( ) - r2 . getCounter ( ) ) % 26 ;
x = r3 . encryptForward ( x ) ;
x = ( 26 + x - r3 . getCounter ( ) ) % 26 ;
//backward direction
x = reflector . encryptForward ( x ) ;
x = ( 26 + x + r3 . getCounter ( ) ) % 26 ;
x = r3 . encryptBackward ( x ) ;
x = ( 26 + x - r3 . getCounter ( ) + r2 . getCounter ( ) ) % 26 ;
x = r2 . encryptBackward ( x ) ;
x = ( 26 + x - r2 . getCounter ( ) + r1 . getCounter ( ) ) % 26 ;
x = r1 . encryptBackward ( x ) ;
x = ( 26 + x - r1 . getCounter ( ) ) % 26 ;
x = plugboard . encrypt ( x ) ;
2015-02-04 20:51:31 +01:00
2015-02-18 21:51:40 +01:00
return ( char ) ( x + 65 ) ; //Add Offset
}
/ * *
* Prepare String for encryption via enigma
2015-02-04 20:51:31 +01:00
* Replace . , ! ? : with X
* Remove all other chars that are not A . . Z
2015-02-18 21:51:40 +01:00
*
* @param word string
* @return prepared string
* /
public static String prepare ( String word )
{
String w = word . toUpperCase ( ) ;
2015-02-04 20:51:31 +01:00
String c = " " ;
2015-02-18 21:51:40 +01:00
for ( int i = 0 ; i < w . length ( ) ; i + + )
{
char x = w . charAt ( i ) ;
if ( x > = 65 & & x < = 90 ) //If x in [A..Z]
{
c = c + x ; //Append to String
}
//if x is special symbol
else
{
if ( x = = '.' | | x = = ',' | | x = = '!' | | x = = '?' | | x = = ':' )
{
//replace x with X and encrypt
c = c + 'X' ;
}
}
}
return c ;
}
2015-02-04 20:51:31 +01:00
2015-02-18 21:51:40 +01:00
/ * *
* Create Plugboard configuration from String .
2015-02-11 20:56:43 +01:00
* String must be in format XY , AZ and so on .
2015-02-04 20:51:31 +01:00
* X and Y are plugs , that will be switched over .
2015-02-11 20:56:43 +01:00
* Don ' t use plugs twice such as in AA or AB , CA . This will cause Exceptions .
2015-02-18 21:51:40 +01:00
*
* @param p String
* @return Array containing plugboard configuration
* /
public static char [ ] [ ] parsePlugs ( String p ) throws InvalidPlugboardConfigurationFormatException
{
2015-02-23 18:19:37 +01:00
p = p . toUpperCase ( ) ;
2015-02-11 20:56:43 +01:00
//Check, if empty
2015-02-18 21:51:40 +01:00
if ( p . length ( ) = = 0 )
2015-02-04 20:51:31 +01:00
{
return null ;
}
2015-02-11 20:56:43 +01:00
//Ensure uppercase and split string
2015-02-04 20:51:31 +01:00
String [ ] in = p . toUpperCase ( ) . split ( " , " ) ;
2015-02-11 20:56:43 +01:00
//Check, whether input have had a correct length. Length+1 divided by 3 should be exactly how much fields there are in the array.
//(2 chars or 2 chars followed by any times a comma and two chars)
2015-02-18 21:51:40 +01:00
if ( in . length ! = ( p . length ( ) + 1 ) / 3 )
2015-02-04 20:51:31 +01:00
{
2015-02-11 20:56:43 +01:00
throw new InvalidPlugboardConfigurationFormatException ( " Error parsing plugs! Maybe you missed a ','? " ) ;
2015-02-18 21:51:40 +01:00
} else
2015-02-04 20:51:31 +01:00
{
2015-02-11 20:56:43 +01:00
//Create new 2 dimensional array for pairs of plugs
2015-02-18 21:51:40 +01:00
char [ ] [ ] plugs = new char [ ( p . length ( ) + 1 ) / 3 ] [ 2 ] ;
2015-02-11 20:56:43 +01:00
//Fill the array
2015-02-18 21:51:40 +01:00
int i = 0 ;
for ( String x : in )
2015-02-04 20:51:31 +01:00
{
2015-02-11 20:56:43 +01:00
//Check, whether string is not representing a pair
2015-02-18 21:51:40 +01:00
if ( x . length ( ) ! = 2 )
2015-02-04 20:51:31 +01:00
{
2015-02-11 20:56:43 +01:00
throw new InvalidPlugboardConfigurationFormatException ( " Error parsing plugs! Maybe you didn't enter a pair somewhere? " ) ;
2015-02-04 20:51:31 +01:00
}
2015-02-11 20:56:43 +01:00
//If it does
2015-02-04 20:51:31 +01:00
else
{
2015-02-23 18:19:37 +01:00
char [ ] pair = x . toCharArray ( ) ;
//Check, if Plugs are in alphabet
if ( pair [ 0 ] < 65 | | pair [ 1 ] < 65 | | pair [ 0 ] > 90 | | pair [ 1 ] > 90 ) throw new InvalidPlugboardConfigurationFormatException ( " Error parsing plugs! Maybe you entered a number or a special character? " ) ;
else
{
//add it to the array
plugs [ i ] = pair ;
i + + ;
}
2015-02-04 20:51:31 +01:00
}
}
return plugs ;
}
2015-02-18 21:51:40 +01:00
}
2015-02-04 20:51:31 +01:00
2015-02-11 20:56:43 +01:00
/ * *
2015-02-18 21:54:26 +01:00
* Set the plugboard to a new created object and set the configuration
2015-02-18 21:51:40 +01:00
*
2015-02-11 20:56:43 +01:00
* @param c configuration
* @throws Plugboard . PlugAlreadyUsedException
* /
2015-02-04 20:51:31 +01:00
public void setPlugboard ( char [ ] [ ] c ) throws Plugboard . PlugAlreadyUsedException
{
plugboard = new Plugboard ( ) ;
2015-02-18 21:51:40 +01:00
if ( c ! = null )
2015-02-04 20:51:31 +01:00
{
2015-02-11 20:56:43 +01:00
//Set each plug pair
2015-02-18 21:51:40 +01:00
for ( char [ ] x : c )
2015-02-04 20:51:31 +01:00
{
2015-02-18 21:51:40 +01:00
plugboard . setPlugPair ( x [ 0 ] , x [ 1 ] ) ;
2015-02-04 20:51:31 +01:00
}
}
}
2015-02-18 21:51:40 +01:00
/ * *
* Set config of the enigma
*
* @param conf configuration
* /
public void setConfiguration ( int [ ] conf )
{
if ( conf . length ! = 10 )
{
setConfiguration ( Enigma . STANDARD_CONFIGURATION ) ;
} else
{
int ro1 = conf [ 0 ] ;
int ro2 = conf [ 1 ] ;
int ro3 = conf [ 2 ] ;
int ref = conf [ 3 ] ;
int r1rot = 26 + conf [ 4 ] - 1 ;
int r2rot = 26 + conf [ 5 ] - 1 ;
int r3rot = 26 + conf [ 6 ] - 1 ;
int ro1Ring = conf [ 7 ] ;
int ro2Ring = conf [ 8 ] ;
int ro3Ring = conf [ 9 ] ;
2015-02-04 20:51:31 +01:00
2015-02-18 21:51:40 +01:00
//Set first rotor
switch ( ro1 )
{
case 1 :
{
r1 = new Rotor ( '1' , ( r1rot ) % 26 , ro1Ring ) ;
break ;
}
case 2 :
{
r1 = new Rotor ( '2' , ( r1rot ) % 26 , ro1Ring ) ;
break ;
}
case 3 :
{
r1 = new Rotor ( '3' , ( r1rot ) % 26 , ro1Ring ) ;
break ;
}
case 4 :
{
r1 = new Rotor ( '4' , ( r1rot ) % 26 , ro1Ring ) ;
break ;
}
case 5 :
{
r1 = new Rotor ( '5' , ( r1rot ) % 26 , ro1Ring ) ;
break ;
}
}
//Set second rotor
switch ( ro2 )
{
case 1 :
{
r2 = new Rotor ( '1' , ( r2rot ) % 26 , ro2Ring ) ;
break ;
}
case 2 :
{
r2 = new Rotor ( '2' , ( r2rot ) % 26 , ro2Ring ) ;
break ;
}
case 3 :
{
r2 = new Rotor ( '3' , ( r2rot ) % 26 , ro2Ring ) ;
break ;
}
case 4 :
{
r2 = new Rotor ( '4' , ( r2rot ) % 26 , ro2Ring ) ;
break ;
}
case 5 :
{
r2 = new Rotor ( '5' , ( r2rot ) % 26 , ro2Ring ) ;
break ;
}
}
//Set third rotor
switch ( ro3 )
{
case 1 :
{
r3 = new Rotor ( '1' , ( r3rot ) % 26 , ro3Ring ) ;
break ;
}
case 2 :
{
r3 = new Rotor ( '2' , ( r3rot ) % 26 , ro3Ring ) ;
break ;
}
case 3 :
{
r3 = new Rotor ( '3' , ( r3rot ) % 26 , ro3Ring ) ;
break ;
}
case 4 :
{
r3 = new Rotor ( '4' , ( r3rot ) % 26 , ro3Ring ) ;
break ;
}
case 5 :
{
r3 = new Rotor ( '5' , ( r3rot ) % 26 , ro3Ring ) ;
break ;
}
}
//Set reflector
switch ( ref )
{
case 1 :
{
reflector = new Rotor ( 'A' , 0 , 0 ) ;
break ;
}
case 2 :
{
reflector = new Rotor ( 'B' , 0 , 0 ) ;
break ;
}
case 3 :
{
reflector = new Rotor ( 'C' , 0 , 0 ) ;
break ;
}
}
}
}
2015-02-11 20:56:43 +01:00
/ * *
* Return the configuration , the enigma machine is in right NOW
2015-02-18 21:51:40 +01:00
*
2015-02-11 20:56:43 +01:00
* @return array containing configuration
* /
public int [ ] getConfiguration ( )
2015-02-04 20:51:31 +01:00
{
2015-02-18 21:51:40 +01:00
int [ ] c = new int [ 10 ] ;
2015-02-04 20:51:31 +01:00
{
c [ 0 ] = r1 . getType ( ) ;
c [ 1 ] = r2 . getType ( ) ;
c [ 2 ] = r3 . getType ( ) ;
2015-02-11 20:56:43 +01:00
c [ 3 ] = reflector . getType ( ) ;
2015-02-04 20:51:31 +01:00
c [ 4 ] = r1 . getCounter ( ) ;
c [ 5 ] = r2 . getCounter ( ) ;
c [ 6 ] = r3 . getCounter ( ) ;
2015-02-18 21:51:40 +01:00
c [ 7 ] = r1 . getRingsetting ( ) ;
c [ 8 ] = r2 . getRingsetting ( ) ;
c [ 9 ] = r3 . getRingsetting ( ) ;
2015-02-04 20:51:31 +01:00
}
return c ;
}
2015-02-24 23:36:24 +01:00
public void setPrefAnomaly ( boolean b )
{
this . prefAnomaly = b ;
}
2015-02-04 20:51:31 +01:00
public static class InvalidPlugboardConfigurationFormatException extends Exception
{
public InvalidPlugboardConfigurationFormatException ( String m )
{
super ( m ) ;
}
}
}