EnigmAndroid/app/src/main/java/de/vanitasvitae/enigmandroid/enigma/rotors/Reflector.java

341 lines
11 KiB
Java

package de.vanitasvitae.enigmandroid.enigma.rotors;
import android.util.Log;
import java.math.BigInteger;
import de.vanitasvitae.enigmandroid.MainActivity;
import de.vanitasvitae.enigmandroid.enigma.Enigma;
import de.vanitasvitae.enigmandroid.enigma.Plugboard;
/**
* Reflector of the enigma machine.
* The reflector was used to reflect the scrambled signal at the end of the wiring back to
* go through another (reversed but not inverting) process of scrambling.
* 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 class Reflector
{
protected int type;
protected String name;
protected int index;
protected String summary;
protected int[] connections;
protected int rotation;
protected int ringSetting;
/**
* This constructor is not accessible from outside this class file.
* Use the one of the createReflector* methods instead to create concrete Reflectors from
* outside this class file
* @param type name indicator of the reflector
* @param connections wiring of the reflector as Integer array
*/
protected Reflector(int type, String name, String summary, int[] connections)
{
this.type = type;
this.name = name;
this.summary = summary;
this.connections = connections;
}
public Reflector getInstance()
{
//noinspection ConstantConditions
return createReflector(this.type).setIndex(this.getIndex());
}
public Reflector getInstance(int rotation, int ringSetting)
{
//noinspection ConstantConditions
return createReflector(this.type).setIndex(this.getIndex())
.setRotation(rotation).setRingSetting(ringSetting);
}
public Reflector setIndex(int index)
{
this.index = index;
return this;
}
public int getIndex()
{
return this.index;
}
public int getRotation()
{
return rotation;
}
public int getRingSetting()
{
return ringSetting;
}
public Reflector setRotation(int rotation)
{
this.rotation = rotation;
return this;
}
public Reflector setRingSetting(int ringSetting)
{
this.ringSetting = ringSetting;
return this;
}
public Reflector setConfiguration(int[] c)
{
this.connections = c;
return this;
}
public BigInteger setConfiguration(BigInteger b)
{
String s = "";
int x;
while((x = Enigma.getValue(b, 27)) != 26 || b.compareTo(BigInteger.ZERO) > 1)
{
s = ((char) (x+65))+s;
b = Enigma.removeDigit(b, 27);
}
Log.d(MainActivity.APP_ID, "Restored: " + s);
this.setConfiguration(Plugboard.stringToConfiguration(s));
return b;
}
public int[] getConfiguration()
{
return connections;
}
/**
* Factory method to create reflectors.
* @param type name of the created reflector
* 1 -> ReflectorA
* 2 -> ReflectorB
* 3 -> ReflectorC
* 4 -> ReflectorThinB
* 5 -> ReflectorThinC
* 6 -> ReflectorEnigma_D_KD_G31
* 7 -> Reflector_K
* 8 -> Reflector_T
* 9 -> Reflector_G312
* 10 -> Reflector_G260
* 11 -> Reflector_R
* default -> ReflectorB
* @return Reflector
*/
public static Reflector createReflector(int type)
{
switch (type)
{
case 0: return new Reflector_A();
case 1: return new Reflector_B();
case 2: return new Reflector_C();
case 10: return new Reflector_Thin_B();
case 11: return new ReflectorThinC();
case 20: return new ReflectorEnigma_D_KD_G31();
case 30: return new Reflector_G312();
case 40: return new Reflector_K_G260();
case 50: return new Reflector_R();
case 60: return new ReflectorEnigma_T();
default:
Log.e(MainActivity.APP_ID," Tried to create Reflector of invalid name "+type);
return null;
}
}
/**
* Substitute an input signal via the wiring of the reflector with a different (!) output.
* The output MUST not be equal to the input for any input, since this was not possible
* due to the electronic implementation of the historical enigma machine.
* @param input input signal
* @return encrypted (substituted) output
*/
public int encrypt(int input)
{
return this.connections[normalize(input)];
}
/**
* Return the size (ie the number of wires/length of the connections array) of the reflector
* @return size
*/
private int getRotorSize()
{
return this.connections.length;
}
/**
* Normalize the input.
* Normalizing means keeping the input via modulo in the range from 0 to n-1, where n is equal
* to the size of the reflector. This is necessary since java allows negative modulo values,
* which can break this implementation
* @param input input signal
* @return "normalized" input signal
*/
private int normalize(int input)
{
return (input + this.getRotorSize()) % this.getRotorSize();
}
/**
* Concrete implementation of ReflectorA
* Used in Enigma I
* AE BJ CM DZ FL GY HX IV KW NR OQ PU ST
*/
public static class Reflector_A extends Reflector
{
public Reflector_A()
{
super(0, "A", "EJMZALYXVBWFCRQUONTSPIKHGD",
new int[]{4,9,12,25,0,11,24,23,21,1,22,5,2,17,16,20,14,13,19,18,15,8,10,7,6,3});
}
}
/**
* Concrete implementation of ReflectorB
* Used in Enigma I, M3
* AY BR CU DH EQ FS GL IP JX KN MO TZ VW
*/
public static class Reflector_B extends Reflector
{
public Reflector_B()
{
super(1, "B", "YRUHQSLDPXNGOKMIEBFZCWVJAT",
new int[]{24,17,20,7,16,18,11,3,15,23,13,6,14,10,12,8,4,1,5,25,2,22,21,9,0,19});
}
}
/**
* Concrete implementation of ReflectorC
* Used in Enigma I, M3
* AF BV CP DJ EI GO HY KR LZ MX NW QT SU
*/
public static class Reflector_C extends Reflector
{
public Reflector_C()
{
super(2, "C", "FVPJIAOYEDRZXWGCTKUGSBNMHL",
new int[]{5,21,15,9,8,0,14,24,4,3,17,25,23,22,6,2,19,10,20,16,18,1,13,12,7,11});
}
}
/**
* Concrete implementation of thin reflector name b (not equal to normal name b!)
* When used with Rotor Beta on rotation 0, the pair was equivalent to normal reflector B
* S->Beta->ThinB->Beta'->X == X->UKWB->S
* Used in Enigma M4
* E N K Q A U Y W J I C O P B L M D X Z V F T H R G S
*/
public static class Reflector_Thin_B extends Reflector
{
public Reflector_Thin_B()
{
super(10, "Thin-B", "ENKQAUYWJICOPBLMDXZVFTHRGS",
new int[]{4,13,10,16,0,20,24,22,9,8,2,14,15,1,11,12,3,23,25,21,5,19,7,17,6,18});
}
}
/**
* Concrete implementation of thin reflector name c (not equal to normal name c!)
* When used with Rotor Gamma on rotation 0, the pair was equivalent to normal reflector C
* S->Gamma->ThinC->Gamma'->X == X->UKWC->S
* Used in Enigma M4
* R D O B J N T K V E H M L F C W Z A X G Y I P S U Q
*/
public static class ReflectorThinC extends Reflector
{
public ReflectorThinC()
{
super(11, "ThinC", "RDOBJNTKVEHMLFCWZAXGYIPSUQ",
new int[]{17,3,14,1,9,13,19,10,21,4,7,12,11,5,2,22,25,0,23,6,24,8,15,18,20,16});
}
}
/**
* Pluggable Reflector of the Enigma machine of name D and KD
* Standard wiring: AI,BM,CE,DT,FG,HR,JY,KS,LQ,NZ,OX,PW,UV
* Has additional ringSetting and can rotate
*/
public static class ReflectorEnigma_D_KD_G31 extends Reflector
{
public static final int[] defaultWiring_D_KD_G31 = {8,12,4,19,2,6,5,17,0,24,18,16,1,25,23,22,11,7,10,3,21,20,15,14,9,13};
public ReflectorEnigma_D_KD_G31()
{
super(20, "Ref-D", "Default: IMETCGFRAYSQBZXWLHKDVUPOJN", defaultWiring_D_KD_G31);
}
}
/**
* Reflector as used in the Enigma name G-312 Abwehr
* R U L Q M Z J S Y G O C E T K W D A H N B X P V I F
*/
public static class Reflector_G312 extends Reflector
{
public Reflector_G312()
{
super(30, "Ref-G312", "RULQMZJSYGOCETKWDAHNBXPVIF",
new int[]{17,20,11,16,12,25,9,18,24,6,14,2,4,19,10,22,3,0,7,13,1,23,15,21,8,5});
}
}
/**
* Reflector as used in the Enigma name G-260 Abwehr
* I M E T C G F R A Y S Q B Z X W L H K D V U P O J N
*/
public static class Reflector_K_G260 extends Reflector
{
public Reflector_K_G260()
{
super(40,"Ref-K/G260", "IMETCGFRAYSQBZXWLHKDVUPOJN",
new int[]{8,12,4,19,2,6,5,17,0,24,18,16,1,25,23,22,11,7,10,3,21,20,15,14,9,13});
}
}
/**
* Reflector as used in the Enigma Type R "Rocket" (Reichsbahn)
* Q Y H O G N E C V P U Z T F D J A X W M K J S R B L
*/
public static class Reflector_R extends Reflector
{
public Reflector_R()
{
super(50, "Ref-R", "QYHOGNECVPUZTFDJAXWMKJSRBL",
new int[]{16,24,7,14,6,13,4,2,21,15,20,25,19,5,3,9,0,23,22,12,10,8,18,17,1,11});
}
}
/**
* Reflector as used in the Enigma name T (Tirpitz)
* G E K P B T A U M O C N I L J D X Z Y F H W V Q S R
*/
public static class ReflectorEnigma_T extends Reflector
{
public ReflectorEnigma_T()
{
super(60, "Ref-T", "GEKPBTAUMOCNILJDXZYFHWVQSR",
new int[]{6,4,10,15,1,19,0,20,12,14,2,13,8,11,9,3,23,25,24,5,7,22,21,16,18,17});
}
}
}