Fixed sonarqube findings

This commit is contained in:
2022-07-04 01:04:06 -04:00
parent 6f300a430a
commit b4817e8bb3
47 changed files with 289 additions and 311 deletions

View File

@@ -0,0 +1,181 @@
//CipherStreamJava/src/main/java/com/mattrixwv/CipherStreamJava/polySubstitution/Bifid.java
//Mattrixwv
// Created: 03-03-22
//Modified: 03-03-22
package com.mattrixwv.cipherstream.polysubstitution;
import com.mattrixwv.cipherstream.exceptions.InvalidCharacterException;
import com.mattrixwv.cipherstream.exceptions.InvalidInputException;
import com.mattrixwv.cipherstream.exceptions.InvalidKeywordException;
public class Bifid{
private String inputString; //The message that needs to be encoded/decoded
private String outputString; //The encoded/decoded message
private String keyword; //The keyword used to create the grid
private PolybiusSquare polybiusSquare; //Used to encode the message to numbers then back into letters
private boolean preserveCapitals; //Persist capitals in the output string
private boolean preserveWhitespace; //Persist whitespace in the output string
private boolean preserveSymbols; //Persist symbols in the output string
//Strips invalid characters from the keyword and creates the grid
private void setKeyword(String keyword) throws InvalidKeywordException{
//Ensure the keyword isn't null
if(keyword == null){
throw new InvalidKeywordException("Keyword cannot be null");
}
//Save the key for polybius to deal with
this.keyword = keyword;
}
//Ensures inputString constraints
private void setInputString(String inputString) throws InvalidInputException{
//Ensure the input string isn't null
if(inputString == null){
throw new InvalidInputException("Input cannot be null");
}
//Apply removal options
if(!preserveCapitals){
inputString = inputString.toUpperCase();
}
if(!preserveWhitespace){
inputString = inputString.replaceAll("\\s", "");
}
if(!preserveSymbols){
inputString = inputString.replaceAll("[^a-zA-Z\\s]", "");
}
//Save the string
this.inputString = inputString;
//Ensure the string isn't blank
if(this.inputString.isBlank()){
throw new InvalidInputException("Input must contain at least 1 letter");
}
}
//Adds all non-letter characters back to the output string
private void formatOutput(String outputString){
//Keep track of where you are in the output
int outputCnt = 0;
StringBuilder output = new StringBuilder();
//Check every character in the input and apply the correct rules to the output
for(char ch : inputString.toCharArray()){
if(Character.isUpperCase(ch)){
output.append(Character.toUpperCase(outputString.charAt(outputCnt++)));
}
else if(Character.isLowerCase(ch)){
output.append(Character.toLowerCase(outputString.charAt(outputCnt++)));
}
else{
output.append(ch);
}
}
//Save the output
this.outputString = output.toString();
}
//Encodes inputString using a polybius square and stores the result in outputString
private void encode() throws InvalidCharacterException, InvalidInputException{
//Get the encoded numbers from a polybius square
String numberResult = polybiusSquare.encode(keyword, inputString).replaceAll("\\s", "");
keyword = polybiusSquare.getKeyword(); //Save the cleaned keyword
//Split the numbers into 2 rows and rejoin the rows to create a new string
StringBuilder row0 = new StringBuilder();
StringBuilder row1 = new StringBuilder();
boolean firstNum = true;
for(char ch : numberResult.toCharArray()){
if(firstNum){
row0.append(ch);
}
else{
row1.append(ch);
}
firstNum = !firstNum;
}
String shuffledResult = row0.toString() + row1.toString();
//Take the new string and decode the numbers using polybius
String letterResult = polybiusSquare.decode(keyword, shuffledResult);
//Format the output
formatOutput(letterResult);
}
//Decodes inputString using a polybius square and stores the result in outputString
private void decode() throws InvalidCharacterException, InvalidInputException{
//Get the decoded number from a polybius square
String numberResult = polybiusSquare.encode(keyword, inputString).replaceAll("\\s", "");
keyword = polybiusSquare.getKeyword();
//Split the numbers into to rows and rejoin the rows to create a new string
String row0 = numberResult.substring(0, numberResult.length() / 2);
String row1 = numberResult.substring(numberResult.length() / 2);
StringBuilder unshuffledResult = new StringBuilder();
for(int cnt = 0;cnt < row0.length();++cnt){
unshuffledResult.append(row0.charAt(cnt));
unshuffledResult.append(row1.charAt(cnt));
}
//Take the new string and decode the numbers using polybius
String letterResult = polybiusSquare.decode(keyword, unshuffledResult.toString());
//Format the outputString
formatOutput(letterResult);
}
//Constructor
public Bifid() throws InvalidCharacterException{
preserveCapitals = false;
preserveWhitespace = false;
preserveSymbols = false;
polybiusSquare = new PolybiusSquare(false, false);
reset();
}
public Bifid(boolean preserveCapitals, boolean preserveWhitespace, boolean preserveSymbols) throws InvalidCharacterException{
this.preserveCapitals = preserveCapitals;
this.preserveWhitespace = preserveWhitespace;
this.preserveSymbols = preserveSymbols;
polybiusSquare = new PolybiusSquare(false, false);
reset();
}
//Encodes inputString using keyword and returns the result
public String encode(String keyword, String inputString) throws InvalidKeywordException, InvalidInputException, InvalidCharacterException{
//Set the parameters
reset();
setKeyword(keyword);
setInputString(inputString);
//Encode and return the message
encode();
return outputString;
}
//Decodes inputString using keyword and returns the result
public String decode(String keyword, String inputString) throws InvalidKeywordException, InvalidInputException, InvalidCharacterException{
//Set the parameters
reset();
setKeyword(keyword);
setInputString(inputString);
//Decode and return the message
decode();
return outputString;
}
//Makes sure all variables are empty
public void reset(){
inputString = "";
outputString = "";
keyword = "";
}
//Gets
public String getInputString(){
return inputString;
}
public String getOutputString(){
return outputString;
}
public String getKeyword(){
return keyword;
}
}

View File

