From 75c63f2daa86839367ec8281583e154b383a2990 Mon Sep 17 00:00:00 2001 From: maxog Date: Tue, 5 Nov 2024 16:34:11 +0700 Subject: [PATCH 01/18] created a file service class methods --- src/FileService.java | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/FileService.java b/src/FileService.java index d2f7112..f6bcd97 100644 --- a/src/FileService.java +++ b/src/FileService.java @@ -1,2 +1,37 @@ +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + public class FileService { + private FileService() { + throw new IllegalStateException("Utility class"); + } + + //Зчитуємо вміст файлу у рядок + public static String readFile(String filePath) throws IOException { + Path path = Path.of(filePath); + return Files.readString(path); + } + + //Записуємо новий вміст у файл за вказаним шляхом + private static void writeFile(String filePath, String content) throws IOException { + Path path = Path.of(filePath); + Files.writeString(path, content); + } + + //Записуємо наданий вміст у файл в одній і тій самій директорії, що й оригінальний файл, але до його імені додаємо суфікс + public static void writeWithSuffix(String originalFilePath, String content, String suffix) throws IOException { + String newFilePath = generateFileNameWithSuffix(originalFilePath, suffix); + writeFile(newFilePath, content); + } + + //Додаємо суфікс до імені файлу + private static String generateFileNameWithSuffix(String originalFilePath, String suffix) { + int dotIndex = originalFilePath.lastIndexOf("."); + if (dotIndex == -1) { + return originalFilePath + suffix; + } else { + return originalFilePath.substring(0, dotIndex) + suffix + originalFilePath.substring(dotIndex); + } + } } From d7460c6100edc89e1a9a0baa0ff3d7f071761454 Mon Sep 17 00:00:00 2001 From: maxog Date: Tue, 5 Nov 2024 17:23:26 +0700 Subject: [PATCH 02/18] initial version of caesar cipher class --- src/CaesarCipher.java | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/CaesarCipher.java b/src/CaesarCipher.java index d1c9a2d..42fc543 100644 --- a/src/CaesarCipher.java +++ b/src/CaesarCipher.java @@ -1,2 +1,34 @@ public class CaesarCipher { + private CaesarCipher() { + throw new IllegalStateException("Utility class"); + } + + private static final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.,«»\"':!? "; + private static final int ALPHABET_SIZE = ALPHABET.length(); + + public static String encrypt(String text, int key) { + return shiftText(text, key); + } + + public static String decrypt(String text, int key) { + return shiftText(text, -key); + } + + //Метод для зсуву символів рядку по алфавіту за визначеним значенням + private static String shiftText(String text, int shift) { + StringBuilder result = new StringBuilder(); + + for (char character : text.toCharArray()) { + int index = ALPHABET.indexOf(character); + + if (index != -1) { //Якщо символ є у вказаному алфавіті - зсуваємо + int shiftedIndex = (index + shift + ALPHABET_SIZE) % ALPHABET_SIZE; + result.append(ALPHABET.charAt(shiftedIndex)); + } else { + result.append(character); + } + } + + return result.toString(); + } } From 35f02924297bb53e2e9a1c7c1032e675f26910d1 Mon Sep 17 00:00:00 2001 From: maxog Date: Tue, 5 Nov 2024 17:41:29 +0700 Subject: [PATCH 03/18] added brute force function --- src/CaesarCipher.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/CaesarCipher.java b/src/CaesarCipher.java index 42fc543..dc327ca 100644 --- a/src/CaesarCipher.java +++ b/src/CaesarCipher.java @@ -1,3 +1,6 @@ +import java.util.HashMap; +import java.util.Map; + public class CaesarCipher { private CaesarCipher() { throw new IllegalStateException("Utility class"); @@ -31,4 +34,15 @@ private static String shiftText(String text, int shift) { return result.toString(); } + + public static Map bruteForceDecrypt(String text) { + Map possibleDecryptions = new HashMap<>(); + + for (int key = 1; key < ALPHABET_SIZE; key++) { + String decryptedText = decrypt(text, key); + possibleDecryptions.put(key, decryptedText); + } + + return possibleDecryptions; + } } From 0b35aa7ce0ad148ed949fe0db2806d3fc7960cec Mon Sep 17 00:00:00 2001 From: maxog Date: Tue, 5 Nov 2024 17:55:48 +0700 Subject: [PATCH 04/18] added ukrainian alphabet functionality --- src/CaesarCipher.java | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/src/CaesarCipher.java b/src/CaesarCipher.java index dc327ca..5af5647 100644 --- a/src/CaesarCipher.java +++ b/src/CaesarCipher.java @@ -6,14 +6,19 @@ private CaesarCipher() { throw new IllegalStateException("Utility class"); } - private static final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.,«»\"':!? "; - private static final int ALPHABET_SIZE = ALPHABET.length(); + private static final String ENGLISH_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.,«»\"':!? "; + private static final String UKRAINIAN_ALPHABET = "АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯабвгґдеєжзиіїйклмнопрстуфхцчшщьюя.,«»\"':!? "; + + private static String currentAlphabet = ENGLISH_ALPHABET; + private static int alphabetSize = currentAlphabet.length(); public static String encrypt(String text, int key) { + selectAlphabet(text); return shiftText(text, key); } public static String decrypt(String text, int key) { + selectAlphabet(text); return shiftText(text, -key); } @@ -22,12 +27,12 @@ private static String shiftText(String text, int shift) { StringBuilder result = new StringBuilder(); for (char character : text.toCharArray()) { - int index = ALPHABET.indexOf(character); + int index = currentAlphabet.indexOf(character); - if (index != -1) { //Якщо символ є у вказаному алфавіті - зсуваємо - int shiftedIndex = (index + shift + ALPHABET_SIZE) % ALPHABET_SIZE; - result.append(ALPHABET.charAt(shiftedIndex)); - } else { + if (index != -1) { // Character is in the selected alphabet + int shiftedIndex = (index + shift + alphabetSize) % alphabetSize; + result.append(currentAlphabet.charAt(shiftedIndex)); + } else { // Character is not in the alphabet, add it as-is result.append(character); } } @@ -35,10 +40,24 @@ private static String shiftText(String text, int shift) { return result.toString(); } + private static void selectAlphabet(String text) { + //Перевіряємо чи символ належить українському алфавіту + for (char character : text.toCharArray()) { + if (UKRAINIAN_ALPHABET.indexOf(character) != -1 && Character.isLetter(character)) { + currentAlphabet = UKRAINIAN_ALPHABET; + alphabetSize = currentAlphabet.length(); + return; + } + } + currentAlphabet = ENGLISH_ALPHABET; + alphabetSize = currentAlphabet.length(); + } + public static Map bruteForceDecrypt(String text) { + selectAlphabet(text); Map possibleDecryptions = new HashMap<>(); - for (int key = 1; key < ALPHABET_SIZE; key++) { + for (int key = 1; key < alphabetSize; key++) { String decryptedText = decrypt(text, key); possibleDecryptions.put(key, decryptedText); } From 11e081a3e19235ed324aeb7c4f23fc8ec0aa5ced Mon Sep 17 00:00:00 2001 From: maxog Date: Tue, 5 Nov 2024 20:13:37 +0700 Subject: [PATCH 05/18] initial work on runner class + a few fixes to file service --- .idea/uiDesigner.xml | 124 +++++++++++++++++++++++++++++++++++++++++++ src/Command.java | 6 +++ src/FileService.java | 27 +++++----- src/Main.java | 8 +++ src/Runner.java | 63 ++++++++++++++++++++++ 5 files changed, 216 insertions(+), 12 deletions(-) create mode 100644 .idea/uiDesigner.xml create mode 100644 src/Command.java diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..2b63946 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Command.java b/src/Command.java new file mode 100644 index 0000000..8e4db14 --- /dev/null +++ b/src/Command.java @@ -0,0 +1,6 @@ +public enum Command { + ENCRYPT, + DECRYPT, + BRUTE_FORCE; + +} diff --git a/src/FileService.java b/src/FileService.java index f6bcd97..3a66b6e 100644 --- a/src/FileService.java +++ b/src/FileService.java @@ -8,30 +8,33 @@ private FileService() { } //Зчитуємо вміст файлу у рядок - public static String readFile(String filePath) throws IOException { - Path path = Path.of(filePath); - return Files.readString(path); + public static String readFile(Path filePath) throws IOException { + return Files.readString(filePath); } //Записуємо новий вміст у файл за вказаним шляхом - private static void writeFile(String filePath, String content) throws IOException { - Path path = Path.of(filePath); - Files.writeString(path, content); + private static void writeFile(Path filePath, String content) throws IOException { + Files.writeString(filePath, content); } //Записуємо наданий вміст у файл в одній і тій самій директорії, що й оригінальний файл, але до його імені додаємо суфікс - public static void writeWithSuffix(String originalFilePath, String content, String suffix) throws IOException { - String newFilePath = generateFileNameWithSuffix(originalFilePath, suffix); + public static void writeWithSuffix(Path originalFilePath, String content, String suffix) throws IOException { + Path newFilePath = generateFileNameWithSuffix(originalFilePath, suffix); writeFile(newFilePath, content); } //Додаємо суфікс до імені файлу - private static String generateFileNameWithSuffix(String originalFilePath, String suffix) { - int dotIndex = originalFilePath.lastIndexOf("."); + private static Path generateFileNameWithSuffix(Path originalFilePath, String suffix) { + String fileName = originalFilePath.getFileName().toString(); + int dotIndex = fileName.lastIndexOf("."); + String newFileName; + if (dotIndex == -1) { - return originalFilePath + suffix; + newFileName = fileName + suffix; } else { - return originalFilePath.substring(0, dotIndex) + suffix + originalFilePath.substring(dotIndex); + newFileName = fileName.substring(0, dotIndex) + suffix + fileName.substring(dotIndex); } + + return originalFilePath.getParent().resolve(newFileName); } } diff --git a/src/Main.java b/src/Main.java index 881c4a5..cd96a39 100644 --- a/src/Main.java +++ b/src/Main.java @@ -1,7 +1,15 @@ + //TIP To Run code, press or // click the icon in the gutter. public class Main { public static void main(String[] args) { + if (args.length < 2) { + System.err.println("Помилка: Недостатня кількість аргументів! " + + "Використання: java -jar myApp.jar "); + return; + } + new Runner().run(args); } + } \ No newline at end of file diff --git a/src/Runner.java b/src/Runner.java index 7b1c652..81865e9 100644 --- a/src/Runner.java +++ b/src/Runner.java @@ -1,2 +1,65 @@ +import java.nio.file.Files; +import java.nio.file.Path; + public class Runner { + public void run(final String[] args){ + final Command command=checkCommand(args); + final Path filePath=checkFile(args); + final Integer key=checkKey(args, command); + if (command==null || filePath==null || key==null){ + return; + } + + switch (command) { + case ENCRYPT -> encryptFile(filePath, key); + case DECRYPT -> decryptFile(filePath, key); + case BRUTE_FORCE -> bruteForce(filePath); + } + } + + private void encryptFile(Path filePath, int key){ + + } + private void decryptFile(Path filePath, int key){ + + } + private void bruteForce(Path filePath){ + + } + + private Command checkCommand(final String [] args){ + Command command=null; + try { + command = Command.valueOf(args[0].toUpperCase()); + } catch (IllegalArgumentException e) { + System.err.println("Помилка: Невірна команда! Доступні команди: ENCRYPT, DECRYPT, BRUTE_FORCE."); + } + return command; + } + + private Path checkFile(final String [] args){ + Path filePath=Path.of(args[1]); + if (!Files.exists(filePath)) { + System.err.println("Помилка: Вказаного файлу не існує!"); + return null; + } + return filePath; + } + + private Integer checkKey(final String [] args,Command command){ + Integer key=null; + + if (command == Command.ENCRYPT || command == Command.DECRYPT) { + if (args.length < 3) { + System.err.println("Помилка: Аргумент обов'язковий!"); + return key; + } + try { + key = Integer.parseInt(args[2]); + } catch (NumberFormatException e) { + System.err.println("Помилка: Ключ має бути числом!"); + } + } + return key; + } } From 592e0fced95812a86dc91f8e8cba1b419d3ec157 Mon Sep 17 00:00:00 2001 From: maxog Date: Tue, 5 Nov 2024 20:33:48 +0700 Subject: [PATCH 06/18] realised methods of starting a program for decryption or encryption --- src/Runner.java | 68 ++++++++++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 29 deletions(-) diff --git a/src/Runner.java b/src/Runner.java index 81865e9..bfd2f57 100644 --- a/src/Runner.java +++ b/src/Runner.java @@ -1,65 +1,75 @@ +import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; public class Runner { public void run(final String[] args){ - final Command command=checkCommand(args); - final Path filePath=checkFile(args); - final Integer key=checkKey(args, command); - if (command==null || filePath==null || key==null){ - return; - } + try { + final Command command=checkCommand(args); + final Path filePath=checkFile(args); + final int key=checkKey(args, command); - switch (command) { - case ENCRYPT -> encryptFile(filePath, key); - case DECRYPT -> decryptFile(filePath, key); - case BRUTE_FORCE -> bruteForce(filePath); + switch (command) { + case ENCRYPT -> encryptFile(filePath, key); + case DECRYPT -> decryptFile(filePath, key); + case BRUTE_FORCE -> bruteForce(filePath); + } + } catch (RuntimeException e){ + System.err.println(e.getMessage()); } } private void encryptFile(Path filePath, int key){ - + try { + String content = FileService.readFile(filePath); + String encryptedContent = CaesarCipher.encrypt(content, key); + FileService.writeWithSuffix(filePath, encryptedContent, "[ENCRYPTED]"); + System.out.println("Файл зашифровано успішно!"); + } catch (IOException e) { + throw new RuntimeException("Помилка при шифруванні файлу: " + e.getMessage(), e); + } } private void decryptFile(Path filePath, int key){ - + try { + String content = FileService.readFile(filePath); + String decryptedContent = CaesarCipher.decrypt(content, key); + FileService.writeWithSuffix(filePath, decryptedContent, "[DECRYPTED]"); + System.out.println("Файл дешифровано успішно!"); + } catch (IOException e) { + throw new RuntimeException("Помилка при дешифрації файлу: " + e.getMessage(), e); + } } private void bruteForce(Path filePath){ } - private Command checkCommand(final String [] args){ - Command command=null; + private Command checkCommand(final String[] args) { try { - command = Command.valueOf(args[0].toUpperCase()); + return Command.valueOf(args[0].toUpperCase()); } catch (IllegalArgumentException e) { - System.err.println("Помилка: Невірна команда! Доступні команди: ENCRYPT, DECRYPT, BRUTE_FORCE."); + throw new RuntimeException("Помилка: Невірна команда! Доступні команди: ENCRYPT, DECRYPT, BRUTE_FORCE."); } - return command; } - private Path checkFile(final String [] args){ - Path filePath=Path.of(args[1]); + private Path checkFile(final String[] args) { + Path filePath = Path.of(args[1]); if (!Files.exists(filePath)) { - System.err.println("Помилка: Вказаного файлу не існує!"); - return null; + throw new RuntimeException("Помилка: Вказаного файлу не існує!"); } return filePath; } - private Integer checkKey(final String [] args,Command command){ - Integer key=null; - + private int checkKey(final String[] args, Command command) { if (command == Command.ENCRYPT || command == Command.DECRYPT) { if (args.length < 3) { - System.err.println("Помилка: Аргумент обов'язковий!"); - return key; + throw new RuntimeException("Помилка: Аргумент обов'язковий!"); } try { - key = Integer.parseInt(args[2]); + return Integer.parseInt(args[2]); } catch (NumberFormatException e) { - System.err.println("Помилка: Ключ має бути числом!"); + throw new RuntimeException("Помилка: Ключ має бути числом!"); } } - return key; + return -1; } } From 1c90c968033e3c140aa65647c1b367ffda845a2b Mon Sep 17 00:00:00 2001 From: maxog Date: Wed, 6 Nov 2024 00:43:43 +0700 Subject: [PATCH 07/18] runner and file service improvements --- src/FileService.java | 7 ++++++- src/Runner.java | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/FileService.java b/src/FileService.java index 3a66b6e..e0f80c9 100644 --- a/src/FileService.java +++ b/src/FileService.java @@ -7,6 +7,9 @@ private FileService() { throw new IllegalStateException("Utility class"); } + private static final String ENCRYPTED="[ENCRYPTED]"; + private static final String DECRYPTED="[DECRYPTED]"; + //Зчитуємо вміст файлу у рядок public static String readFile(Path filePath) throws IOException { return Files.readString(filePath); @@ -25,7 +28,9 @@ public static void writeWithSuffix(Path originalFilePath, String content, String //Додаємо суфікс до імені файлу private static Path generateFileNameWithSuffix(Path originalFilePath, String suffix) { - String fileName = originalFilePath.getFileName().toString(); + String fileName = originalFilePath.getFileName().toString() + .replace(ENCRYPTED, "") + .replace(DECRYPTED, ""); int dotIndex = fileName.lastIndexOf("."); String newFileName; diff --git a/src/Runner.java b/src/Runner.java index bfd2f57..aedae04 100644 --- a/src/Runner.java +++ b/src/Runner.java @@ -12,7 +12,7 @@ public void run(final String[] args){ switch (command) { case ENCRYPT -> encryptFile(filePath, key); case DECRYPT -> decryptFile(filePath, key); - case BRUTE_FORCE -> bruteForce(filePath); + case BRUTE_FORCE -> bruteForceFile(filePath); } } catch (RuntimeException e){ System.err.println(e.getMessage()); @@ -39,7 +39,7 @@ private void decryptFile(Path filePath, int key){ throw new RuntimeException("Помилка при дешифрації файлу: " + e.getMessage(), e); } } - private void bruteForce(Path filePath){ + private void bruteForceFile(Path filePath){ } From 80576ce7655bde5142b13bb14b779f0066d4dbf9 Mon Sep 17 00:00:00 2001 From: maxog Date: Wed, 6 Nov 2024 01:47:39 +0700 Subject: [PATCH 08/18] implemented cli interface + general improvements --- src/CLI.java | 68 +++++++++++++++++++++++++++++++++++++++++++++++++ src/Main.java | 8 +++--- src/Runner.java | 22 +++++++++++----- 3 files changed, 86 insertions(+), 12 deletions(-) diff --git a/src/CLI.java b/src/CLI.java index b75a17b..945dd80 100644 --- a/src/CLI.java +++ b/src/CLI.java @@ -1,2 +1,70 @@ +import java.nio.file.Path; +import java.util.Scanner; + public class CLI { + private final Scanner scanner; + private final Runner runner; + + public CLI() { + this.scanner = new Scanner(System.in); + this.runner = new Runner(); + } + + public void start() { + Command command = promptCommand(); + Path filePath = promptFilePath(); + String key = ""; + + if (command != Command.BRUTE_FORCE){ + key=promptKey(command).toString(); + } + + new Runner().run(new String[]{command.name(), filePath.toString(), key}); + } + + private Command promptCommand() { + Command command = null; + while (command == null) { + System.out.println("Введіть команду:"); + String input = scanner.nextLine().trim(); + + try{ + command = runner.checkCommand(input); + } catch (RuntimeException e) { + System.err.println(e.getMessage()); + } + } + return command; + } + + private Path promptFilePath() { + Path filePath = null; + while (filePath == null) { + System.out.println("Введіть повний шлях до файлу:"); + String pathInput = scanner.nextLine(); + + try { + filePath = runner.checkFile(pathInput); + } catch (RuntimeException e) { + System.err.println(e.getMessage()); + } + } + return filePath; + } + + private Integer promptKey(Command command) { + Integer key = null; + while (key == null) { + System.out.println("Введіть ключ (ціле число):"); + String keyInput = scanner.nextLine().trim(); + + try { + key = runner.checkKey(new String[]{"", "", keyInput}, command); + } catch (RuntimeException e) { + System.err.println(e.getMessage()); + } + + } + return key; + } } diff --git a/src/Main.java b/src/Main.java index cd96a39..6276437 100644 --- a/src/Main.java +++ b/src/Main.java @@ -4,12 +4,10 @@ public class Main { public static void main(String[] args) { if (args.length < 2) { - System.err.println("Помилка: Недостатня кількість аргументів! " + - "Використання: java -jar myApp.jar "); - return; + new CLI().start(); + }else { + new Runner().run(args); } - - new Runner().run(args); } } \ No newline at end of file diff --git a/src/Runner.java b/src/Runner.java index aedae04..20f3394 100644 --- a/src/Runner.java +++ b/src/Runner.java @@ -3,10 +3,11 @@ import java.nio.file.Path; public class Runner { + public void run(final String[] args){ try { - final Command command=checkCommand(args); - final Path filePath=checkFile(args); + final Command command=checkCommand(args[0]); + final Path filePath=checkFile(args[1]); final int key=checkKey(args, command); switch (command) { @@ -43,23 +44,30 @@ private void bruteForceFile(Path filePath){ } - private Command checkCommand(final String[] args) { + Command checkCommand(String commandString) { try { - return Command.valueOf(args[0].toUpperCase()); + return Command.valueOf(commandString.toUpperCase()); } catch (IllegalArgumentException e) { throw new RuntimeException("Помилка: Невірна команда! Доступні команди: ENCRYPT, DECRYPT, BRUTE_FORCE."); } } - private Path checkFile(final String[] args) { - Path filePath = Path.of(args[1]); + Path checkFile(String filePathString) { + Path filePath = sanitizePath(filePathString); if (!Files.exists(filePath)) { throw new RuntimeException("Помилка: Вказаного файлу не існує!"); } return filePath; } - private int checkKey(final String[] args, Command command) { + private Path sanitizePath(String inputPath) { + if (inputPath.startsWith("\"") && inputPath.endsWith("\"")) { + inputPath = inputPath.substring(1, inputPath.length() - 1); + } + return Path.of(inputPath); + } + + int checkKey(String[] args, Command command) { if (command == Command.ENCRYPT || command == Command.DECRYPT) { if (args.length < 3) { throw new RuntimeException("Помилка: Аргумент обов'язковий!"); From 8620aaa1eb29f0a3f513aa423966b3c450033f12 Mon Sep 17 00:00:00 2001 From: maxog Date: Wed, 6 Nov 2024 11:42:57 +0700 Subject: [PATCH 09/18] initial brutforcer class --- src/BruteForcer.java | 93 +++++++++++++++++++++++++++++++++++++++++++ src/CaesarCipher.java | 18 +++------ 2 files changed, 98 insertions(+), 13 deletions(-) create mode 100644 src/BruteForcer.java diff --git a/src/BruteForcer.java b/src/BruteForcer.java new file mode 100644 index 0000000..2c1e76e --- /dev/null +++ b/src/BruteForcer.java @@ -0,0 +1,93 @@ +import java.util.HashMap; +import java.util.Map; + +public class BruteForcer { + private final Map letterFrequencies; + private String mostLikelyText; + private int mostLikelyKey; + + private static final Map DEFAULT_ENGLISH_FREQUENCIES = createEnglishFrequencyMap(); + + + private static Map createEnglishFrequencyMap() { + Map map = new HashMap<>(); + char[] letters = {'e', 'a', 'r', 'i', 'o', 't', 'n', 's', 'l', 'c', 'u', 'd', 'p', 'm', 'h', 'g', 'b', 'f', + 'y', 'w', 'k', 'v', 'x', 'z', 'j', 'q'}; + double[] frequencies = {11.1607, 8.4966, 7.5809, 7.5448, 7.1635, 6.9509, 6.6544, 5.7351, 5.4893, 4.5388, + 3.6308, 3.3844, 3.1671, 3.0129, 3.0034, 2.4705, 2.0720, 1.8121, 1.7779, 1.2899, 1.1016, 1.0074, 0.2902, + 0.2722, 0.1965, 0.1962}; for (int i = 0; i < letters.length; i++) { map.put(letters[i], frequencies[i]); + } + return map; + } + + public BruteForcer(String staticAnalysisText) { + if (staticAnalysisText != null) { + this.letterFrequencies = calculateLetterFrequency(staticAnalysisText); + } else { + this.letterFrequencies = DEFAULT_ENGLISH_FREQUENCIES; + } + } + + public BruteForcer() { + this(null); + } + + public void bruteForce(String encryptedText) { + int likelyKey = 0; + String likelyText = encryptedText; + double bestMatchScore = Double.MAX_VALUE; + + for (int key = 0; key < letterFrequencies.size(); key++) { + String decryptedText = CaesarCipher.decrypt(encryptedText, key); + double score = calculateMatchScore(decryptedText); + + if (score < bestMatchScore) { + bestMatchScore = score; + likelyKey = key; + likelyText = decryptedText; + } + } + this.mostLikelyKey = likelyKey; + this.mostLikelyText = likelyText; + } + + private Map calculateLetterFrequency(String text) { + Map counts = new HashMap<>(); + int totalLetters = 0; + + for (char c : text.toLowerCase().toCharArray()) { + if (Character.isLetter(c)) { + counts.put(c, counts.getOrDefault(c, 0) + 1); + totalLetters++; + } + } + + Map frequencies = new HashMap<>(); + for (Map.Entry entry : counts.entrySet()) { + frequencies.put(entry.getKey(), (entry.getValue() * 100.0) / totalLetters); + } + return frequencies; + } + + private double calculateMatchScore(String text) { + Map textFrequency = calculateLetterFrequency(text); + double score = 0.0; + + for (Map.Entry entry : this.letterFrequencies.entrySet()) { + char letter = entry.getKey(); + double expectedFrequency = entry.getValue(); + double actualFrequency = textFrequency.getOrDefault(letter, 0.0); + + score += Math.pow(actualFrequency - expectedFrequency, 2); + } + return score; + } + + public String getMostLikelyText() { + return mostLikelyText; + } + + public int getMostLikelyKey() { + return mostLikelyKey; + } +} diff --git a/src/CaesarCipher.java b/src/CaesarCipher.java index 5af5647..7ea49cd 100644 --- a/src/CaesarCipher.java +++ b/src/CaesarCipher.java @@ -6,8 +6,8 @@ private CaesarCipher() { throw new IllegalStateException("Utility class"); } - private static final String ENGLISH_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.,«»\"':!? "; - private static final String UKRAINIAN_ALPHABET = "АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯабвгґдеєжзиіїйклмнопрстуфхцчшщьюя.,«»\"':!? "; + private static final String ENGLISH_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + private static final String UKRAINIAN_ALPHABET = "АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯабвгґдеєжзиіїйклмнопрстуфхцчшщьюя"; private static String currentAlphabet = ENGLISH_ALPHABET; private static int alphabetSize = currentAlphabet.length(); @@ -22,7 +22,7 @@ public static String decrypt(String text, int key) { return shiftText(text, -key); } - //Метод для зсуву символів рядку по алфавіту за визначеним значенням + //Метод для зсуву символів рядка по алфавіту за визначеним значенням private static String shiftText(String text, int shift) { StringBuilder result = new StringBuilder(); @@ -53,15 +53,7 @@ private static void selectAlphabet(String text) { alphabetSize = currentAlphabet.length(); } - public static Map bruteForceDecrypt(String text) { - selectAlphabet(text); - Map possibleDecryptions = new HashMap<>(); - - for (int key = 1; key < alphabetSize; key++) { - String decryptedText = decrypt(text, key); - possibleDecryptions.put(key, decryptedText); - } - - return possibleDecryptions; + public static String bruteForceDecrypt(String text) { + return null; } } From f13c45f9cf902a8b6ecc998994ab1a275b8b5576 Mon Sep 17 00:00:00 2001 From: maxog Date: Wed, 6 Nov 2024 12:18:41 +0700 Subject: [PATCH 10/18] working bruteforcer for english --- src/CLI.java | 38 ++++++++++++++++++++++++++++++-------- src/Main.java | 1 - src/Runner.java | 35 +++++++++++++++++++++++++++++++++-- 3 files changed, 63 insertions(+), 11 deletions(-) diff --git a/src/CLI.java b/src/CLI.java index 945dd80..1fdda38 100644 --- a/src/CLI.java +++ b/src/CLI.java @@ -13,22 +13,31 @@ public CLI() { public void start() { Command command = promptCommand(); Path filePath = promptFilePath(); - String key = ""; + String key = null; + Path filePathForStaticAnalysis = null; - if (command != Command.BRUTE_FORCE){ - key=promptKey(command).toString(); + if (command == Command.BRUTE_FORCE) { + filePathForStaticAnalysis = promptOptionalFilePathForStaticAnalysis(); + } else { + key = promptKey(command).toString(); } - new Runner().run(new String[]{command.name(), filePath.toString(), key}); + if (command == Command.BRUTE_FORCE && filePathForStaticAnalysis != null) { + runner.run(new String[]{command.name(), filePath.toString(), filePathForStaticAnalysis.toString()}); + } else if (command == Command.BRUTE_FORCE) { + runner.run(new String[]{command.name(), filePath.toString()}); + } else { + runner.run(new String[]{command.name(), filePath.toString(), key}); + } } private Command promptCommand() { Command command = null; while (command == null) { - System.out.println("Введіть команду:"); + System.out.println("Введіть команду (ENCRYPT, DECRYPT, або BRUTE_FORCE):"); String input = scanner.nextLine().trim(); - try{ + try { command = runner.checkCommand(input); } catch (RuntimeException e) { System.err.println(e.getMessage()); @@ -63,8 +72,21 @@ private Integer promptKey(Command command) { } catch (RuntimeException e) { System.err.println(e.getMessage()); } - } return key; } -} + + private Path promptOptionalFilePathForStaticAnalysis() { + System.out.println("Введіть повний шлях до файлу для частотного аналізу (або залиште порожнім, щоб пропустити):"); + String pathInput = scanner.nextLine().trim(); + + if (!pathInput.isEmpty()) { + try { + return runner.checkFile(pathInput); + } catch (RuntimeException e) { + System.err.println(e.getMessage()); + } + } + return null; + } +} \ No newline at end of file diff --git a/src/Main.java b/src/Main.java index 6276437..9d7db85 100644 --- a/src/Main.java +++ b/src/Main.java @@ -9,5 +9,4 @@ public static void main(String[] args) { new Runner().run(args); } } - } \ No newline at end of file diff --git a/src/Runner.java b/src/Runner.java index 20f3394..32cd850 100644 --- a/src/Runner.java +++ b/src/Runner.java @@ -9,11 +9,12 @@ public void run(final String[] args){ final Command command=checkCommand(args[0]); final Path filePath=checkFile(args[1]); final int key=checkKey(args, command); + final Path filePathForStaticAnalysis = checkFilePathForStaticAnalysis(args, command); switch (command) { case ENCRYPT -> encryptFile(filePath, key); case DECRYPT -> decryptFile(filePath, key); - case BRUTE_FORCE -> bruteForceFile(filePath); + case BRUTE_FORCE -> bruteForceFile(filePath,filePathForStaticAnalysis); } } catch (RuntimeException e){ System.err.println(e.getMessage()); @@ -40,10 +41,29 @@ private void decryptFile(Path filePath, int key){ throw new RuntimeException("Помилка при дешифрації файлу: " + e.getMessage(), e); } } - private void bruteForceFile(Path filePath){ + private void bruteForceFile(Path filePath, Path filePathForStaticAnalysis) { + try { + String content = FileService.readFile(filePath); + String textForStaticAnalysis = null; + if (filePathForStaticAnalysis != null) { + textForStaticAnalysis = FileService.readFile(filePathForStaticAnalysis); + } + + BruteForcer bruteForcer = new BruteForcer(textForStaticAnalysis); + bruteForcer.bruteForce(content); + int mostLikelyKey = bruteForcer.getMostLikelyKey(); + String mostLikelyText = bruteForcer.getMostLikelyText(); + + FileService.writeWithSuffix(filePath, mostLikelyText, "[BRUTE_FORCE " + mostLikelyKey + "]"); + + System.out.println("Файл дешифровано успішно з ключем: " + mostLikelyKey); + } catch (IOException e) { + throw new RuntimeException("Помилка при дешифрації файлу: " + e.getMessage(), e); + } } + Command checkCommand(String commandString) { try { return Command.valueOf(commandString.toUpperCase()); @@ -80,4 +100,15 @@ int checkKey(String[] args, Command command) { } return -1; } + + Path checkFilePathForStaticAnalysis(String[] args, Command command) { + if (command == Command.BRUTE_FORCE && args.length >= 3) { + Path filePathForStaticAnalysis = sanitizePath(args[2]); + if (!Files.exists(filePathForStaticAnalysis)) { + throw new RuntimeException("Помилка: Файлу для частотного аналізу не існує!"); + } + return filePathForStaticAnalysis; + } + return null; + } } From c781fcefa28ea3e93df8339c7d5275b59c910cc2 Mon Sep 17 00:00:00 2001 From: maxog Date: Wed, 6 Nov 2024 15:54:01 +0700 Subject: [PATCH 11/18] realised brute force for both ukrainian and english texts --- src/BruteForcer.java | 47 +++++++++++++++++++++++++++++++++---------- src/CaesarCipher.java | 8 ++++---- src/Runner.java | 2 +- 3 files changed, 41 insertions(+), 16 deletions(-) diff --git a/src/BruteForcer.java b/src/BruteForcer.java index 2c1e76e..b4459ad 100644 --- a/src/BruteForcer.java +++ b/src/BruteForcer.java @@ -6,8 +6,21 @@ public class BruteForcer { private String mostLikelyText; private int mostLikelyKey; - private static final Map DEFAULT_ENGLISH_FREQUENCIES = createEnglishFrequencyMap(); + public BruteForcer(String staticAnalysisText, String encryptedText) { + if (staticAnalysisText != null) { + this.letterFrequencies = calculateLetterFrequency(staticAnalysisText); + } else { + if (isUkrainianText(encryptedText)) { + this.letterFrequencies = createUkrainianFrequencyMap(); + } else { + this.letterFrequencies = createEnglishFrequencyMap(); + } + } + } + public BruteForcer(String encryptedText) { + this(null, encryptedText); + } private static Map createEnglishFrequencyMap() { Map map = new HashMap<>(); @@ -15,21 +28,33 @@ private static Map createEnglishFrequencyMap() { 'y', 'w', 'k', 'v', 'x', 'z', 'j', 'q'}; double[] frequencies = {11.1607, 8.4966, 7.5809, 7.5448, 7.1635, 6.9509, 6.6544, 5.7351, 5.4893, 4.5388, 3.6308, 3.3844, 3.1671, 3.0129, 3.0034, 2.4705, 2.0720, 1.8121, 1.7779, 1.2899, 1.1016, 1.0074, 0.2902, - 0.2722, 0.1965, 0.1962}; for (int i = 0; i < letters.length; i++) { map.put(letters[i], frequencies[i]); - } - return map; + 0.2722, 0.1965, 0.1962}; + for (int i = 0; i < letters.length; i++) { + map.put(letters[i], frequencies[i]); + } + return map; } - public BruteForcer(String staticAnalysisText) { - if (staticAnalysisText != null) { - this.letterFrequencies = calculateLetterFrequency(staticAnalysisText); - } else { - this.letterFrequencies = DEFAULT_ENGLISH_FREQUENCIES; + private static Map createUkrainianFrequencyMap() { + Map map = new HashMap<>(); + char[] letters = {'о', 'а', 'н', 'і', 'и', 'в', 'р', 'т', 'е', 'с', 'к', 'л', 'у', 'д', 'м', 'п', 'я', 'з', + 'ь', 'г', 'б', 'й', 'х', 'ч', 'ц', 'ї', 'ж', 'ш', 'ю', 'є', 'ф', 'щ', 'ґ'}; + double[] frequencies = {9.28, 8.34, 7.10, 6.23, 6.00, 5.50, 5.48, 4.77, 4.59, 4.57, 4.00, 3.93, 3.38, 3.06, + 3.02, 2.84, 2.16, 2.10, 1.83, 1.59, 1.53, 1.24, 1.17, 1.15, 1.02, 0.84, 0.71, 0.71, 0.70, 0.39, 0.35, + 0.32, 0.01}; + for (int i = 0; i < letters.length; i++) { + map.put(letters[i], frequencies[i]); } + return map; } - public BruteForcer() { - this(null); + private static boolean isUkrainianText(String text) { + for (char c : text.toCharArray()) { + if (CaesarCipher.getUkrainianAlphabet().indexOf(c) != -1) { + return true; + } + } + return false; } public void bruteForce(String encryptedText) { diff --git a/src/CaesarCipher.java b/src/CaesarCipher.java index 7ea49cd..cbd716d 100644 --- a/src/CaesarCipher.java +++ b/src/CaesarCipher.java @@ -12,6 +12,10 @@ private CaesarCipher() { private static String currentAlphabet = ENGLISH_ALPHABET; private static int alphabetSize = currentAlphabet.length(); + public static String getUkrainianAlphabet(){ + return UKRAINIAN_ALPHABET; + } + public static String encrypt(String text, int key) { selectAlphabet(text); return shiftText(text, key); @@ -52,8 +56,4 @@ private static void selectAlphabet(String text) { currentAlphabet = ENGLISH_ALPHABET; alphabetSize = currentAlphabet.length(); } - - public static String bruteForceDecrypt(String text) { - return null; - } } diff --git a/src/Runner.java b/src/Runner.java index 32cd850..03b3020 100644 --- a/src/Runner.java +++ b/src/Runner.java @@ -49,7 +49,7 @@ private void bruteForceFile(Path filePath, Path filePathForStaticAnalysis) { textForStaticAnalysis = FileService.readFile(filePathForStaticAnalysis); } - BruteForcer bruteForcer = new BruteForcer(textForStaticAnalysis); + BruteForcer bruteForcer = new BruteForcer(textForStaticAnalysis, content); bruteForcer.bruteForce(content); int mostLikelyKey = bruteForcer.getMostLikelyKey(); From ceae6c274a8af3f7b083a0080cb78ed732a2f4ae Mon Sep 17 00:00:00 2001 From: maxog Date: Wed, 6 Nov 2024 16:13:36 +0700 Subject: [PATCH 12/18] final fixes --- src/BruteForcer.java | 4 ---- src/CLI.java | 13 +++---------- src/CaesarCipher.java | 3 --- src/Main.java | 2 +- src/Runner.java | 23 ++++++++++++++++++++--- 5 files changed, 24 insertions(+), 21 deletions(-) diff --git a/src/BruteForcer.java b/src/BruteForcer.java index b4459ad..0e1cd27 100644 --- a/src/BruteForcer.java +++ b/src/BruteForcer.java @@ -18,10 +18,6 @@ public BruteForcer(String staticAnalysisText, String encryptedText) { } } - public BruteForcer(String encryptedText) { - this(null, encryptedText); - } - private static Map createEnglishFrequencyMap() { Map map = new HashMap<>(); char[] letters = {'e', 'a', 'r', 'i', 'o', 't', 'n', 's', 'l', 'c', 'u', 'd', 'p', 'm', 'h', 'g', 'b', 'f', diff --git a/src/CLI.java b/src/CLI.java index 1fdda38..094f099 100644 --- a/src/CLI.java +++ b/src/CLI.java @@ -13,22 +13,15 @@ public CLI() { public void start() { Command command = promptCommand(); Path filePath = promptFilePath(); - String key = null; + int key = 0; Path filePathForStaticAnalysis = null; if (command == Command.BRUTE_FORCE) { filePathForStaticAnalysis = promptOptionalFilePathForStaticAnalysis(); } else { - key = promptKey(command).toString(); - } - - if (command == Command.BRUTE_FORCE && filePathForStaticAnalysis != null) { - runner.run(new String[]{command.name(), filePath.toString(), filePathForStaticAnalysis.toString()}); - } else if (command == Command.BRUTE_FORCE) { - runner.run(new String[]{command.name(), filePath.toString()}); - } else { - runner.run(new String[]{command.name(), filePath.toString(), key}); + key = promptKey(command); } + runner.run(command,filePath,key,filePathForStaticAnalysis); } private Command promptCommand() { diff --git a/src/CaesarCipher.java b/src/CaesarCipher.java index cbd716d..ea7d072 100644 --- a/src/CaesarCipher.java +++ b/src/CaesarCipher.java @@ -1,6 +1,3 @@ -import java.util.HashMap; -import java.util.Map; - public class CaesarCipher { private CaesarCipher() { throw new IllegalStateException("Utility class"); diff --git a/src/Main.java b/src/Main.java index 9d7db85..c762506 100644 --- a/src/Main.java +++ b/src/Main.java @@ -6,7 +6,7 @@ public static void main(String[] args) { if (args.length < 2) { new CLI().start(); }else { - new Runner().run(args); + new Runner().runWithArgs(args); } } } \ No newline at end of file diff --git a/src/Runner.java b/src/Runner.java index 03b3020..9f5cb99 100644 --- a/src/Runner.java +++ b/src/Runner.java @@ -4,7 +4,7 @@ public class Runner { - public void run(final String[] args){ + public void runWithArgs(final String[] args){ try { final Command command=checkCommand(args[0]); final Path filePath=checkFile(args[1]); @@ -21,6 +21,18 @@ public void run(final String[] args){ } } + public void run(Command command, Path filePath,int key, Path filePathForStaticAnalysis){ + try { + switch (command) { + case ENCRYPT -> encryptFile(filePath, key); + case DECRYPT -> decryptFile(filePath, key); + case BRUTE_FORCE -> bruteForceFile(filePath,filePathForStaticAnalysis); + } + } catch (RuntimeException e){ + System.err.println(e.getMessage()); + } + } + private void encryptFile(Path filePath, int key){ try { String content = FileService.readFile(filePath); @@ -31,6 +43,7 @@ private void encryptFile(Path filePath, int key){ throw new RuntimeException("Помилка при шифруванні файлу: " + e.getMessage(), e); } } + private void decryptFile(Path filePath, int key){ try { String content = FileService.readFile(filePath); @@ -41,6 +54,7 @@ private void decryptFile(Path filePath, int key){ throw new RuntimeException("Помилка при дешифрації файлу: " + e.getMessage(), e); } } + private void bruteForceFile(Path filePath, Path filePathForStaticAnalysis) { try { String content = FileService.readFile(filePath); @@ -57,13 +71,16 @@ private void bruteForceFile(Path filePath, Path filePathForStaticAnalysis) { FileService.writeWithSuffix(filePath, mostLikelyText, "[BRUTE_FORCE " + mostLikelyKey + "]"); - System.out.println("Файл дешифровано успішно з ключем: " + mostLikelyKey); + if (mostLikelyKey!=0){ + System.out.println("Файл дешифровано успішно з ключем: " + mostLikelyKey); + } else { + System.out.println("Файл не вдалось розшифрувати("); + } } catch (IOException e) { throw new RuntimeException("Помилка при дешифрації файлу: " + e.getMessage(), e); } } - Command checkCommand(String commandString) { try { return Command.valueOf(commandString.toUpperCase()); From 9e28fc0e91cf8108b25322942fe8a6b31bda420e Mon Sep 17 00:00:00 2001 From: maxog Date: Wed, 6 Nov 2024 16:18:32 +0700 Subject: [PATCH 13/18] final fixes --- .idea/artifacts/CaesarCipher_jar.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .idea/artifacts/CaesarCipher_jar.xml diff --git a/.idea/artifacts/CaesarCipher_jar.xml b/.idea/artifacts/CaesarCipher_jar.xml new file mode 100644 index 0000000..72c236d --- /dev/null +++ b/.idea/artifacts/CaesarCipher_jar.xml @@ -0,0 +1,11 @@ + + + $PROJECT_DIR$/out/artifacts/CaesarCipher_jar + + + + + + + + \ No newline at end of file From 48bdd1f2eac324c8755ef3e32d4bddb9b6f653e5 Mon Sep 17 00:00:00 2001 From: maxog Date: Wed, 6 Nov 2024 16:25:57 +0700 Subject: [PATCH 14/18] final fixes --- .idea/artifacts/CaesarCipher_jar.xml | 3 --- src/META-INF/MANIFEST.MF | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 src/META-INF/MANIFEST.MF diff --git a/.idea/artifacts/CaesarCipher_jar.xml b/.idea/artifacts/CaesarCipher_jar.xml index 72c236d..a6c0d2d 100644 --- a/.idea/artifacts/CaesarCipher_jar.xml +++ b/.idea/artifacts/CaesarCipher_jar.xml @@ -2,9 +2,6 @@ $PROJECT_DIR$/out/artifacts/CaesarCipher_jar - - - diff --git a/src/META-INF/MANIFEST.MF b/src/META-INF/MANIFEST.MF new file mode 100644 index 0000000..5ee19cb --- /dev/null +++ b/src/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: Main + From 0de31e1c9c7c88817589646f4ebd2db0c24fe4d4 Mon Sep 17 00:00:00 2001 From: maxog Date: Wed, 6 Nov 2024 17:00:39 +0700 Subject: [PATCH 15/18] final fixes --- .idea/compiler.xml | 6 ++++++ src/Runner.java | 12 +++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) create mode 100644 .idea/compiler.xml diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..3e85750 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/src/Runner.java b/src/Runner.java index 9f5cb99..d4ace85 100644 --- a/src/Runner.java +++ b/src/Runner.java @@ -67,15 +67,17 @@ private void bruteForceFile(Path filePath, Path filePathForStaticAnalysis) { bruteForcer.bruteForce(content); int mostLikelyKey = bruteForcer.getMostLikelyKey(); + + if (mostLikelyKey==0){ + System.out.println("Файл не вдалось розшифрувати(:"); + return; + } + String mostLikelyText = bruteForcer.getMostLikelyText(); FileService.writeWithSuffix(filePath, mostLikelyText, "[BRUTE_FORCE " + mostLikelyKey + "]"); - if (mostLikelyKey!=0){ - System.out.println("Файл дешифровано успішно з ключем: " + mostLikelyKey); - } else { - System.out.println("Файл не вдалось розшифрувати("); - } + System.out.println("Файл дешифровано успішно з ключем: " + mostLikelyKey); } catch (IOException e) { throw new RuntimeException("Помилка при дешифрації файлу: " + e.getMessage(), e); } From 84d9fd75ff5d45ab325d6326215d9455cc252d4c Mon Sep 17 00:00:00 2001 From: maxog Date: Wed, 6 Nov 2024 17:05:26 +0700 Subject: [PATCH 16/18] final fixes --- .idea/compiler.xml | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 .idea/compiler.xml diff --git a/.idea/compiler.xml b/.idea/compiler.xml deleted file mode 100644 index 3e85750..0000000 --- a/.idea/compiler.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file From f975f38f25b23ad58f33236ede9477b5d6498da9 Mon Sep 17 00:00:00 2001 From: mxk77 <104596966+mxk77@users.noreply.github.com> Date: Wed, 6 Nov 2024 17:31:00 +0700 Subject: [PATCH 17/18] Create README.md --- README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..7bf688e --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +Проєкт реалізує криптоаналізатор для класичного шифру Цезаря (без кодування спецсимволів), що дозволяє шифрувати та розшифровувати тексти англійською та українською мовами з вказаним ключем, а також підбирати ключ до зашифрованих файлів аналізуючи частоту символів у варіантах з різними ключами. Успішно реалізовано шифрування, розшифрування та підбір ключа з автоматичним визначенням мови зашифрованого тексту (українська/англійська) та використання відповідного словника за замовчуванням, у разі відсутнього аргументу шляху до файлу для текстового аналізу. Також було розроблено клас CLI для роботи з програмою, якщо вона запущена без аргументів. Не вдалось розібратись як зібрати jar, вказавши опцію для кодування, щоб при роботі з програмою через командний рядок не вказувати щоразу опцію -Dfile.encoding=UTF-8 для коректного відображення кирилиці та правильного сприйняття програмою шляхів до файлів з кириличними символами, якщо вони передаються в режимі роботи через CLI. При перевірці хотілось би, щоб ви звернули увагу на обробку та прокидування помилок, адже суттєво кращого рішення не вдалось придумати, та загальний підхід до реалізації проєкту. From 2dcf7c9c3c0197d6191836fda8a1088c6d2308bf Mon Sep 17 00:00:00 2001 From: mxk77 <104596966+mxk77@users.noreply.github.com> Date: Wed, 6 Nov 2024 17:32:04 +0700 Subject: [PATCH 18/18] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7bf688e..38ade2d 100644 --- a/README.md +++ b/README.md @@ -1 +1 @@ -Проєкт реалізує криптоаналізатор для класичного шифру Цезаря (без кодування спецсимволів), що дозволяє шифрувати та розшифровувати тексти англійською та українською мовами з вказаним ключем, а також підбирати ключ до зашифрованих файлів аналізуючи частоту символів у варіантах з різними ключами. Успішно реалізовано шифрування, розшифрування та підбір ключа з автоматичним визначенням мови зашифрованого тексту (українська/англійська) та використання відповідного словника за замовчуванням, у разі відсутнього аргументу шляху до файлу для текстового аналізу. Також було розроблено клас CLI для роботи з програмою, якщо вона запущена без аргументів. Не вдалось розібратись як зібрати jar, вказавши опцію для кодування, щоб при роботі з програмою через командний рядок не вказувати щоразу опцію -Dfile.encoding=UTF-8 для коректного відображення кирилиці та правильного сприйняття програмою шляхів до файлів з кириличними символами, якщо вони передаються в режимі роботи через CLI. При перевірці хотілось би, щоб ви звернули увагу на обробку та прокидування помилок, адже суттєво кращого рішення не вдалось придумати, та загальний підхід до реалізації проєкту. +Проєкт реалізує криптоаналізатор для класичного шифру Цезаря (без кодування спецсимволів), що дозволяє шифрувати та розшифровувати тексти англійською та українською мовами з вказаним ключем, а також підбирати ключ до зашифрованих файлів аналізуючи частоту символів у варіантах з різними ключами. Успішно реалізовано шифрування, розшифрування та підбір ключа з автоматичним визначенням мови зашифрованого тексту (українська/англійська) та використання відповідного словника за замовчуванням, у разі відсутнього аргументу шляху до файлу для текстового аналізу. Також було розроблено клас CLI для роботи з програмою, якщо вона запущена без аргументів. Не вдалось розібратись як зібрати jar, вказавши опцію для кодування, щоб при роботі з програмою через командний рядок не вказувати щоразу опцію -Dfile.encoding=UTF-8 для коректного відображення кирилиці та правильного сприйняття програмою шляхів до файлів з кириличними символами, якщо вони передаються в режимі роботи через CLI. При перевірці хотілось би, щоб ви звернули увагу на обробку та прокидування вийнятків, адже суттєво кращого рішення не вдалось придумати, та загальний підхід до реалізації проєкту.