EnigmAndroid/app/src/main/java/de/vanitasvitae/enigmandroid/enigma/Enigma.java

223 lines
5.7 KiB
Java
Executable File

package de.vanitasvitae.enigmandroid.enigma;
import java.security.SecureRandom;
import java.util.Random;
/**
* Main component of the Enigma machine
* This is the mostly abstract base of any enigma machine.
* 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.
* @author vanitasvitae
*/
public abstract class Enigma
{
protected static String machineType;
protected int machineTypeOffset = 0;
protected boolean doAnomaly = false; //Has the time come to handle an anomaly?
protected boolean prefAnomaly; //Do you WANT to simulate the anomaly?
protected Random rand;
public Enigma(int off)
{
this.machineTypeOffset = off;
initialize();
}
public Enigma()
{
initialize();
}
public int getMachineTypeOffset()
{
return machineTypeOffset;
}
/**
* Set the enigma to an initial state
*/
public abstract void initialize();
/**
* Encrypt / Decrypt a given String w.
* w must be prepared using prepare(w) beforehand.
* Doing so changes the state of the rotors but not the state of the plugboard and the
* ringSettings
*
* @param w Text to decrypt/encryptString
* @return encrypted/decrypted string
*/
public String encryptString(String w)
{
//output string
String output = "";
//for each char x in k
for (char x : w.toCharArray())
{
output = output + this.encryptChar(x);
}
//return en-/decrypted string
return output;
}
/**
* Set the enigma into the next mechanical state.
* This rotates the first rotor and eventually also the second/third.
* Also this method handles the anomaly in case it should happen.
*/
public abstract void nextState();
/**
* Set the enigma into a completely random state using a unseeded SecureRandom object.
*/
public void randomState()
{
this.rand = new SecureRandom();
generateState();
}
/**
* Set the enigma to a random state based on the initialization of rand.
* Don not choose a rotor twice, set random rotations, ringSettings, ukw and possibly
* plugboard / rewirable ukw configurations.
*/
protected abstract void generateState();
/**
* Substitute char k by sending the signal through the enigma.
* The signal passes the plugboard, the rotors and returns back after going through the
* reflector wheel.
*
* @param k input char
* @return substituted output char
*/
public abstract char encryptChar(char k);
/**
* Set the state of the enigma
* @param state new state
*/
public abstract void setState(EnigmaStateBundle state);
/**
* Return an object representing the current state of the enigma
* @return state
*/
public abstract EnigmaStateBundle getState();
/**
* Set the rand into a certain state based on seed.
* Then set the enigmas state.
* @param seed
*/
public void setStateFromSeed(String seed)
{
rand = new Random(seed.hashCode());
generateState();
}
public abstract void restoreState(String mem);
public abstract String stateToString();
public static String numToMachineType(int n)
{
switch (n) {
case 0: return "I";
case 1: return "M3";
case 2: return "M4";
case 3: return "G31";
case 4: return "G312";
case 5: return "G260";
case 6: return "D";
case 7: return "K";
case 8: return "KS";
case 9: return "KSA";
case 10: return "R";
default: return "T";
}
}
public static String chooseEnigmaFromSeed(String seed)
{
return numToMachineType(seed.hashCode() % 12);
}
public static String chooseEnigmaFromSave(String save)
{
int index = save.indexOf(":");
if(index != -1) save = save.substring(0, index);
long s = Long.valueOf(save);
return numToMachineType(getValue(s,12));
}
/**
* set prefAnomaly variable
* @param b boolean
*/
public void setPrefAnomaly(boolean b)
{
this.prefAnomaly = b;
}
/**
* Return the type indicator of the enigma machine
* @return type
*/
public String getMachineType()
{
return machineType;
}
/**
*
* @param s source
* @param d domain (max value) of the value
* @return value
*/
protected static int getValue(long s, int d)
{
return (int) ((s%d)+d)%d;
}
/**
* remove a digit of domain d from source s
* @param s source
* @param d domain (max value)
* @return trimmed source
*/
protected static long removeDigit(long s, int d)
{
return (s-(s%d))/d;
}
/**
*
* @param s source
* @param b base (max value)
* @param v actual value
* @return lengthened source
*/
protected static long addDigit(long s, int v, int b)
{
long x = s;
x*=b;
x+=(v%b);
return x;
}
}