From a142b679a974444009fd7d885f8f39fe3ef9c16f Mon Sep 17 00:00:00 2001 From: Mattrixwv Date: Mon, 26 Jul 2021 00:58:13 -0400 Subject: [PATCH] Added Vigenere cipher --- .../mattrixwv/CipherStreamJava/Vigenere.java | 135 ++++++++++++++++++ .../CipherStreamJava/TestVigenere.java | 65 +++++++++ 2 files changed, 200 insertions(+) create mode 100644 src/main/java/mattrixwv/CipherStreamJava/Vigenere.java create mode 100644 src/test/java/mattrixwv/CipherStreamJava/TestVigenere.java diff --git a/src/main/java/mattrixwv/CipherStreamJava/Vigenere.java b/src/main/java/mattrixwv/CipherStreamJava/Vigenere.java new file mode 100644 index 0000000..5e97064 --- /dev/null +++ b/src/main/java/mattrixwv/CipherStreamJava/Vigenere.java @@ -0,0 +1,135 @@ +//CipherStreamJava/src/main/java/mattrixwv/CipherStreamJava/Vigenere.java +//Matthew Ellison +// Created: 07-25-21 +//Modified: 07-25-21 +//This is the declaration of the Vigenere class +package mattrixwv.CipherStreamJava; + +import java.util.ArrayList; + +public class Vigenere{ + public static final String version = "1.0"; //The current library's version number + private String inputString; //This is the string that needs encoded/decoded + private String outputString; //This is the string that is output after encoding/decoding + private String keyword; //This is the keyword that is resposible for determining the offsets that you change each character by + private ArrayList offset; //Holds the offsets coputed from each character in the keyword + + //Uses keyword to calculate the offset for the Caesar cipher for each character + private void setOffset(){ + //Reserve the correct size to increase speed later + offset.ensureCapacity(keyword.length()); + + //Loop through every letter in keyword and get the offset from A + for(int cnt = 0;cnt < keyword.length();++cnt){ + char letter = keyword.charAt(cnt); + offset.add((letter - 'A') % 26); + } + } + //Sets inputString + private void setInputString(String input){ + //Convert all letters to uppercase + input = input.toUpperCase(); + //Remove all characters except capital letters + input = input.replaceAll("[^A-Z]", ""); + //Save the string + inputString = input; + } + //Sets keyword + private void setKeyword(String key) throws Exception{ + //Convert all letters to uppercase + key = key.toUpperCase(); + //Remove all characters except capital letters + key = key.replaceAll("[^A-Z]", ""); + //Save the string + keyword = key; + + //Make sure offset is empty before adding to it + offset.clear(); + setOffset(); + //If after all the eliminating of unusable characters the keyword is empty throw an exception + if(keyword == ""){ + throw new Exception("The keyword cannot be empty"); + } + } + //Encodes inputString and stores the result in outputString + private String encode(){ + StringBuilder output = new StringBuilder(); + + //Step through every character in the inputString and advance it the correct amount, according to offset + for(int cnt = 0;cnt < inputString.length();++cnt){ + char letter = (char)(inputString.charAt(cnt) + offset.get(cnt % offset.size())); + //Make sure the character is still a letter, if not, wrap around + if(letter < 'A'){ + letter += 26; + } + else if(letter > 'Z'){ + letter -= 26; + } + output.append(letter); + } + + outputString = output.toString(); + return outputString; + } + //Decodes inputString and stores the result in outputString + private String decode(){ + StringBuilder output = new StringBuilder(); + + //Step through every character in the inputString and advance it the correct amount, according to offset + for(int cnt = 0;cnt < inputString.length();++cnt){ + char letter = (char)(inputString.charAt(cnt) - offset.get(cnt % offset.size())); + if(letter < 'A'){ + letter += 26; + } + else if(letter > 'Z'){ + letter -= 26; + } + output.append(letter); + } + + outputString = output.toString(); + return outputString; + } + + + //Constructor + public Vigenere(){ + offset = new ArrayList(); + reset(); + } + //Returns the current inputString + public String getInputString(){ + return inputString; + } + //Returns the current outputString + public String getOutputString(){ + return outputString; + } + //Returns the current keyword + public String getKeyword(){ + return keyword; + } + //Returns the current offsets (Used mostly in bug fixing) + public ArrayList getOffsets(){ + return offset; + } + //Encodes input using key and returns the result + public String encode(String key, String input) throws Exception{ + reset(); + setKeyword(key); + setInputString(input); + return encode(); + } + //Decodes input using key and returns the result + public String decode(String key, String input) throws Exception{ + reset(); + setKeyword(key); + setInputString(input); + return decode(); + } + //Makes sure all of the variables are empty + public void reset(){ + inputString = outputString = keyword = ""; + offset.clear(); + } +} diff --git a/src/test/java/mattrixwv/CipherStreamJava/TestVigenere.java b/src/test/java/mattrixwv/CipherStreamJava/TestVigenere.java new file mode 100644 index 0000000..14ec239 --- /dev/null +++ b/src/test/java/mattrixwv/CipherStreamJava/TestVigenere.java @@ -0,0 +1,65 @@ +//CipherStreamJava/src/main/java/mattrixwv/CipherStreamJava/TestVigenere.java +//Matthew Ellison +// Created: 07-25-21 +//Modified: 07-25-21 +//These are the tests for the Vigenere class +package mattrixwv.CipherStreamJava; + + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + + +public class TestVigenere{ + @Test + public void testDecode() throws Exception{ + Vigenere cipher = new Vigenere(); + + //Test 1 + String input = "xzb"; + String keyword = "xyz"; + String correctOutput = "ABC"; + String output = cipher.decode(keyword, input); + assertEquals("Vigenere Decoding failed the first test", correctOutput, output); + + //Test 2 + input = "LXFOPVEFRNHR"; + keyword = "LEMON"; + correctOutput = "ATTACKATDAWN"; + output = cipher.decode(keyword, input); + assertEquals("Vigenere Decoding failed the second test", correctOutput, output); + + //Test 3 + input = "CSASTPKVSIQUTGQUCSASTPIUAQJB"; + keyword = "ABCD"; + correctOutput = "CRYPTOISSHORTFORCRYPTOGRAPHY"; + output = cipher.decode(keyword, input); + assertEquals("Vigenere Decoding failed the third test", correctOutput, output); + } + @Test + public void testEncode() throws Exception{ + Vigenere cipher = new Vigenere(); + + //Test 1 + String input = "abc"; + String keyword = "xyz"; + String correctOutput = "XZB"; + String output = cipher.encode(keyword, input); + assertEquals("Vigenere Encoding failed the first test", correctOutput, output); + + //Test 2 + input = "Attack at dawn"; + keyword = "Lemon"; + correctOutput = "LXFOPVEFRNHR"; + output = cipher.encode(keyword, input); + assertEquals("Vigenere Encoding failed the second test", correctOutput, output); + + //Test 3 + input = "'Crypto' is short for 'Cryptography'"; + keyword = "abcd"; + correctOutput = "CSASTPKVSIQUTGQUCSASTPIUAQJB"; + output = cipher.encode(keyword, input); + assertEquals("Vigenere Encoding failed the third test", correctOutput, output); + } +}