//CipherStreamJava/src/main/java/com/mattrixwv/CipherStreamJava/combination/ADFGX.java //Mattrixwv // Created: 01-25-22 //Modified: 07-09-22 package com.mattrixwv.cipherstream.combination; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.mattrixwv.cipherstream.exceptions.InvalidCharacterException; import com.mattrixwv.cipherstream.exceptions.InvalidInputException; import com.mattrixwv.cipherstream.exceptions.InvalidKeywordException; import com.mattrixwv.cipherstream.polysubstitution.Columnar; import com.mattrixwv.cipherstream.polysubstitution.PolybiusSquare; public class ADFGX{ private static final Logger logger = LoggerFactory.getLogger(ADFGX.class); //Internal fields private String inputString; //The string that needs encoded/decoded private String outputString; //The string that is output after encoding/decoding private String squareKeyword; //The keyword used in the Polybius Square private String keyword; //The keyword used in the Columnar cipher private boolean preserveCapitals; //Whether to respect capitals in the output string private boolean preserveWhitespace; //Whether to respect whitespace in the output string private boolean preserveSymbols; //Whether to respect symbols in the output string //Internal ciphers private PolybiusSquare polybiusSquare; //The first step in encoding private Columnar columnar; //The second step in encoding //Ensures Polybius keyword constraints private void setSquareKeyword(String squareKeyword) throws InvalidKeywordException{ if(squareKeyword == null){ throw new InvalidKeywordException("Square keyword cannot be null"); } logger.debug("squareKeyword = {}", squareKeyword); this.squareKeyword = squareKeyword; } //Ensures Columnar keyword constraints private void setKeyword(String keyword) throws InvalidKeywordException{ if(keyword == null){ throw new InvalidKeywordException("Keyword cannot be null"); } logger.debug("keyword = {}", keyword); this.keyword = keyword; } //Ensures inputString constraints private void setInputString(String inputString) throws InvalidInputException{ if(inputString == null){ throw new InvalidInputException("Input cannot be null"); } logger.debug("original input string '{}'", inputString); if(!preserveCapitals){ logger.debug("Removing capitals"); inputString = inputString.toUpperCase(); } if(!preserveWhitespace){ logger.debug("Removing whitespace"); inputString = inputString.replaceAll("\\s", ""); } if(!preserveSymbols){ logger.debug("Removing symbols"); inputString = inputString.replaceAll("[^a-zA-Z\\s]", ""); } this.inputString = inputString; if(this.inputString.isBlank()){ throw new InvalidInputException("Input cannot be blank"); } logger.debug("cleaned input string '{}'", inputString); } //Format the output string with capitals, symbols, and numbers that are in the input string private void formatOutputStringEncode(){ logger.debug("Formatting output string to match input string"); StringBuilder output = new StringBuilder(); int outputLocation = 0; for(char ch : inputString.toCharArray()){ logger.debug("Input character {}", ch); if(Character.isUpperCase(ch)){ logger.debug("Converting output to uppercase"); output.append(Character.toUpperCase(outputString.charAt(outputLocation++))); output.append(Character.toUpperCase(outputString.charAt(outputLocation++))); } else if(Character.isLowerCase(ch)){ logger.debug("Converting output to lowercase"); output.append(Character.toLowerCase(outputString.charAt(outputLocation++))); output.append(Character.toLowerCase(outputString.charAt(outputLocation++))); } else{ logger.debug("Appending symbol to output"); output.append(ch); } } logger.debug("Saving output string '{}'", outputString); outputString = output.toString(); } private void formatOutputStringDecode(){ logger.debug("Formatting output string to match input string"); StringBuilder output = new StringBuilder(); int outputLocation = 0; for(int inputLocation = 0;inputLocation < inputString.length();++inputLocation){ char ch = inputString.charAt(inputLocation); logger.debug("Input character {}", ch); if(Character.isUpperCase(ch)){ logger.debug("Converting output to uppercase"); output.append(Character.toUpperCase(outputString.charAt(outputLocation++))); ++inputLocation; } else if(Character.isLowerCase(ch)){ logger.debug("Converting output to lowercase"); output.append(Character.toLowerCase(outputString.charAt(outputLocation++))); ++inputLocation; } else{ logger.debug("Appending symbol to output"); output.append(ch); } } logger.debug("Saving output string '{}'", output); outputString = output.toString(); } //Encodes the inputString and stores the result in outputString private void encode() throws InvalidCharacterException, InvalidInputException, InvalidKeywordException{ //Encode the input with polybius logger.debug("Encoding using Polybius Square"); String polybiusOutput = polybiusSquare.encode(squareKeyword, inputString); squareKeyword = polybiusSquare.getKeyword(); //Change polybius to use the correct symbols logger.debug("Replacing coordinates with letters"); polybiusOutput = polybiusOutput.replace("1", "A").replace("2", "D").replace("3", "F").replace("4", "G").replace("5", "X"); //Encode polybius's output with columnar logger.debug("Encoding using columnar"); String columnarOutput = columnar.encode(keyword, polybiusOutput); keyword = columnar.getKeyword(); outputString = columnarOutput; //Add whatever is needed to the output string formatOutputStringEncode(); } //Decodes the inputString and stores the result in outputString private void decode() throws InvalidKeywordException, InvalidCharacterException, InvalidInputException{ //Decode the input with columnar logger.debug("Decoding using columnar"); String columnarOutput = columnar.decode(keyword, inputString); keyword = columnar.getKeyword(); //Change the symbols to the correct ones for polybius logger.debug("Replacing letters with coordinates"); columnarOutput = columnarOutput.replace("A", "1").replace("D", "2").replace("F", "3").replace("G", "4").replace("X", "5"); //Decode with polybius logger.debug("Decoding using Polybius Square"); String polybiusOutput = polybiusSquare.decode(squareKeyword, columnarOutput); squareKeyword = polybiusSquare.getKeyword(); outputString = polybiusOutput; //Add whatever is needed to the output string formatOutputStringDecode(); } //Constructor public ADFGX() throws InvalidCharacterException{ preserveCapitals = false; preserveWhitespace = false; preserveSymbols = false; reset(); } public ADFGX(boolean preserveCapitals, boolean preserveWhitespace, boolean preserveSymbols) throws InvalidCharacterException{ this.preserveCapitals = preserveCapitals; this.preserveWhitespace = preserveWhitespace; this.preserveSymbols = preserveSymbols; reset(); } //Encodes inputString using keyword and returns the result public String encode(String squareKeyword, String keyword, String inputString) throws InvalidKeywordException, InvalidInputException, InvalidCharacterException{ setSquareKeyword(squareKeyword); setKeyword(keyword); setInputString(inputString); encode(); return outputString; } //Decodes inputString using keyword and returns the result public String decode(String squareKeyword, String keyword, String inputString) throws InvalidKeywordException, InvalidInputException, InvalidCharacterException{ setSquareKeyword(squareKeyword); setKeyword(keyword); setInputString(inputString); decode(); return outputString; } //Returns the cleaned inputString public String getInputString(){ return inputString; } //Returns the outputString public String getOutputString(){ return outputString; } //Returns the cleaned Polybius Square keyword public String getSquareKeyword(){ return squareKeyword; } //Returns the cleaned Columnar keyword public String getKeyword(){ return keyword; } //Makes sure all of the variables are empty public void reset() throws InvalidCharacterException{ logger.debug("Resetting fields"); polybiusSquare = new PolybiusSquare(false, false); columnar = new Columnar(false, false, false, true, 'B'); inputString = ""; outputString = ""; squareKeyword = ""; keyword = ""; } }