@@ -0,0 +1,459 @@
//MattrixwvWebsite/src/main/java/com/mattrixwv/CipherStreamJava/polySubstitution/Columnar.java
//Mattrixwv
// Created: 01-16-22
//Modified: 03-03-22
package com.mattrixwv.cipherstream.polysubstitution;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import com.mattrixwv.cipherstream.exceptions.InvalidCharacterException;
import com.mattrixwv.cipherstream.exceptions.InvalidInputException;
import com.mattrixwv.cipherstream.exceptions.InvalidKeywordException;
public class Columnar{
private String inputString; //The message that needs to be encoded/decoded
private String outputString; //The encoded/decoded message
private String keyword; //The keyword used to create the grid
private char characterToAdd; //The character that is added to the end of a string to bring it to the correct length
private int charsAdded; //The number of characters that were added to the end of the message
private ArrayList<ArrayList<Character>> grid; //The grid used to encode/decode the message
private boolean preserveCapitals; //Persist capitals in the output string
private boolean preserveWhitespace; //Persist whitespace in the output string
private boolean preserveSymbols; //Persist symbols in the output string
private boolean removePadding; //Remove the padding letters added to the cipher
//Strip the inputString of all non-letter characters and change them to capitals
private String getCleanInputString(){
return inputString.toUpperCase().replaceAll("[^A-Z]", "");
}
//Create the grid from the keyword
private void createGridEncode(){
//Add the keyword to the first row in the array
grid = new ArrayList<>();
grid.add(new ArrayList<>(Arrays.asList(keyword.chars().mapToObj(c -> (char)c).toArray(Character[]::new))));
//Create the input that will be used for encoding
String gridInputString = getCleanInputString();
//Create arrays from the inputString of keyword.size length and add them each as new rows to the grid
//?gridRow could be changed to grid.size(), but would it be worth the extra confusion? Probably not unless I really want to min/max
for(int gridRow = 1;(keyword.length() * gridRow) <= gridInputString.length();++gridRow){
grid.add(new ArrayList<>(Arrays.asList(
gridInputString.substring(keyword.length() * (gridRow - 1), (keyword.length() * gridRow))
.chars().mapToObj(c->(char)c).toArray(Character[]::new)
)));
}
}
private void createGridDecode(){
//Add the keyword to the first row in the array
grid = new ArrayList<>();
StringBuilder orderedKeyword = new StringBuilder();
for(int cnt : getKeywordAlphaLocations()){
orderedKeyword.append(keyword.charAt(cnt));
}
grid.add(new ArrayList<>(Arrays.asList(orderedKeyword.chars().mapToObj(c -> (char)c).toArray(Character[]::new))));
//Create the input that will be used for encoding
String gridInputString = getCleanInputString();
//Make sure the grid has the appropritate number of rows
int numRows = inputString.length() / keyword.length();
while(grid.size() <= numRows){
grid.add(new ArrayList<>());
}
//Add each character to the grid
int rowCnt = 1;
for(char ch : gridInputString.toCharArray()){
grid.get(rowCnt++).add(ch);
if(rowCnt > numRows){
rowCnt = 1;
}
}
}
//Strips invalid characters from the string that needs encoded/decoded
private void setInputStringEncode(String inputString) throws InvalidInputException{
//Ensure the input isn't null
if(inputString == null){
throw new InvalidInputException("Input must not be null");
}
//Apply removal options
if(!preserveCapitals){
inputString = inputString.toUpperCase();
}
if(!preserveWhitespace){
inputString = inputString.replaceAll("\\s", "");
}
if(!preserveSymbols){
inputString = inputString.replaceAll("[^a-zA-Z\\s]", "");
}
//Make sure the input is the correct length
this.inputString = inputString;
StringBuilder inputStringBuilder = new StringBuilder();
inputStringBuilder.append(inputString);
int cleanLength = getCleanInputString().length();
int charsToAdd = (cleanLength % keyword.length());
if(charsToAdd != 0){
charsToAdd = keyword.length() - charsToAdd;
}
for(int cnt = 0;cnt < charsToAdd;++cnt){
inputStringBuilder.append(characterToAdd);
}
charsAdded = charsToAdd;
inputString = inputStringBuilder.toString();
//Save the string
this.inputString = inputString;
//Ensure the string isn't blank
if(this.inputString.isBlank() || getCleanInputString().isBlank()){
throw new InvalidInputException("Input cannot be blank");
}
}
private void setInputStringDecode(String inputString) throws InvalidInputException{
//Ensure the input isn't null
if(inputString == null){
throw new InvalidInputException("Input must not be null");
}
//Apply removal options
if(!preserveCapitals){
inputString = inputString.toUpperCase();
}
if(!preserveWhitespace){
inputString = inputString.replaceAll("[\\s]", "");
}
if(!preserveSymbols){
inputString = inputString.replaceAll("[^a-zA-Z\\s]", "");
}
//Make sure the input is the correct length
charsAdded = 0;
this.inputString = inputString;
//Figure out how many rows there will be
int numRows = getCleanInputString().length() / keyword.length();
//Get the number of characters the input is over the limit
int numCharsOver = getCleanInputString().length() % keyword.length();
if(numCharsOver > 0){
//Get the first n of the characters in the keyword and their encoded column locations
ArrayList<Integer> originalLocations = getKeywordOriginalLocations();
ArrayList<Integer> longColumns = new ArrayList<>();
for(int cnt = 0;cnt < numCharsOver;++cnt){
longColumns.add(originalLocations.get(cnt));
}
//Add letters where they need to be added to fill out the grid
StringBuilder input = new StringBuilder();
int col = 0;
int row = 0;
for(char ch : inputString.toCharArray()){
if(!Character.isAlphabetic(ch)){
input.append(ch);
continue;
}
if(row < numRows){
input.append(ch);
++row;
}
else{
if(longColumns.contains(col)){
input.append(ch);
row = 0;
}
else{
input.append(characterToAdd);
++charsAdded;
input.append(ch);
row = 1;
}
++col;
}
}
if(!longColumns.contains(col)){
input.append(characterToAdd);
++charsAdded;
}
inputString = input.toString();
}
//Save the input
this.inputString = inputString;
//Ensure the string isn't blank
if(this.inputString.isBlank() || getCleanInputString().isBlank()){
throw new InvalidInputException("Input cannot be blank");
}
}
//Creates the output string from the grid
private void createOutputStringFromColumns(){
//Get the current rows of any characters that you added
ArrayList<Integer> colsAddedTo = new ArrayList<>();
if(removePadding){
ArrayList<Integer> cols = getKeywordOriginalLocations();
Collections.reverse(cols);
for(int cnt = 0;cnt < charsAdded;++cnt){
colsAddedTo.add(cols.get(cnt));
}
}
else{
charsAdded = 0;
}
//Turn the grid into a string
StringBuilder gridOutput = new StringBuilder();
for(int col = 0;col < grid.get(0).size();++col){
for(int row = 1;row < grid.size();++row){
gridOutput.append(grid.get(row).get(col));
}
if(colsAddedTo.contains(col)){
gridOutput.deleteCharAt(gridOutput.length() - 1);
}
}
//Preserve any remaining symbols in the string
StringBuilder output = new StringBuilder();
for(int outputLoc = 0, inputLoc = 0;inputLoc < (inputString.length() - charsAdded);){
char inputChar = inputString.charAt(inputLoc++);
if(Character.isUpperCase(inputChar)){
output.append(Character.toUpperCase(gridOutput.charAt(outputLoc++)));
}
else if(Character.isLowerCase(inputChar)){
output.append(Character.toLowerCase(gridOutput.charAt(outputLoc++)));
}
else{
output.append(inputChar);
}
}
//Save and return the output
outputString = output.toString();
}
private void createOutputStringFromRows(){
//Turn the grid into a string
StringBuilder gridOutput = new StringBuilder();
for(int row = 1;row < grid.size();++row){
for(int col = 0;col < grid.get(row).size();++col){
gridOutput.append(grid.get(row).get(col));
}
}
//Remove any added characters
if(removePadding){
for(int cnt = 0;cnt < charsAdded;++cnt){
gridOutput.deleteCharAt(gridOutput.length() - 1);
}
}
else{
charsAdded = 0;
}
ArrayList<Integer> colsAddedTo = new ArrayList<>();
if(removePadding){
ArrayList<Integer> cols = getKeywordOriginalLocations();
Collections.reverse(cols);
for(int cnt = 0;cnt < charsAdded;++cnt){
colsAddedTo.add(cols.get(cnt));
}
}
//Preserve any remaining symbols in the string
StringBuilder output = new StringBuilder();
for(int outputLoc = 0, inputLoc = 0, row = 1, col = 0;inputLoc < inputString.length();){
char inputChar = inputString.charAt(inputLoc++);
if(((row + 1) == grid.size()) && (colsAddedTo.contains(col)) && (Character.isAlphabetic(inputChar))){
++col;
row = 1;
continue;
}
if(Character.isUpperCase(inputChar)){
output.append(Character.toUpperCase(gridOutput.charAt(outputLoc++)));
++row;
}
else if(Character.isLowerCase(inputChar)){
output.append(Character.toLowerCase(gridOutput.charAt(outputLoc++)));
++row;
}
else{
output.append(inputChar);
}
if(row == grid.size()){
++col;
row = 1;
}
}
//Save and return the output
outputString = output.toString();
}
//Strips invalid characters from the keyword and creates the grid
private void setKeyword(String keyword) throws InvalidKeywordException{
//Ensure the keyword isn't null
if(keyword == null){
throw new NullPointerException("Keyword cannot be null");
}
//Strip all non-letter characters and change them to uppercase
this.keyword = keyword.toUpperCase().replaceAll("[^A-Z]", "");
//Make sure a valid keyword is present
if(this.keyword.length() < 2){
throw new InvalidKeywordException("The keyword must contain at least 2 letters");
}
}
//Set the character that is added to the end of the string
private void setCharacterToAdd(char characterToAdd) throws InvalidCharacterException{
if(!Character.isAlphabetic(characterToAdd)){
throw new InvalidCharacterException("Character to add must be a letter");
}
if(!preserveCapitals){
this.characterToAdd = Character.toUpperCase(characterToAdd);
}
else{
this.characterToAdd = characterToAdd;
}
}
//Returns a list of integers that represents the location of the characters of the keyword in alphabetic order
private ArrayList<Integer> getKeywordAlphaLocations(){
ArrayList<Integer> orderedLocations = new ArrayList<>();
//go through every letter and check it against the keyword
for(char ch = 'A';ch <= 'Z';++ch){
for(int cnt = 0;cnt < keyword.length();++cnt){
//If the current letter is the same as the letter we are looking for add the location to the array
if(keyword.charAt(cnt) == ch){
orderedLocations.add(cnt);
}
}
}
//Return the alphabetic locations
return orderedLocations;
}
private ArrayList<Integer> getKeywordOriginalLocations(){
//Figure out the order the columns are in
ArrayList<Integer> orderedLocations = getKeywordAlphaLocations();
//Figure out what order the columns need rearanged to
ArrayList<Integer> originalOrder = new ArrayList<>();
for(int orgCnt = 0;orgCnt < orderedLocations.size();++orgCnt){
for(int orderedCnt = 0;orderedCnt < orderedLocations.size();++orderedCnt){
if(orderedLocations.get(orderedCnt) == orgCnt){
originalOrder.add(orderedCnt);
break;
}
}
}
return originalOrder;
}
//Rearanges the grid based on the list of numbers given
private void rearangeGrid(ArrayList<Integer> listOrder){
//Create a new grid and make sure it is the same size as the original grid
int numCol = grid.get(0).size();
ArrayList<ArrayList<Character>> newGrid = new ArrayList<>(grid.size());
for(int cnt = 0;cnt < grid.size();++cnt){
newGrid.add(new ArrayList<>(numCol));
}
//Step through the list order, pull out the columns, and add them to the new grid
for(int col : listOrder){
for(int row = 0;row < grid.size();++row){
newGrid.get(row).add(grid.get(row).get(col));
}
}
//Save the new grid
grid = newGrid;
}
//Encodes inputString using the Columnar cipher and stores the result in outputString
private void encode(){
//Create the grid
createGridEncode();
//Figure out the new column order
ArrayList<Integer> orderedLocations = getKeywordAlphaLocations();
//Rearange the grid to the new order
rearangeGrid(orderedLocations);
//Create the output
createOutputStringFromColumns();
}
//Decodes inputString using the Columnar cipher and stores the result in outputString
private void decode(){
//Create the grid
createGridDecode();
ArrayList<Integer> originalOrder = getKeywordOriginalLocations();
//Rearange the grid to the original order
rearangeGrid(originalOrder);
//Create the output
createOutputStringFromRows();
}
//Constructor
public Columnar() throws InvalidCharacterException{
preserveCapitals = false;
preserveWhitespace = false;
preserveSymbols = false;
removePadding = false;
setCharacterToAdd('x');
reset();
}
public Columnar(boolean preserveCapitals, boolean preserveWhitespace, boolean preserveSymbols, boolean removePadding) throws InvalidCharacterException{
this.preserveCapitals = preserveCapitals;
this.preserveWhitespace = preserveWhitespace;
this.preserveSymbols = preserveSymbols;
this.removePadding = removePadding;
setCharacterToAdd('x');
reset();
}
public Columnar(boolean preserveCapitals, boolean preserveWhitespace, boolean preserveSymbols, boolean removePadding, char characterToAdd) throws InvalidCharacterException{
this.preserveCapitals = preserveCapitals;
this.preserveWhitespace = preserveWhitespace;
this.preserveSymbols = preserveSymbols;
this.removePadding = removePadding;
setCharacterToAdd(characterToAdd);
reset();
}
//Encodes inputString using keyword and returns the result
public String encode(String keyword, String inputString) throws InvalidKeywordException, InvalidInputException{
//Set the parameters
reset();
setKeyword(keyword);
setInputStringEncode(inputString);
//Encode and return the message
encode();
return outputString;
}
//Encodes inputString using keyword and returns the result
public String decode(String keyword, String inputString) throws InvalidKeywordException, InvalidInputException{
//Set the parameters
reset();
setKeyword(keyword);
setInputStringDecode(inputString);
//Decode and return the message
decode();
return outputString;
}
//Makes sure all variables are empty
public void reset(){
inputString = "";
outputString = "";
keyword = "";
grid = new ArrayList<>();
charsAdded = 0;
}
//Gets
public String getInputString(){
return inputString;
}
public String getOutputString(){
return outputString;
}
public String getKeyword(){
return keyword;
}
}

