diff --git a/src/main/java/com/javarush/kostromin/ConsoleRunner.java b/src/main/java/com/javarush/kostromin/ConsoleRunner.java new file mode 100644 index 0000000..e5c151e --- /dev/null +++ b/src/main/java/com/javarush/kostromin/ConsoleRunner.java @@ -0,0 +1,9 @@ +package com.javarush.kostromin; + +import com.javarush.kostromin.view.console.ConsoleApplication; + +public class ConsoleRunner { + public static void main(String[] args) { + new ConsoleApplication().run(); + } +} \ No newline at end of file diff --git a/src/main/java/com/javarush/kostromin/command/BaseCipher.java b/src/main/java/com/javarush/kostromin/command/BaseCipher.java new file mode 100644 index 0000000..665790d --- /dev/null +++ b/src/main/java/com/javarush/kostromin/command/BaseCipher.java @@ -0,0 +1,23 @@ +package com.javarush.kostromin.command; + +import static com.javarush.kostromin.constant.Alphabet.ALPHABET; + +public abstract class BaseCipher { + + protected String processText(String text, int shift) { + StringBuilder result = new StringBuilder(); + int n = ALPHABET.length(); + shift = ((shift % n) + n) % n; + + for (char c : text.toCharArray()) { + int index = ALPHABET.indexOf(c); + if (index != -1) { + int newIndex = (index + shift) % n; + result.append(ALPHABET.charAt(newIndex)); + } else { + result.append(c); + } + } + return result.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/com/javarush/kostromin/command/BruteForceMethod.java b/src/main/java/com/javarush/kostromin/command/BruteForceMethod.java new file mode 100644 index 0000000..835a326 --- /dev/null +++ b/src/main/java/com/javarush/kostromin/command/BruteForceMethod.java @@ -0,0 +1,40 @@ +package com.javarush.kostromin.command; +import com.javarush.kostromin.constant.Alphabet; + +import java.util.Arrays; +import java.util.List; + +public class BruteForceMethod { + private static final List COMMON_WORDS = Arrays.asList( + " и ", " в ", " не ", " на ", " что ", " с ", " это ", " как ", " а ", "потому", "так" + ); + + public int findKey(String encryptedText) { + DecryptMethodCaesar decryptor = new DecryptMethodCaesar(); + int maxMatches = -1; + int bestKey = 0; + int alphabetLength = Alphabet.ALPHABET.length(); + + for (int key = 1; key < alphabetLength; key++) { + String decrypted = decryptor.decrypt(encryptedText, key); + int matches = countCommonWords(decrypted); + + if (matches > maxMatches) { + maxMatches = matches; + bestKey = key; + } + } + return bestKey; + } + + private int countCommonWords(String text) { + String lowerText = text.toLowerCase(); + int count = 0; + for (String word : COMMON_WORDS) { + if (lowerText.contains(word)) { + count++; + } + } + return count; + } +} \ No newline at end of file diff --git a/src/main/java/com/javarush/kostromin/command/DecryptMethodCaesar.java b/src/main/java/com/javarush/kostromin/command/DecryptMethodCaesar.java new file mode 100644 index 0000000..0787527 --- /dev/null +++ b/src/main/java/com/javarush/kostromin/command/DecryptMethodCaesar.java @@ -0,0 +1,7 @@ +package com.javarush.kostromin.command; + +public class DecryptMethodCaesar extends BaseCipher { + public String decrypt(String text, int key) { + return processText(text, -key); + } +} \ No newline at end of file diff --git a/src/main/java/com/javarush/kostromin/command/EncryptMethodCaesar.java b/src/main/java/com/javarush/kostromin/command/EncryptMethodCaesar.java new file mode 100644 index 0000000..2c74b28 --- /dev/null +++ b/src/main/java/com/javarush/kostromin/command/EncryptMethodCaesar.java @@ -0,0 +1,7 @@ +package com.javarush.kostromin.command; + +public class EncryptMethodCaesar extends BaseCipher { + public String encrypt(String text, int key) { + return processText(text, key); + } +} \ No newline at end of file diff --git a/src/main/java/com/javarush/kostromin/constant/Alphabet.java b/src/main/java/com/javarush/kostromin/constant/Alphabet.java new file mode 100644 index 0000000..b51a396 --- /dev/null +++ b/src/main/java/com/javarush/kostromin/constant/Alphabet.java @@ -0,0 +1,7 @@ +package com.javarush.kostromin.constant; + +public class Alphabet { + public static final String ALPHABET = + "абвгдеёжзийклмнопрстуфхцчшщъыьэюяАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ0123456789 .,!?:;-()"; + +} \ No newline at end of file diff --git a/src/main/java/com/javarush/kostromin/constant/Constants.java b/src/main/java/com/javarush/kostromin/constant/Constants.java new file mode 100644 index 0000000..5efe227 --- /dev/null +++ b/src/main/java/com/javarush/kostromin/constant/Constants.java @@ -0,0 +1,10 @@ +package com.javarush.kostromin.constant; + +import java.io.File; + +public class Constants { + public static final String TXT_FOLDER = System.getProperty("user.dir") + + File.separator + + "text" + + File.separator; +} diff --git a/src/main/java/com/javarush/kostromin/controller/MainController.java b/src/main/java/com/javarush/kostromin/controller/MainController.java new file mode 100644 index 0000000..0ff502a --- /dev/null +++ b/src/main/java/com/javarush/kostromin/controller/MainController.java @@ -0,0 +1,96 @@ +package com.javarush.kostromin.controller; + +import com.javarush.kostromin.command.BruteForceMethod; +import com.javarush.kostromin.command.DecryptMethodCaesar; +import com.javarush.kostromin.command.EncryptMethodCaesar; +import com.javarush.kostromin.constant.Alphabet; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Paths; + +public class MainController { + public void executeCommand(String command, String[] args) { + try { + switch (command) { + case "encrypt": + validateFileExists(args[0]); + validateKey(args[2]); + encryptFile(args[0], args[1], Integer.parseInt(args[2])); + break; + case "decrypt": + validateFileExists(args[0]); + validateKey(args[2]); + decryptFile(args[0], args[1], Integer.parseInt(args[2])); + break; + case "bruteforce": + validateFileExists(args[0]); + bruteForceFile(args[0], args[1]); + break; + default: + System.out.println("Unknown command: " + command); + } + } catch (RuntimeException e) { + System.out.println("Error: " + e.getMessage()); + } + } + + private void validateFileExists(String filePath) { + if (!new File(filePath).exists()) { + throw new IllegalArgumentException("File does not exist: " + filePath); + } + } + + private void validateKey(String keyFromKeyboard) { + try { + int key = Integer.parseInt(keyFromKeyboard); + int alphabetLength = Alphabet.ALPHABET.length(); + if (key < 0 || key >= alphabetLength) { + throw new IllegalArgumentException("Key must be between 0 and " + + (alphabetLength - 1)); + } + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Key must be a valid integer"); + } + } + + private void encryptFile(String sourceFile, String destFile, int key) { + try { + String contentText = new String(Files.readAllBytes(Paths.get(sourceFile))); + EncryptMethodCaesar encryptor = new EncryptMethodCaesar(); + String encryptedContent = encryptor.encrypt(contentText, key); + Files.write(Paths.get(destFile), encryptedContent.getBytes()); + System.out.println("File encrypted successfully with key: " + key); + } catch (Exception e) { + throw new RuntimeException("Encryption failed: " + e.getMessage()); + } + } + + private void decryptFile(String sourceFile, String destFile, int key) { + try { + String contentText = new String(Files.readAllBytes(Paths.get(sourceFile))); + DecryptMethodCaesar decryptor = new DecryptMethodCaesar(); + String decryptedContent = decryptor.decrypt(contentText, key); + Files.write(Paths.get(destFile), decryptedContent.getBytes()); + System.out.println("File decrypted successfully with key: " + key); + } catch (Exception e) { + throw new RuntimeException("Decryption failed: " + e.getMessage()); + } + } + + private void bruteForceFile(String sourceFile, String destFile) { + try { + String contentText = new String(Files.readAllBytes(Paths.get(sourceFile))); + BruteForceMethod bruteForce = new BruteForceMethod(); + int foundKey = bruteForce.findKey(contentText); + + DecryptMethodCaesar decryptor = new DecryptMethodCaesar(); + String decryptedContent = decryptor.decrypt(contentText, foundKey); + Files.write(Paths.get(destFile), decryptedContent.getBytes()); + + System.out.println("Brute force completed. Found key: " + foundKey); + } catch (Exception e) { + throw new RuntimeException("Brute force failed: " + e.getMessage()); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/javarush/kostromin/view/console/ConsoleApplication.java b/src/main/java/com/javarush/kostromin/view/console/ConsoleApplication.java new file mode 100644 index 0000000..cc0d802 --- /dev/null +++ b/src/main/java/com/javarush/kostromin/view/console/ConsoleApplication.java @@ -0,0 +1,150 @@ +package com.javarush.kostromin.view.console; + +import com.javarush.kostromin.constant.Alphabet; +import com.javarush.kostromin.controller.MainController; + +import java.io.File; +import java.util.Scanner; + +import static com.javarush.kostromin.constant.Constants.TXT_FOLDER; + +public class ConsoleApplication { + private final MainController controller = new MainController(); + + public void run() { + Scanner scanner = new Scanner(System.in); + while (true) { + printMenu(); + String choice = scanner.nextLine(); + System.out.println(TXT_FOLDER); + switch (choice) { + case "1": + executeEncryptCommand(scanner); + break; + case "2": + executeDecryptCommand(scanner); + break; + case "3": + executeBruteForceCommand(scanner); + break; + case "4": + return; + default: + System.out.println("Invalid option"); + } + } + } + + + private void executeEncryptCommand(Scanner scanner) { + System.out.println("Enter input file [Push 'Enter' for default: text/text.txt]:"); + String inputFile = getInputFilePath(scanner, "text.txt"); + + System.out.println("Enter output file [Push 'Enter' for for default: text/encrypted.txt]:"); + String outputFile = getOutputFilePath(scanner, "encrypted.txt"); + + System.out.println("Enter key:"); + int key = getValidKey(scanner); + + controller.executeCommand("encrypt", new String[]{inputFile, outputFile, String.valueOf(key)}); + } + + private void executeDecryptCommand(Scanner scanner) { + System.out.println("Enter input file [Push 'Enter' for default: text/encrypted.txt]:"); + String inputFile = getInputFilePath(scanner, "encrypted.txt"); + + System.out.println("Enter output file [Push 'Enter' for default: text/decrypted.txt]:"); + String outputFile = getOutputFilePath(scanner, "decrypted.txt"); + + System.out.println("Enter key:"); + int key = getValidKey(scanner); + + controller.executeCommand("decrypt", new String[]{inputFile, outputFile, String.valueOf(key)}); + } + + private void executeBruteForceCommand(Scanner scanner) { + System.out.println("Enter input file [Push 'Enter' for default: text/encrypted.txt]:"); + String inputFile = getInputFilePath(scanner, "encrypted.txt"); + + System.out.println("Enter output file [Push 'Enter' for default: text/decrypted_bruteforce.txt]:"); + String outputFile = getOutputFilePath(scanner, "decrypted_bruteforce.txt"); + + controller.executeCommand("bruteforce", new String[]{inputFile, outputFile}); + } + + private String getInputFilePath(Scanner scanner, String defaultPath) { + String userInputPath = scanner.nextLine().trim(); + if (userInputPath.isEmpty()) { + userInputPath = TXT_FOLDER + defaultPath; + } + + if (!new File(userInputPath).exists()) { + System.out.println("File does not exist: " + userInputPath); + System.out.println("Please enter a valid file path:"); + return getInputFilePath(scanner, defaultPath); + } + + return userInputPath; + } + + private String getOutputFilePath(Scanner scanner, String defaultPath) { + String userInputPath = scanner.nextLine().trim(); + if (userInputPath.isEmpty()) { + return TXT_FOLDER + defaultPath; + } else { + String pathWithTxt = ensureTxtExtension(userInputPath); + if (!pathWithTxt.contains(File.separator) && !pathWithTxt.contains("/") && !pathWithTxt.contains("\\")) { + return TXT_FOLDER + pathWithTxt; + } + + return pathWithTxt; + } + } + + private String ensureTxtExtension(String filePath) { + if (filePath.endsWith(File.separator)) { + return filePath + "output.txt"; + } + if (!filePath.toLowerCase().endsWith(".txt")) { + if (filePath.contains(".")) { + int lastDotIndex = filePath.lastIndexOf('.'); + filePath = filePath.substring(0, lastDotIndex) + ".txt"; + } else { + filePath += ".txt"; + } + } + + return filePath; + } + + private int getValidKey(Scanner scanner) { + while (true) { + try { + String userInput = scanner.nextLine().trim(); + int key = Integer.parseInt(userInput); + + if (key < 0 || key >= Alphabet.ALPHABET.length()) { + System.out.println("Key must be between 0 and " + + (Alphabet.ALPHABET.length() - 1)); + continue; + } + + return key; + } catch (NumberFormatException e) { + System.out.println("Please enter a valid integer key:"); + } + } + } + + private void printMenu() { + System.out.println("\n Caesar Cipher Application "); + System.out.println("-----------------------------"); + System.out.println("|1. Encrypt"); + System.out.println("|2. Decrypt with key"); + System.out.println("|3. Brute force"); + System.out.println("|4. Exit"); + System.out.println("-----------------------------"); + System.out.println("|Choose an option: "); + System.out.println("-----------------------------"); + } +} \ No newline at end of file