Я хочу изучать Java, поэтому я портировал свою реализацию Enigma на C #. Он получил UnitTests и работает.
Я ищу обзор, рассказывающий мне, где я не знаю лучших практик, где я нарушаю соглашения об именах, где я выгляжу как программист на C #, пишущий на Java 🙂
Спасибо и развлекайся, Гарри
https://github.com/HaraldLeitner/Enigma
BusniessLogic.java
package main;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class BusinessLogic {
private List<Roll> Rolls;
private List<Roll> RollsReverse;
public BusinessLogic(List<Roll> rolls) {
Rolls = rolls;
RollsReverse = new ArrayList<Roll>(rolls);
Collections.reverse(RollsReverse);
}
public void TransformFile(String inputFfilename, String outputFilename, Enums.Mode mode) throws IOException {
final int buffersize = 65536;
FileInputStream fileInStream = new FileInputStream(inputFfilename);
FileOutputStream fileOutStream = new FileOutputStream(outputFilename);
byte[] buffer = new byte[buffersize];
int readCount = 0;
while ((readCount = fileInStream.read(buffer, 0, buffersize)) > 0) {
TransformByteArray(buffer, mode);
fileOutStream.write(buffer, 0, readCount);
}
fileInStream.close();
fileOutStream.close();
}
public void TransformByteArray(byte[] input, Enums.Mode mode) {
if (mode == Enums.Mode.Encode) {
for (int i = 0; i < input.length; i++) {
for (Roll roll : Rolls)
input[i] = roll.Encrypt(input[i]);
RollOn();
}
}
if (mode == Enums.Mode.Decode) {
for (int i = 0; i < input.length; i++) {
for (Roll roll : RollsReverse)
input[i] = roll.Decrypt(input[i]);
RollOn();
}
}
}
private void RollOn() {
for (Roll roll : Rolls) {
if (!roll.RollOn())
break;
}
}
}
Enigma.Properties
TransitionCount = 53
Enums.java
package main;
public class Enums
{
public enum Mode
{
Encode,
Decode
};
}
Program.java
package main;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Random;
public class Program {
private static List<Roll> Rolls;
private static Enums.Mode Mode;
private static String KeyFilename;
private static String InputFileName;
private static int TransitionCount;
public static void main(String[] args) throws Exception {
if (args.length != 3) {
System.out.println("Generate key with 'keygen x key.file' where x > 3 is the number of rolls.");
System.out.println("Encrypt a file with 'enc a.txt key.file'");
System.out.println("Decrypt a file with 'dec a.txt key.file'");
return;
}
ReadProperties();
KeyFilename = args[2];
if (args[0].compareToIgnoreCase("keygen") == 0) {
Keygen(Integer.parseInt(args[1]));
return;
}
InputFileName = args[1];
CreateRolls();
if (args[0].compareToIgnoreCase("enc") == 0)
Mode = Enums.Mode.Encode;
else if (args[0].compareToIgnoreCase("dec") == 0)
Mode = Enums.Mode.Decode;
else
throw new Exception("Undefined Encryption Mode.");
BusinessLogic businessLogic = new BusinessLogic(Rolls);
businessLogic.TransformFile(InputFileName, InputFileName + "." + Mode, Mode);
}
private static void ReadProperties() throws FileNotFoundException, IOException {
Properties prop = new Properties();
prop.load(new FileInputStream("Enigma.properties"));
TransitionCount = Integer.parseInt(prop.getProperty("TransitionCount"));
}
private static void CreateRolls() throws Exception {
Rolls = new ArrayList<Roll>();
int rollKeylength = 256 + TransitionCount;
byte[] definition = new byte[(int) new File(KeyFilename).length()];
FileInputStream fileInputStream = new FileInputStream(KeyFilename);
fileInputStream.read(definition);
fileInputStream.close();
if (definition.length % rollKeylength > 0)
throw new Exception("Invalid Keysize");
int rollCount = definition.length / rollKeylength;
for (int rollNumber = 0; rollNumber < rollCount; rollNumber++) {
List<Integer> transitions = new ArrayList<Integer>();
for (int index = 0; index < TransitionCount; index++)
transitions.add((int) definition[rollNumber * rollKeylength + 256 + index]);
byte[] singleRoll = new byte[256];
for(int index = 0; index < 256; index ++)
singleRoll[index] = definition[rollNumber * rollKeylength + index];
Rolls.add(new Roll(singleRoll, transitions));
}
for (Roll roll : Rolls)
roll.CheckInput(TransitionCount);
}
private static void Keygen(int rollCount) throws Exception {
if (rollCount < 4)
throw new Exception("Not enough rolls.");
Random random = new Random();
if((new File(KeyFilename)).exists())
Files.delete(Paths.get(KeyFilename));
byte[] key = new byte[(256 + TransitionCount) * rollCount] ;
for (int i = 0; i < rollCount; i++) {
byte[] transform = new byte[256];
for (int j = 0; j <= 255; j++)
transform[j] = (byte) j;
while (!IsTwisted(transform)) {
for (int j = 0; j < 256 * 2; j++) {
int rand1 = random.nextInt(256);
int rand2 = random.nextInt(256);
byte temp = transform[rand1];
transform[rand1] = transform[rand2];
transform[rand2] = temp;
}
}
for (int index = 0; index < 256; index++)
key[(256 + TransitionCount) * i + index] = transform[index];
List<Integer> transitions = new ArrayList<Integer>();
while (transitions.size() < TransitionCount)
{
int rand = random.nextInt(256);
if (!transitions.contains(rand))
transitions.add(rand);
}
for (int index = 0; index < TransitionCount; index++)
key[(256 + TransitionCount) * i + 256 + index] = (byte)(int) transitions.get(index);
}
FileOutputStream fileOutputStream = new FileOutputStream(KeyFilename);
fileOutputStream.write(key);
fileOutputStream.close();
System.out.println("Keys generated.");
Thread.sleep(1000);
}
private static boolean IsTwisted(byte[] trans) {
for (int i = 0; i <= 255; i++)
if (trans[i] == i)
return false;
return true;
}
}
Roll.java
package main;
import java.util.Collections;
import java.util.List;
public class Roll
{
private int Position; //This is the actual position of this roll starting at 0
private byte[] Transitions; //This is the wiring of the roll: if Transitions[0] = 0x04 the value 0x00 will be mapped to 0x04
private List<Integer> TurnOverIndices; //While rolling after each char encryption the next roll will also rotate, if these indices contain Position
private byte[] ReTransitions; //Reverted transitionlist for decryption
public Roll(byte[] transitions, List<Integer> turnOverIndices) {
Transitions = transitions;
TurnOverIndices = turnOverIndices;
Position = 0;
ReTransitions = new byte[256];
for (int i = -128; i < 128; i++)
ReTransitions[Transitions[i + 128] + 128] = (byte) i;
}
public void CheckInput(int transitionCount) throws Exception {
if (Transitions.length != 256)
throw new Exception("Wrong Transition length ");
for (int i = -128; i < 128; i++) {
boolean found = false;
for (int j = 0; j < 256; j++)
{
if (Transitions[j] == i)
{
found = true;
break;
}
}
if (!found)
throw new Exception("Transitions not 1-1 complete. Problem at " + i);
}
if (TurnOverIndices.size() != transitionCount)
throw new Exception("Wrong TurnOverIndices length ");
Collections.sort(TurnOverIndices);
for (int i = 0; i < TurnOverIndices.size() - 1; i++)
if (TurnOverIndices.get(i) == TurnOverIndices.get(i + 1))
throw new Exception("Turnoverindizes has doubles");
}
public byte Encrypt(byte input) {
return Transitions[((input + Position + 128)%256)];
}
public byte Decrypt(byte input) {
return (byte) (ReTransitions[input + 128] - Position);
}
public boolean RollOn() {
Position = (Position + 1) % 256;
return TurnOverIndices.contains(Position);
}
}
UnitTest.java
package test;
import static org.junit.jupiter.api.Assertions.*;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.imageio.stream.FileImageInputStream;
import javax.xml.stream.events.EntityDeclaration;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import main.*;
class UnitTest {
byte[] transLinear = new byte[256]; // here every char is mapped to itself
byte[] transLinearInvert = new byte[256]; // match the first to the last etc
byte[] transShift1 = new byte[256]; // 'a' is mapped to 'b' etc
byte[] transShift2 = new byte[256]; // 'a' is mapped to 'c' etc
private BusinessLogic BusinessLogicEncode;
private BusinessLogic BusinessLogicDecode;
byte[] encryptedMsg;
byte[] decryptedMsg;
void Crypt(byte[] msg) {
encryptedMsg = msg.clone();
BusinessLogicEncode.TransformByteArray(encryptedMsg, Enums.Mode.Enc);
decryptedMsg = encryptedMsg.clone();
BusinessLogicDecode.TransformByteArray(decryptedMsg, Enums.Mode.Dec);
}
@BeforeEach
public void Init() {
for (int i = -0; i < 256; i++)
transLinear[i] = (byte) (i - 128);
for (int i = 0; i < 256; i++)
transLinearInvert[i] = (byte) (255 - i - 128);
for (int i = 0; i < 256; i++)
transShift1[i] = (byte) ((i + 1 - 128) % 256);
for (int i = 0; i < 256; i++)
transShift2[i] = (byte) ((i + 2 - 128) % 256);
}
void InitBusinessLogic(ArrayList<byte[]> transitions, ArrayList<ArrayList<Integer>> turnovers) {
if (transitions.size() != turnovers.size())
assertFalse(true, "There must be as much transitions as roll defs!");
List<Roll> rollsEncrypt = new ArrayList<Roll>();
List<Roll> rollsDecrypt = new ArrayList<Roll>();
for (int i = 0; i < transitions.size(); i++) {
rollsEncrypt.add(new Roll(transitions.get(i), turnovers.get(i)));
rollsDecrypt.add(new Roll(transitions.get(i), turnovers.get(i)));
}
BusinessLogicEncode = new BusinessLogic(rollsEncrypt);
BusinessLogicDecode = new BusinessLogic(rollsDecrypt); // need a second, because the enc BusinessLogic has
// turned over rolls
}
@Test
public void OneByte1RollLinear() {
for (int i = -128; i < 128; i++) {
ArrayList<Integer> turnover = new ArrayList<>(Arrays.asList(0));
ArrayList<ArrayList<Integer>> turnovers = new ArrayList<ArrayList<Integer>>();
turnovers.add(turnover);
ArrayList<byte[]> transformation = new ArrayList<byte[]>();
transformation.add(transLinear);
InitBusinessLogic(transformation, turnovers);
Crypt(new byte[] { (byte) i });
assertEquals(i, encryptedMsg[0]);
assertEquals(i, decryptedMsg[0]);
}
}
@Test
public void OneByte1RollShift1() {
for (int i = -128; i < 128; i++) {
ArrayList<Integer> turnover = new ArrayList<>(Arrays.asList(0));
ArrayList<ArrayList<Integer>> turnovers = new ArrayList<ArrayList<Integer>>();
turnovers.add(turnover);
ArrayList<byte[]> transformation = new ArrayList<byte[]>();
transformation.add(transShift1);
InitBusinessLogic(transformation, turnovers);
Crypt(new byte[] { (byte) i });
assertEquals((byte) (i + 1), encryptedMsg[0]);
assertEquals(i, decryptedMsg[0]);
}
}
@Test
public void OneByte1RollShift2() {
for (int i = -128; i < 128; i++) {
ArrayList<Integer> turnover = new ArrayList<>(Arrays.asList(0));
ArrayList<ArrayList<Integer>> turnovers = new ArrayList<ArrayList<Integer>>();
turnovers.add(turnover);
ArrayList<byte[]> transformation = new ArrayList<byte[]>();
transformation.add(transShift2);
InitBusinessLogic(transformation, turnovers);
Crypt(new byte[] { (byte) i });
assertEquals((byte) (i + 2), encryptedMsg[0]);
assertEquals(i, decryptedMsg[0]);
}
}
@Test
public void TwoByte1RollLinear() {
for (int i = -128; i < 128; i++) {
ArrayList<Integer> turnover = new ArrayList<>(Arrays.asList(0));
ArrayList<ArrayList<Integer>> turnovers = new ArrayList<ArrayList<Integer>>();
turnovers.add(turnover);
ArrayList<byte[]> transformation = new ArrayList<byte[]>();
transformation.add(transLinear);
InitBusinessLogic(transformation, turnovers);
Crypt(new byte[] { (byte) i, (byte) ((i + 1)) });
assertEquals(i, encryptedMsg[0]);
assertEquals((byte) (i + 2), encryptedMsg[1]);
assertEquals(i, decryptedMsg[0]);
assertEquals((byte) (i + 1), decryptedMsg[1]);
}
}
@Test
public void TwoByte1RollShift() {
for (int i = -128; i < 128; i++) {
ArrayList<Integer> turnover = new ArrayList<>(Arrays.asList(0));
ArrayList<ArrayList<Integer>> turnovers = new ArrayList<ArrayList<Integer>>();
turnovers.add(turnover);
ArrayList<byte[]> transformation = new ArrayList<byte[]>();
transformation.add(transShift1);
InitBusinessLogic(transformation, turnovers);
Crypt(new byte[] { (byte) i, (byte) ((i + 1)) });
assertEquals((byte) (i + 1), encryptedMsg[0]);
assertEquals((byte) (i + 3), encryptedMsg[1]);
assertEquals(i, decryptedMsg[0]);
assertEquals((byte) (i + 1), decryptedMsg[1]);
}
}
@Test
public void TwoByte1RollInvert() {
for (int i = -128; i < 128; i++) {
ArrayList<Integer> turnover = new ArrayList<>(Arrays.asList(0));
ArrayList<ArrayList<Integer>> turnovers = new ArrayList<ArrayList<Integer>>();
turnovers.add(turnover);
ArrayList<byte[]> transformation = new ArrayList<byte[]>();
transformation.add(transLinearInvert);
InitBusinessLogic(transformation, turnovers);
Crypt(new byte[] { (byte) i, (byte) ((i)) });
assertEquals((byte) (-i - 1), encryptedMsg[0]);
assertEquals((byte) (-i - 2), encryptedMsg[1]);
assertEquals(i, decryptedMsg[0]);
assertEquals(i, decryptedMsg[1]);
}
}
@Test
public void TwoByte2RollLinearInvert() {
for (int i = -128; i < 128; i++) {
ArrayList<Integer> turnover = new ArrayList<>(Arrays.asList(0));
ArrayList<ArrayList<Integer>> turnovers = new ArrayList<ArrayList<Integer>>();
turnovers.add(turnover);
turnovers.add(turnover);
ArrayList<byte[]> transformation = new ArrayList<byte[]>();
transformation.add(transLinearInvert);
transformation.add(transLinearInvert);
InitBusinessLogic(transformation, turnovers);
Crypt(new byte[] { (byte) i, (byte) ((i + 1)) });
assertEquals(i, encryptedMsg[0]);
assertEquals((byte) (i + 2), encryptedMsg[1]);
assertEquals(i, decryptedMsg[0]);
assertEquals((byte) (i + 1), decryptedMsg[1]);
}
}
@Test
public void TwoByte2RollShift() {
for (int i = -128; i < 128; i++) {
ArrayList<Integer> turnover = new ArrayList<>(Arrays.asList(0));
ArrayList<ArrayList<Integer>> turnovers = new ArrayList<ArrayList<Integer>>();
turnovers.add(turnover);
turnovers.add(turnover);
ArrayList<byte[]> transformation = new ArrayList<byte[]>();
transformation.add(transShift1);
transformation.add(transShift1);
InitBusinessLogic(transformation, turnovers);
Crypt(new byte[] { (byte) i, (byte) ((i + 1)) });
assertEquals((byte) (i + 2), encryptedMsg[0]);
assertEquals((byte) (i + 4), encryptedMsg[1]);
assertEquals(i, decryptedMsg[0]);
assertEquals((byte) (i + 1), decryptedMsg[1]);
}
}
@Test
public void TwoByte2RollShift2() {
ArrayList<Integer> turnover = new ArrayList<>(Arrays.asList(0));
ArrayList<ArrayList<Integer>> turnovers = new ArrayList<ArrayList<Integer>>(0);
turnovers.add(turnover);
turnovers.add(turnover);
ArrayList<byte[]> transformation = new ArrayList<byte[]>();
transformation.add(transShift2);
transformation.add(transShift2);
InitBusinessLogic(transformation, turnovers);
Crypt(new byte[] { 7, 107 });
assertEquals(11, encryptedMsg[0]);
assertEquals(112, encryptedMsg[1]);
assertEquals(7, decryptedMsg[0]);
assertEquals(107, decryptedMsg[1]);
}
@Test
public void TwoByte2RollInvert() {
for (int i = -128; i < 128; i++) {
ArrayList<Integer> turnover = new ArrayList<>(Arrays.asList(0));
ArrayList<ArrayList<Integer>> turnovers = new ArrayList<ArrayList<Integer>>();
turnovers.add(turnover);
turnovers.add(turnover);
ArrayList<byte[]> transformation = new ArrayList<byte[]>();
transformation.add(transLinearInvert);
transformation.add(transLinearInvert);
InitBusinessLogic(transformation, turnovers);
Crypt(new byte[] { (byte) i, (byte) ((i + 1)) });
assertEquals((byte) (i), encryptedMsg[0]);
assertEquals((byte) (i + 2), encryptedMsg[1]);
assertEquals(i, decryptedMsg[0]);
assertEquals((byte) (i + 1), decryptedMsg[1]);
}
}
@Test
public void ThreeByte2RollTransit() {
ArrayList<Integer> always = new ArrayList<>();
for (int j = 0; j < 256; j++)
always.add(j);
for (int i = -128; i < 128; i++) {
ArrayList<ArrayList<Integer>> turnovers = new ArrayList<ArrayList<Integer>>();
turnovers.add(always);
turnovers.add(always);
ArrayList<byte[]> transformation = new ArrayList<byte[]>();
transformation.add(transLinear);
transformation.add(transLinear);
InitBusinessLogic(transformation, turnovers);
Crypt(new byte[] { (byte) i, (byte) (i + 1), (byte) (i + 2) });
assertEquals((byte) (i), encryptedMsg[0]);
assertEquals((byte) (i + 3), encryptedMsg[1]);
assertEquals((byte) (i + 6), encryptedMsg[2]);
assertEquals(i, decryptedMsg[0]);
assertEquals((byte) (i + 1), decryptedMsg[1]);
assertEquals((byte) (i + 2), decryptedMsg[2]);
}
}
@Test
public void TwoByte2DifferentRollsTransit() {
ArrayList<Integer> turnover = new ArrayList<>(Arrays.asList(0, 1, 2, 3, 4));
ArrayList<ArrayList<Integer>> turnovers = new ArrayList<ArrayList<Integer>>();
turnovers.add(turnover);
turnovers.add(turnover);
ArrayList<byte[]> transformation = new ArrayList<byte[]>();
transformation.add(transLinear);
transformation.add(transShift1);
InitBusinessLogic(transformation, turnovers);
Crypt(new byte[] { 7, 107 });
assertEquals(8, encryptedMsg[0]);
assertEquals(110, encryptedMsg[1]);
assertEquals(7, decryptedMsg[0]);
assertEquals(107, decryptedMsg[1]);
}
@Test
public void TwoByte2DifferentRollsTransit3() {
ArrayList<Integer> turnover = new ArrayList<>(Arrays.asList(0, 1, 2, 3, 4));
ArrayList<ArrayList<Integer>> turnovers = new ArrayList<ArrayList<Integer>>();
turnovers.add(turnover);
turnovers.add(turnover);
ArrayList<byte[]> transformation = new ArrayList<byte[]>();
transformation.add(transLinear);
transformation.add(transLinearInvert);
InitBusinessLogic(transformation, turnovers);
Crypt(new byte[] { 7, 107 });
assertEquals(-8, encryptedMsg[0]);
assertEquals(-110, encryptedMsg[1]);
assertEquals(7, decryptedMsg[0]);
assertEquals(107, decryptedMsg[1]);
}
@Test
public void RealLive()
{
int msgSize = 5 * 65536;
byte[] msg = new byte[msgSize];
for (int i = 0; i < msgSize; i++)
msg[i] = (byte)(i);
ArrayList<Integer> turnover1 = new ArrayList<>(Arrays.asList(0, 22, 44, 100));
ArrayList<Integer> turnover2 = new ArrayList<>(Arrays.asList(11, 44, 122, 200));
ArrayList<Integer> turnover3 = new ArrayList<>(Arrays.asList(33, 77, 99, 222));
ArrayList<Integer> turnover4 = new ArrayList<>(Arrays.asList(55, 67, 79, 240));
ArrayList<ArrayList<Integer>> turnovers = new ArrayList<ArrayList<Integer>>();
turnovers.add(turnover1);
turnovers.add(turnover2);
turnovers.add(turnover3);
turnovers.add(turnover4);
ArrayList<byte[]> transformation = new ArrayList<byte[]>();
transformation.add(transLinear);
transformation.add(transLinearInvert);
transformation.add(transShift1);
transformation.add(transShift2);
InitBusinessLogic(transformation, turnovers);
Crypt(msg);
assertEquals(msg.length, decryptedMsg.length);
Crypt(msg);
for (int i = 0; i < msgSize; i++)
assertEquals(msg[i], decryptedMsg[i]);
}
@Test
public void Integrationtest() throws Exception
{
int msgSize = 5 * 65536; //bigger than buffersize:-)
String keyname = "any.key";
String msgFileName = "msg.file";
byte[] msg = new byte[msgSize];
for (int i = 0; i < msgSize; i++)
msg[i] = (byte)(i % 256);
FileOutputStream fileOutputStream = new FileOutputStream(msgFileName);
fileOutputStream.write(msg);
fileOutputStream.close();
Program.main(new String[] { "keygen", "4", keyname});
Program.main(new String[] { "enc", msgFileName, keyname });
Program.main(new String[] { "dec", msgFileName + ".Enc", keyname });
byte[] encdec = new byte[msgSize];
FileInputStream fileInputStream = new FileInputStream(msgFileName + ".Enc.Dec");
fileInputStream.read(encdec);
fileInputStream.close();
for(int i = 0; i < msg.length; i++)
assertEquals(msg[i], encdec[i]);
assertEquals(msg.length, encdec.length);
}
}
```