View File

@@ -0,0 +1,270 @@
//CipherStreamJava/src/main/java/com/mattrixwv/CipherStreamJava/polySubstitution/Hill.java
//Mattrixwv
// Created: 01-31-22
//Modified: 02-17-22
package com.mattrixwv.cipherstream.polysubstitution;
import java.security.InvalidKeyException;
import java.util.ArrayList;
import com.mattrixwv.cipherstream.exceptions.InvalidCharacterException;
import com.mattrixwv.cipherstream.exceptions.InvalidInputException;
import com.mattrixwv.matrix.ModMatrix;
import com.mattrixwv.matrix.exceptions.InvalidGeometryException;
import com.mattrixwv.matrix.exceptions.InvalidScalarException;
public class Hill{
private boolean preserveCapitals;
private boolean preserveWhitespace;
private boolean preserveSymbols;
private boolean removePadding;
private String inputString;
private String outputString;
private char characterToAdd;
private int charsAdded;
private ModMatrix key;
private void setKey(ModMatrix key) throws InvalidKeyException{
//Make sure the mod is correct
if(key.getMod() != 26){
throw new InvalidKeyException("This algorithm uses the english alphabet, so the mod for the key must be 26");
}
//Make sure the matrix is square
if(!key.isSquare()){
throw new InvalidKeyException("The key must be a square matrix");
}
//Make sure the matrix is invertable
try{
key.inverse();
}
catch(InvalidGeometryException | InvalidScalarException error){
throw new InvalidKeyException("The key does not have an inverse mod 26");
}
//Set the key
this.key = new ModMatrix(key);
}
private void setInputString(String inputString) throws InvalidInputException{
//Remove anything that needs removed
if(inputString == null){
throw new InvalidInputException("Input must not be null");
}
if(!preserveCapitals){
inputString = inputString.toUpperCase();
}
if(!preserveWhitespace){
inputString = inputString.replaceAll("[\\s]", "");
}
if(!preserveSymbols){
inputString = inputString.replaceAll("[^a-zA-Z\\s]", "");
}
//Make sure the input is correct length
this.inputString = inputString;
int cleanLength = getCleanInputString().length();
int charsToAdd = (cleanLength % key.getNumRows());
StringBuilder inputStringBuilder = new StringBuilder();
inputStringBuilder.append(inputString);
if(charsToAdd != 0){
charsToAdd = key.getNumRows() - charsToAdd;
}
for(int cnt = 0;cnt < charsToAdd;++cnt){
inputStringBuilder.append(characterToAdd);
}
charsAdded = charsToAdd;
inputString = inputStringBuilder.toString();
this.inputString = inputString;
//Make sure the input isn't blank
if(this.inputString.isBlank() || getCleanInputString().isBlank()){
throw new InvalidInputException("Input cannot be blank");
}
}
private String getCleanInputString(){
return inputString.toUpperCase().replaceAll("[^A-Z]", "");
}
private void setCharacterToAdd(char characterToAdd) throws InvalidCharacterException{
//Make sure the character is a letter
if(!Character.isAlphabetic(characterToAdd)){
throw new InvalidCharacterException("Character to add must be a letter");
}
//Save the characterToAdd
if(!preserveCapitals){
this.characterToAdd = Character.toUpperCase(characterToAdd);
}
else{
this.characterToAdd = characterToAdd;
}
}
private String polishOutputString(){
//Add the extra characters back to the output and remove the added characters
int outputCnt = 0;
StringBuilder outputBuilder = new StringBuilder();
for(char ch : inputString.toCharArray()){
if(Character.isUpperCase(ch)){
outputBuilder.append(Character.toUpperCase(outputString.charAt(outputCnt++)));
}
else if(Character.isLowerCase(ch)){
outputBuilder.append(Character.toLowerCase(outputString.charAt(outputCnt++)));
}
else{
outputBuilder.append(ch);
}
}
if(removePadding){
String tempString = outputBuilder.substring(0, outputBuilder.length() - charsAdded);
outputBuilder = new StringBuilder();
outputBuilder.append(tempString);
}
return outputBuilder.toString();
}
private ArrayList<ModMatrix> getInputVectors(){
//Get the number of columns in the key
int numCols = key.getNumCols();
//Get a clean inputString
String cleanInput = getCleanInputString();
//Break the inputString up into lengths of numCols
ArrayList<ModMatrix> vectors = new ArrayList<>();
for(int cnt = 0;cnt < cleanInput.length();cnt += numCols){
String subString = cleanInput.substring(cnt, cnt + numCols);
int[] grid = new int[numCols];
//Subtract 65 from each character so that A=0, B=1, ...
for(int subCnt = 0;subCnt < subString.length();++subCnt){
grid[subCnt] = subString.charAt(subCnt) - 65;
}
//Create a vector from the new values
ModMatrix vector = new ModMatrix(26);
vector.addCol(grid);
//Add the vector to the array
vectors.add(vector);
}
//Return the array of vectors
return vectors;
}
private String getOutputFromVectors(ArrayList<ModMatrix> outputVectors){
//Go through each element in the vector
StringBuilder outputBuilder = new StringBuilder();
for(ModMatrix vector : outputVectors){
//Add 65 to each element and add it to the string
for(int cnt = 0;cnt < vector.getNumRows();++cnt){
outputBuilder.append((char)(vector.get(cnt, 0) + 65));
}
}
//Return the new string
return outputBuilder.toString();
}
private String encode(){
//Get an array of vectors that we are going to encode
ArrayList<ModMatrix> inputVectors = getInputVectors();
//Multiply the key by each vector and add the result to a new vector
ArrayList<ModMatrix> outputVectors = new ArrayList<>();
for(ModMatrix inputVector : inputVectors){
ModMatrix outputVector = key.multiply(inputVector);
outputVectors.add(outputVector);
}
//Take the array of results and turn them back into letters
outputString = getOutputFromVectors(outputVectors);
//Add the extra characters back to the output and remove the added characters
outputString = polishOutputString();
//Save the output
return outputString;
}
private String decode(){
//Get the array of vectors that we are going to decode
ArrayList<ModMatrix> inputVectors = getInputVectors();
//Multiply the inverse of the key by each vector and add the result to a new vector
ModMatrix inverseKey = key.inverse();
ArrayList<ModMatrix> outputVectors = new ArrayList<>();
for(ModMatrix inputVector : inputVectors){
ModMatrix outputVector = inverseKey.multiply(inputVector);
outputVectors.add(outputVector);
}
//Take the array of results and turn them back into letters
outputString = getOutputFromVectors(outputVectors);
//Add the extra characters back to the output and remove the added characters
outputString = polishOutputString();
//Save the output
return outputString;
}
public Hill() throws InvalidCharacterException{
preserveCapitals = false;
preserveWhitespace = false;
preserveSymbols = false;
removePadding = false;
setCharacterToAdd('x');
reset();
}
public Hill(boolean preserveCapitals, boolean preserveWhitespace, boolean preserveSymbols, boolean removePadding) throws InvalidCharacterException{
this.preserveCapitals = preserveCapitals;
this.preserveWhitespace = preserveWhitespace;
this.preserveSymbols = preserveSymbols;
this.removePadding = removePadding;
setCharacterToAdd('x');
reset();
}
public Hill(boolean preserveCapitals, boolean preserveWhitespace, boolean preserveSymbols, boolean removePadding, char characterToAdd) throws InvalidCharacterException{
this.preserveCapitals = preserveCapitals;
this.preserveWhitespace = preserveWhitespace;
this.preserveSymbols = preserveSymbols;
this.removePadding = removePadding;
setCharacterToAdd(characterToAdd);
reset();
}
public String encode(int[][] key, String inputString) throws InvalidKeyException, InvalidInputException{
return encode(new ModMatrix(key, 26), inputString);
}
public String encode(ModMatrix key, String inputString) throws InvalidKeyException, InvalidInputException{
setKey(key);
setInputString(inputString);
return encode();
}
public String decode(int[][] key, String inputString) throws InvalidKeyException, InvalidInputException{
return decode(new ModMatrix(key, 26), inputString);
}
public String decode(ModMatrix key, String inputString) throws InvalidKeyException, InvalidInputException{
setKey(key);
setInputString(inputString);
return decode();
}
public void reset(){
inputString = "";
outputString = "";
key = new ModMatrix(26);
charsAdded = 0;
}
public String getInputString(){
return inputString;
}
public String getOutputString(){
return outputString;
}
public ModMatrix getKey(){
return key;
}
}

