Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,18 @@
<artifactId>maven-surefire-report-plugin</artifactId>
<version>3.4.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.4.1</version>
<configuration>
<archive>
<manifest>
<mainClass>ua.com.javarush.gnew.Main</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
31 changes: 9 additions & 22 deletions src/main/java/ua/com/javarush/gnew/Main.java
Original file line number Diff line number Diff line change
@@ -1,32 +1,19 @@
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 ua.com.javarush.gnew.runner.AppRunner;
import ua.com.javarush.gnew.ui.MainWindow;

import java.nio.file.Path;
import javax.swing.*;

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);
// SwingUtilities.invokeLater(() -> new MainWindow().setVisible(true));

try {
if (runOptions.getCommand() == Command.ENCRYPT) {
String content = fileManager.read(runOptions.getFilePath());
String encryptedContent = cypher.encrypt(content, runOptions.getKey());
String fileName = runOptions.getFilePath().getFileName().toString();
String newFileName = fileName.substring(0, fileName.length() - 4) + " [ENCRYPTED].txt";

Path newFilePath = runOptions.getFilePath().resolveSibling(newFileName);
fileManager.write(newFilePath, encryptedContent);
}
} catch (Exception e) {
System.out.println(e.getMessage());
try{
new AppRunner().run(args);
}catch (Exception e){
System.out.println("Error: " + e.getMessage());
}

}
}
54 changes: 35 additions & 19 deletions src/main/java/ua/com/javarush/gnew/crypto/Cypher.java
Original file line number Diff line number Diff line change
@@ -1,33 +1,49 @@
package ua.com.javarush.gnew.crypto;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import ua.com.javarush.gnew.language.Language;
import ua.com.javarush.gnew.service.TextAnalyzer;

