diff --git a/out/artifacts/GNEW_M1_FP_jar/GNEW-M1-FP.jar b/out/artifacts/GNEW_M1_FP_jar/GNEW-M1-FP.jar new file mode 100644 index 0000000..ec15503 Binary files /dev/null and b/out/artifacts/GNEW_M1_FP_jar/GNEW-M1-FP.jar differ diff --git a/readme.md b/readme.md index a17a9ac..b401552 100644 --- a/readme.md +++ b/readme.md @@ -13,6 +13,7 @@ ``` -k Key -f File path +-fa File path for frequency analysis (only used in brute force mode). ``` ### Example: @@ -20,9 +21,11 @@ -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 +-bf -f "/path/to/file[ENCRYPTED].txt" -fa "/path/to/reference.txt" ``` ### Argument could be in any order ``` --e -f "/path/to/file.txt" -k 1 -``` \ No newline at end of file +-e -f "/path/to/file.txt" -k 1 (Чомусь коли я видаляв класи вони не видалялись на GitHab, довелось чистити кеш Git та відновляти інформацію з останнього коміту, поідеї такої проблеми вже не має бути) +``` + diff --git a/src/main/java/ua/com/javarush/gnew/JavaFX/Controller.java b/src/main/java/ua/com/javarush/gnew/JavaFX/Controller.java new file mode 100644 index 0000000..567bb2d --- /dev/null +++ b/src/main/java/ua/com/javarush/gnew/JavaFX/Controller.java @@ -0,0 +1,91 @@ +//package ua.com.javarush.gnew.JavaFX; +// +//import javafx.fxml.FXML; +//import javafx.scene.control.Button; +//import javafx.scene.control.TextField; +//import javafx.scene.control.Alert; +//import javafx.scene.control.Alert.AlertType; +//import ua.com.javarush.gnew.runner.CipherApplication; +// +//public class Controller { +// @FXML +// private TextField filePathField; +// +// @FXML +// private TextField helperFilePathField; +// +// @FXML +// private TextField keyField; +// +// @FXML +// private Button encryptButton, decryptButton, bruteForceButton, clearButton; +// +// @FXML +// private void handleEncrypt() { +// processAction("encrypt"); +// } +// +// @FXML +// private void handleDecrypt() { +// processAction("decrypt"); +// } +// +// @FXML +// private void handleBruteForce() { +// processAction("bruteforce"); +// } +// +// @FXML +// private void handleClear() { +// filePathField.setText(""); +// helperFilePathField.setText(""); +// keyField.setText(""); +// } +// +// private void processAction(String mode) { +// String filePath = filePathField.getText(); +// String helperFilePath = helperFilePathField.getText(); +// String key = keyField.getText(); +// +// if (filePath.isEmpty()) { +// showError("Please specify the file path."); +// return; +// } +// +// try { +// CipherApplication app = CipherApplication.getInstance(); +// if (mode.equals("encrypt")) { +// app.run(new String[]{"-e", "-f", filePath, "-k", key}); +// showSuccess("File successfully encrypted."); +// } else if (mode.equals("decrypt")) { +// app.run(new String[]{"-d", "-f", filePath, "-k", key}); +// showSuccess("File successfully decrypted."); +// } else if (mode.equals("bruteforce")) { +// if (helperFilePath.isEmpty()) { +// app.run(new String[]{"-bf", "-f", filePath}); +// } else { +// app.run(new String[]{"-bf", "-f", filePath, "-fa", helperFilePath}); +// } +// showSuccess("Brute force completed successfully."); +// } +// } catch (Exception e) { +// showError("An error occurred: " + e.getMessage()); +// } +// } +// +// private void showError(String message) { +// Alert alert = new Alert(AlertType.ERROR); +// alert.setTitle("Error"); +// alert.setHeaderText(null); +// alert.setContentText(message); +// alert.showAndWait(); +// } +// +// private void showSuccess(String message) { +// Alert alert = new Alert(AlertType.INFORMATION); +// alert.setTitle("Success"); +// alert.setHeaderText(null); +// alert.setContentText(message); +// alert.showAndWait(); +// } +//} diff --git a/src/main/java/ua/com/javarush/gnew/JavaFX/JavaFXApp.java b/src/main/java/ua/com/javarush/gnew/JavaFX/JavaFXApp.java new file mode 100644 index 0000000..dc9dfea --- /dev/null +++ b/src/main/java/ua/com/javarush/gnew/JavaFX/JavaFXApp.java @@ -0,0 +1,32 @@ +//package ua.com.javarush.gnew.JavaFX; +// +//import javafx.application.Application; +//import javafx.fxml.FXMLLoader; +//import javafx.scene.Parent; +//import javafx.scene.Scene; +//import javafx.stage.Stage; +// +//public class JavaFXApp extends Application { +// +// @Override +// public void start(Stage primaryStage) throws Exception { +// FXMLLoader loader = new FXMLLoader(getClass().getResource("/view.fxml")); +// Parent root = loader.load(); +// +// Scene scene = new Scene(root); +// +// primaryStage.setTitle("Cipher Application"); +// primaryStage.setScene(scene); +// +// primaryStage.setOnCloseRequest(event -> { +// System.out.println("Application closed"); +// }); +// +// primaryStage.show(); +// } +// +// public static void launchApp(String[] args) { +// Application.launch(args); +// } +//} + diff --git a/src/main/java/ua/com/javarush/gnew/Main.java b/src/main/java/ua/com/javarush/gnew/Main.java index 5906828..770308e 100644 --- a/src/main/java/ua/com/javarush/gnew/Main.java +++ b/src/main/java/ua/com/javarush/gnew/Main.java @@ -1,32 +1,18 @@ package ua.com.javarush.gnew; -import ua.com.javarush.gnew.crypto.Cypher; -import ua.com.javarush.gnew.file.FileManager; -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; +import ua.com.javarush.gnew.runner.CipherApplication; -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); - 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"; +public class Main { - Path newFilePath = runOptions.getFilePath().resolveSibling(newFileName); - fileManager.write(newFilePath, encryptedContent); - } - } catch (Exception e) { - System.out.println(e.getMessage()); - } + public static void main(String[] args) { +// if (args.length == 0) { +// JavaFXApp.launchApp(args);//Графічний інтерфес +// } else { + CipherApplication app = CipherApplication.getInstance(); + app.run(args); +// app.runInteractive();//Відповідає за консоль +// } } -} \ No newline at end of file +} diff --git a/src/main/java/ua/com/javarush/gnew/arg/ArgumentParser.java b/src/main/java/ua/com/javarush/gnew/arg/ArgumentParser.java new file mode 100644 index 0000000..e4e68f2 --- /dev/null +++ b/src/main/java/ua/com/javarush/gnew/arg/ArgumentParser.java @@ -0,0 +1,42 @@ +package ua.com.javarush.gnew.arg; + +public class ArgumentParser { + + public static Arguments parse(String[] args) { + String mode = null; + String file = null; + int key = 0; + String frequencyAnalysisFile = null; + + for (int i = 0; i < args.length; i++) { + switch (args[i]) { + case "-e": + mode = "-e"; + break; + case "-d": + mode = "-d"; + break; + case "-bf": + mode = "-bf"; + break; + case "-k": + key = Integer.parseInt(args[++i]); + break; + case "-f": + file = args[++i]; + break; + case "-fa": + frequencyAnalysisFile = args[++i]; + break; + default: + throw new IllegalArgumentException("Unknown argument: " + args[i]); + } + } + + if (file == null || mode == null) { + throw new IllegalArgumentException("File or mode not specified. Use '-e' for encryption, '-d' for decryption, or '-bf' for brute force."); + } + + return new Arguments(mode, file, key, frequencyAnalysisFile); + } +} \ No newline at end of file diff --git a/src/main/java/ua/com/javarush/gnew/arg/Arguments.java b/src/main/java/ua/com/javarush/gnew/arg/Arguments.java new file mode 100644 index 0000000..2e36718 --- /dev/null +++ b/src/main/java/ua/com/javarush/gnew/arg/Arguments.java @@ -0,0 +1,46 @@ +package ua.com.javarush.gnew.arg; + +public class Arguments { + private final String mode; + private final String filePath; + private final int key; + private final String frequencyAnalysisFilePath; + + public Arguments(String mode, String filePath, int key, String frequencyAnalysisFilePath) { + this.mode = mode; + this.filePath = filePath; + this.key = key; + this.frequencyAnalysisFilePath = frequencyAnalysisFilePath; + } + + public String getMode() { + return mode; + } + + public String getFilePath() { + return filePath; + } + + public int getKey() { + return key; + } + public String getFrequencyAnalysisFilePath() { + return frequencyAnalysisFilePath; + } + + public boolean isEncryptionMode() { + return "-e".equals(mode); + } + + public boolean isDecryptionMode() { + return "-d".equals(mode); + } + + public boolean isBruteForce() { + return "-bf".equals(mode); + } + public boolean hasFrequencyAnalysisFile() { + return frequencyAnalysisFilePath != null; + } +} + diff --git a/src/main/java/ua/com/javarush/gnew/bruteForce/BruteForce.java b/src/main/java/ua/com/javarush/gnew/bruteForce/BruteForce.java new file mode 100644 index 0000000..0d581b1 --- /dev/null +++ b/src/main/java/ua/com/javarush/gnew/bruteForce/BruteForce.java @@ -0,0 +1,37 @@ +package ua.com.javarush.gnew.bruteForce; + +import ua.com.javarush.gnew.languageDetector.CreateLanguage; +import ua.com.javarush.gnew.languageDetector.EnglishLanguageDetector; +import ua.com.javarush.gnew.languageDetector.LanguageDetector; +import ua.com.javarush.gnew.crypto.EncryptionUtil; + +import java.util.List; +import java.util.Set; + +public class BruteForce { + private final EncryptionUtil encryptionUtil = new EncryptionUtil(); + private final DecryptionHelper decryptionHelper = new DecryptionHelper(); + + public int brute_force(String s) { + int result = 0; + int maxPopular = 0; + + LanguageDetector languageStrategy = new CreateLanguage().createLanguageStrategy(s); + + int alphabetSize = languageStrategy.getAlphabetSize(); + + for (int i = 0; i < alphabetSize; i++) { + String decrypted = encryptionUtil.decrypt(s, i); + int popular = decryptionHelper.evaluateText(decrypted, + languageStrategy.getCommonWords(), + languageStrategy.getCommonEndings(), + languageStrategy.getRareCombinations()); + if (popular > maxPopular) { + maxPopular = popular; + result = i; + } + } + return result; + } +} + diff --git a/src/main/java/ua/com/javarush/gnew/bruteForce/DecryptionHelper.java b/src/main/java/ua/com/javarush/gnew/bruteForce/DecryptionHelper.java new file mode 100644 index 0000000..766bc7f --- /dev/null +++ b/src/main/java/ua/com/javarush/gnew/bruteForce/DecryptionHelper.java @@ -0,0 +1,36 @@ +package ua.com.javarush.gnew.bruteForce; + +import java.util.List; +import java.util.Set; + +public class DecryptionHelper { + + public int evaluateText(String s, Set commonWords, List commonEndings, List rareCombinations) { + String[] words = s.split("\\s+"); + int popular = 0; + + for (String word : words) { + word = word.replaceAll("[^a-zA-Zа-яА-ЯіІїЇєЄґҐ]", "").toLowerCase(); + + for (String rare : rareCombinations) { + if (word.contains(rare)) { + return 0; + } + } + + if (commonWords.contains(word)) { + popular++; + } + + for (String ending : commonEndings) { + if (word.endsWith(ending)) { + popular++; + break; + } + } + } + + return popular; + } +} + diff --git a/src/main/java/ua/com/javarush/gnew/bruteForce/FrequencyAnalysis.java b/src/main/java/ua/com/javarush/gnew/bruteForce/FrequencyAnalysis.java new file mode 100644 index 0000000..67ca9cb --- /dev/null +++ b/src/main/java/ua/com/javarush/gnew/bruteForce/FrequencyAnalysis.java @@ -0,0 +1,80 @@ +package ua.com.javarush.gnew.bruteForce; + +import ua.com.javarush.gnew.crypto.EncryptionUtil; +import ua.com.javarush.gnew.language.Language; +import ua.com.javarush.gnew.languageDetector.CreateLanguage; +import ua.com.javarush.gnew.languageDetector.LanguageDetector; + +import java.util.*; + +public class FrequencyAnalysis { + private int key_bf = 0; + private final DecryptionHelper decryptionHelper = new DecryptionHelper(); + public int getKey_bf(){ + return key_bf; + } + + public String analysis(String encryptedText, String referenceText) { + LanguageDetector languageDetector = new CreateLanguage().createLanguageStrategy(encryptedText); + + HashMap mapEncrypted = getMap(encryptedText); + HashMap mapReference = getMap(referenceText); + + List> listEncrypted = new ArrayList<>(mapEncrypted.entrySet()); + List> listReference = new ArrayList<>(mapReference.entrySet()); + + List alphabet = new Language().getAlphabet(listReference.get(0).getKey()); + + sortByValue(listEncrypted); + sortByValue(listReference); + + String bestDecryption = null; + int bestKey = 0; + int maxPopularity = 0; + + int iterations = Math.min(3, Math.min(listEncrypted.size(), listReference.size())); + + for (int k = 0; k < iterations; k++) { + char encryptedLetter = listEncrypted.get(k).getKey(); + char referenceLetter = listReference.get(k).getKey(); + + // Обчислюємо ключ + int key = (alphabet.indexOf(encryptedLetter) - alphabet.indexOf(referenceLetter) + languageDetector.getAlphabetSize()) % languageDetector.getAlphabetSize(); + + // Дешифруємо текст з поточним ключем + String decryptedText = new EncryptionUtil().decrypt(encryptedText, key); + + // Оцінюємо розшифрований текст + int popularity = decryptionHelper.evaluateText( + decryptedText, + languageDetector.getCommonWords(), + languageDetector.getCommonEndings(), + languageDetector.getRareCombinations() + ); + + // Оновлюємо найкращий ключ, якщо розшифрований текст популярніший + if (popularity > maxPopularity) { + maxPopularity = popularity; + bestKey = key; + bestDecryption = decryptedText; + } + } + key_bf = bestKey; + + return bestDecryption; + } + + private HashMap getMap(String s) { + HashMap map = new HashMap<>(); + for (char c : s.toLowerCase().toCharArray()) { + if (Character.isAlphabetic(c)) { + map.put(c, map.getOrDefault(c, 0) + 1); + } + } + return map; + } + + private void sortByValue(List> list) { + list.sort((o1, o2) -> o2.getValue().compareTo(o1.getValue())); + } +} 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/EncryptionUtil.java b/src/main/java/ua/com/javarush/gnew/crypto/EncryptionUtil.java new file mode 100644 index 0000000..da35918 --- /dev/null +++ b/src/main/java/ua/com/javarush/gnew/crypto/EncryptionUtil.java @@ -0,0 +1,36 @@ +package ua.com.javarush.gnew.crypto; + +import ua.com.javarush.gnew.language.Language; + +import java.util.ArrayList; + +public class EncryptionUtil { + + public String encrypt(String input, int key) { + StringBuilder builder = new StringBuilder(); + for (char symbol : input.toCharArray()) { + ArrayList alphabet = new Language().getAlphabet(symbol); + if (alphabet != null) { + builder.append(newChar(alphabet, key, symbol)); + } else { + builder.append(symbol); + } + } + return builder.toString(); + } + + public String decrypt(String input, int key) { + return encrypt(input, -key); + } + + public static char newChar(ArrayList alp, int key, char c) { + int index = alp.indexOf(c); + + int sum = (index + key) % alp.size(); + if (sum < 0) { + sum += alp.size(); + } + return alp.get(sum); + } +} + 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..e55e15e 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,13 @@ import java.nio.file.Path; public class FileManager { - public String read(Path filePath) throws IOException { - return Files.readString(filePath); + + public static void write(String filePath, String content) throws IOException { + Files.write(Path.of(filePath), content.getBytes()); } - public void write(Path filePath, String content) throws IOException { - Files.writeString(filePath, content); + public static String read(String filePath) throws IOException { + return Files.readString(Path.of(filePath)); } } + diff --git a/src/main/java/ua/com/javarush/gnew/file/NewFileName.java b/src/main/java/ua/com/javarush/gnew/file/NewFileName.java new file mode 100644 index 0000000..0dbca45 --- /dev/null +++ b/src/main/java/ua/com/javarush/gnew/file/NewFileName.java @@ -0,0 +1,12 @@ +package ua.com.javarush.gnew.file; + +public class NewFileName { + public static String getNewFileName(String file, String suffix) { + int dotIndex = file.lastIndexOf('.'); + if (dotIndex == -1) { + return file + suffix + ".txt"; + } else { + return file.substring(0, dotIndex) + suffix + file.substring(dotIndex); + } + } +} diff --git a/src/main/java/ua/com/javarush/gnew/language/Language.java b/src/main/java/ua/com/javarush/gnew/language/Language.java index 067dd2f..960e32e 100644 --- a/src/main/java/ua/com/javarush/gnew/language/Language.java +++ b/src/main/java/ua/com/javarush/gnew/language/Language.java @@ -1,12 +1,31 @@ package ua.com.javarush.gnew.language; import java.util.ArrayList; +import java.util.Arrays; +public class Language { + public static final ArrayList CON_ALP = 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' + )); -public abstract class Language { + public static final ArrayList ALP = 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' + )); - private final ArrayList alphabet; + // Ukrainian alphabet + public static final ArrayList UKR_CON_ALP = new ArrayList<>(Arrays.asList( + 'А', 'Б', 'В', 'Г', 'Ґ', 'Д', 'Е', 'Є', 'Ж', 'З', 'И', 'І', 'Ї', 'Й', 'К', 'Л', 'М', 'Н', 'О', 'П', 'Р', 'С', 'Т', 'У', 'Ф', 'Х', 'Ц', 'Ч', 'Ш', 'Щ', 'Ь', 'Ю', 'Я' + )); - public Language(ArrayList alphabet) { - this.alphabet = alphabet; + public static final ArrayList UKR_ALP = new ArrayList<>(Arrays.asList( + 'а', 'б', 'в', 'г', 'ґ', 'д', 'е', 'є', 'ж', 'з', 'и', 'і', 'ї', 'й', 'к', 'л', 'м', 'н', 'о', 'п', 'р', 'с', 'т', 'у', 'ф', 'х', 'ц', 'ч', 'ш', 'щ', 'ь', 'ю', 'я' + )); + public ArrayList getAlphabet(char symbol) { + if (CON_ALP.contains(symbol) || ALP.contains(symbol)) { + return CON_ALP.contains(symbol) ? CON_ALP : ALP; + } else if (UKR_CON_ALP.contains(symbol) || UKR_ALP.contains(symbol)) { + return UKR_CON_ALP.contains(symbol) ? UKR_CON_ALP : UKR_ALP; + } else { + return null; + } } } diff --git a/src/main/java/ua/com/javarush/gnew/languageDetector/CreateLanguage.java b/src/main/java/ua/com/javarush/gnew/languageDetector/CreateLanguage.java new file mode 100644 index 0000000..d5d661b --- /dev/null +++ b/src/main/java/ua/com/javarush/gnew/languageDetector/CreateLanguage.java @@ -0,0 +1,32 @@ +package ua.com.javarush.gnew.languageDetector; + +public class CreateLanguage { + + public LanguageDetector createLanguageStrategy(String text) { + if (isEnglish(text)) { + return new EnglishLanguageDetector(); + } else if (isUkrainian(text)) { + return new UkrainianLanguageDetector(); + } else { + throw new IllegalArgumentException("Unsupported language detected."); + } + } + + private boolean isEnglish(String text) { + for (char c : text.toLowerCase().toCharArray()) { + if ("abcdefghijklmnopqrstuvwxyz".indexOf(c) != -1) { + return true; + } + } + return false; + } + + private boolean isUkrainian(String text) { + for (char c : text.toLowerCase().toCharArray()) { + if ("абвгґдежзийклмнопрстуфхцчшщьюяіїє".indexOf(c) != -1) { + return true; + } + } + return false; + } +} diff --git a/src/main/java/ua/com/javarush/gnew/languageDetector/EnglishLanguageDetector.java b/src/main/java/ua/com/javarush/gnew/languageDetector/EnglishLanguageDetector.java new file mode 100644 index 0000000..ca3a71b --- /dev/null +++ b/src/main/java/ua/com/javarush/gnew/languageDetector/EnglishLanguageDetector.java @@ -0,0 +1,46 @@ +package ua.com.javarush.gnew.languageDetector; + +import java.util.List; +import java.util.Set; + +public class EnglishLanguageDetector implements LanguageDetector { + private static final Set COMMON_WORDS_EN = Set.of( + "the", "be", "to", "of", "and", "in", "that", "have", "I", + "it", "for", "not", "on", "with", "he", "as", "you", "do", "at", + "this", "but", "his", "by", "from", "they", "we", "say", "her", + "she", "or", "an", "will", "my", "one", "all", "would", "there", + "their", "what", "so", "up", "out", "if", "about", "who", "get", + "which", "go", "me" + ); + + private static final List COMMON_ENDINGS_EN = List.of( + "ing", "ed", "s", "es", "ly", "er", "est", "ness", + "ful", "less", "tion", "able", "ive", "ous", "ment" + ); + + private static final List RARE_COMBINATIONS_EN = List.of( + "qj", "qx", "vw", "zk", "kp", "xq", "jh", "bv", "zx", + "qq", "ww", "xx", "zz", "vv", "hh", "kk" + ); + + @Override + public Set getCommonWords() { + return COMMON_WORDS_EN; + } + + @Override + public List getCommonEndings() { + return COMMON_ENDINGS_EN; + } + + @Override + public List getRareCombinations() { + return RARE_COMBINATIONS_EN; + } + + @Override + public int getAlphabetSize() { + return 26; + } +} + diff --git a/src/main/java/ua/com/javarush/gnew/languageDetector/LanguageDetector.java b/src/main/java/ua/com/javarush/gnew/languageDetector/LanguageDetector.java new file mode 100644 index 0000000..962323c --- /dev/null +++ b/src/main/java/ua/com/javarush/gnew/languageDetector/LanguageDetector.java @@ -0,0 +1,12 @@ +package ua.com.javarush.gnew.languageDetector; + +import java.util.List; +import java.util.Set; + +public interface LanguageDetector { + Set getCommonWords(); + List getCommonEndings(); + List getRareCombinations(); + int getAlphabetSize(); +} + diff --git a/src/main/java/ua/com/javarush/gnew/languageDetector/UkrainianLanguageDetector.java b/src/main/java/ua/com/javarush/gnew/languageDetector/UkrainianLanguageDetector.java new file mode 100644 index 0000000..6d04d9c --- /dev/null +++ b/src/main/java/ua/com/javarush/gnew/languageDetector/UkrainianLanguageDetector.java @@ -0,0 +1,45 @@ +package ua.com.javarush.gnew.languageDetector; + +import java.util.List; +import java.util.Set; + +public class UkrainianLanguageDetector implements LanguageDetector { + private static final Set COMMON_WORDS_UA = Set.of( + "і", "в", "на", "що", "з", "не", "до", "це", "як", "я", + "він", "ти", "ми", "вона", "ви", "вони", "цей", "той", + "який", "яка", "воно", "якщо", "але", "тому", "вже", "був", "була", + "було", "та", "бо", "коли", "де", "про", "його", "її", "їх" + ); + + private static final List COMMON_ENDINGS_UA = List.of( + "ий", "ого", "ому", "ім", "ими", "ий", "им", "ів", "ити", "имо", + "ти", "ла", "ло", "ли", "ти", "ть", "є", "но", "ено", "єно", + "ан", "ен", "ян", "к", "че", "ка", "чи" + ); + + private static final List RARE_COMBINATIONS_UA = List.of( + "цщ", "шщ", "жщ", "йй", "шч", "щц", "щщ", "фг", "фз", "гф", + "йй", "юя", "аї", "яє", "йг", "гщ", "щж", "щш", "щр", "цф" + ); + + @Override + public Set getCommonWords() { + return COMMON_WORDS_UA; + } + + @Override + public List getCommonEndings() { + return COMMON_ENDINGS_UA; + } + + @Override + public List getRareCombinations() { + return RARE_COMBINATIONS_UA; + } + + @Override + public int getAlphabetSize() { + return 33; + } +} + diff --git a/src/main/java/ua/com/javarush/gnew/runner/ArgumentsParser.java b/src/main/java/ua/com/javarush/gnew/runner/ArgumentsParser.java deleted file mode 100644 index eb42462..0000000 --- a/src/main/java/ua/com/javarush/gnew/runner/ArgumentsParser.java +++ /dev/null @@ -1,62 +0,0 @@ -package ua.com.javarush.gnew.runner; - -import java.nio.file.Path; - -public class ArgumentsParser { - public RunOptions parse(String[] args) { - Command command = null; - Integer key = null; - Path filePath = null; - - for (int i = 0; i < args.length; i++) { - String arg = args[i]; - - switch (arg) { - case "-e": - command = Command.ENCRYPT; - break; - - case "-d": - command = Command.DECRYPT; - break; - - case "-bf": - command = Command.BRUTEFORCE; - break; - case "-k": - if (i + 1 < args.length) { - key = Integer.parseInt(args[++i]); - } else { - throw new IllegalArgumentException("Missing value for key"); - } - break; - - case "-f": - if (i + 1 < args.length) { - filePath = Path.of(args[++i]); - } else { - throw new IllegalArgumentException("Missing value for file"); - } - break; - - default: - throw new IllegalArgumentException("Unknown argument: " + arg); - } - } - - if (command == null) { - throw new IllegalArgumentException("Command (-e, -d, or -bf) is required"); - } - - if (key == null) { - throw new IllegalArgumentException("Key is required for encrypt or decrypt mode"); - } - - if (filePath == null) { - throw new IllegalArgumentException("File path is required"); - } - - return new RunOptions(command, key, filePath); - } - -} diff --git a/src/main/java/ua/com/javarush/gnew/runner/CipherApplication.java b/src/main/java/ua/com/javarush/gnew/runner/CipherApplication.java new file mode 100644 index 0000000..2f24b58 --- /dev/null +++ b/src/main/java/ua/com/javarush/gnew/runner/CipherApplication.java @@ -0,0 +1,76 @@ +package ua.com.javarush.gnew.runner; + +import ua.com.javarush.gnew.arg.ArgumentParser; +import ua.com.javarush.gnew.arg.Arguments; +import ua.com.javarush.gnew.bruteForce.BruteForce; +import ua.com.javarush.gnew.bruteForce.FrequencyAnalysis; +import ua.com.javarush.gnew.crypto.EncryptionUtil; +import ua.com.javarush.gnew.file.FileManager; +import ua.com.javarush.gnew.file.NewFileName; + +import java.util.Scanner; + +public class CipherApplication { + private static CipherApplication runner; + private CipherApplication(){} + public static CipherApplication getInstance(){ + if (runner == null){ + runner = new CipherApplication(); + } + return runner; + } + public void run(String[] args){ + try { + Arguments arguments = ArgumentParser.parse(args); + + String content = FileManager.read(arguments.getFilePath()); + String result; + String newFile; + + EncryptionUtil encryptionUtil = new EncryptionUtil(); + if (arguments.isEncryptionMode()) { + result = encryptionUtil.encrypt(content, arguments.getKey()); + newFile = NewFileName.getNewFileName(arguments.getFilePath(), "[ENCRYPTED]"); + } else if (arguments.isDecryptionMode()) { + result = encryptionUtil.decrypt(content, arguments.getKey()); + newFile = NewFileName.getNewFileName(arguments.getFilePath(), "[DECRYPTED]"); + } else if (arguments.isBruteForce()) { + if (arguments.hasFrequencyAnalysisFile()) { + String referenceContent = FileManager.read(arguments.getFrequencyAnalysisFilePath()); + FrequencyAnalysis frequencyAnalysis = new FrequencyAnalysis(); + result = frequencyAnalysis.analysis(content, referenceContent); + int foundKey = frequencyAnalysis.getKey_bf(); + newFile = NewFileName.getNewFileName(arguments.getFilePath(), "[DECRYPTED_KEY_" + foundKey + "]"); + System.out.println("Key found using frequency analysis: " + foundKey); + } else { + // Стандартний brute force + int key = new BruteForce().brute_force(content); + result = encryptionUtil.decrypt(content, key); + newFile = NewFileName.getNewFileName(arguments.getFilePath(), "[DECRYPTED]"); + System.out.println("Key found using brute force: " + key); + } + }else { + throw new IllegalArgumentException("Invalid mode. Use '-e' for encryption, '-d' for decryption, or '-bf' for brute force."); + } + + FileManager.write(newFile, result); + System.out.println("Operation completed successfully. Output file: " + newFile); + } catch (Exception e) { + e.printStackTrace(); + } + } + public void runInteractive(){ + try(Scanner scanner = new Scanner(System.in)) { + String string = ""; + while (!"exit".equals(string)) { + System.out.print("Enter command or 'exit' to quit: "); + string = scanner.nextLine(); + if ("exit".equalsIgnoreCase(string)) { + break; + } + String[] strings = string.split(" "); + run(strings); + } + } + } +} diff --git a/src/main/java/ua/com/javarush/gnew/runner/Command.java b/src/main/java/ua/com/javarush/gnew/runner/Command.java deleted file mode 100644 index 54ddeac..0000000 --- a/src/main/java/ua/com/javarush/gnew/runner/Command.java +++ /dev/null @@ -1,7 +0,0 @@ -package ua.com.javarush.gnew.runner; - -public enum Command { - ENCRYPT, - DECRYPT, - BRUTEFORCE -} \ No newline at end of file diff --git a/src/main/java/ua/com/javarush/gnew/runner/RunOptions.java b/src/main/java/ua/com/javarush/gnew/runner/RunOptions.java deleted file mode 100644 index 45e700b..0000000 --- a/src/main/java/ua/com/javarush/gnew/runner/RunOptions.java +++ /dev/null @@ -1,54 +0,0 @@ -package ua.com.javarush.gnew.runner; - -import java.nio.file.Path; - -public class RunOptions { - /** - * Command to be executed. - * -e option for encryption. - * -d option for decryption. - * -b option for brute force. - */ - private final Command command; - - /** - * Key to be used for encryption or decryption. - * For encryption mode, this is the shift value. - * -k option is required. - */ - private final Integer key; - - /** - * Path to the file to be processed. - * For encryption and decryption modes, this is the file to be encrypted or decrypted. - * -f option is required. - */ - private final Path filePath; - - public RunOptions(Command command, Integer key, Path filePath) { - this.command = command; - this.key = key; - this.filePath = filePath; - } - - public Command getCommand() { - return command; - } - - public Integer getKey() { - return key; - } - - public Path getFilePath() { - return filePath; - } - - @Override - public String toString() { - return "CommandOptions{" + - "command='" + command + '\'' + - ", key=" + key + - ", filePath=" + filePath + - '}'; - } -} diff --git a/src/main/java/ua/com/javarush/gnew/text.txt b/src/main/java/ua/com/javarush/gnew/text.txt new file mode 100644 index 0000000..003bf04 --- /dev/null +++ b/src/main/java/ua/com/javarush/gnew/text.txt @@ -0,0 +1,38 @@ +THE TRAGEDY OF HAMLET, PRINCE OF DENMARK + + + by William Shakespeare + + + + Dramatis Personae + + Claudius, King of Denmark. + Marcellus, Officer. + Hamlet, son to the former, and nephew to the present king. + Polonius, Lord Chamberlain. + Horatio, friend to Hamlet. + Laertes, son to Polonius. + Voltemand, courtier. + Cornelius, courtier. + Rosencrantz, courtier. + Guildenstern, courtier. + Osric, courtier. + A Gentleman, courtier. + A Priest. + Marcellus, officer. + Bernardo, officer. + Francisco, a soldier + Reynaldo, servant to Polonius. + Players. + Two Clowns, gravediggers. + Fortinbras, Prince of Norway. \s + A Norwegian Captain. + English Ambassadors. + + Getrude, Queen of Denmark, mother to Hamlet. + Ophelia, daughter to Polonius. + + Ghost of Hamlet's Father. + + Lords, ladies, Officers, Soldiers, Sailors, Messengers, Attendants."""; \ No newline at end of file diff --git a/src/main/java/ua/com/javarush/gnew/text[ENCRYPTED].txt b/src/main/java/ua/com/javarush/gnew/text[ENCRYPTED].txt new file mode 100644 index 0000000..27b0b0c --- /dev/null +++ b/src/main/java/ua/com/javarush/gnew/text[ENCRYPTED].txt @@ -0,0 +1,38 @@ +Врйє йлз, врйє йлз, +Їєтл йгкж е яьйє! +Кьцл опьїє кь мьмгнж +Орйкєйє нщвьйє?.. +Флй яьо яжпгн кг нлеяжщя +Я опгмр, щі мєїєкр? +Флй яьо їєтл кг мнєомьїл, +Щі оялш вєпєкр?.. + +Юл яьо їєтл кь ояжп кь ойжт млнлвєїл, +Млїєяьїє оїчлеє... флй кг еьплмєїє, +Кг яєкгоїє я йлнг, кг нлейєїє я млїж?. +Кг мєпьїє ю їшвг, цл я йгкг юлїєпч, +Кг мєпьїє ю, еь цл мнліїєкьш влїш, +Флал крвдр ояжплй? "Кжфлал нлюєпч", — +Кг оіьеьїє ю кь ойжт... + +Іяжпє йлз, вжпє! +Кьцл д яьо ілтья щ, кьцл влаїщвья? +Фє еьмїьфг огнуг лвкл кь яожй ояжпж, +Щі щ е яьйє мїьіья?.. Йлдг, ж яаьвья... +Йлдг, кьивгпчощ вжялфг +Огнуг, іьнж лфж, +Цл еьмїьфрпч кь ож врйє, — +Щ южїчхг кг тлфр. +Лвкр оїчлер е лфги іьнєт — +Ж мьк кьв мькьйє! +Врйє йлз, врйє йлз, +Їєтл йгкж е яьйє! + +Еь іьнжз лфгкщпь, +Еь флнкжз юнляє +Огнуг няьїлощ, ойжщїлоч, +Яєїєяьїл йляр, +Яєїєяьїл, щі рйжїл, +Еь пгйкжз клфж, +Еь яєхкгяєи оьв егїгкєи, +Еь їьоіє вжялфж... \ No newline at end of file diff --git a/src/main/java/ua/com/javarush/gnew/text[ENCRYPTED][DECRYPTED].txt b/src/main/java/ua/com/javarush/gnew/text[ENCRYPTED][DECRYPTED].txt new file mode 100644 index 0000000..f5d163a --- /dev/null +++ b/src/main/java/ua/com/javarush/gnew/text[ENCRYPTED][DECRYPTED].txt @@ -0,0 +1,14 @@ +Афіша вистави "Енеїди" Івана Котляревського початку ХХ століття +Істину, схоже, відшукати було нелегко. Змінити культурну ідентичність, відмовитися від традиції безболісно не вдавалося. + +Інша держава, якій треба ревно служити, інші прапори й символи. Успішна імперська кар'єра не притлумлювала відчуття втрати. + +Котляревський вирішив протистояти руїнницьким обставинам, звернувшись до невичерпного живого мовного джерела. Він береться писати про козацьку минувшину, переборюючи гірку певність, що, може, творить пам'ятник навіки втраченій батьківщині. + +Розповідаючи про спалену ворогами-греками Трою, мусив же думати про власну сплюндровану столицю, про зруйнований гетьманський Батурин. + +Однак те, що багатьом здавалося кінцем, завершенням, дорогою, але безвідносною до сучасності, пам'яттю про колишні звитяги й велич, - виявилося початком і провістям. + +Письменник чутливо вловив дух часу, опинився, що називається, у тренді. + +Це вже була доба романтизму з її зосередженістю на національній своєрідності, з пафосом націєтворення. Український політичний рух поступово міцнішав. \ No newline at end of file diff --git a/src/main/resources/META-INF/MANIFEST.MF b/src/main/resources/META-INF/MANIFEST.MF new file mode 100644 index 0000000..e523bee --- /dev/null +++ b/src/main/resources/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: ua.com.javarush.gnew.Main + diff --git a/src/main/resources/view.fxml b/src/main/resources/view.fxml new file mode 100644 index 0000000..4580758 --- /dev/null +++ b/src/main/resources/view.fxml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/ua/com/javarush/gnew/MainTest.java b/src/test/java/ua/com/javarush/gnew/MainTest.java index b7f6356..89d57f6 100644 --- a/src/test/java/ua/com/javarush/gnew/MainTest.java +++ b/src/test/java/ua/com/javarush/gnew/MainTest.java @@ -15,7 +15,7 @@ import static org.junit.jupiter.api.Assertions.*; class MainTest { - private static final boolean UKRAINIAN_LANGUAGE_TEST = false; + private static final boolean UKRAINIAN_LANGUAGE_TEST = true; private static final String ENCRYPT_COMMAND = "-e"; private static final String DECRYPT_COMMAND = "-d"; private static final String BF_COMMAND = "-bf";