View File

@@ -0,0 +1,120 @@
//CipherStreamJava/src/main/java/com/mattrixwv/CipherStreamJava/Morse.java
//Matthew Ellison
// Created: 07-28-21
//Modified: 01-16-22
package com.mattrixwv.cipherstream.polysubstitution;
public class Morse{
//Holds the Morse representation of the alphanumeric characters
private static final String[] code = {
".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", //A-L
"--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--..", //M-Z
"-----", ".----", "..---", "...--", "....-", ".....", "-....", "--...", "---..", "----." //0-9
};
private String inputString; //The string that needs encoded/decoded
private String outputString; //The encoded/decoded message
//Encodes inputString and stores the result in outputString
private String encode(){
StringBuilder output = new StringBuilder();
//Loop through every element in the input string and see what type it is
for(char letter : inputString.toCharArray()){
//If the character is a letter get teh correct combination from code and add it to the output
if(Character.isUpperCase(letter)){
output.append(code[letter - 65]);
output.append(' ');
}
//If it is a number get the correct combination from code and add it to the output
else if(Character.isDigit(letter)){
int tempNum = Integer.parseInt(Character.toString(letter));
output.append(code[tempNum + 26]);
output.append(' ');
}
}
//Remove the final space from the output
if(output.length() > 0){
output.replace(output.length() - 1, output.length(), "");
}
//Save and return the output
outputString = output.toString();
return outputString;
}
//Decodes inputString and stores the result in outputString
private String decode(){
StringBuilder output = new StringBuilder();
for(String current : inputString.split(" ")){
boolean found = false;
//Loop through the code and see if the current letter
for(int cnt = 0;(cnt < 26) && (!found);++cnt){
//See if current is the same as an element in code
if(current.equals(code[cnt])){
//Add 65 to cnt to get the correct capital letter
output.append((char)(cnt + 'A'));
found = true;
}
}
//Loop through code and see if current is a number
for(int cnt = 26;(cnt < 36) && (!found);++cnt){
if(current.equals(code[cnt])){
//Remove 26 from cnt to get the correct number
output.append(Integer.toString(cnt - 26));
found = true;
}
}
//If it is neither print an error in the output
if(!found){
output.append("<Unknown symbol: " + current + ">");
}
}
//Save and return the output
outputString = output.toString();
return outputString;
}
//Encodes input and returns the result
private void setEncodeInputString(String input){
//Make sure the letters are all uppercase
input = input.toUpperCase();
//Remove all characters that are not capital letters
input = input.replaceAll("[^A-Z0-9]", "");
//Save the new input
inputString = input;
}
//Decodes input and returns the result
private void setDecodeInputString(String input){
//Remove all characters except ., -, and ' '
input = input.replaceAll("[^ \\.\\-]", "");
//Save the new input
inputString = input;
}
//Constructor
public Morse(){
reset();
}
//Returns inputString
public String getInputString(){
return inputString;
}
//Returns outputString
public String getOutputString(){
return outputString;
}
//Encodes input and returns the result
public String encode(String input){
setEncodeInputString(input);
return encode();
}
//Decoes input and returns the result
public String decode(String input){
setDecodeInputString(input);
return decode();
}
//Makes sure all variables are empty
public void reset(){
inputString = outputString = "";
}
}

View File