public class Cypher {
private final ArrayList<Character> 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'));
private static final TextAnalyzer TEXT_ANALYZER = new TextAnalyzer();
private final Language language;

public Cypher(Language language) {
this.language = language;
}

public String encrypt(String input, int key) {
key = Math.negateExact(key);
public String encrypt(String text, int key) {
return shiftText(text, key);
}

ArrayList<Character> rotatedAlphabet = new ArrayList<>(originalAlphabet);
Collections.rotate(rotatedAlphabet, key);
char[] charArray = input.toCharArray();
public String decrypt(String text, int key) {
return shiftText(text, -key);
}

StringBuilder builder = new StringBuilder();
for (char symbol : charArray) {
builder.append(processSymbol(symbol, rotatedAlphabet));
private String shiftText(String text, int key) {
StringBuilder result = new StringBuilder();
for (char symbol : text.toCharArray()) {
if (language.contains(symbol)) {
int index = language.indexOf(symbol);
int shiftedIndex = (index + key + language.size()) % language.size();
result.append(language.get(shiftedIndex));
} else {
result.append(symbol);
}
}
return builder.toString();
return result.toString();
}

private Character processSymbol(char symbol, ArrayList<Character> rotatedAlphabet) {
if (!originalAlphabet.contains(symbol)) {
return symbol;
public String bruteForce(String encryptedText) {
String bestGuess = "";
int bestScore = Integer.MIN_VALUE;
for (int key = 1; key < language.size(); key++) {
String decrypted = decrypt(encryptedText, key);
int score = TEXT_ANALYZER.evaluate(decrypted);
if (score > bestScore) {
bestScore = score;
bestGuess = decrypted;
}
}
int index = originalAlphabet.indexOf(symbol);

return rotatedAlphabet.get(index);
return bestGuess;
}
}
17 changes: 13 additions & 4 deletions src/main/java/ua/com/javarush/gnew/file/FileManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,20 @@
import java.nio.file.Path;

public class FileManager {
public String read(Path filePath) throws IOException {
return Files.readString(filePath);
public String read(Path filePath) {
try {
return Files.readString(filePath);
} catch (IOException e) {
throw new RuntimeException("Cannot read file: " + filePath, e);
}
}

public void write(Path filePath, String content) throws IOException {
Files.writeString(filePath, content);
public void write(Path filePath, String content) {
try {
Files.writeString(filePath, content);
} catch (IOException e) {
throw new RuntimeException("Cannot write file: " + filePath, e);
}
}

}
16 changes: 16 additions & 0 deletions src/main/java/ua/com/javarush/gnew/language/EnglishLanguage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package ua.com.javarush.gnew.language;

import java.util.List;

public class EnglishLanguage extends Language {
private static final List<Character> ENGLISH_ALPHABET = List.of('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 EnglishLanguage() {
super(ENGLISH_ALPHABET);
}
}
26 changes: 23 additions & 3 deletions src/main/java/ua/com/javarush/gnew/language/Language.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,32 @@
package ua.com.javarush.gnew.language;

import java.util.ArrayList;
import java.util.List;

public abstract class Language {

private final ArrayList<Character> alphabet;
private final List<Character> alphabet;

public Language(ArrayList<Character> alphabet) {
public Language(List<Character> alphabet) {
this.alphabet = alphabet;
}

public List<Character> getAlphabet() {
return alphabet;
}

public int indexOf(char symbol) {
return alphabet.indexOf(symbol);
}

public char get(int index) {
return alphabet.get(index);
}

public int size() {
return alphabet.size();
}

public boolean contains(char symbol) {
return alphabet.contains(symbol);
}
}
18 changes: 18 additions & 0 deletions src/main/java/ua/com/javarush/gnew/language/UkrainianLanguage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package ua.com.javarush.gnew.language;

import java.util.List;

public class UkrainianLanguage extends Language {
private static final List<Character> UKRAINIAN_ALPHABET = List.of('А', 'Б', 'В', 'Г', 'Ґ', 'Д', 'Е', 'Є', 'Ж', 'З',
'И', 'І', 'Ї', 'Й', 'К', 'Л', 'М', 'Н', 'О', 'П',
'Р', 'С', 'Т', 'У', 'Ф', 'Х', 'Ц', 'Ч', 'Ш', 'Щ',
'Ь', 'Ю', 'Я', 'а', 'б', 'в', 'г', 'ґ', 'д', 'е', 'є', 'ж', 'з',
'и', 'і', 'ї', 'й', 'к', 'л', 'м', 'н', 'о', 'п',
'р', 'с', 'т', 'у', 'ф', 'х', 'ц', 'ч', 'ш', 'щ',
'ь', 'ю', 'я', '.', ',', '«', '»', '"', '\'', ':', '!', '?', ' '
);

public UkrainianLanguage() {
super(UKRAINIAN_ALPHABET);
}
}
80 changes: 80 additions & 0 deletions src/main/java/ua/com/javarush/gnew/runner/AppRunner.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package ua.com.javarush.gnew.runner;

import ua.com.javarush.gnew.crypto.Cypher;
import ua.com.javarush.gnew.file.FileManager;
import ua.com.javarush.gnew.language.Language;
import ua.com.javarush.gnew.service.ArgumentsParser;
import ua.com.javarush.gnew.service.LanguageDetector;

import java.nio.file.Path;
import java.util.Scanner;

public class AppRunner {
private final ArgumentsParser argumentsParser = new ArgumentsParser();
private final FileManager fileManager = new FileManager();
private final LanguageDetector detector = new LanguageDetector();


public void run(String[] args) {
if (args.length == 0) {
args = getArgsFromScanner();
}

RunOptions runOptions = argumentsParser.parse(args);
String newFilePath = runWithOptions(runOptions);

System.out.println("File saved to: " + newFilePath);
}

private String generateNewFileName(RunOptions runOptions) {
String fileName = runOptions.getFilePath().getFileName().toString();
String suffix = runOptions.getCommand() == Command.ENCRYPT ? "[ENCRYPTED]" : "[DECRYPTED]";
String baseName = fileName.substring(0, fileName.length() - 4);
return baseName + " " + suffix + ".txt";
}

private String[] getArgsFromScanner() {
Scanner scanner = new Scanner(System.in);

System.out.println("Enter command (ENCRYPT / DECRYPT / BRUTE_FORCE):");
String commandInput = scanner.nextLine().trim().toUpperCase();

System.out.println("Enter path to file:");
String filePath = scanner.nextLine().trim();

if ("BRUTE_FORCE".equals(commandInput)) {
return new String[]{"-bf", "-f", filePath};
}

System.out.println("Enter key :");
String keyInput = scanner.nextLine().trim();

return switch (commandInput) {
case "ENCRYPT" -> new String[]{"-e", "-k", keyInput, "-f", filePath};
case "DECRYPT" -> new String[]{"-d", "-k", keyInput, "-f", filePath};
default -> throw new IllegalArgumentException("Unsupported command: " + commandInput);
};

}

public String runWithOptions(RunOptions runOptions) {
String content = fileManager.read(runOptions.getFilePath());
Language detectedLanguage = detector.detect(content);
Cypher cypher = new Cypher(detectedLanguage);

String processedContent;
if (runOptions.getCommand() == Command.ENCRYPT) {
processedContent = cypher.encrypt(content, runOptions.getKey());
} else if (runOptions.getCommand() == Command.DECRYPT) {
processedContent = cypher.decrypt(content, runOptions.getKey());
} else {
processedContent = cypher.bruteForce(content);
}

String newFileName = generateNewFileName(runOptions);
Path newFilePath = runOptions.getFilePath().resolveSibling(newFileName);
fileManager.write(newFilePath, processedContent);
return newFileName;
}

}
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
package ua.com.javarush.gnew.runner;
package ua.com.javarush.gnew.service;

import ua.com.javarush.gnew.runner.Command;
import ua.com.javarush.gnew.runner.RunOptions;

import java.nio.file.Path;

Expand Down Expand Up @@ -48,7 +51,7 @@ public RunOptions parse(String[] args) {
throw new IllegalArgumentException("Command (-e, -d, or -bf) is required");
}

if (key == null) {
if ((command == Command.ENCRYPT || command == Command.DECRYPT) & key == null) {
throw new IllegalArgumentException("Key is required for encrypt or decrypt mode");
}

Expand Down
26 changes: 26 additions & 0 deletions src/main/java/ua/com/javarush/gnew/service/LanguageDetector.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package ua.com.javarush.gnew.service;

import ua.com.javarush.gnew.language.EnglishLanguage;
import ua.com.javarush.gnew.language.Language;
import ua.com.javarush.gnew.language.UkrainianLanguage;

import java.util.List;

public class LanguageDetector {
private static final double PROBABILITY_COEFFICIENT = 0.7;
private final List<Language> languages = List.of(new EnglishLanguage(), new UkrainianLanguage());

public Language detect(String text) {
for (Language language : languages) {
long count = text.chars()
.filter(symbol -> language.getAlphabet().contains((char) symbol)).count();

double ration = (double) count / text.length();

if (ration > PROBABILITY_COEFFICIENT) {
return language;
}
}
return new EnglishLanguage();
}
}
30 changes: 30 additions & 0 deletions src/main/java/ua/com/javarush/gnew/service/TextAnalyzer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package ua.com.javarush.gnew.service;

public class TextAnalyzer {
private static final int PUNCTUATION_COEFFICIENT = 2;
private static final int LENGTH_COEFFICIENT = 5;

public int evaluate(String text) {
int score = 0;
score += countMatches(text, ' ') * PUNCTUATION_COEFFICIENT;
score += countMatches(text, '.') * PUNCTUATION_COEFFICIENT;
score += countMatches(text, ',') * PUNCTUATION_COEFFICIENT;
score += countMatches(text, '!') * PUNCTUATION_COEFFICIENT;
score += countMatches(text, '?') * PUNCTUATION_COEFFICIENT;

if (text.matches(".*[а-яА-Яa-zA-Z]{4,}.*")) {
score += LENGTH_COEFFICIENT;
}
return score;
}

private int countMatches(String text, char symbol) {
int count = 0;
for (char c : text.toCharArray()) {
if (c == symbol) {
count++;
}
}
return count;
}
}
Loading