diff --git a/pom.xml b/pom.xml index 65d1499..1f9805b 100644 --- a/pom.xml +++ b/pom.xml @@ -13,8 +13,9 @@ UTF-8 - 14 - 14 + 17 + 17 + 17 diff --git a/src/main/java/mattrixwv/CipherStreamJava/Playfair.java b/src/main/java/mattrixwv/CipherStreamJava/Playfair.java index 00cdd2f..09d00da 100644 --- a/src/main/java/mattrixwv/CipherStreamJava/Playfair.java +++ b/src/main/java/mattrixwv/CipherStreamJava/Playfair.java @@ -7,32 +7,23 @@ package mattrixwv.CipherStreamJava; public class Playfair{ - //Classes to help with error handling - private class LetterNotFound{ - private char letter; - public LetterNotFound(char letter){ - this.letter = letter; + //An exception to indicate a bad string was given as a parameter + public class InvalidCharacterException extends Exception{ + InvalidCharacterException(){ + super(); } - public char getLetter(){ - return letter; + InvalidCharacterException(String message){ + super(message); } - } - public class InvalidGrid{ - private String type; - private int size; - public InvalidGrid(String type, int size){ - this.type = type; - this.size = size; - } - public String getType(){ - return type; - } - public int getSize(){ - return size; + InvalidCharacterException(String message, Throwable throwable){ + super(message, throwable); } } //Variables + private boolean leaveCapitals; //Whether to respect captials in the output string + private boolean leaveWhitespace; //Whether to respect whitespace in the output string + private boolean leaveSymbols; //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 @@ -42,57 +33,127 @@ public class Playfair{ private char[][] grid; //The grid used to encoded/decode the message //Create the grid from the keyword private void createGrid(){ - int row = 0; - int column = 0; - boolean found = false; - - //Add any new letters from the keyword to the grid - //If you reach row 5 then the entire grid has been filled - char current = '\0'; - for(int cnt = 0;(cnt < keyword.length()) && (row < 5);++cnt){ - current = keyword.charAt(cnt); - //If the current letter needs to be replaced, do so - if(current == replaced){ - current = replacer; - } - - //Search the grid for the current letter - found = checkGrid(current); - - //If the letter is not in the grid add it - if(!found){ - grid[row][column] = keyword.charAt(cnt); - ++column; - //If the column number is too high reset it and advance the row - if(column >= 5){ - column = 0; - ++row; - } + 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; } } } - //Returns true if the letter is found in the grid - private boolean checkGrid(char letter){ - //TODO: - return true; - } - //Searches the grid for letter and sets row & col to its location in grid - //TODO: This needs to be reworked - private void searchGrid(char letter, int row, int col){ - //TODO: - } //Strips invalid characters from the string that needs encoded/decoded - private void setInputString(String input){ - //TODO: + private void setInputString(String inputString) throws InvalidCharacterException{ + //Make sure the input string is not null + if(inputString == null){ + throw new InvalidCharacterException("The input string cannot be null"); + } + + //Set the options + if(!leaveCapitals){ + inputString.toLowerCase(); + } + if(!leaveWhitespace){ + inputString = inputString.replaceAll("\\s+", ""); + } + if(!leaveSymbols){ + inputString = inputString.replaceAll("[^a-zA-Z0-9\\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"); + } + + //Replace characters that need replaced + StringBuilder sanitizedInput = new StringBuilder(); + for(int inputCnt = 0;inputCnt < inputString.length();++inputCnt){ + //Get the first letter + char firstLetter = inputString.charAt(inputCnt++); + //Make sure the first letter doesn't need replaced + if(firstLetter == replaced){ + firstLetter = replacer; + } + + //Save all of the characters inbetween letters + StringBuilder inBetween = new StringBuilder(); + while((!Character.isAlphabetic(inputString.charAt(inputCnt))) && (inputCnt != inputString.length())){ + inBetween.append(inputString.charAt(inputCnt++)); + } + + //Get the second letter + char secondLetter = '\0'; + if(inputCnt != inputString.length()){ + secondLetter = inputString.charAt(inputCnt++); + } + else{ + secondLetter = doubled; + } + //Make sure the second letter doesn't need replaced + if(secondLetter == replaced){ + secondLetter = replacer; + } + if(secondLetter == firstLetter){ + secondLetter = doubled; + --inputCnt; + } + + //Add the letters to the sanitized string + sanitizedInput.append(firstLetter); + sanitizedInput.append(inBetween.toString()); + sanitizedInput.append(secondLetter); + } + this.inputString = sanitizedInput.toString(); + } + //Returns the inputs string ready for encoding + private String getPreparedInputString(){ + String cleanString = inputString.toUpperCase(); + cleanString = cleanString.replaceAll("[^A-Z]", ""); + return cleanString; } //Strips invalid character from the keyword and creates the grid private void setKeyword(String key){ - //TODO: + //Change everything to uppercase + key = key.toUpperCase(); + + //Removing everything except capital letters + key = key.replaceAll("[^A-Z]", ""); + + //Add all letters in the alphabet to the key + key += "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + //Replace all replaced characters + key = key.replaceAll(Character.toString(replaced), Character.toString(replacer)); + + //Remove all duplicate chatacters + StringBuilder uniqueKey = new StringBuilder(); + key.chars().distinct().forEach(c -> uniqueKey.append((char)c)); + keyword = uniqueKey.toString(); + + //Create the grid from the sanitized keyword + createGrid(); } //Encoded inputString using the Playfair cipher and stores the result in outputString private String encode(){ - //TODO: - return null; + StringBuilder output = new StringBuilder(); + int inputCnt = 0; + String cleanString = getPreparedInputString(); + while(inputCnt < inputString.length()){ + //Get the next 2 letters to be encoded + char firstLetter = inputString.charAt(inputCnt++); + char secondLetter = '\0'; + StringBuilder inBetween = new StringBuilder(); + + //TODO: + //Find the letters in the grid + + //Encode the letters + + //Add the new letters to the output string + } + + //Return the output string } //Decodes inputString using the Playfair cipher and stores the result in outputString private String decode(){ @@ -105,40 +166,110 @@ public class Playfair{ replaced = 'J'; replacer = 'I'; doubled = 'X'; + leaveCapitals = false; + leaveWhitespace = false; + leaveSymbols = false; + } + public Playfair(boolean leaveCapitals, boolean leaveWhitespace, boolean leaveSymbols){ + reset(); + replaced = 'J'; + replacer = 'I'; + doubled = 'X'; + this.leaveCapitals = leaveCapitals; + this.leaveWhitespace = leaveWhitespace; + this.leaveSymbols = leaveSymbols; + } + public Playfair(boolean leaveCapitals, boolean leaveWhitespace, boolean leaveSymbols, char replaced, char replacer, char doubled) throws InvalidCharacterException{ + reset(); + setReplaced(replaced); + setReplacer(replacer); + setDoubled(doubled); + this.leaveCapitals = leaveCapitals; + this.leaveWhitespace = leaveWhitespace; + this.leaveSymbols = leaveSymbols; } //Sets the keyword and inputString and encodes the message - public String encode(String keyword, String input){ - //TODO: - return null; + public String encode(String keyword, String input) throws InvalidCharacterException{ + reset(); + setKeyword(keyword); + setInputString(input); + return encode(); } //Sets the keyword and inputString and decodes the message - public String decode(String keyword, String input){ - //TODO: - return null; + public String decode(String keyword, String input) throws InvalidCharacterException{ + reset(); + setKeyword(keyword); + setInputString(input); + return decode(); } //Makes sure all variables are empty public void reset(){ - //TODO: + grid = new char[5][5]; } //Gets public char getReplaced(){ return replaced; } - public void setReplaced(char replaced){ - //TODO: + public void setReplaced(char replaced) throws InvalidCharacterException{ + if(!Character.isAlphabetic(replaced)){ + throw new InvalidCharacterException("The replaced characgter 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"); + } + + if((Character.isAlphabetic(replaced)) && (replaced != replacer)){ + this.replaced = Character.toUpperCase(replaced); + } } public char getReplacer(){ return replacer; } - public void setReplacer(char replacer){ - //TODO: + 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){ - //TODO: + 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; @@ -150,7 +281,13 @@ public class Playfair{ return outputString; } public String getGrid(){ - //TODO: - return null; + StringBuilder gridString = new StringBuilder(); + for(char[] row : grid){ + for(char col : row){ + gridString.append(col); + } + } + + return gridString.toString(); } }