@@ -0,0 +1,437 @@
//CipherStreamJava/src/main/java/com/mattrixwv/CipherStreamJava/polySubstitution/Playfair.java
//Matthew Ellison
// Created: 07-30-21
//Modified: 02-17-22
package com.mattrixwv.cipherstream.polysubstitution;
import com.mattrixwv.cipherstream.exceptions.InvalidCharacterException;
import com.mattrixwv.cipherstream.exceptions.InvalidInputException;
public class Playfair{
//A class representing the location of a character in the grid
private class CharLocation{
private int x;
private int y;
public CharLocation(int x, int y){
this.x = x;
this.y = y;
}
public int getX(){
return x;
}
public int getY(){
return y;
}
}
//Variables
private boolean preserveCapitals; //Whether to respect captials 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
private char replaced; //The letter that will need to be replaced in the grid and any input string or keyword
private char replacer; //The letter that replaced replaced in the input string or keyword
private char doubled; //The letter that will be placed between double letters in the input string if necessary or to make the string length even
private String inputString; //The message that needs to be encoded/decoded
private String outputString; //The encoded/decoded message
private String keyword; //The keyword used to create the grid
private char[][] grid; //The grid used to encode/decode the message
//Create the grid from the keyword
private void createGrid(){
for(int row = 0;row < 5;++row){
for(int col = 0;col < 5;++col){
char letter = keyword.charAt((5 * row) + col);
grid[row][col] = letter;
}
}
}
//Strips invalid characters from the string that needs encoded/decoded
private void setInputString(String inputString, boolean encoding) throws InvalidCharacterException, InvalidInputException{
//Make sure the input string is not null
if(inputString == null){
throw new NullPointerException("The input string cannot be null");
}
//Set the options
if(!preserveCapitals){
inputString = inputString.toUpperCase();
}
if(!preserveWhitespace){
inputString = inputString.replaceAll("\\s", "");
}
if(!preserveSymbols){
inputString = inputString.replaceAll("[^a-zA-Z\\s]", "");
}
//Make replace all of the replacers with replaced
inputString = inputString.replaceAll(Character.toString(replaced), Character.toString(replacer));
//If there is nothing in the input string throw an exception
if(inputString.isBlank()){
throw new InvalidCharacterException("The input string cannot be blank");
}
//If this is encoding parse it and clean up an problems
if(encoding){
setEncodingInputString(inputString);
}
//If this is decoding just add it without parsing it
else{
//Throw an exception if replaced is included
if(inputString.contains(Character.toString(replaced))){
throw new InvalidCharacterException("An encoded message cannot contain a letter that needs replaced");
}
this.inputString = inputString;
}
if(this.inputString.isBlank() || getPreparedInputString().isBlank()){
throw new InvalidInputException("Input must have at least 1 letter");
}
}
private void setEncodingInputString(String inputString){
//Replace characters that need replaced
inputString = inputString.replaceAll(Character.toString(replaced), Character.toString(replacer));
//Check if there are any doubled characters
StringBuilder cleanInput = new StringBuilder();
int letterCount = 0;
for(int cnt = 0;cnt < inputString.length();){
//Advance until you find a letter, saving the input for inclusion
StringBuilder prepend = new StringBuilder();
while((cnt < inputString.length()) && !Character.isAlphabetic(inputString.charAt(cnt))){
prepend.append(inputString.charAt(cnt++));
}
//If we have reached the end of the string end the loop
if(cnt == inputString.length()){
cleanInput.append(prepend);
break;
}
//Get the next character
char firstLetter = inputString.charAt(cnt++);
++letterCount;
//Advance until you find a letter, saving the input for inclusion
StringBuilder middle = new StringBuilder();
while((cnt < inputString.length()) && !Character.isAlphabetic(inputString.charAt(cnt))){
middle.append(inputString.charAt(cnt++));
}
char secondLetter = '\0';
//If we have not reached the end of the string get the next character
if(cnt != inputString.length()){
secondLetter = inputString.charAt(cnt++);
++letterCount;
}
//If the second character is the same as the first character set the pointer back and use the doubled character
if(secondLetter == firstLetter){
--cnt;
secondLetter = doubled;
}
//Add all of the gathered input to the cleaned up input
cleanInput.append(prepend);
cleanInput.append(firstLetter);
cleanInput.append(middle);
if(secondLetter != '\0'){
cleanInput.append(secondLetter);
}
}
//Check if there are an odd number of characters
if((letterCount % 2) == 1){
int lastLetterLocation = cleanInput.length() - 1;
while(!Character.isAlphabetic(cleanInput.charAt(lastLetterLocation))){
--lastLetterLocation;
}
if(cleanInput.charAt(lastLetterLocation) == doubled){
cleanInput.append(replacer);
}
else{
cleanInput.append(doubled);
}
}
this.inputString = cleanInput.toString();
}
//Returns the input string ready for encoding
private String getPreparedInputString(){
String cleanString = inputString.toUpperCase();
cleanString = cleanString.replaceAll("[^A-Z]", "");
return cleanString;
}
//Strips invalid characters from the keyword and creates the grid
private void setKeyword(String keyword){
if(keyword == null){
throw new NullPointerException("Keyword cannot be null");
}
//Change everything to uppercase
keyword = keyword.toUpperCase();
//Removing everything except capital letters
keyword = keyword.replaceAll("[^A-Z]", "");
//Add all letters in the alphabet to the key
keyword += "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
//Replace all replaced characters
keyword = keyword.replaceAll(Character.toString(replaced), Character.toString(replacer));
//Remove all duplicate chatacters
StringBuilder uniqueKey = new StringBuilder();
keyword.chars().distinct().forEach(c -> uniqueKey.append((char)c));
this.keyword = uniqueKey.toString();
//Create the grid from the sanitized keyword
createGrid();
}
//Returns the location of the given character in the grid
private CharLocation findChar(char letter) throws InvalidInputException{
for(int row = 0;row < grid.length;++row){
for(int col = 0;col < grid[row].length;++col){
if(grid[row][col] == letter){
return new CharLocation(row, col);
}
}
}
//If it was not found something went wrong
throw new InvalidInputException("The character '" + letter + "' was not found in the grid");
}
//Returns the location in the grid of x and y, adjusting for out of bounds
private char getGridChar(int x, int y){
if(x < 0){
x += 5;
}
if(y < 0){
y += 5;
}
return grid[x % 5][y % 5];
}
//Adds characters that aren't letters to the output
private void addCharactersToCleanString(String cleanString){
int outputCnt = 0;
StringBuilder fullOutput = new StringBuilder();
for(int inputCnt = 0;inputCnt < inputString.length();++inputCnt){
if(Character.isUpperCase(inputString.charAt(inputCnt))){
fullOutput.append(cleanString.charAt(outputCnt++));
}
else if(Character.isLowerCase(inputString.charAt(inputCnt))){
fullOutput.append(Character.toLowerCase(cleanString.charAt(outputCnt++)));
}
else{
fullOutput.append(inputString.charAt(inputCnt));
}
}
outputString = fullOutput.toString();
}
//Encodes inputString using the Playfair cipher and stores the result in outputString
private String encode() throws InvalidInputException{
StringBuilder output = new StringBuilder();
int inputCnt = 0;
String cleanString = getPreparedInputString();
while(inputCnt < cleanString.length()){
//Get the next 2 letters to be encoded
char firstLetter = cleanString.charAt(inputCnt++);
char secondLetter = cleanString.charAt(inputCnt++);
//Find the letters in the grid
CharLocation firstLocation = findChar(firstLetter);
CharLocation secondLocation = findChar(secondLetter);
//Encode the letters
if(firstLocation.getX() == secondLocation.getX()){
firstLetter = getGridChar(firstLocation.getX(), firstLocation.getY() + 1);
secondLetter = getGridChar(secondLocation.getX(), secondLocation.getY() + 1);
}
else if(firstLocation.getY() == secondLocation.getY()){
firstLetter = getGridChar(firstLocation.getX() + 1, firstLocation.getY());
secondLetter = getGridChar(secondLocation.getX() + 1, secondLocation.getY());
}
else{
firstLetter = getGridChar(firstLocation.getX(), secondLocation.getY());
secondLetter = getGridChar(secondLocation.getX(), firstLocation.getY());
}
//Add the new letters to the output string
output.append(firstLetter);
output.append(secondLetter);
}
//Add other characters to the output string
addCharactersToCleanString(output.toString());
//Return the output string
return outputString;
}
//Decodes inputString using the Playfair cipher and stores the result in outputString
private String decode() throws InvalidInputException{
StringBuilder output = new StringBuilder();
int inputCnt = 0;
String cleanString = getPreparedInputString();
while(inputCnt < cleanString.length()){
//Get the next 2 letters to be encoded
char firstLetter = cleanString.charAt(inputCnt++);
char secondLetter = cleanString.charAt(inputCnt++);
//Find the letters in the grid
CharLocation firstLocation = findChar(firstLetter);
CharLocation secondLocation = findChar(secondLetter);
//Decode the letters
if(firstLocation.getX() == secondLocation.getX()){
firstLetter = getGridChar(firstLocation.getX(), firstLocation.getY() - 1);
secondLetter = getGridChar(secondLocation.getX(), secondLocation.getY() - 1);
}
else if(firstLocation.getY() == secondLocation.getY()){
firstLetter = getGridChar(firstLocation.getX() - 1, firstLocation.getY());
secondLetter = getGridChar(secondLocation.getX() - 1, secondLocation.getY());
}
else{
firstLetter = getGridChar(firstLocation.getX(), secondLocation.getY());
secondLetter = getGridChar(secondLocation.getX(), firstLocation.getY());
}
//Add the new letters to the output string
output.append(firstLetter);
output.append(secondLetter);
}
//Add other characters to the output string
addCharactersToCleanString(output.toString());
//Return the output string
return outputString;
}
public Playfair() throws InvalidCharacterException{
reset();
preserveCapitals = false;
preserveWhitespace = false;
preserveSymbols = false;
setReplaced('J');
setReplacer('I');
setDoubled('X');
}
public Playfair(boolean preserveCapitals, boolean preserveWhitespace, boolean preserveSymbols) throws InvalidCharacterException{
reset();
this.preserveCapitals = preserveCapitals;
this.preserveWhitespace = preserveWhitespace;
this.preserveSymbols = preserveSymbols;
setReplaced('J');
setReplacer('I');
setDoubled('X');
}
public Playfair(boolean preserveCapitals, boolean preserveWhitespace, boolean preserveSymbols, char replaced, char replacer, char doubled) throws InvalidCharacterException{
reset();
this.preserveCapitals = preserveCapitals;
this.preserveWhitespace = preserveWhitespace;
this.preserveSymbols = preserveSymbols;
setReplaced(replaced);
setReplacer(replacer);
setDoubled(doubled);
}
//Sets the keyword and inputString and encodes the message
public String encode(String keyword, String input) throws InvalidCharacterException, InvalidInputException{
reset();
setKeyword(keyword);
setInputString(input, true);
return encode();
}
//Sets the keyword and inputString and decodes the message
public String decode(String keyword, String input) throws InvalidCharacterException, InvalidInputException{
reset();
setKeyword(keyword);
setInputString(input, false);
return decode();
}
//Makes sure all variables are empty
public void reset(){
grid = new char[5][5];
inputString = "";
outputString = "";
keyword = "";
}
//Gets
public char getReplaced(){
return replaced;
}
public void setReplaced(char replaced) throws InvalidCharacterException{
if(!Character.isAlphabetic(replaced)){
throw new InvalidCharacterException("The replaced character must be a letter");
}
if(replaced == replacer){
throw new InvalidCharacterException("The replaced letter cannot be the same as the replacing letter");
}
if(replaced == doubled){
throw new InvalidCharacterException("The replaced letter cannot be the same as the replacing letter");
}
this.replaced = Character.toUpperCase(replaced);
}
public char getReplacer(){
return replacer;
}
public void setReplacer(char replacer) throws InvalidCharacterException{
//Make sure the character is a letter
if(!Character.isAlphabetic(replacer)){
throw new InvalidCharacterException("The replacer must be a letter");
}
//Make sure the character isn't the same as what it is supposed to replace
if(replacer == replaced){
throw new InvalidCharacterException("The replacer cannot be the same letter as what it is replacing");
}
//Make sure the replacer isn't the same as the double letter replacer
if(replacer == doubled){
throw new InvalidCharacterException("The replacer cannot be the same as the double letter replacer");
}
this.replacer = Character.toUpperCase(replacer);
}
public char getDoubled(){
return doubled;
}
public void setDoubled(char doubled) throws InvalidCharacterException{
//Make sure the character is a letter
if(!Character.isAlphabetic(doubled)){
throw new InvalidCharacterException("The double letter replacement must be a letter");
}
//Make sure the 2 replacers are the same
if(doubled == replacer){
throw new InvalidCharacterException("The double letter replacement cannot be the same as the regular replacer");
}
//Make sure the double letter replacement isn't the same as the letter being replaced
if(doubled == replaced){
throw new InvalidCharacterException("The double letter replacement cannot be the same as the letter replaced");
}
this.doubled = Character.toUpperCase(doubled);
}
public String getKeyword(){
return keyword;
}
public String getInputString(){
return inputString;
}
public String getOutputString(){
return outputString;
}
public String getGrid(){
StringBuilder gridString = new StringBuilder();
for(char[] row : grid){
for(char col : row){
gridString.append(col);
}
}
return gridString.toString();
}
}

View File

