From 9621b2178e7e84b017b78716da5c5a854b4afb42 Mon Sep 17 00:00:00 2001 From: Matthew Ellison Date: Mon, 21 Mar 2022 21:28:37 +0000 Subject: [PATCH] Created RailFence cipher --- .../polySubstitution/RailFence.java | 241 ++++++++++++++++++ 1 file changed, 241 insertions(+) create mode 100644 src/main/java/com/mattrixwv/CipherStreamJava/polySubstitution/RailFence.java diff --git a/src/main/java/com/mattrixwv/CipherStreamJava/polySubstitution/RailFence.java b/src/main/java/com/mattrixwv/CipherStreamJava/polySubstitution/RailFence.java new file mode 100644 index 0000000..7d803f2 --- /dev/null +++ b/src/main/java/com/mattrixwv/CipherStreamJava/polySubstitution/RailFence.java @@ -0,0 +1,241 @@ +//CipherStreamJava/src/main/java/com/mattrixwv/CipherStreamJava/polySubstitution/RailFence.java +//Mattrixwv +// Created: 03-21-22 +//Modified: 03-21-22 +package com.mattrixwv.CipherStreamJava.polySubstitution; + + +import java.math.BigDecimal; + +import com.mattrixwv.CipherStreamJava.exceptions.InvalidBaseException; +import com.mattrixwv.CipherStreamJava.exceptions.InvalidInputException; + + +public class RailFence{ + //Variables + private String inputString; + private String outputString; + private StringBuilder[] fence; + private boolean preserveCapitals; + private boolean preserveWhitespace; + private boolean preserveSymbols; + + 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"); + } + } + private void setNumRails(int numRails) throws InvalidBaseException{ + if(numRails <= 0){ + throw new InvalidBaseException(); + } + + fence = new StringBuilder[numRails]; + for(int cnt = 0;cnt < numRails;++cnt){ + fence[cnt] = new StringBuilder(); + } + } + private String getCleanInputString(){ + return inputString.replaceAll("[^a-zA-Z]", ""); + } + 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(); + } + private String getDecodedStringFromFence(){ + boolean down = true; + int rail = 0; + int outsideCol = 0; + int insideCol = -1; + StringBuilder output = new StringBuilder(); + while(true){ + 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)); + } + + if(down){ + ++rail; + } + else{ + --rail; + } + if(rail >= fence.length){ + down = false; + rail -= 2; + } + else if(rail < 0){ + down = true; + rail += 2; + } + } + + return output.toString(); + } + 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()); + } + private void decode(){ + 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()); + } + + 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; + } + fence[fence.length - 1].append(cleanInputString.substring(start)); + + 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; + } +}