diff --git a/readme.md b/readme.md index a17a9ac..f9c4867 100644 --- a/readme.md +++ b/readme.md @@ -1,7 +1,10 @@ +# CAESAR CIPHER +author Serhii Lahuta -## Run the program +# ENGLISH +### Run the program -### Commands: +#### Commands: ``` -e Encrypt @@ -9,20 +12,49 @@ -bf Brute force ``` -### Arguments: +#### Arguments: ``` -k Key -f File path ``` -### Example: +#### Example: ``` -e -k 1 -f "/path/to/file.txt" - Encrypt file with key 1 -d -k 5 -f "/path/to/file [ENCRYPTED].txt" - Decrypt file with key 5 -bf -f "/path/to/file [ENCRYPTED].txt" - Brute force decrypt file ``` -### Argument could be in any order +#### Argument could be in any order +``` +-e -f "/path/to/file.txt" -k 1 +``` + +# УКРАЇНСЬКА +### Запуск програми + +#### Команди: + +``` +-e Зашифрувати +-d Розшифрувати +-bf Підбір коду +``` + +#### Аргуметни: +``` +-k Ключ +-f Шлях до файлу +``` + +#### Приклад: +``` +-e -k 1 -f "/path/to/file.txt" - Зашифрувати файл з ключем 1 +-d -k 5 -f "/path/to/file [ENCRYPTED].txt" - Розшифрувати файл з ключем 5 +-bf -f "/path/to/file [ENCRYPTED].txt" - Розшифрувати файл методом підбору ключа +``` + +#### Аргументи можуть бути у будь-якому порядку ``` -e -f "/path/to/file.txt" -k 1 ``` \ No newline at end of file diff --git a/src/main/java/ua/com/javarush/gnew/Main.java b/src/main/java/ua/com/javarush/gnew/Main.java index 5906828..a0a355d 100644 --- a/src/main/java/ua/com/javarush/gnew/Main.java +++ b/src/main/java/ua/com/javarush/gnew/Main.java @@ -1,32 +1,39 @@ package ua.com.javarush.gnew; -import ua.com.javarush.gnew.crypto.Cypher; +import ua.com.javarush.gnew.crypto.Cryptor; +import ua.com.javarush.gnew.crypto.KeyManager; import ua.com.javarush.gnew.file.FileManager; +import ua.com.javarush.gnew.file.NewFileNamePath; import ua.com.javarush.gnew.runner.ArgumentsParser; import ua.com.javarush.gnew.runner.Command; import ua.com.javarush.gnew.runner.RunOptions; -import java.nio.file.Path; - public class Main { public static void main(String[] args) { - Cypher cypher = new Cypher(); FileManager fileManager = new FileManager(); ArgumentsParser argumentsParser = new ArgumentsParser(); RunOptions runOptions = argumentsParser.parse(args); + KeyManager keyManager = new KeyManager(); try { - if (runOptions.getCommand() == Command.ENCRYPT) { - String content = fileManager.read(runOptions.getFilePath()); - String encryptedContent = cypher.encrypt(content, runOptions.getKey()); - String fileName = runOptions.getFilePath().getFileName().toString(); - String newFileName = fileName.substring(0, fileName.length() - 4) + " [ENCRYPTED].txt"; - - Path newFilePath = runOptions.getFilePath().resolveSibling(newFileName); - fileManager.write(newFilePath, encryptedContent); + String content = fileManager.read(runOptions.getFilePath()); + Cryptor cryptor; + if(runOptions.getCommand() == Command.ENCRYPT || runOptions.getCommand() == Command.DECRYPT){ + int key = keyManager.getKey(runOptions); + cryptor = new Cryptor(content, key); + String cryptoContent = cryptor.cypher(); + NewFileNamePath path = new NewFileNamePath(); + fileManager.write(path.newPath(runOptions) , cryptoContent); + } else if (runOptions.getCommand() == Command.BRUTEFORCE) { + cryptor = new Cryptor(content, keyManager.keySelection(runOptions)); + String cryptoContent = cryptor.cypher(); + NewFileNamePath path = new NewFileNamePath(); + fileManager.write(path.newPath(runOptions) , cryptoContent); } } catch (Exception e) { System.out.println(e.getMessage()); } + + } } \ No newline at end of file diff --git a/src/main/java/ua/com/javarush/gnew/crypto/ConstantsForCryptor.java b/src/main/java/ua/com/javarush/gnew/crypto/ConstantsForCryptor.java new file mode 100644 index 0000000..9f3eeb1 --- /dev/null +++ b/src/main/java/ua/com/javarush/gnew/crypto/ConstantsForCryptor.java @@ -0,0 +1,22 @@ +package ua.com.javarush.gnew.crypto; + +import java.util.ArrayList; +import java.util.Arrays; + +public enum ConstantsForCryptor { + ALPHABET(new ArrayList<>(Arrays.asList('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', + 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z'))), + PUNCTUATION (new ArrayList<>(Arrays.asList(' ', ',', '!', '?', ':', ';', '-', + '(', ')', '[', ']', '{', '}','#', '.', '@', '*', '+', '=', '_', '&', + '\\', '/', '₴', '~', '`'))); + + private final ArrayList CHARS_ARRAY_CONSTANT; + + ConstantsForCryptor(ArrayList CHARS_ARRAY_CONSTANS) { + this.CHARS_ARRAY_CONSTANT = CHARS_ARRAY_CONSTANS; + } + public ArrayList getCharsArrayConstant() { + return this.CHARS_ARRAY_CONSTANT; + } +} diff --git a/src/main/java/ua/com/javarush/gnew/crypto/Cryptor.java b/src/main/java/ua/com/javarush/gnew/crypto/Cryptor.java new file mode 100644 index 0000000..8c69546 --- /dev/null +++ b/src/main/java/ua/com/javarush/gnew/crypto/Cryptor.java @@ -0,0 +1,63 @@ +package ua.com.javarush.gnew.crypto; + + +import java.util.HashMap; +import java.util.Map; + +public class Cryptor { + + private String input ; + private int key; + + public Cryptor(String input, int key){ + this.input =input ; + this.key = key; + } + + + public Cryptor(String input){ + this.input = input; + } + + public String cypher() { + + Rotator rotator = new Rotator(); + + char[] charsArray = input.toCharArray(); + + StringBuilder sb = new StringBuilder(); + SymbolsBelonging symBel = new SymbolsBelonging(); + for(char symbol : charsArray) { + if(ConstantsForCryptor.ALPHABET.getCharsArrayConstant().contains(Character.toUpperCase(symbol))){ + sb.append(symBel.symbolsBelongingABC(symbol, rotator.rotateAlphabet(key))); + }else if (ConstantsForCryptor.PUNCTUATION.getCharsArrayConstant().contains(symbol)) { + sb.append(symBel.symbolsBelongingPUNCTUATION(symbol, rotator.rotatePunctuation(key))); + }else { + sb.append(symbol); + } + } + return sb.toString(); + } + + public char MostFrequentChar(){ + + char[] charsArray = input.toCharArray(); + + Map frequencyMap = new HashMap<>(); + for(char symbol : charsArray){ + frequencyMap.put(symbol, frequencyMap.getOrDefault(symbol, 0) + 1); + } + + char mostFrequentChar = '\0'; + int maxFrequency = 0; + + for (Map.Entry entry : frequencyMap.entrySet()) { + if (entry.getValue() > maxFrequency) { + mostFrequentChar = entry.getKey(); + maxFrequency = entry.getValue(); + } + } + return mostFrequentChar; + } + +} diff --git a/src/main/java/ua/com/javarush/gnew/crypto/Cypher.java b/src/main/java/ua/com/javarush/gnew/crypto/Cypher.java deleted file mode 100644 index 2b01247..0000000 --- a/src/main/java/ua/com/javarush/gnew/crypto/Cypher.java +++ /dev/null @@ -1,33 +0,0 @@ -package ua.com.javarush.gnew.crypto; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; - -public class Cypher { - private final ArrayList originalAlphabet = new ArrayList<>(Arrays.asList('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z')); - - - public String encrypt(String input, int key) { - key = Math.negateExact(key); - - ArrayList rotatedAlphabet = new ArrayList<>(originalAlphabet); - Collections.rotate(rotatedAlphabet, key); - char[] charArray = input.toCharArray(); - - StringBuilder builder = new StringBuilder(); - for (char symbol : charArray) { - builder.append(processSymbol(symbol, rotatedAlphabet)); - } - return builder.toString(); - } - - private Character processSymbol(char symbol, ArrayList rotatedAlphabet) { - if (!originalAlphabet.contains(symbol)) { - return symbol; - } - int index = originalAlphabet.indexOf(symbol); - - return rotatedAlphabet.get(index); - } -} diff --git a/src/main/java/ua/com/javarush/gnew/crypto/KeyManager.java b/src/main/java/ua/com/javarush/gnew/crypto/KeyManager.java new file mode 100644 index 0000000..033ab2a --- /dev/null +++ b/src/main/java/ua/com/javarush/gnew/crypto/KeyManager.java @@ -0,0 +1,29 @@ +package ua.com.javarush.gnew.crypto; + +import ua.com.javarush.gnew.file.FileManager; +import ua.com.javarush.gnew.runner.RunOptions; +import ua.com.javarush.gnew.runner.Command; + + +public class KeyManager { + + public int getKey(RunOptions runOptions){ + if (runOptions.getCommand() == Command.ENCRYPT) { + return (runOptions.getKey() % 26) * -1; + }else if (runOptions.getCommand() == Command.DECRYPT) { + return runOptions.getKey() % 26; + } else if (runOptions.getCommand() == Command.BRUTEFORCE) { + return keySelection(runOptions); + }else { + return 0; + } + } + + public int keySelection(RunOptions runOptions) { + FileManager fileManager = new FileManager(); + String input =fileManager.read(runOptions.getFilePath()); + Cryptor cryptor = new Cryptor(input); + return ConstantsForCryptor.PUNCTUATION.getCharsArrayConstant().indexOf(cryptor.MostFrequentChar()); + } + +} diff --git a/src/main/java/ua/com/javarush/gnew/crypto/Rotator.java b/src/main/java/ua/com/javarush/gnew/crypto/Rotator.java new file mode 100644 index 0000000..c8db628 --- /dev/null +++ b/src/main/java/ua/com/javarush/gnew/crypto/Rotator.java @@ -0,0 +1,22 @@ +package ua.com.javarush.gnew.crypto; + +import java.util.ArrayList; +import java.util.Collections; + +public class Rotator { + + protected ArrayList rotateAlphabet(int key){ + + + ArrayList rotateAlphabet = new ArrayList<>(ConstantsForCryptor.ALPHABET.getCharsArrayConstant()); + Collections.rotate(rotateAlphabet, key); + return rotateAlphabet; + } + + protected ArrayList rotatePunctuation(Integer key){ + ArrayList rotatePunctuation = new ArrayList<>(ConstantsForCryptor.PUNCTUATION.getCharsArrayConstant()); + Collections.rotate(rotatePunctuation, key); + return rotatePunctuation; + } + +} diff --git a/src/main/java/ua/com/javarush/gnew/crypto/SymbolsBelonging.java b/src/main/java/ua/com/javarush/gnew/crypto/SymbolsBelonging.java new file mode 100644 index 0000000..0a11b23 --- /dev/null +++ b/src/main/java/ua/com/javarush/gnew/crypto/SymbolsBelonging.java @@ -0,0 +1,18 @@ +package ua.com.javarush.gnew.crypto; + +import java.util.ArrayList; + +public class SymbolsBelonging { + protected Character symbolsBelongingABC(char symbol, ArrayList rotateAlphabet) { + int index = ConstantsForCryptor.ALPHABET.getCharsArrayConstant().indexOf(Character.toUpperCase(symbol)); + if(Character.isLowerCase(symbol)){ + return Character.toLowerCase(rotateAlphabet.get(index)); + } + return rotateAlphabet.get(index); + } + + protected Character symbolsBelongingPUNCTUATION(char symbol, ArrayList rotatePunctuation){ + int index = ConstantsForCryptor.PUNCTUATION.getCharsArrayConstant().indexOf(symbol); + return rotatePunctuation.get(index); + } +} diff --git a/src/main/java/ua/com/javarush/gnew/file/FileManager.java b/src/main/java/ua/com/javarush/gnew/file/FileManager.java index d60744c..fb8a42c 100644 --- a/src/main/java/ua/com/javarush/gnew/file/FileManager.java +++ b/src/main/java/ua/com/javarush/gnew/file/FileManager.java @@ -5,11 +5,21 @@ import java.nio.file.Path; public class FileManager { - public String read(Path filePath) throws IOException { - return Files.readString(filePath); + public String read(Path filePath) { + String content = null; + try { + content = Files.readString(filePath); + } catch (IOException e) { + System.out.println("Ошибка при чтении файла: " + e.getMessage()); + } + return content; } - public void write(Path filePath, String content) throws IOException { - Files.writeString(filePath, content); + public void write(Path filePath, String content) { + try { + Files.writeString(filePath, content); + } catch (IOException e) { + System.out.println("Ошибка при записи в файл: " + e.getMessage()); + } } } diff --git a/src/main/java/ua/com/javarush/gnew/file/FileNameTag.java b/src/main/java/ua/com/javarush/gnew/file/FileNameTag.java new file mode 100644 index 0000000..ccd8c07 --- /dev/null +++ b/src/main/java/ua/com/javarush/gnew/file/FileNameTag.java @@ -0,0 +1,39 @@ +package ua.com.javarush.gnew.file; + +import ua.com.javarush.gnew.crypto.KeyManager; +import ua.com.javarush.gnew.runner.Command; +import ua.com.javarush.gnew.runner.RunOptions; + +public class FileNameTag { + + protected String fileNameNotExtension(RunOptions runOptions){ + String fileName = runOptions.getFilePath().getFileName().toString(); + int lastDotIndex = fileName.lastIndexOf('.'); + return fileName.substring(0, lastDotIndex); + } + + protected String nameTag(RunOptions runOptions){ + StringBuilder tag = new StringBuilder(); + if(runOptions.getCommand() == Command.ENCRYPT){ + tag.append("[ENCRYPTED]"); + } else if (runOptions.getCommand() == Command.DECRYPT) { + tag.append("[DECRYPTED]"); + } else if (runOptions.getCommand() == Command.BRUTEFORCE) { + tag.append("[DECRYPTED] [WITH KEY "); + KeyManager keyManager = new KeyManager(); + tag.append(keyManager.getKey(runOptions)); + tag.append("]"); + } + return tag.toString(); + } + + protected String fileNameTag(RunOptions runOptions){ + StringBuilder sb = new StringBuilder(); + sb.append(fileNameNotExtension(runOptions)); + sb.append(nameTag(runOptions)); + return sb.toString() + ".txt"; + + } + + +} diff --git a/src/main/java/ua/com/javarush/gnew/file/NewFileNamePath.java b/src/main/java/ua/com/javarush/gnew/file/NewFileNamePath.java new file mode 100644 index 0000000..2b38f31 --- /dev/null +++ b/src/main/java/ua/com/javarush/gnew/file/NewFileNamePath.java @@ -0,0 +1,12 @@ +package ua.com.javarush.gnew.file; + +import ua.com.javarush.gnew.runner.RunOptions; +import java.nio.file.Path; + +public class NewFileNamePath { + + public Path newPath(RunOptions runOptions) { + FileNameTag tag = new FileNameTag(); + return Path.of(tag.fileNameTag(runOptions)); + } +} diff --git a/src/main/java/ua/com/javarush/gnew/language/Language.java b/src/main/java/ua/com/javarush/gnew/language/Language.java deleted file mode 100644 index 067dd2f..0000000 --- a/src/main/java/ua/com/javarush/gnew/language/Language.java +++ /dev/null @@ -1,12 +0,0 @@ -package ua.com.javarush.gnew.language; - -import java.util.ArrayList; - -public abstract class Language { - - private final ArrayList alphabet; - - public Language(ArrayList alphabet) { - this.alphabet = alphabet; - } -} diff --git a/src/main/java/ua/com/javarush/gnew/runner/ArgumentsParser.java b/src/main/java/ua/com/javarush/gnew/runner/ArgumentsParser.java index eb42462..678d1a4 100644 --- a/src/main/java/ua/com/javarush/gnew/runner/ArgumentsParser.java +++ b/src/main/java/ua/com/javarush/gnew/runner/ArgumentsParser.java @@ -48,7 +48,7 @@ public RunOptions parse(String[] args) { throw new IllegalArgumentException("Command (-e, -d, or -bf) is required"); } - if (key == null) { + if (key == null && command == Command.ENCRYPT || command == Command.DECRYPT) { throw new IllegalArgumentException("Key is required for encrypt or decrypt mode"); } diff --git a/src/main/java/ua/com/javarush/gnew/runner/RunOptions.java b/src/main/java/ua/com/javarush/gnew/runner/RunOptions.java index 45e700b..13891ed 100644 --- a/src/main/java/ua/com/javarush/gnew/runner/RunOptions.java +++ b/src/main/java/ua/com/javarush/gnew/runner/RunOptions.java @@ -7,7 +7,7 @@ public class RunOptions { * Command to be executed. * -e option for encryption. * -d option for decryption. - * -b option for brute force. + * -bf option for brute force. */ private final Command command; @@ -27,7 +27,12 @@ public class RunOptions { public RunOptions(Command command, Integer key, Path filePath) { this.command = command; - this.key = key; + if( key != null){ + this.key = key; + }else { + this.key = 0; + } + this.filePath = filePath; }