@@ -0,0 +1,352 @@
//CipherStreamJava/src/main/java/com/mattrixwv/CipherStreamJava/polySubstitution/PolybiusSquare.java
//Mattrixwv
// Created: 01-04-22
//Modified: 02-17-22
package com.mattrixwv.cipherstream.polysubstitution;
import java.util.StringJoiner;
import com.mattrixwv.cipherstream.exceptions.InvalidCharacterException;
import com.mattrixwv.cipherstream.exceptions.InvalidInputException;
public class PolybiusSquare{
//A class representing the location of a character in the grid
protected class CharLocation{
private int x;
private int y;
public CharLocation(int x, int y){
this.x = x;
this.y = y;
}
public int getX(){
return x;
}
public int getY(){
return y;
}
}
//Variables
protected String inputString; //The message that needs to be encoded/decoded
protected String outputString; //The encoded/decoded message
protected String keyword; //The keyword used to create the grid
protected char[][] grid; //The grid used to encode/decode the message
protected char replaced; //The letter that will need to be replaced in the grid and any input string or keyword
protected char replacer; //The letter that replaces replaced in the input string or keyword
protected boolean preserveWhitespace; //Whether to respect whitespace in the output string
protected boolean preserveSymbols; //Whether to respect symbols in the output string
//Create the grid from the keyword
protected void createGrid(){
for(int row = 0;row < 5;++row){
for(int col = 0;col < 5;++col){
char letter = keyword.charAt((5 * row) + col);
grid[row][col] = letter;
}
}
}
//Strips invalid characters from the string that needs encoded/decoded
protected void setInputStringEncoding(String inputString) throws InvalidCharacterException, InvalidInputException{
if(inputString == null){
throw new NullPointerException("Input cannot be null");
}
//Make sure the string doesn't contain any numbers
for(char ch = '0';ch <= '9';++ch){
if(inputString.contains(Character.toString(ch))){
throw new InvalidCharacterException("Inputs for encoding cannot contain numbers");
}
}
//Change to upper case
inputString = inputString.toUpperCase();
//Remove any whitespace if selected
if(!preserveWhitespace){
inputString = inputString.replaceAll("\\s", "");
}
//Remove any symbols if selected
if(!preserveSymbols){
inputString = inputString.replaceAll("[^a-zA-Z\\s]", "");
}
if(!preserveWhitespace && !preserveSymbols){
//Add whitespace after every character for the default look
StringJoiner spacedString = new StringJoiner(" ");
for(int cnt = 0;cnt < inputString.length();++cnt){
spacedString.add(Character.toString(inputString.charAt(cnt)));
}
inputString = spacedString.toString();
}
//Replace any characters that need replaced
inputString = inputString.replaceAll(Character.toString(replaced), Character.toString(replacer));
//Save the string
this.inputString = inputString;
if(this.inputString.isBlank() || getPreparedInputStringEncoding().isBlank()){
throw new InvalidInputException("Input must contain at least 1 letter");
}
}
protected void setInputStringDecoding(String inputString) throws InvalidCharacterException, InvalidInputException{
if(inputString == null){
throw new NullPointerException("Input cannot be null");
}
//Make sure the string contains an even number of digits and no letters
int numberOfDigits = 0;
for(int cnt = 0;cnt < inputString.length();++cnt){
char ch = inputString.charAt(cnt);
if(Character.isDigit(ch)){
++numberOfDigits;
}
else if(Character.isAlphabetic(ch)){
throw new InvalidCharacterException("Inputs for decoding cannot contains letters");
}
}
if((numberOfDigits % 2) != 0){
throw new InvalidCharacterException("There must be an even number of digits in an encoded string");
}
//Remove any whitespace if selected
if(!preserveWhitespace){
inputString = inputString.replaceAll("\\s", "");
}
//Remove any symbols if selected
if(!preserveSymbols){
inputString = inputString.replaceAll("[^0-9\\s]", "");
}
//Save the string
this.inputString = inputString;
if(this.inputString.isBlank() || getPreparedInputStringDecoding().isBlank()){
throw new InvalidInputException("Input must contain at least 1 letter");
}
}
//Returns the input string ready for encoding
protected String getPreparedInputStringEncoding(){
String cleanString = inputString.toUpperCase();
cleanString = cleanString.replaceAll("[^A-Z]", "");
return cleanString;
}
protected String getPreparedInputStringDecoding(){
return inputString.replaceAll("[^0-9]", "");
}
//Strips invalid characters from the keyword and creates the grid
protected void setKeyword(String keyword){
if(keyword == null){
throw new NullPointerException("Keyword cannot be null");
}
//Change everything to uppercase
keyword = keyword.toUpperCase();
//Remove everything except capital letters
keyword = keyword.replaceAll("[^A-Z]", "");
//Add all letters in the alphabet to the key
keyword += "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
//Replace all replaced characters
keyword = keyword.replaceAll(Character.toString(replaced), Character.toString(replacer));
//Remove all duplicate characters
StringBuilder uniqueKey = new StringBuilder();
keyword.chars().distinct().forEach(c -> uniqueKey.append((char)c));
this.keyword = uniqueKey.toString();
//Create the grid from the sanitized keyword
createGrid();
}
//Returns the location of the given charcter in the grid
protected CharLocation findChar(char letter) throws InvalidInputException{
for(int row = 0;row < grid.length;++row){
for(int col = 0;col < grid[row].length;++col){
if(grid[row][col] == letter){
return new CharLocation(row, col);
}
}
}
//If it was not found something went wrong
throw new InvalidInputException("The character '" + letter + "' was not found in the grid");
}
//Adds characters that aren't letters to the output
protected void addCharactersToCleanStringEncode(String cleanString){
int outputCnt = 0;
StringBuilder fullOutput = new StringBuilder();
for(int inputCnt = 0;inputCnt < inputString.length();++inputCnt){
//Add both numbers of any letters to the output
if(Character.isAlphabetic(inputString.charAt(inputCnt))){
fullOutput.append(cleanString.charAt(outputCnt++));
fullOutput.append(cleanString.charAt(outputCnt++));
}
//Add any other characters that appear to the output
else{
fullOutput.append(inputString.charAt(inputCnt));
}
}
outputString = fullOutput.toString();
}
protected void addCharactersToCleanStringDecode(String cleanString){
int outputCnt = 0;
StringBuilder fullOutput = new StringBuilder();
for(int inputCnt = 0;inputCnt < inputString.length();++inputCnt){
//Add the letter to the output and skip the second number
if(Character.isDigit(inputString.charAt(inputCnt))){
fullOutput.append(cleanString.charAt(outputCnt++));
++inputCnt;
}
//Add any other characters that appear to the output
else{
fullOutput.append(inputString.charAt(inputCnt));
}
}
outputString = fullOutput.toString();
}
//Encodes inputString using the Playfair cipher and stores the result in outputString
private String encode() throws InvalidInputException{
StringBuilder output = new StringBuilder();
String cleanString = getPreparedInputStringEncoding();
for(int cnt = 0;cnt < cleanString.length();++cnt){
//Get the next character to be encoded
char ch = cleanString.charAt(cnt);
//Find the letter in the grid
CharLocation location = findChar(ch);
//Add the grid location to the output
output.append(location.getX() + 1);
output.append(location.getY() + 1);
}
//Add other characters to the output string
addCharactersToCleanStringEncode(output.toString());
//Return the output string
return outputString;
}
//Decodes inputString using the Playfair cipher and stores the result in outputString
private String decode(){
StringBuilder output = new StringBuilder();
String cleanString = getPreparedInputStringDecoding();
for(int cnt = 0;cnt < cleanString.length();){
//Get the digits indicationg the location of the next character
char firstDigit = cleanString.charAt(cnt++);
char secondDigit = cleanString.charAt(cnt++);
//Get the next character
char letter = grid[Integer.valueOf(Character.toString(firstDigit)) - 1][Integer.valueOf(Character.toString(secondDigit)) - 1];
//Add the new letter to the output
output.append(letter);
}
//Add other characters to the output
addCharactersToCleanStringDecode(output.toString());
//Return the output string
return outputString;
}
public PolybiusSquare() throws InvalidCharacterException{
reset();
setReplaced('J');
setReplacer('I');
preserveWhitespace = false;
preserveSymbols = false;
}
public PolybiusSquare(boolean preserveWhitespace, boolean preserveSymbols) throws InvalidCharacterException{
reset();
setReplaced('J');
setReplacer('I');
this.preserveWhitespace = preserveWhitespace;
this.preserveSymbols = preserveSymbols;
}
public PolybiusSquare(boolean preserveWhitespace, boolean preserveSymbols, char replaced, char replacer) throws InvalidCharacterException{
reset();
setReplaced(replaced);
setReplacer(replacer);
this.preserveWhitespace = preserveWhitespace;
this.preserveSymbols = preserveSymbols;
}
//Sets the keyword and inputString and encodes the message
public String encode(String inputString) throws InvalidCharacterException, InvalidInputException{
return encode("", inputString);
}
public String encode(String keyword, String inputString) throws InvalidCharacterException, InvalidInputException{
reset();
setKeyword(keyword);
setInputStringEncoding(inputString);
return encode();
}
//Sets the keyword and inputString and decodes the message
public String decode(String inputString) throws InvalidCharacterException, InvalidInputException{
return decode("", inputString);
}
public String decode(String keyword, String inputString) throws InvalidCharacterException, InvalidInputException{
reset();
setKeyword(keyword);
setInputStringDecoding(inputString);
return decode();
}
//Makes sure all variables are empty
public void reset(){
grid = new char[5][5];
inputString = "";
outputString = "";
keyword = "";
}
//Gets
public char getReplaced(){
return replaced;
}
public void setReplaced(char replaced) throws InvalidCharacterException{
if(!Character.isAlphabetic(replaced)){
throw new InvalidCharacterException("The replaced character must be a letter");
}
if(replaced == replacer){
throw new InvalidCharacterException("The replaced letter cannot be the same as the replacing letter");
}
this.replaced = Character.toUpperCase(replaced);
}
public char getReplacer(){
return replacer;
}
public void setReplacer(char replacer) throws InvalidCharacterException{
if(!Character.isAlphabetic(replacer)){
throw new InvalidCharacterException("The replacer character must be a letter");
}
if(replaced == replacer){
throw new InvalidCharacterException("The replacer letter cannot be the same as the replaced letter");
}
this.replacer = replacer;
}
public String getKeyword(){
return keyword;
}
public String getInputString(){
return inputString;
}
public String getOutputString(){
return outputString;
}
public String getGrid(){
StringBuilder gridString = new StringBuilder();
for(char[] row : grid){
for(char col : row){
gridString.append(col);
}
}
return gridString.toString();
}
}

View File

@@ -0,0 +1,254 @@
//CipherStreamJava/src/main/java/com/mattrixwv/CipherStreamJava/polySubstitution/RailFence.java
//Mattrixwv
// Created: 03-21-22
//Modified: 03-22-22
package com.mattrixwv.cipherstream.polysubstitution;
import java.math.BigDecimal;
import com.mattrixwv.cipherstream.exceptions.InvalidInputException;
import com.mattrixwv.cipherstream.exceptions.InvalidBaseException;
public class RailFence{
//Variables
private String inputString; //The message that needs to be encoded/decoded
private String outputString; //The encoded/decoded message
private StringBuilder[] fence; //The fence used for encoding/decoding
private boolean preserveCapitals; //Persist capitals in the output string
private boolean preserveWhitespace; //Persist whitespace in the output string
private boolean preserveSymbols; //Persist symbols in the output string
//Strips invalid characters from the string that needs encoded/decoded
private void setInputString(String inputString) throws InvalidInputException{
//Ensure the input string isn't null
if(inputString == null){
throw new InvalidInputException("Input cannot be null");
}
//Apply removal options
if(!preserveCapitals){
inputString = inputString.toUpperCase();
}
if(!preserveWhitespace){
inputString = inputString.replaceAll("\\s", "");
}
if(!preserveSymbols){
inputString = inputString.replaceAll("[^a-zA-Z\\s]", "");
}
//Save the string
this.inputString = inputString;
//Ensure the string isn't blank
if(this.inputString.isBlank()){
throw new InvalidInputException("Input must contain at least 1 letter");
}
}
//Ensures the number of rails is valid and sets up the fence
private void setNumRails(int numRails) throws InvalidBaseException{
if(numRails < 2){
throw new InvalidBaseException("You must use at least 2 rails");
}
fence = new StringBuilder[numRails];
for(int cnt = 0;cnt < numRails;++cnt){
fence[cnt] = new StringBuilder();
}
}
//Strip the inputString of all non-letter characters
private String getCleanInputString(){
return inputString.replaceAll("[^a-zA-Z]", "");
}
//Ensures capitals, lowercase, and symbols are displayed in the output string
private void formatOutput(String outputString){
StringBuilder output = new StringBuilder();
int outputLoc = 0;
for(char ch : inputString.toCharArray()){
if(Character.isUpperCase(ch)){
output.append(Character.toUpperCase(outputString.charAt(outputLoc++)));
}
else if(Character.isLowerCase(ch)){
output.append(Character.toLowerCase(outputString.charAt(outputLoc++)));
}
else{
output.append(ch);
}
}
this.outputString = output.toString();
}
//Returns the decoded string found in the fence after all characters are placed correctly
private String getDecodedStringFromFence(){
boolean down = true;
int rail = 0;
int outsideCol = 0;
int insideCol = -1;
StringBuilder output = new StringBuilder();
while(true){
//Get the next character based on what rail you are currently usinig
if(rail == 0){
if(outsideCol >= fence[rail].length()){
break;
}
output.append(fence[rail].charAt(outsideCol));
++insideCol;
}
else if(rail == (fence.length - 1)){
if(outsideCol >= fence[rail].length()){
break;
}
output.append(fence[rail].charAt(outsideCol++));
++insideCol;
}
else{
if(insideCol >= fence[rail].length()){
break;
}
output.append(fence[rail].charAt(insideCol));
}
//Make sure you're still in bounds
if(down){
++rail;
}
else{
--rail;
}
if(rail >= fence.length){
down = false;
rail -= 2;
}
else if(rail < 0){
down = true;
rail += 2;
}
}
return output.toString();
}
//Encodes inputString using the RailFence cipher and stores the result in outputString
private void encode(){
boolean up = true;
int rail = 0;
for(char ch : getCleanInputString().toCharArray()){
fence[rail].append(ch);
//Advance to the next rail
if(up){
++rail;
}
else{
--rail;
}
//Make sure you're still in bounds
if(rail == fence.length){
up = false;
rail -= 2;
}
else if(rail == -1){
up = true;
rail += 2;
}
}
StringBuilder output = new StringBuilder();
for(StringBuilder segment : fence){
output.append(segment);
}
formatOutput(output.toString());
}
//Decodes inputString using the RailFence cipher and stores the result in outputString
private void decode(){
//Determine the number of characters on each rail
String cleanInputString = getCleanInputString();
int cycleLength = 2 * (fence.length - 1);
BigDecimal k = new BigDecimal(cleanInputString.length()).divide(new BigDecimal(cycleLength));
int numInTopRail = (int)Math.ceil(k.doubleValue());
int numInMiddleRails = (numInTopRail * 2);
int numInBottomRail = 0;
boolean goingDown = true;
int middleNum = 0;
if(k.remainder(BigDecimal.ONE).compareTo(new BigDecimal("0.5")) <= 0){
numInMiddleRails -= 1;
numInBottomRail = (int)Math.floor(k.doubleValue());
goingDown = true;
middleNum = k.remainder(BigDecimal.ONE).multiply(new BigDecimal(cycleLength)).intValue() - 1;
}
else{
numInBottomRail = numInTopRail;
goingDown = false;
middleNum = (cycleLength - (k.remainder(BigDecimal.ONE).multiply(new BigDecimal(cycleLength))).intValue());
}
//Add the correct number of characters to each rail
fence[0].append(cleanInputString.substring(0, numInTopRail));
int start = numInTopRail;
int end = numInTopRail + numInMiddleRails;
for(int cnt = 1;cnt < (fence.length - 1);++cnt){
if((!goingDown) && (middleNum >= cnt)){
end -= 1;
}
fence[cnt].append(cleanInputString.substring(start, end));
start = end;
end += numInMiddleRails;
}
end = start + numInBottomRail;
fence[fence.length - 1].append(cleanInputString.substring(start, end));
//Get the decoded string from the constructed fence
String output = getDecodedStringFromFence();
formatOutput(output);
}
//Constructor
public RailFence(){
preserveCapitals = false;
preserveWhitespace = false;
preserveSymbols = false;
}
public RailFence(boolean preserveCapitals, boolean preserveWhitespace, boolean preserveSymbols){
this.preserveCapitals = preserveCapitals;
this.preserveWhitespace = preserveWhitespace;
this.preserveSymbols = preserveSymbols;
}
//Encodes inputString using a Rail Fence of length numRails and returns the result
public String encode(int numRails, String inputString) throws InvalidBaseException, InvalidInputException{
//Set the parameters
setNumRails(numRails);
setInputString(inputString);
//Encode
encode();
return outputString;
}
//Decodes inputString using a Rail Fence of length numRails and returns the result
public String decode(int numRails, String inputString) throws InvalidBaseException, InvalidInputException{
//Set the parameters
setNumRails(numRails);
setInputString(inputString);
//Decode
decode();
return outputString;
}
//Makes sure all variables are empty
public void reset(){
inputString = "";
outputString = "";
fence = null;
}
//Gets
public String getInputString(){
return inputString;
}
public String getOutputString(){
return outputString;
}
public int getNumRails(){
return fence.length;
}
}

View File

@@ -0,0 +1,416 @@
//CipherStreamJava/src/main/java/com/mattrixwv/CipherStreamJava/polySubstitution/Trifid.java
//Mattrixwv
// Created: 03-03-22
//Modified: 03-03-22
package com.mattrixwv.cipherstream.polysubstitution;
import java.util.ArrayList;
import java.util.StringJoiner;
import com.mattrixwv.cipherstream.exceptions.InvalidCharacterException;
import com.mattrixwv.cipherstream.exceptions.InvalidInputException;
import com.mattrixwv.cipherstream.exceptions.InvalidKeywordException;
import com.mattrixwv.cipherstream.exceptions.InvalidBaseException;
public class Trifid{
//A class representing the location of a character in the grid
private class CharLocation{
private int x;
private int y;
private int z;
public CharLocation(int x, int y, int z){
this.x = x;
this.y = y;
this.z = z;
}
public int getX(){
return x;
}
public int getY(){
return y;
}
public int getZ(){
return z;
}
public String toString(){
return "[" + (z + 1) + ", " + (x + 1) + ", " + (y + 1) + "]";
}
}
//Variables
private String inputString; //The message that needs to be encoded/decoded
private String outputString; //The encoded/decoded message
private String keyword; //The keyword used to create the grid
private int groupSize; //The size of the groups used to break up the input
private char[][][] grid; //The grid used to encode/decode the message
private char fillIn; //The character added to the alphabet to meet the 27 character requirement
private boolean preserveCapitals; //Persist capitals in the output string
private boolean preserveWhitespace; //Persist whitespace in the output string
private boolean preserveSymbols; //Persist symbols in the output string
//Makes sure the fillIn is a valid character
private void setFillIn(char fillIn) throws InvalidCharacterException{
//Make sure the character is a printing character
if((fillIn < ' ') || (fillIn > '~')){
throw new InvalidCharacterException("Fill in character must be a printing character");
}
//Make sure the character is not a letter
if(Character.isAlphabetic(fillIn)){
throw new InvalidCharacterException("Fill in must not be a letter");
}
//Save the fillIn character
this.fillIn = fillIn;
}
//Strips invalid characters from the keyword and creates the grid
private void setKeyword(String keyword) throws InvalidKeywordException{
//Ensure the keyword isn't null
if(keyword == null){
throw new InvalidKeywordException("Keyword cannot be null");
}
//Change everything to uppercase
keyword = keyword.toUpperCase();
//Remove everything except capital letters
keyword = keyword.replaceAll("[^A-Z" + fillIn + "]", "");
//Add all letters in the alphabet and fillIn to the key
keyword += "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + fillIn;
//Remove all duplicate characters
StringBuilder uniqueKey = new StringBuilder();
keyword.chars().distinct().forEach(c -> uniqueKey.append((char)c));
this.keyword = uniqueKey.toString();
//Create the grid from the sanitized keyword
createGrid();
}
//Creates the grid from the keyword
private void createGrid(){
for(int layerCnt = 0;layerCnt < grid.length;++layerCnt){
for(int rowCnt = 0;rowCnt < grid[layerCnt].length;++rowCnt){
for(int colCnt = 0;colCnt < grid[layerCnt][rowCnt].length;++colCnt){
int loc = 0;
loc = colCnt + (rowCnt * grid[layerCnt][rowCnt].length) + (layerCnt * grid[layerCnt].length * grid[layerCnt][rowCnt].length);
grid[layerCnt][rowCnt][colCnt] = keyword.charAt(loc);
}
}
}
}
//Ensures groupSize constraints
private void setGroupSize(int groupSize) throws InvalidBaseException{
if(groupSize <= 0){
throw new InvalidBaseException("Group size must be > 0");
}
this.groupSize = groupSize;
}
//Ensures inputString constraints
private void setInputString(String inputString) throws InvalidInputException{
//Ensure the input string isn't null
if(inputString == null){
throw new InvalidInputException("Input cannot be null");
}
//Apply removal options
if(!preserveCapitals){
inputString = inputString.toUpperCase();
}
if(!preserveWhitespace){
if(Character.isWhitespace(fillIn)){
throw new InvalidInputException("If fillIn is whitespace, whitespace must be preserved");
}
inputString = inputString.replaceAll("\\s", "");
}
if(!preserveSymbols){
inputString = inputString.replaceAll("[^a-zA-Z" + fillIn + "\\s]", "");
}
//Save the string
this.inputString = inputString;
//Ensure the string isn't blank
if(this.inputString.isBlank()){
throw new InvalidInputException("Input must contain at least 1 letter");
}
}
//Returns the inputString with only letters
private String getCleanInputString(){
return inputString.toUpperCase().replaceAll("[^A-Z" + fillIn + "]", "");
}
//Returns the location of the given character in the grid
private CharLocation findChar(char letter) throws InvalidCharacterException{
for(int layer = 0;layer < grid.length;++layer){
for(int row = 0;row < grid[layer].length;++row){
for(int col = 0;col < grid[layer][row].length;++col){
if(grid[layer][row][col] == letter){
return new CharLocation(row, col, layer);
}
}
}
}
//If it was not found something went wrong
throw new InvalidCharacterException("The character '" + letter + "' was not found in the grid");
}
//Return the character from the location provided
private char getChar(CharLocation location) throws InvalidCharacterException{
if(location.getX() > 2){
throw new InvalidCharacterException("x cannot be larget than 2");
}
if(location.getY() > 2){
throw new InvalidCharacterException("y cannot be larget than 2");
}
if(location.getZ() > 2){
throw new InvalidCharacterException("z cannot be larget than 2");
}
return grid[location.getZ()][location.getX()][location.getY()];
}
//Adds all non-letter characters back to the output string
private void formatOutput(String outputString){
//Keep track of where you are in the output
int outputCnt = 0;
StringBuilder output = new StringBuilder();
//Check every character in the input and apply the correct rules to the output
for(char ch : inputString.toCharArray()){
if(Character.isUpperCase(ch)){
output.append(Character.toUpperCase(outputString.charAt(outputCnt++)));
}
else if(Character.isLowerCase(ch)){
output.append(Character.toLowerCase(outputString.charAt(outputCnt++)));
}
else{
output.append(ch);
}
}
//Save the output
this.outputString = output.toString();
}
//Encodes inputString using a polybius square and stores the result in outputString
private void encode() throws InvalidCharacterException{
//Step through every element in the sanitized inputString encoding the letters
ArrayList<CharLocation> locations = new ArrayList<>();
for(char ch : getCleanInputString().toCharArray()){
//Get the location of the char in the grid
CharLocation location = findChar(ch);
locations.add(location);
}
//Split the locations up by group
int numGroups = inputString.length() / groupSize;
if(numGroups == 0){
numGroups = 1;
}
ArrayList<ArrayList<CharLocation>> groups = new ArrayList<>(numGroups);
for(int cnt = 0;cnt < numGroups;++cnt){
groups.add(new ArrayList<>());
}
int groupCnt = -1;
for(int locCnt = 0;locCnt < locations.size();++locCnt){
//If you've reached the end of the group move to the next one
if((locCnt % groupSize) == 0){
++groupCnt;
}
groups.get(groupCnt).add(locations.get(locCnt));
}
//Split the coordinates into rows
ArrayList<Integer> coordinates = new ArrayList<>(locations.size() * 3);
for(ArrayList<CharLocation> group : groups){
//Split the coordinates up into 3 rows
ArrayList<Integer> layers = new ArrayList<>(group.size());
ArrayList<Integer> rows = new ArrayList<>(group.size());
ArrayList<Integer> cols = new ArrayList<>(group.size());
for(CharLocation loc : group){
layers.add(loc.getZ());
rows.add(loc.getX());
cols.add(loc.getY());
}
coordinates.addAll(layers);
coordinates.addAll(rows);
coordinates.addAll(cols);
}
//Create new locations from the rows of coordinates
ArrayList<CharLocation> newLocations = new ArrayList<>(locations.size());
for(int cnt = 0;cnt < coordinates.size();){
int z = coordinates.get(cnt++);
int x = coordinates.get(cnt++);
int y = coordinates.get(cnt++);
newLocations.add(new CharLocation(x, y, z));
}
//Get the new letters from the grid
StringBuilder output = new StringBuilder();
for(CharLocation loc : newLocations){
output.append(getChar(loc));
}
//Format the output
formatOutput(output.toString());
}
//Decodes inputString using a polybius square and stores the result in outputString
private void decode() throws InvalidCharacterException{
//Step through every element in the sanitized inputString encoding the letters
ArrayList<CharLocation> locations = new ArrayList<>();
for(char ch : getCleanInputString().toCharArray()){
//Get the location of the char in the grid
CharLocation location = findChar(ch);
locations.add(location);
}
//Split the locations up by group
int numGroups = inputString.length() / groupSize;
if(numGroups == 0){
numGroups = 1;
}
ArrayList<ArrayList<CharLocation>> groups = new ArrayList<>(numGroups);
for(int cnt = 0;cnt < numGroups;++cnt){
groups.add(new ArrayList<>());
}
int groupCnt = -1;
for(int locCnt = 0;locCnt < locations.size();++locCnt){
//If you've reached the end of the group move to the next one
if((locCnt % groupSize) == 0){
++groupCnt;
}
groups.get(groupCnt).add(locations.get(locCnt));
}
//Split the coordinates into rows by group and create the original grid locations
ArrayList<CharLocation> originalLocations = new ArrayList<>(locations.size());
for(ArrayList<CharLocation> group : groups){
//Read all of the coordinates from the group out into a row
ArrayList<Integer> coordinates = new ArrayList<>(group.size() * 3);
for(CharLocation loc : group){
coordinates.add(loc.getZ());
coordinates.add(loc.getX());
coordinates.add(loc.getY());
}
//Read out the coordinates into new locations
ArrayList<CharLocation> originalGroup = new ArrayList<>(group.size());
for(int cnt = 0;cnt < group.size();++cnt){
originalGroup.add(new CharLocation(0, 0, 0));
}
int coordinateCnt = 0;
for(CharLocation loc : originalGroup){
loc.z = coordinates.get(coordinateCnt++);
}
for(CharLocation loc : originalGroup){
loc.x = coordinates.get(coordinateCnt++);
}
for(CharLocation loc : originalGroup){
loc.y = coordinates.get(coordinateCnt++);
}
originalLocations.addAll(originalGroup);
}
//Get the original letters from the grid
StringBuilder output = new StringBuilder();
for(CharLocation loc : originalLocations){
output.append(getChar(loc));
}
//Format the output
formatOutput(output.toString());
}
//Constructor
public Trifid() throws InvalidCharacterException{
preserveCapitals = false;
preserveWhitespace = false;
preserveSymbols = false;
setFillIn('+');
}
public Trifid(boolean preserveCapitals, boolean preserveWhitespace, boolean preserveSymbols) throws InvalidCharacterException{
this.preserveCapitals = preserveCapitals;
this.preserveWhitespace = preserveWhitespace;
this.preserveSymbols = preserveSymbols;
setFillIn('+');
}
public Trifid(boolean preserveCapitals, boolean preserveWhitespace, boolean preserveSymbols, char fillIn) throws InvalidCharacterException{
this.preserveCapitals = preserveCapitals;
this.preserveWhitespace = preserveWhitespace;
this.preserveSymbols = preserveSymbols;
setFillIn(fillIn);
}
//Encodes inputString using keyword and groupSize and returns the result
public String encode(String keyword, String inputString) throws InvalidBaseException, InvalidKeywordException, InvalidInputException, InvalidCharacterException{
return encode(keyword, inputString.length(), inputString);
}
public String encode(String keyword, int groupSize, String inputString) throws InvalidBaseException, InvalidKeywordException, InvalidInputException, InvalidCharacterException{
//Set the parameters
reset();
setKeyword(keyword);
setGroupSize(groupSize);
setInputString(inputString);
//Encode and return the message
encode();
return outputString;
}
//Decodes inputString using keyword and groupSize and returns the result
public String decode(String keyword, String inputString) throws InvalidBaseException, InvalidKeywordException, InvalidInputException, InvalidCharacterException{
return decode(keyword, inputString.length(), inputString);
}
public String decode(String keyword, int groupSize, String inputString) throws InvalidBaseException, InvalidKeywordException, InvalidInputException, InvalidCharacterException{
//Set the parameters
reset();
setKeyword(keyword);
setGroupSize(groupSize);
setInputString(inputString);
//Decode and return the message
decode();
return outputString;
}
//Makes sure all variables are empty
public void reset(){
inputString = "";
outputString = "";
keyword = "";
groupSize = Integer.MAX_VALUE;
grid = new char[3][3][3];
}
//Gets
public String getInputString(){
return inputString;
}
public String getOutputString(){
return outputString;
}
public String getKeyword(){
return keyword;
}
public int getGroupSize(){
return groupSize;
}
public char getFillIn(){
return fillIn;
}
public String getGrid(){
StringJoiner layers = new StringJoiner("\n\n");
for(char[][] layer : grid){
StringJoiner gridJoiner = new StringJoiner("\n");
for(char[] row : layer){
StringJoiner rowJoiner = new StringJoiner(" ", "[", "]");
for(char ch : row){
rowJoiner.add(Character.toString(ch));
}
gridJoiner.add(rowJoiner.toString());
}
layers.add(gridJoiner.toString());
}
return layers.toString();
}
}