From 151cd622478147d417da5581e6eda9b83db24f3e Mon Sep 17 00:00:00 2001 From: lucas Date: Thu, 19 Dec 2024 17:12:00 +0100 Subject: [PATCH 1/3] algo choice working for password of a site (to do for database) --- databases.json | 7 +- src/Classes/AlgorithmChoice.java | 70 ++++++++++ src/Classes/Database.java | 18 +++ src/Classes/DatabasesManager.java | 32 +++-- src/Classes/Menu.java | 155 ++++++++++++++++------ src/Classes/SiteManager.java | 208 +++++++++++++++++++++++++----- test3.json | 29 +++++ 7 files changed, 441 insertions(+), 78 deletions(-) create mode 100644 src/Classes/AlgorithmChoice.java create mode 100644 src/Classes/Database.java create mode 100644 test3.json diff --git a/databases.json b/databases.json index 3f862b5..791bf29 100644 --- a/databases.json +++ b/databases.json @@ -1,3 +1,8 @@ { - "esffs": "e4aebaf0f1b173cdf19ae33a5539cc4e52990f37473f6f41623e1a3a346fa713" + "esffs": "e4aebaf0f1b173cdf19ae33a5539cc4e52990f37473f6f41623e1a3a346fa713", + "lucasTest": "afd9e22b642671f1deea86ad057bee0cd4f1521d5fe845176a28b8dc9be5ab1b", + "test2": "bef57ec7f53a6d40beb640a780a639c83bc29ac8a9816f1fc6c5c6dcd93c4721", + "luc": "4c0b50889cd1fe5d08c46245b26b456afd2210aaa65faa6cd91c21c3a8745f2a", + "test3": "796b4a082e2eaa33c18e56665fe78487d902793cabb227b624248708701d400a", + "lucas": "a6c05149f59a2e2c6523fe289117ed4cd92a896a8db5883014bb7a6737adee66" } \ No newline at end of file diff --git a/src/Classes/AlgorithmChoice.java b/src/Classes/AlgorithmChoice.java new file mode 100644 index 0000000..be6c523 --- /dev/null +++ b/src/Classes/AlgorithmChoice.java @@ -0,0 +1,70 @@ +package Classes; + +import Classes.Enigma.Enigma; // Import the Enigma class for encryption and decryption + + +public class AlgorithmChoice { + + ////////////// ENCRYPTION /////////// + // Methods for each encryption algorithm + + // Encrypts using the Enigma encryption algorithm + public static String encryptEnigma(String password) { + Enigma encryptionBox = new Enigma(); // Create an instance of the Enigma encryption box + // Calls the Enigma's encrypt method to encrypt the password + return encryptionBox.encrypt(password); + } + + // Encrypts using the RC4 algorithm + public static String encryptRC4(String password) { + RC4 encryptionBox = new RC4(); // Create an instance of the RC4 encryption box + String key = "key"; // The encryption key for RC4 + encryptionBox.init(key); // Initialize the RC4 encryption with the key + // Calls the RC4's encrypt method to encrypt the password + return encryptionBox.encrypt(password); + } + + // Encrypts using the ROT(x) algorithm + public static String encryptROT(String password, int x) { + // Calls the ROTX's encrypt method to perform a ROT(x) shift on the password + return ROTX.encryptROT(password, x); + } + + // Encrypts using the Vigenère cipher algorithm + public static String encryptVigenere(String password, String key) { + // Uses the VigenereAlgo class to encrypt the password with the given key + return VigenereAlgo.encrypt(password, key); + } + + /////////// DECRYPTION /////////// + // Methods for each decryption algorithm + + // Decrypts using the Enigma decryption algorithm + public static String decryptEnigma(String encryptedMessage) { + Enigma decryptionBox = new Enigma(); // Create an instance of the Enigma decryption box + // Calls the Enigma's decrypt method to decrypt the encrypted message + return decryptionBox.decrypt(encryptedMessage); + } + + // Decrypts using the RC4 algorithm + public static String decryptRC4(String encryptedMessage) { + // Create an instance of the RC4 decryption box + RC4 decryptionBox = new RC4(); + String key = "key"; // The decryption key for RC4 + decryptionBox.init(key); // Initialize the RC4 decryption with the key + // Calls the RC4's decrypt method to decrypt the encrypted message + return decryptionBox.decrypt(encryptedMessage); + } + + // Decrypts using the ROT(x) algorithm + public static String decryptROT(String input, int x) { + // Calls the ROTX's decrypt method to reverse the ROT(x) shift on the input + return ROTX.decryptROT(input, x); + } + + // Decrypts using the Vigenère cipher algorithm + public static String decryptVigenere(String encryptedMessage, String key) { + // Uses the VigenereAlgo class to decrypt the encrypted message with the given key + return VigenereAlgo.decrypt(encryptedMessage, key); + } +} diff --git a/src/Classes/Database.java b/src/Classes/Database.java new file mode 100644 index 0000000..acecc70 --- /dev/null +++ b/src/Classes/Database.java @@ -0,0 +1,18 @@ +package Classes; + +public class Database{ + private final String hashedPassword; + private final String databaseName; + private final String encryptionMode; + + + public Database (String databaseName, String hashedPassword, String encryptionMode) { + this.databaseName = databaseName; + this.hashedPassword = hashedPassword; + this.encryptionMode = encryptionMode; + } + + + + +} diff --git a/src/Classes/DatabasesManager.java b/src/Classes/DatabasesManager.java index 284d52f..b8aa32a 100644 --- a/src/Classes/DatabasesManager.java +++ b/src/Classes/DatabasesManager.java @@ -13,45 +13,57 @@ import java.util.Map; public class DatabasesManager { - private final File databasesFile; - private final Map databases; - Sha256 sha256 = new Sha256(); + private final File databasesFile; // The file where the databases and their passwords are stored + private final Map databases; // A map holding the database names as keys and their hashed passwords as values + private final Sha256 sha256 = new Sha256(); // Instance of the Sha256 class for password hashing + + // Constructor initializing the file and loading the existing databases public DatabasesManager(File databasesFile) { this.databasesFile = databasesFile; - this.databases = loadDatabases(); + this.databases = loadDatabases(); // Load existing databases from file } + // Function to verify if the provided password matches the stored password for a database public boolean verifyDatabase(String dbName, String password) { - String hashedPassword = sha256.calculateHash(password); + String hashedPassword = sha256.calculateHash(password); // Hash the provided password + // Check if the database exists and the hashed password matches the stored one return databases.containsKey(dbName) && databases.get(dbName).equals(hashedPassword); } + // Function to create a new database with a hashed password public void createDatabase(String dbName, String password) { + // If the database already exists, throw an exception if (databases.containsKey(dbName)) { throw new IllegalArgumentException("Database already exists."); } + // Hash the password and add the new database to the map String hashedPassword = sha256.calculateHash(password); databases.put(dbName, hashedPassword); - saveDatabases(); + saveDatabases(); // Save the updated databases list to the file } + // Function to load the databases from the JSON file public Map loadDatabases() { + // If the file doesn't exist, return an empty map if (!databasesFile.exists()) return new HashMap<>(); try (FileReader reader = new FileReader(databasesFile)) { + // Use Gson to parse the JSON file into a map of database names and passwords Gson gson = new Gson(); - Type type = new TypeToken>() {}.getType(); - return gson.fromJson(reader, type); + Type type = new TypeToken>() {}.getType(); // Define the type for the map + return gson.fromJson(reader, type); // Return the map of databases } catch (IOException e) { - return new HashMap<>(); + return new HashMap<>(); // Return an empty map if there was an error reading the file } } + // Function to save the databases and their hashed passwords to the JSON file private void saveDatabases() { try (FileWriter writer = new FileWriter(databasesFile)) { + // Use Gson to convert the map of databases to a JSON format and write it to the file Gson gson = new GsonBuilder().setPrettyPrinting().create(); gson.toJson(databases, writer); } catch (IOException e) { - e.printStackTrace(); + e.printStackTrace(); // Print the error if there is an issue writing to the file } } } diff --git a/src/Classes/Menu.java b/src/Classes/Menu.java index a3b8821..cf95fb3 100644 --- a/src/Classes/Menu.java +++ b/src/Classes/Menu.java @@ -1,54 +1,137 @@ package Classes; import java.io.File; -import java.util.Map; import java.util.Scanner; public class Menu { + // Main function, starting point of the program public static void main(String[] args) { + // Create a scanner object for user input Scanner scanner = new Scanner(System.in); + // File where the database information is stored File databasesFile = new File("databases.json"); + // Initialize the database manager DatabasesManager dbManager = new DatabasesManager(databasesFile); + // Display a welcome message System.out.println("Welcome to the Encryption/Decryption Program"); - System.out.println("Choose an option:"); - System.out.println("1. Choose an existing database"); - System.out.println("2. Create a new database"); - int dbChoice = scanner.nextInt(); - scanner.nextLine(); - - if (dbChoice == 1) { - System.out.println("Enter the name of the database:"); - String dbName = scanner.nextLine(); - System.out.println("Enter the password:"); - String inputPassword = scanner.nextLine(); - - if (dbManager.verifyDatabase(dbName, inputPassword)) { - System.out.println("Successfully connected to the database: " + dbName); - SiteManager siteManager = new SiteManager(new File(dbName + ".json")); - siteManager.manageSites(scanner); - } else { - System.out.println("Incorrect database name or password."); + // Start an infinite loop to show the main menu + while (true) { + // Display the options in the main menu + System.out.println("Choose an option:"); + System.out.println("1. Choose an existing database"); + System.out.println("2. Create a new database"); + System.out.println("3. Exit"); + // Read user choice + int dbChoice = scanner.nextInt(); + scanner.nextLine(); // Clear buffer + + // Process the user choice using a switch statement + switch (dbChoice) { + case 1 -> handleExistingDatabase(scanner, dbManager); // Handle selecting an existing database + case 2 -> handleNewDatabase(scanner, dbManager); // Handle creating a new database + case 3 -> { // Exit the program + System.out.println("Exiting program. Goodbye!"); + return; // Exit the main method and the program + } + default -> System.out.println("Invalid choice. Please try again."); // Invalid choice } - } else if (dbChoice == 2) { - System.out.println("Enter the name of the new database:"); - String dbName = scanner.nextLine(); - System.out.println("Choose a password option:"); - System.out.println("1. Enter a custom password"); - System.out.println("2. Generate a random password"); - int passwordChoice = scanner.nextInt(); - scanner.nextLine(); - - String password = passwordChoice == 1 - ? scanner.nextLine() - : PasswordUtils.generateRandomPassword(12); - - System.out.println("Generated password: " + password); - dbManager.createDatabase(dbName, password); + } + } + + // Function to handle the case when the user wants to choose an existing database + private static void handleExistingDatabase(Scanner scanner, DatabasesManager dbManager) { + // Ask for the name of the database + System.out.println("Enter the name of the database:"); + String dbName = scanner.nextLine(); + // Ask for the password of the database + System.out.println("Enter the password:"); + String inputPassword = scanner.nextLine(); + + // Check if the database name and password are correct + if (dbManager.verifyDatabase(dbName, inputPassword)) { + System.out.println("Successfully connected to the database: " + dbName); + // Create a SiteManager for managing the database's sites SiteManager siteManager = new SiteManager(new File(dbName + ".json")); - siteManager.manageSites(scanner); + // Display the main action menu for the site manager + mainActionMenu(scanner, siteManager); } else { - System.out.println("Invalid choice."); + // Inform the user if the credentials are incorrect + System.out.println("Incorrect database name or password."); + } + } + + // Function to handle the case when the user wants to create a new database + private static void handleNewDatabase(Scanner scanner, DatabasesManager dbManager) { + // Ask for the name of the new database + System.out.println("Enter the name of the new database:"); + String dbName = scanner.nextLine(); + + // Ask the user to choose a password option + System.out.println("Choose a password option:"); + System.out.println("1. Enter a custom password"); + System.out.println("2. Generate a random password"); + // Read user choice for password generation + int passwordChoice = scanner.nextInt(); + scanner.nextLine(); // Clear buffer + + // Generate or ask for a custom password based on the user's choice + String password = switch (passwordChoice) { + case 1 -> { + System.out.println("Enter your custom password:"); + yield scanner.nextLine(); // Return the custom password + } + case 2 -> { + // Generate a random password and display it + String generatedPassword = PasswordUtils.generateRandomPassword(12); + System.out.println("Generated password: " + generatedPassword); + yield generatedPassword; // Return the generated password + } + default -> { + System.out.println("Invalid choice. Defaulting to generated password."); + yield PasswordUtils.generateRandomPassword(12); // Default to random password + } + }; + + // Create the new database with the chosen name and password + dbManager.createDatabase(dbName, password); + + // Create a SiteManager for the new database + SiteManager siteManager = new SiteManager(new File(dbName + ".json")); + + // Display the main action menu for the site manager + mainActionMenu(scanner, siteManager); + } + + // Function to display the main action menu for managing sites and performing actions + private static void mainActionMenu(Scanner scanner, SiteManager siteManager) { + // Ensure an encryption algorithm is selected (commented out here) + // siteManager.chooseEncryptionAlgorithm(scanner); + + // Start an infinite loop to show the action menu + while (true) { + // Display the options for actions in the site manager + System.out.println("Choose an action:"); + System.out.println("1. Manage sites"); + System.out.println("2. Decrypt a password"); + System.out.println("3. Back to main menu"); + // Read user choice for the action + int action = scanner.nextInt(); + scanner.nextLine(); // Clear buffer + + // Process the action choice using a switch statement + switch (action) { + case 1 -> siteManager.manageSites(scanner, siteManager.encryptionAlgorithm); // Manage sites, passing the encryption algorithm + case 2 -> { // Decrypt a password + siteManager.chooseEncryptionAlgorithm(scanner); // Choose the encryption algorithm + siteManager.handleEncryptionDecryption(scanner); // Handle encryption/decryption process + } + case 3 -> { // Return to the main menu + System.out.println("Returning to the main menu..."); + return; // Exit the current loop and return to the main menu + } + default -> System.out.println("Invalid choice. Please try again."); // Invalid choice + } } } } diff --git a/src/Classes/SiteManager.java b/src/Classes/SiteManager.java index a5e8bcc..90b1924 100644 --- a/src/Classes/SiteManager.java +++ b/src/Classes/SiteManager.java @@ -1,5 +1,9 @@ package Classes; +import Classes.Enigma.Enigma; +import Classes.Enigma.Plugboard; +import Classes.Enigma.Reflector; +import Classes.Enigma.Rotors; import com.google.gson.Gson; import com.google.gson.GsonBuilder; @@ -10,40 +14,173 @@ import java.util.*; public class SiteManager { - private final File dbFile; - private final List> sites; + private final File dbFile; // The file where the site data is stored + private final List> sites; // List of sites, each represented as a map of properties + public String encryptionAlgorithm; // Selected encryption algorithm + // Constructor initializing the database file and loading sites from the file public SiteManager(File dbFile) { this.dbFile = dbFile; this.sites = loadSites(); } - public void manageSites(Scanner scanner) { + // Function to manage the sites (add, modify, delete, or exit) + public void manageSites(Scanner scanner, String encryptionAlgo) { + chooseEncryptionAlgorithm(scanner); // Let the user choose an encryption algorithm + while (true) { + // Display menu options System.out.println("Choose an action:"); System.out.println("1. Add a site"); System.out.println("2. Modify a site"); System.out.println("3. Delete a site"); System.out.println("4. Exit"); int choice = scanner.nextInt(); - scanner.nextLine(); + scanner.nextLine(); // Clear buffer + // Handle user's choice switch (choice) { - case 1 -> addSite(scanner); - case 2 -> modifySite(scanner); - case 3 -> deleteSite(scanner); - case 4 -> { return; } + case 1 -> addSite(scanner); // Add a new site + case 2 -> modifySite(scanner); // Modify an existing site + case 3 -> deleteSite(scanner); // Delete a site + case 4 -> { + return; // Exit the site management menu + } default -> System.out.println("Invalid choice."); } } } + // Function to handle encryption/decryption of passwords + public void handleEncryptionDecryption(Scanner scanner) { + System.out.println("Choose an action:"); + + // Offer the user to decrypt a password + System.out.println("1. Decrypt a password"); + int choice = scanner.nextInt(); + scanner.nextLine(); // Clear buffer + + if (choice == 1) { + // Ask for the site name to decrypt the password for + System.out.println("Enter site name:"); + String siteName = scanner.nextLine(); + Optional> siteOpt = sites.stream() + .filter(site -> site.get("siteName").equals(siteName)) + .findFirst(); + + // Check if the site exists + if (siteOpt.isPresent()) { + Map site = siteOpt.get(); + String encryptedPassword = site.get("password"); + + // Decrypt the password and display it + String decryptedPassword = decryptPassword(encryptedPassword, scanner); + System.out.println("Decrypted password: " + decryptedPassword); + } else { + System.out.println("Site not found."); + } + } else { + System.out.println("Invalid choice."); + } + } + + // Function to encrypt a password based on the selected algorithm + private String encryptPassword(String password, Scanner scanner) { + return switch (encryptionAlgorithm) { + case "Enigma" -> { + // Configuration for the Enigma machine + System.out.print("Enter the configuration for Enigma - Rotors (example: I II III): "); + String rotorsConfig = scanner.nextLine().trim(); + Rotors rotors = new Rotors(); + + System.out.print("Enter the configuration for the Reflector (example: B): "); + String reflectorConfig = scanner.nextLine().trim(); + Reflector reflector = new Reflector(); + + System.out.print("Enter the plugboard configuration (example: AB CD EF): "); + String plugboardConfig = scanner.nextLine().trim(); + Plugboard plugboard = new Plugboard(); + + // Create the Enigma machine instance and encrypt the password + Enigma enigmaMachine = new Enigma(rotors, reflector, plugboard); + yield enigmaMachine.encrypt(password); + } + case "RC4" -> AlgorithmChoice.encryptRC4(password); // RC4 encryption + case "ROT" -> { + System.out.println("Enter the value of X for ROT(X):"); + int x = scanner.nextInt(); + scanner.nextLine(); + yield AlgorithmChoice.encryptROT(password, x); // ROT encryption + } + case "Vigenere" -> { + System.out.println("Enter the key for Vigenère:"); + String key = scanner.nextLine(); + yield AlgorithmChoice.encryptVigenere(password, key); // Vigenère encryption + } + default -> throw new IllegalStateException("Unknown encryption algorithm: " + encryptionAlgorithm); // Error for unknown algorithm + }; + } + + // Function to decrypt a password based on the selected algorithm + private String decryptPassword(String encryptedPassword, Scanner scanner) { + return switch (encryptionAlgorithm) { + case "Enigma" -> AlgorithmChoice.decryptEnigma(encryptedPassword); // Enigma decryption + case "RC4" -> AlgorithmChoice.decryptRC4(encryptedPassword); // RC4 decryption + case "ROT" -> { + System.out.println("Enter the value of X for ROT(X):"); + int x = scanner.nextInt(); + scanner.nextLine(); + yield AlgorithmChoice.decryptROT(encryptedPassword, x); // ROT decryption + } + case "Vigenere" -> { + System.out.println("Enter the key for Vigenère:"); + String key = scanner.nextLine(); + if (key == null || key.isEmpty()) { + throw new IllegalArgumentException("Key for Vigenère cannot be null or empty"); + } + yield AlgorithmChoice.decryptVigenere(encryptedPassword, key); // Vigenère decryption + } + default -> throw new IllegalStateException("Unknown encryption algorithm: " + encryptionAlgorithm); // Error for unknown algorithm + }; + } + + // Function to choose an encryption algorithm + public void chooseEncryptionAlgorithm(Scanner scanner) { + System.out.println("Choose an encryption algorithm:"); + System.out.println("1. Enigma"); + System.out.println("2. RC4"); + System.out.println("3. ROT(X)"); + System.out.println("4. Vigenère"); + + // Read the user's choice + int algoChoice = scanner.nextInt(); + scanner.nextLine(); // Clear buffer + + // Set the encryption algorithm based on user's choice + encryptionAlgorithm = switch (algoChoice) { + case 1 -> "Enigma"; + case 2 -> "RC4"; + case 3 -> "ROT"; + case 4 -> "Vigenere"; + default -> { + System.out.println("Invalid choice, defaulting to ROT."); + yield "ROT"; // Default to ROT + } + }; + System.out.println("Selected encryption algorithm: " + encryptionAlgorithm); + } + + // Function to add a new site with encrypted password public void addSite(String siteName, String username, String password) { - Map site = Map.of("siteName", siteName, "username", username, "password", password); - sites.add(site); - saveSites(); + Map site = new HashMap<>(); + site.put("siteName", siteName); + site.put("username", username); + site.put("password", password); + sites.add(site); // Add site to the list + saveSites(); // Save the updated sites list to file } + // Function to add a new site using user input public void addSite(Scanner scanner) { System.out.println("Enter site name:"); String siteName = scanner.nextLine(); @@ -51,27 +188,31 @@ public void addSite(Scanner scanner) { String username = scanner.nextLine(); System.out.println("Enter password:"); String password = scanner.nextLine(); - addSite(siteName, username, password); + + // Encrypt the password and add the site + String encryptedPassword = encryptPassword(password, scanner); + addSite(siteName, username, encryptedPassword); } + // Function to modify an existing site's username or password public void modifySite(String siteName, String newUsername, String newPassword) { for (Map site : sites) { if (site.get("siteName").equals(siteName)) { + // Update the username and/or password if provided if (newUsername != null && !newUsername.isEmpty()) { site.put("username", newUsername); } if (newPassword != null && !newPassword.isEmpty()) { site.put("password", newPassword); } - System.out.println("Modified site: " + site); - saveSites(); + saveSites(); // Save the updated list of sites return; } } - System.out.println("Site not found for modification: " + siteName); - throw new IllegalArgumentException("Site not found: " + siteName); + throw new IllegalArgumentException("Site not found: " + siteName); // Site not found } + // Function to modify a site using user input public void modifySite(Scanner scanner) { System.out.println("Enter the site name to modify:"); String siteName = scanner.nextLine(); @@ -79,40 +220,45 @@ public void modifySite(Scanner scanner) { String newUsername = scanner.nextLine(); System.out.println("Enter the new password (leave empty to keep current):"); String newPassword = scanner.nextLine(); - modifySite(siteName, newUsername, newPassword); + modifySite(siteName, newUsername, newPassword); // Modify the site } - + // Function to delete a site by name public void deleteSite(String siteName) { - sites.removeIf(site -> site.get("siteName").equals(siteName)); - saveSites(); + sites.removeIf(site -> site.get("siteName").equals(siteName)); // Remove the site from the list + saveSites(); // Save the updated list of sites } + // Function to delete a site using user input public void deleteSite(Scanner scanner) { System.out.println("Enter the site name to delete:"); String siteName = scanner.nextLine(); - deleteSite(siteName); + deleteSite(siteName); // Delete the site } - + // Function to load sites from the JSON file public List> loadSites() { - if (!dbFile.exists()) return new ArrayList<>(); - try (FileReader reader = new FileReader(dbFile)) { + if (!dbFile.exists()) return new ArrayList<>(); // Return an empty list if the file doesn't exist + + try (FileReader fileReader = new FileReader(dbFile)) { + // Parse the file content using Gson Gson gson = new Gson(); - Map data = gson.fromJson(reader, Map.class); - return (List>) data.get("sites"); + List> sitesList = gson.fromJson(fileReader, ArrayList.class); + return sitesList != null ? sitesList : new ArrayList<>(); // Return the loaded sites or an empty list if parsing fails } catch (IOException e) { - return new ArrayList<>(); + System.out.println("Error reading file: " + e.getMessage()); + return new ArrayList<>(); // Return an empty list in case of error } } + // Function to save sites to the JSON file public void saveSites() { - try (FileWriter writer = new FileWriter(dbFile)) { + try (FileWriter fileWriter = new FileWriter(dbFile)) { + // Write the sites list to the file in JSON format Gson gson = new GsonBuilder().setPrettyPrinting().create(); - Map data = Map.of("sites", sites); - gson.toJson(data, writer); + gson.toJson(sites, fileWriter); } catch (IOException e) { - e.printStackTrace(); + System.out.println("Error saving sites: " + e.getMessage()); } } } diff --git a/test3.json b/test3.json new file mode 100644 index 0000000..7ae7b3c --- /dev/null +++ b/test3.json @@ -0,0 +1,29 @@ +{ + "sites": [ + { + "password": "qoqsschebdschzcejq", + "siteName": "testVG", + "username": "vg" + }, + { + "password": "susyuijkdjuijhej", + "siteName": "testRot", + "username": "rot" + }, + { + "password": "01101000 00001001 01010111 10000100 01000001 11111100 00001111 00111111 00100110 00111111 01101101 00001000 01100010 00001111 01110001 11001001", + "siteName": "testRC4", + "username": "rc4" + }, + { + "password": "qleqrxhdvananbokjdp", + "siteName": "testEnigma", + "username": "en" + }, + { + "password": "cir", + "siteName": "feds", + "username": "dcs" + } + ] +} \ No newline at end of file From 2803670b206d3d7d957327b894a46c56b87e8ad9 Mon Sep 17 00:00:00 2001 From: Nabil Date: Fri, 20 Dec 2024 01:48:19 +0100 Subject: [PATCH 2/3] refactor : restructure encryption classes and update test data --- databases.json | 8 - src/Classes/AlgorithmChoice.java | 10 +- src/Classes/DatabasesManager.java | 104 +++++--- src/Classes/EncryptionAlgorithm.java | 7 + src/Classes/EncryptionStack.java | 28 ++ src/Classes/Enigma/Enigma.java | 68 +++-- src/Classes/Menu.java | 230 +++++++++-------- src/Classes/RC4.java | 2 +- src/Classes/ROTX.java | 76 +++--- src/Classes/SiteManager.java | 369 ++++++++++++--------------- src/Classes/VigenereAlgo.java | 123 ++++----- src/Tests/DatabasesManagerTest.java | 42 +-- src/Tests/SiteManagerTest.java | 135 ++++++++-- src/Tests/VigenereTest.java | 44 ++-- src/Tests/assets/test_databases.json | 5 +- src/Tests/assets/test_sites.json | 20 +- src/Tests/test_databases.json | 3 - src/Tests/test_sites.json | 3 - test3.json | 29 --- 19 files changed, 704 insertions(+), 602 deletions(-) delete mode 100644 databases.json create mode 100644 src/Classes/EncryptionAlgorithm.java create mode 100644 src/Classes/EncryptionStack.java delete mode 100644 src/Tests/test_databases.json delete mode 100644 src/Tests/test_sites.json delete mode 100644 test3.json diff --git a/databases.json b/databases.json deleted file mode 100644 index 791bf29..0000000 --- a/databases.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "esffs": "e4aebaf0f1b173cdf19ae33a5539cc4e52990f37473f6f41623e1a3a346fa713", - "lucasTest": "afd9e22b642671f1deea86ad057bee0cd4f1521d5fe845176a28b8dc9be5ab1b", - "test2": "bef57ec7f53a6d40beb640a780a639c83bc29ac8a9816f1fc6c5c6dcd93c4721", - "luc": "4c0b50889cd1fe5d08c46245b26b456afd2210aaa65faa6cd91c21c3a8745f2a", - "test3": "796b4a082e2eaa33c18e56665fe78487d902793cabb227b624248708701d400a", - "lucas": "a6c05149f59a2e2c6523fe289117ed4cd92a896a8db5883014bb7a6737adee66" -} \ No newline at end of file diff --git a/src/Classes/AlgorithmChoice.java b/src/Classes/AlgorithmChoice.java index be6c523..2bcd9a7 100644 --- a/src/Classes/AlgorithmChoice.java +++ b/src/Classes/AlgorithmChoice.java @@ -32,8 +32,9 @@ public static String encryptROT(String password, int x) { // Encrypts using the Vigenère cipher algorithm public static String encryptVigenere(String password, String key) { - // Uses the VigenereAlgo class to encrypt the password with the given key - return VigenereAlgo.encrypt(password, key); + VigenereAlgo vigenere = new VigenereAlgo(); + vigenere.setKey(key); + return vigenere.encrypt(password); } /////////// DECRYPTION /////////// @@ -64,7 +65,8 @@ public static String decryptROT(String input, int x) { // Decrypts using the Vigenère cipher algorithm public static String decryptVigenere(String encryptedMessage, String key) { - // Uses the VigenereAlgo class to decrypt the encrypted message with the given key - return VigenereAlgo.decrypt(encryptedMessage, key); + VigenereAlgo vigenere = new VigenereAlgo(); + vigenere.setKey(key); + return vigenere.decrypt(encryptedMessage); } } diff --git a/src/Classes/DatabasesManager.java b/src/Classes/DatabasesManager.java index b8aa32a..f82c82b 100644 --- a/src/Classes/DatabasesManager.java +++ b/src/Classes/DatabasesManager.java @@ -14,56 +14,96 @@ public class DatabasesManager { private final File databasesFile; // The file where the databases and their passwords are stored - private final Map databases; // A map holding the database names as keys and their hashed passwords as values - private final Sha256 sha256 = new Sha256(); // Instance of the Sha256 class for password hashing + private final Map databases; // A map holding the database names as keys and their info as values + private final Sha256 sha256 = new Sha256(); - // Constructor initializing the file and loading the existing databases public DatabasesManager(File databasesFile) { this.databasesFile = databasesFile; - this.databases = loadDatabases(); // Load existing databases from file + this.databases = new HashMap<>(); // Initialize the map before the try-catch block + if (!databasesFile.exists()) { + try { + databasesFile.createNewFile(); + saveDatabases(); // Sauvegarder une base de données vide + } catch (IOException e) { + e.printStackTrace(); + } + } else { + this.databases.putAll(loadDatabases()); + } } - // Function to verify if the provided password matches the stored password for a database public boolean verifyDatabase(String dbName, String password) { - String hashedPassword = sha256.calculateHash(password); // Hash the provided password - // Check if the database exists and the hashed password matches the stored one - return databases.containsKey(dbName) && databases.get(dbName).equals(hashedPassword); + DatabaseInfo dbInfo = databases.get(dbName); + if (dbInfo == null) { + return false; + } + String hashedPassword = sha256.calculateHash(password); + return hashedPassword.equals(dbInfo.getHashedPassword()); } - // Function to create a new database with a hashed password - public void createDatabase(String dbName, String password) { - // If the database already exists, throw an exception - if (databases.containsKey(dbName)) { - throw new IllegalArgumentException("Database already exists."); - } - // Hash the password and add the new database to the map + public void createDatabase(String dbName, String password, String algorithm) { String hashedPassword = sha256.calculateHash(password); - databases.put(dbName, hashedPassword); - saveDatabases(); // Save the updated databases list to the file + DatabaseInfo dbInfo = new DatabaseInfo(hashedPassword, algorithm); + databases.put(dbName, dbInfo); + saveDatabases(); } - // Function to load the databases from the JSON file - public Map loadDatabases() { - // If the file doesn't exist, return an empty map - if (!databasesFile.exists()) return new HashMap<>(); + public Map loadDatabases() { + if (!databasesFile.exists()) { + return new HashMap<>(); + } try (FileReader reader = new FileReader(databasesFile)) { - // Use Gson to parse the JSON file into a map of database names and passwords - Gson gson = new Gson(); - Type type = new TypeToken>() {}.getType(); // Define the type for the map - return gson.fromJson(reader, type); // Return the map of databases + Type type = new TypeToken>() {}.getType(); + return new Gson().fromJson(reader, type); } catch (IOException e) { - return new HashMap<>(); // Return an empty map if there was an error reading the file + e.printStackTrace(); + return new HashMap<>(); } } - // Function to save the databases and their hashed passwords to the JSON file private void saveDatabases() { try (FileWriter writer = new FileWriter(databasesFile)) { - // Use Gson to convert the map of databases to a JSON format and write it to the file - Gson gson = new GsonBuilder().setPrettyPrinting().create(); - gson.toJson(databases, writer); + new GsonBuilder().setPrettyPrinting().create().toJson(databases, writer); } catch (IOException e) { - e.printStackTrace(); // Print the error if there is an issue writing to the file + e.printStackTrace(); + } + } + + public void encryptAllSites(EncryptionStack encryptionStack) { + for (Map.Entry entry : databases.entrySet()) { + String dbName = entry.getKey(); + DatabaseInfo dbInfo = entry.getValue(); + File siteFile = new File(dbName + ".json"); + if (siteFile.exists()) { + try { + String content = new String(java.nio.file.Files.readAllBytes(siteFile.toPath())); + String encryptedContent = encryptionStack.encrypt(content); + try (FileWriter writer = new FileWriter(siteFile)) { + writer.write(encryptedContent); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + // Inner class to hold database information + public static class DatabaseInfo { + private final String hashedPassword; + private final String algorithm; + + public DatabaseInfo(String hashedPassword, String algorithm) { + this.hashedPassword = hashedPassword; + this.algorithm = algorithm; + } + + public String getHashedPassword() { + return hashedPassword; + } + + public String getAlgorithm() { + return algorithm; } } -} +} \ No newline at end of file diff --git a/src/Classes/EncryptionAlgorithm.java b/src/Classes/EncryptionAlgorithm.java new file mode 100644 index 0000000..cf70914 --- /dev/null +++ b/src/Classes/EncryptionAlgorithm.java @@ -0,0 +1,7 @@ +package Classes; + +public interface EncryptionAlgorithm { + void init(String key); + String encrypt(String data); + String decrypt(String data); +} \ No newline at end of file diff --git a/src/Classes/EncryptionStack.java b/src/Classes/EncryptionStack.java new file mode 100644 index 0000000..d7821c0 --- /dev/null +++ b/src/Classes/EncryptionStack.java @@ -0,0 +1,28 @@ +package Classes; + +import java.util.ArrayList; +import java.util.List; + +public class EncryptionStack { + private final List algorithms = new ArrayList<>(); + + public void addAlgorithm(EncryptionAlgorithm algorithm) { + algorithms.add(algorithm); + } + + public String encrypt(String data) { + String result = data; + for (EncryptionAlgorithm algorithm : algorithms) { + result = algorithm.encrypt(result); + } + return result; + } + + public String decrypt(String data) { + String result = data; + for (int i = algorithms.size() - 1; i >= 0; i--) { + result = algorithms.get(i).decrypt(result); + } + return result; + } +} \ No newline at end of file diff --git a/src/Classes/Enigma/Enigma.java b/src/Classes/Enigma/Enigma.java index 39aa0fe..6eaf455 100644 --- a/src/Classes/Enigma/Enigma.java +++ b/src/Classes/Enigma/Enigma.java @@ -1,52 +1,64 @@ package Classes.Enigma; -public class Enigma { - private Rotors rotors = new Rotors(); // Rotors component - private Reflector reflector = new Reflector(); // Reflector component - private Plugboard plugboard = new Plugboard(); // Plugboard component +import Classes.EncryptionAlgorithm; + +public class Enigma implements EncryptionAlgorithm { + private Rotors rotors = new Rotors(); // Rotors component of the Enigma machine + private Reflector reflector = new Reflector(); // Reflector component of the Enigma machine + private Plugboard plugboard = new Plugboard(); // Plugboard component of the Enigma machine public Enigma() { + // Default constructor } public Enigma(Rotors rotors, Reflector reflector, Plugboard plugboard) { + // Constructor with parameters to initialize the components this.rotors = rotors; this.reflector = reflector; this.plugboard = plugboard; } - public Rotors getRotors() { - return rotors; // Return the rotors component - } - - public Reflector getReflector() { - return reflector; // Return the reflector component - } - - public Plugboard getPlugboard() { - return plugboard; // Return the plugboard component + @Override + public void init(String key) { + // Initialize the Enigma machine with the given key + // This could involve setting the initial positions of the rotors, etc. } + @Override public String encrypt(String message) { - StringBuilder encryptedMessage = new StringBuilder(); - for (char c : message.toCharArray()) { - if (Character.isLetter(c)) { - c = Character.toUpperCase(c); // Convert to uppercase - c = plugboard.swap(c); // Swap using plugboard - c = rotors.rotate(c); // Rotate through rotors - c = reflector.reflect(c); // Reflect the character - c = rotors.rotateBack(c); // Rotate back through rotors - c = plugboard.swap(c); // Swap using plugboard again + StringBuilder encryptedMessage = new StringBuilder(); // StringBuilder to build the encrypted message + for (char c : message.toCharArray()) { // Iterate through each character in the message + if (Character.isLetter(c)) { // Process only letters + c = Character.toUpperCase(c); // Convert character to uppercase + c = plugboard.swap(c); // Swap character using the plugboard + c = rotors.rotate(c); // Rotate character through the rotors + c = reflector.reflect(c); // Reflect character using the reflector + c = rotors.rotateBack(c); // Rotate character back through the rotors + c = plugboard.swap(c); // Swap character again using the plugboard if (Character.isLowerCase(message.charAt(encryptedMessage.length()))) { - c = Character.toLowerCase(c); // Convert back to lowercase if needed + c = Character.toLowerCase(c); // Convert back to lowercase if original character was lowercase } } - encryptedMessage.append(c); // Append the encrypted character + encryptedMessage.append(c); // Append the processed character to the encrypted message } - return encryptedMessage.toString(); + return encryptedMessage.toString(); // Return the final encrypted message } + @Override public String decrypt(String message) { - rotors.resetToInitialPosition(); // Reset rotors to initial positions - return encrypt(message); // Decrypt by re-encrypting + rotors.resetToInitialPosition(); // Reset rotors to their initial position + return encrypt(message); // Decrypt by re-encrypting the message + } + + public Rotors getRotors() { + return rotors; // Getter for rotors + } + + public Reflector getReflector() { + return reflector; // Getter for reflector + } + + public Plugboard getPlugboard() { + return plugboard; // Getter for plugboard } } \ No newline at end of file diff --git a/src/Classes/Menu.java b/src/Classes/Menu.java index cf95fb3..361c8ce 100644 --- a/src/Classes/Menu.java +++ b/src/Classes/Menu.java @@ -1,137 +1,153 @@ package Classes; import java.io.File; +import java.util.List; +import java.util.Map; import java.util.Scanner; public class Menu { - // Main function, starting point of the program public static void main(String[] args) { - // Create a scanner object for user input Scanner scanner = new Scanner(System.in); - // File where the database information is stored File databasesFile = new File("databases.json"); - // Initialize the database manager - DatabasesManager dbManager = new DatabasesManager(databasesFile); - - // Display a welcome message - System.out.println("Welcome to the Encryption/Decryption Program"); - // Start an infinite loop to show the main menu + while (true) { - // Display the options in the main menu - System.out.println("Choose an option:"); + System.out.println("\nChoose an option:"); System.out.println("1. Choose an existing database"); System.out.println("2. Create a new database"); System.out.println("3. Exit"); - // Read user choice - int dbChoice = scanner.nextInt(); - scanner.nextLine(); // Clear buffer - - // Process the user choice using a switch statement - switch (dbChoice) { - case 1 -> handleExistingDatabase(scanner, dbManager); // Handle selecting an existing database - case 2 -> handleNewDatabase(scanner, dbManager); // Handle creating a new database - case 3 -> { // Exit the program + int choice = scanner.nextInt(); + scanner.nextLine(); + + switch (choice) { + case 1 -> handleExistingDatabase(scanner); + case 2 -> handleNewDatabase(scanner); + case 3 -> { System.out.println("Exiting program. Goodbye!"); - return; // Exit the main method and the program + return; } - default -> System.out.println("Invalid choice. Please try again."); // Invalid choice + default -> System.out.println("Invalid choice. Please try again."); } } } - // Function to handle the case when the user wants to choose an existing database - private static void handleExistingDatabase(Scanner scanner, DatabasesManager dbManager) { - // Ask for the name of the database - System.out.println("Enter the name of the database:"); - String dbName = scanner.nextLine(); - // Ask for the password of the database - System.out.println("Enter the password:"); - String inputPassword = scanner.nextLine(); - - // Check if the database name and password are correct - if (dbManager.verifyDatabase(dbName, inputPassword)) { - System.out.println("Successfully connected to the database: " + dbName); - // Create a SiteManager for managing the database's sites - SiteManager siteManager = new SiteManager(new File(dbName + ".json")); - // Display the main action menu for the site manager - mainActionMenu(scanner, siteManager); - } else { - // Inform the user if the credentials are incorrect - System.out.println("Incorrect database name or password."); + private static void handleExistingDatabase(Scanner scanner) { + System.out.println("Enter database filename:"); + String filename = scanner.nextLine(); + File dbFile = new File(filename + ".json"); + + if (!dbFile.exists()) { + System.out.println("Database does not exist."); + return; } - } - // Function to handle the case when the user wants to create a new database - private static void handleNewDatabase(Scanner scanner, DatabasesManager dbManager) { - // Ask for the name of the new database - System.out.println("Enter the name of the new database:"); - String dbName = scanner.nextLine(); - - // Ask the user to choose a password option - System.out.println("Choose a password option:"); - System.out.println("1. Enter a custom password"); - System.out.println("2. Generate a random password"); - // Read user choice for password generation - int passwordChoice = scanner.nextInt(); - scanner.nextLine(); // Clear buffer - - // Generate or ask for a custom password based on the user's choice - String password = switch (passwordChoice) { - case 1 -> { - System.out.println("Enter your custom password:"); - yield scanner.nextLine(); // Return the custom password - } - case 2 -> { - // Generate a random password and display it - String generatedPassword = PasswordUtils.generateRandomPassword(12); - System.out.println("Generated password: " + generatedPassword); - yield generatedPassword; // Return the generated password - } - default -> { - System.out.println("Invalid choice. Defaulting to generated password."); - yield PasswordUtils.generateRandomPassword(12); // Default to random password + SiteManager siteManager = new SiteManager(dbFile); + siteManager.setEncryptionAlgorithm("Enigma"); + + while (true) { + System.out.println("\nSite Management Menu:"); + System.out.println("1. Add new site"); + System.out.println("2. Modify site"); + System.out.println("3. Delete site"); + System.out.println("4. View all sites"); + System.out.println("5. Return to main menu"); + + int choice = scanner.nextInt(); + scanner.nextLine(); + + switch (choice) { + case 1 -> addSite(scanner, siteManager); + case 2 -> modifySite(scanner, siteManager); + case 3 -> deleteSite(scanner, siteManager); + case 4 -> viewSites(siteManager); + case 5 -> { + return; + } + default -> System.out.println("Invalid choice. Please try again."); } - }; + } + } + + private static void handleNewDatabase(Scanner scanner) { + System.out.println("Enter new database filename:"); + String filename = scanner.nextLine(); + File dbFile = new File(filename + ".json"); + + if (dbFile.exists()) { + System.out.println("Database already exists."); + return; + } + + try { + SiteManager siteManager = new SiteManager(dbFile); + siteManager.setEncryptionAlgorithm("Enigma"); + System.out.println("Database created successfully."); + } catch (Exception e) { + System.out.println("Error creating database: " + e.getMessage()); + } + } + + private static void addSite(Scanner scanner, SiteManager siteManager) { + System.out.println("Enter site name:"); + String siteName = scanner.nextLine(); + + System.out.println("Enter username:"); + String username = scanner.nextLine(); + + System.out.println("Enter password:"); + String password = scanner.nextLine(); - // Create the new database with the chosen name and password - dbManager.createDatabase(dbName, password); + try { + siteManager.addSite(siteName, username, password); + System.out.println("Site added successfully."); + } catch (Exception e) { + System.out.println("Error adding site: " + e.getMessage()); + } + } - // Create a SiteManager for the new database - SiteManager siteManager = new SiteManager(new File(dbName + ".json")); + private static void modifySite(Scanner scanner, SiteManager siteManager) { + System.out.println("Enter site name to modify:"); + String siteName = scanner.nextLine(); + + System.out.println("Enter new username (or press Enter to skip):"); + String newUsername = scanner.nextLine(); + + System.out.println("Enter new password (or press Enter to skip):"); + String newPassword = scanner.nextLine(); - // Display the main action menu for the site manager - mainActionMenu(scanner, siteManager); + try { + siteManager.modifySite(siteName, + newUsername.isEmpty() ? null : newUsername, + newPassword.isEmpty() ? null : newPassword); + System.out.println("Site modified successfully."); + } catch (Exception e) { + System.out.println("Error modifying site: " + e.getMessage()); + } } - // Function to display the main action menu for managing sites and performing actions - private static void mainActionMenu(Scanner scanner, SiteManager siteManager) { - // Ensure an encryption algorithm is selected (commented out here) - // siteManager.chooseEncryptionAlgorithm(scanner); + private static void deleteSite(Scanner scanner, SiteManager siteManager) { + System.out.println("Enter site name to delete:"); + String siteName = scanner.nextLine(); - // Start an infinite loop to show the action menu - while (true) { - // Display the options for actions in the site manager - System.out.println("Choose an action:"); - System.out.println("1. Manage sites"); - System.out.println("2. Decrypt a password"); - System.out.println("3. Back to main menu"); - // Read user choice for the action - int action = scanner.nextInt(); - scanner.nextLine(); // Clear buffer - - // Process the action choice using a switch statement - switch (action) { - case 1 -> siteManager.manageSites(scanner, siteManager.encryptionAlgorithm); // Manage sites, passing the encryption algorithm - case 2 -> { // Decrypt a password - siteManager.chooseEncryptionAlgorithm(scanner); // Choose the encryption algorithm - siteManager.handleEncryptionDecryption(scanner); // Handle encryption/decryption process - } - case 3 -> { // Return to the main menu - System.out.println("Returning to the main menu..."); - return; // Exit the current loop and return to the main menu - } - default -> System.out.println("Invalid choice. Please try again."); // Invalid choice - } + try { + siteManager.deleteSite(siteName); + System.out.println("Site deleted successfully."); + } catch (Exception e) { + System.out.println("Error deleting site: " + e.getMessage()); + } + } + + private static void viewSites(SiteManager siteManager) { + List> sites = siteManager.getSites(); + if (sites.isEmpty()) { + System.out.println("No sites found."); + return; + } + + System.out.println("\nStored Sites:"); + for (Map site : sites) { + System.out.println("\nSite Name: " + site.get("siteName")); + System.out.println("Username: " + site.get("username")); + System.out.println("Password: " + site.get("password")); } } -} +} \ No newline at end of file diff --git a/src/Classes/RC4.java b/src/Classes/RC4.java index dd9f3c7..2a8cd25 100644 --- a/src/Classes/RC4.java +++ b/src/Classes/RC4.java @@ -1,6 +1,6 @@ package Classes; -public class RC4 { +public class RC4 implements EncryptionAlgorithm { private int[] S = new int[256]; private int[] T = new int[256]; diff --git a/src/Classes/ROTX.java b/src/Classes/ROTX.java index 1f77f24..765baa0 100644 --- a/src/Classes/ROTX.java +++ b/src/Classes/ROTX.java @@ -1,58 +1,50 @@ package Classes; -public class ROTX { +public class ROTX implements EncryptionAlgorithm { + private int x; // The rotation amount for the ROTX algorithm - // Encryption function - public static String encryptROT(String input, int x) { - StringBuilder encryptedString = new StringBuilder(); + public ROTX(int x) { + this.x = x; // Initialize the rotation amount + } - // Normalisation of X to be in the interval [0, 25] - x = x % 26; // ensure that x is in [0, 25] - if (x < 0) { - x += 26; // IF X is negative we adjust it to be positive - } - // Iterate through each character of the string - for (char character : input.toCharArray()) { - // Check if the character is a letter (uppercase or lowercase) - if (Character.isLetter(character)) { - // Determine the base depending on whether the letter is uppercase or lowercase - char base = Character.isLowerCase(character) ? 'a' : 'A'; - // Apply ROT(X) encryption - char encryptedChar = (char) ((character - base + x) % 26 + base); - encryptedString.append(encryptedChar); - } else { - // Append non-alphabetic characters without changing them - encryptedString.append(character); - } + @Override + public void init(String key) { + try { + this.x = Integer.parseInt(key); // Parse the key as an integer + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Key must be an integer for ROTX"); // Throw an exception if the key is not a valid integer } + } - return encryptedString.toString(); + @Override + public String encrypt(String data) { + return encryptROT(data, x); // Encrypt the data using the ROTX algorithm } - // Decryption function - public static String decryptROT(String input, int x) { - StringBuilder decryptedString = new StringBuilder(); + @Override + public String decrypt(String data) { + return decryptROT(data, x); // Decrypt the data using the ROTX algorithm + } - // Normalisation of X to be in the interval [0, 25] - x = x % 26; // ensure that x is in [0, 25] + public static String encryptROT(String input, int x) { + StringBuilder encryptedString = new StringBuilder(); // StringBuilder to build the encrypted string + x = x % 26; // Ensure the rotation amount is within the range of 0-25 if (x < 0) { - x += 26; // IF X is negative we adjust it to be positive + x += 26; // Adjust for negative rotation amounts } - // Iterate through each character of the string - for (char character : input.toCharArray()) { - // Check if the character is a letter (uppercase or lowercase) - if (Character.isLetter(character)) { - // Determine the base depending on whether the letter is uppercase or lowercase - char base = Character.isLowerCase(character) ? 'a' : 'A'; - // Apply ROT(X) decryption (subtract x instead of adding it) - char decryptedChar = (char) ((character - base - x + 26) % 26 + base); - decryptedString.append(decryptedChar); + for (char character : input.toCharArray()) { // Iterate over each character in the input string + if (Character.isLetter(character)) { // Check if the character is a letter + char base = Character.isLowerCase(character) ? 'a' : 'A'; // Determine the base character ('a' for lowercase, 'A' for uppercase) + char encryptedChar = (char) ((character - base + x) % 26 + base); // Calculate the encrypted character + encryptedString.append(encryptedChar); // Append the encrypted character to the result } else { - // Append non-alphabetic characters without changing them - decryptedString.append(character); + encryptedString.append(character); // Append non-letter characters unchanged } } + return encryptedString.toString(); // Return the encrypted string + } - return decryptedString.toString(); + public static String decryptROT(String input, int x) { + return encryptROT(input, -x); // Decrypt by encrypting with the negative rotation amount } -} +} \ No newline at end of file diff --git a/src/Classes/SiteManager.java b/src/Classes/SiteManager.java index 90b1924..6c9f683 100644 --- a/src/Classes/SiteManager.java +++ b/src/Classes/SiteManager.java @@ -1,264 +1,215 @@ package Classes; -import Classes.Enigma.Enigma; -import Classes.Enigma.Plugboard; -import Classes.Enigma.Reflector; -import Classes.Enigma.Rotors; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; +import Classes.Enigma.*; +import com.google.gson.*; +import com.google.gson.reflect.TypeToken; -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; +import java.io.*; +import java.lang.reflect.Type; import java.util.*; public class SiteManager { - private final File dbFile; // The file where the site data is stored - private final List> sites; // List of sites, each represented as a map of properties - public String encryptionAlgorithm; // Selected encryption algorithm + private final File dbFile; + private final List> sites; + private String encryptionAlgorithm; + private final Map testParameters; + private boolean isTestMode; - // Constructor initializing the database file and loading sites from the file public SiteManager(File dbFile) { this.dbFile = dbFile; + this.testParameters = new HashMap<>(); + this.isTestMode = false; + initializeDatabase(); this.sites = loadSites(); } - // Function to manage the sites (add, modify, delete, or exit) - public void manageSites(Scanner scanner, String encryptionAlgo) { - chooseEncryptionAlgorithm(scanner); // Let the user choose an encryption algorithm - - while (true) { - // Display menu options - System.out.println("Choose an action:"); - System.out.println("1. Add a site"); - System.out.println("2. Modify a site"); - System.out.println("3. Delete a site"); - System.out.println("4. Exit"); - int choice = scanner.nextInt(); - scanner.nextLine(); // Clear buffer - - // Handle user's choice - switch (choice) { - case 1 -> addSite(scanner); // Add a new site - case 2 -> modifySite(scanner); // Modify an existing site - case 3 -> deleteSite(scanner); // Delete a site - case 4 -> { - return; // Exit the site management menu - } - default -> System.out.println("Invalid choice."); + private void initializeDatabase() { + if (!dbFile.exists()) { + try { + dbFile.createNewFile(); + saveSites(); + } catch (IOException e) { + throw new RuntimeException("Failed to initialize database", e); } } } - // Function to handle encryption/decryption of passwords - public void handleEncryptionDecryption(Scanner scanner) { - System.out.println("Choose an action:"); - - // Offer the user to decrypt a password - System.out.println("1. Decrypt a password"); - int choice = scanner.nextInt(); - scanner.nextLine(); // Clear buffer - - if (choice == 1) { - // Ask for the site name to decrypt the password for - System.out.println("Enter site name:"); - String siteName = scanner.nextLine(); - Optional> siteOpt = sites.stream() - .filter(site -> site.get("siteName").equals(siteName)) - .findFirst(); - - // Check if the site exists - if (siteOpt.isPresent()) { - Map site = siteOpt.get(); - String encryptedPassword = site.get("password"); - - // Decrypt the password and display it - String decryptedPassword = decryptPassword(encryptedPassword, scanner); - System.out.println("Decrypted password: " + decryptedPassword); - } else { - System.out.println("Site not found."); - } - } else { - System.out.println("Invalid choice."); + public void configureTestMode(boolean enabled, String algorithm, Object... params) { + this.isTestMode = enabled; + this.encryptionAlgorithm = algorithm; + if (params != null && params.length > 0) { + configureTestParameters(algorithm, params); } } - // Function to encrypt a password based on the selected algorithm - private String encryptPassword(String password, Scanner scanner) { - return switch (encryptionAlgorithm) { - case "Enigma" -> { - // Configuration for the Enigma machine - System.out.print("Enter the configuration for Enigma - Rotors (example: I II III): "); - String rotorsConfig = scanner.nextLine().trim(); - Rotors rotors = new Rotors(); - - System.out.print("Enter the configuration for the Reflector (example: B): "); - String reflectorConfig = scanner.nextLine().trim(); - Reflector reflector = new Reflector(); - - System.out.print("Enter the plugboard configuration (example: AB CD EF): "); - String plugboardConfig = scanner.nextLine().trim(); - Plugboard plugboard = new Plugboard(); - - // Create the Enigma machine instance and encrypt the password - Enigma enigmaMachine = new Enigma(rotors, reflector, plugboard); - yield enigmaMachine.encrypt(password); - } - case "RC4" -> AlgorithmChoice.encryptRC4(password); // RC4 encryption - case "ROT" -> { - System.out.println("Enter the value of X for ROT(X):"); - int x = scanner.nextInt(); - scanner.nextLine(); - yield AlgorithmChoice.encryptROT(password, x); // ROT encryption - } - case "Vigenere" -> { - System.out.println("Enter the key for Vigenère:"); - String key = scanner.nextLine(); - yield AlgorithmChoice.encryptVigenere(password, key); // Vigenère encryption + private void configureTestParameters(String algorithm, Object... params) { + testParameters.clear(); + if ("Enigma".equals(algorithm)) { + if (params.length != 3) { + throw new IllegalArgumentException("Enigma requires rotors, reflector, and plugboard parameters"); } - default -> throw new IllegalStateException("Unknown encryption algorithm: " + encryptionAlgorithm); // Error for unknown algorithm - }; - } - - // Function to decrypt a password based on the selected algorithm - private String decryptPassword(String encryptedPassword, Scanner scanner) { - return switch (encryptionAlgorithm) { - case "Enigma" -> AlgorithmChoice.decryptEnigma(encryptedPassword); // Enigma decryption - case "RC4" -> AlgorithmChoice.decryptRC4(encryptedPassword); // RC4 decryption - case "ROT" -> { - System.out.println("Enter the value of X for ROT(X):"); - int x = scanner.nextInt(); - scanner.nextLine(); - yield AlgorithmChoice.decryptROT(encryptedPassword, x); // ROT decryption + Rotors rotors = new Rotors(); + if (params[0] instanceof char[]) { + rotors.setPositions((char[]) params[0]); } - case "Vigenere" -> { - System.out.println("Enter the key for Vigenère:"); - String key = scanner.nextLine(); - if (key == null || key.isEmpty()) { - throw new IllegalArgumentException("Key for Vigenère cannot be null or empty"); + testParameters.put("rotors", rotors); + testParameters.put("reflector", new Reflector()); + Plugboard plugboard = new Plugboard(); + if (params[2] instanceof String[][]) { + for (String[] pair : (String[][]) params[2]) { + if (pair.length == 2) { + plugboard.connect(pair[0].charAt(0), pair[1].charAt(0)); + } } - yield AlgorithmChoice.decryptVigenere(encryptedPassword, key); // Vigenère decryption - } - default -> throw new IllegalStateException("Unknown encryption algorithm: " + encryptionAlgorithm); // Error for unknown algorithm - }; - } - - // Function to choose an encryption algorithm - public void chooseEncryptionAlgorithm(Scanner scanner) { - System.out.println("Choose an encryption algorithm:"); - System.out.println("1. Enigma"); - System.out.println("2. RC4"); - System.out.println("3. ROT(X)"); - System.out.println("4. Vigenère"); - - // Read the user's choice - int algoChoice = scanner.nextInt(); - scanner.nextLine(); // Clear buffer - - // Set the encryption algorithm based on user's choice - encryptionAlgorithm = switch (algoChoice) { - case 1 -> "Enigma"; - case 2 -> "RC4"; - case 3 -> "ROT"; - case 4 -> "Vigenere"; - default -> { - System.out.println("Invalid choice, defaulting to ROT."); - yield "ROT"; // Default to ROT } - }; - System.out.println("Selected encryption algorithm: " + encryptionAlgorithm); + testParameters.put("plugboard", plugboard); + } } - // Function to add a new site with encrypted password public void addSite(String siteName, String username, String password) { + validateEncryptionAlgorithm(); Map site = new HashMap<>(); site.put("siteName", siteName); site.put("username", username); - site.put("password", password); - sites.add(site); // Add site to the list - saveSites(); // Save the updated sites list to file + site.put("password", encryptPassword(password, null)); + sites.add(site); + saveSites(); } - // Function to add a new site using user input - public void addSite(Scanner scanner) { - System.out.println("Enter site name:"); - String siteName = scanner.nextLine(); - System.out.println("Enter username:"); - String username = scanner.nextLine(); - System.out.println("Enter password:"); - String password = scanner.nextLine(); - - // Encrypt the password and add the site - String encryptedPassword = encryptPassword(password, scanner); - addSite(siteName, username, encryptedPassword); - } - - // Function to modify an existing site's username or password public void modifySite(String siteName, String newUsername, String newPassword) { - for (Map site : sites) { - if (site.get("siteName").equals(siteName)) { - // Update the username and/or password if provided + sites.stream() + .filter(site -> site.get("siteName").equals(siteName)) + .findFirst() + .ifPresent(site -> { if (newUsername != null && !newUsername.isEmpty()) { site.put("username", newUsername); } if (newPassword != null && !newPassword.isEmpty()) { - site.put("password", newPassword); + site.put("password", encryptPassword(newPassword, null)); } - saveSites(); // Save the updated list of sites - return; - } - } - throw new IllegalArgumentException("Site not found: " + siteName); // Site not found + saveSites(); + }); } - // Function to modify a site using user input - public void modifySite(Scanner scanner) { - System.out.println("Enter the site name to modify:"); - String siteName = scanner.nextLine(); - System.out.println("Enter the new username (leave empty to keep current):"); - String newUsername = scanner.nextLine(); - System.out.println("Enter the new password (leave empty to keep current):"); - String newPassword = scanner.nextLine(); - modifySite(siteName, newUsername, newPassword); // Modify the site + public void deleteSite(String siteName) { + sites.removeIf(site -> site.get("siteName").equals(siteName)); + saveSites(); } - // Function to delete a site by name - public void deleteSite(String siteName) { - sites.removeIf(site -> site.get("siteName").equals(siteName)); // Remove the site from the list - saveSites(); // Save the updated list of sites + private String encryptPassword(String password, Scanner scanner) { + validateEncryptionAlgorithm(); + if (isTestMode) { + return performTestModeEncryption(password); + } + if (scanner == null) { + scanner = new Scanner(System.in); + } + return performNormalEncryption(password, scanner); } - // Function to delete a site using user input - public void deleteSite(Scanner scanner) { - System.out.println("Enter the site name to delete:"); - String siteName = scanner.nextLine(); - deleteSite(siteName); // Delete the site + private String performTestModeEncryption(String password) { + if ("Enigma".equals(encryptionAlgorithm)) { + Rotors rotors = (Rotors) testParameters.get("rotors"); + Reflector reflector = (Reflector) testParameters.get("reflector"); + Plugboard plugboard = (Plugboard) testParameters.get("plugboard"); + + if (rotors == null || reflector == null || plugboard == null) { + throw new IllegalStateException("Enigma components not properly configured for test mode"); + } + + Enigma enigmaMachine = new Enigma(rotors, reflector, plugboard); + return enigmaMachine.encrypt(password); + } + throw new IllegalStateException("Unknown encryption algorithm: " + encryptionAlgorithm); } - // Function to load sites from the JSON file - public List> loadSites() { - if (!dbFile.exists()) return new ArrayList<>(); // Return an empty list if the file doesn't exist + private String performNormalEncryption(String password, Scanner scanner) { + if ("Enigma".equals(encryptionAlgorithm)) { + Rotors rotors = new Rotors(); + Reflector reflector = new Reflector(); + Plugboard plugboard = new Plugboard(); + + System.out.print("Enter the initial positions for rotors (3 letters, e.g., ABC): "); + String rotorPositions = scanner.nextLine().trim().toUpperCase(); + if (rotorPositions.length() != 3) { + throw new IllegalArgumentException("Must provide exactly 3 positions for rotors"); + } + rotors.setPositions(rotorPositions.toCharArray()); + + System.out.print("Enter plugboard connections (pairs of letters separated by space, e.g., AB CD EF): "); + String plugboardConfig = scanner.nextLine().trim().toUpperCase(); + if (!plugboardConfig.isEmpty()) { + String[] pairs = plugboardConfig.split(" "); + for (String pair : pairs) { + if (pair.length() == 2) { + plugboard.connect(pair.charAt(0), pair.charAt(1)); + } + } + } + + Enigma enigmaMachine = new Enigma(rotors, reflector, plugboard); + return enigmaMachine.encrypt(password); + } + throw new IllegalStateException("Unknown encryption algorithm: " + encryptionAlgorithm); + } + + private List> loadSites() { + if (!dbFile.exists()) return new ArrayList<>(); try (FileReader fileReader = new FileReader(dbFile)) { - // Parse the file content using Gson - Gson gson = new Gson(); - List> sitesList = gson.fromJson(fileReader, ArrayList.class); - return sitesList != null ? sitesList : new ArrayList<>(); // Return the loaded sites or an empty list if parsing fails - } catch (IOException e) { - System.out.println("Error reading file: " + e.getMessage()); - return new ArrayList<>(); // Return an empty list in case of error + Type mapType = new TypeToken>>(){}.getType(); + List> loadedSites = new Gson().fromJson(fileReader, mapType); + return loadedSites != null ? loadedSites : new ArrayList<>(); + } catch (IOException | JsonSyntaxException e) { + throw new RuntimeException("Error reading sites from file", e); } } - // Function to save sites to the JSON file public void saveSites() { try (FileWriter fileWriter = new FileWriter(dbFile)) { - // Write the sites list to the file in JSON format - Gson gson = new GsonBuilder().setPrettyPrinting().create(); - gson.toJson(sites, fileWriter); + new GsonBuilder().setPrettyPrinting().create().toJson(sites, fileWriter); } catch (IOException e) { - System.out.println("Error saving sites: " + e.getMessage()); + throw new RuntimeException("Error saving sites to file", e); + } + } + + private void validateEncryptionAlgorithm() { + if (encryptionAlgorithm == null) { + throw new IllegalStateException("Encryption algorithm is not set"); + } + } + + public List> getSites() { + return new ArrayList<>(sites); + } + + public void setEncryptionAlgorithm(String algorithm) { + this.encryptionAlgorithm = algorithm; + } + public void setTestMode(boolean enabled) { + this.isTestMode = enabled; + } + + public void setTestParameters(String algorithm) { + this.encryptionAlgorithm = algorithm; + } + + public void encryptSites(String algorithm) { + if ("Enigma".equals(algorithm)) { + List> encryptedSites = new ArrayList<>(); + for (Map site : sites) { + Map encryptedSite = new HashMap<>(site); + String password = site.get("password"); + if (password != null && !password.isEmpty()) { + encryptedSite.put("password", encryptPassword(password, null)); + } + encryptedSites.add(encryptedSite); + } + sites.clear(); + sites.addAll(encryptedSites); + saveSites(); + } else { + throw new IllegalArgumentException("Unsupported encryption algorithm: " + algorithm); } } -} +} \ No newline at end of file diff --git a/src/Classes/VigenereAlgo.java b/src/Classes/VigenereAlgo.java index c43039e..122322c 100644 --- a/src/Classes/VigenereAlgo.java +++ b/src/Classes/VigenereAlgo.java @@ -1,131 +1,106 @@ package Classes; +public class VigenereAlgo implements EncryptionAlgorithm { + private String key; -public class VigenereAlgo { - - - String plainText = "TEST"; - - String key = "LONGKEY"; - // Call encryption function and display the result - String encryptedText = encrypt(plainText, key); + @Override + public void init(String key) { + if (!isValidKey(key)) { // Check if the key is valid + throw new IllegalArgumentException("Key must contain only alphabetic characters."); + } + this.key = key; // Initialize the key + } + public void setKey(String key) { + if (!isValidKey(key)) { // Check if the key is valid + throw new IllegalArgumentException("Key must contain only alphabetic characters."); + } + this.key = key; // Set the key + } - // Call decryption function and display the result - String decryptedText = decrypt(encryptedText, key); + @Override + public String encrypt(String plainText) { + return encryptVigenere(plainText, key); // Encrypt the plain text using Vigenere cipher + } + @Override + public String decrypt(String encryptedText) { + return decryptVigenere(encryptedText, key); // Decrypt the encrypted text using Vigenere cipher + } - // Validate that the key does not contain numbers private static boolean isValidKey(String key) { for (char c : key.toCharArray()) { - if (Character.isDigit(c)) { - return false; // Reject if the key contains any digit + if (Character.isDigit(c)) { // Check if the key contains any digits + return false; } } - return true; // Key is valid if it contains no digits + return true; // Key is valid if it contains only alphabetic characters } - // Encrypt the plaintext using the Vigenere cipher algorithm - public static String encrypt(String plainText, String key) { - if (!isValidKey(key)) { - throw new IllegalArgumentException("Key must contain only alphabetic characters."); - } - + private static String encryptVigenere(String plainText, String key) { StringBuilder encryptedText = new StringBuilder(); - - // Clean the key to contain only alphabetical characters - key = cleanKey(key); - // Generate a full-length key that matches the length of the plaintext - key = generateFullKey(plainText, key); + key = cleanKey(key); // Clean the key + key = generateFullKey(plainText, key); // Generate the full key for (int i = 0, keyIndex = 0; i < plainText.length(); i++) { char pi = plainText.charAt(i); - - // Only encrypt alphabetic characters - if (Character.isLetter(pi)) { + if (Character.isLetter(pi)) { // Check if the character is a letter boolean isUpperCase = Character.isUpperCase(pi); char normalizedPi = Character.toLowerCase(pi); char ki = key.charAt(keyIndex++); - // Encryption formula: Ci = (Pi + Ki) mod 26 - char ci = (char) (((normalizedPi - 'a' + ki - 'a') % 26) + 'a'); - encryptedText.append(isUpperCase ? Character.toUpperCase(ci) : ci); + char ci = (char) (((normalizedPi - 'a' + ki - 'a') % 26) + 'a'); // Encrypt the character + encryptedText.append(isUpperCase ? Character.toUpperCase(ci) : ci); // Append the encrypted character } else { - // Keep non-alphabetic characters unchanged - encryptedText.append(pi); + encryptedText.append(pi); // Append non-letter characters as is } } - - return encryptedText.toString(); + return encryptedText.toString(); // Return the encrypted text } - // Decrypt the ciphertext using the Vigenere cipher algorithm - public static String decrypt(String encryptedText, String key) { - if (!isValidKey(key)) { - throw new IllegalArgumentException("Key must contain only alphabetic characters."); - } - + private static String decryptVigenere(String encryptedText, String key) { StringBuilder decryptedText = new StringBuilder(); - - // Clean the key to contain only alphabetical characters - key = cleanKey(key); - // Generate a full-length key that matches the length of the ciphertext - key = generateFullKey(encryptedText, key); + key = cleanKey(key); // Clean the key + key = generateFullKey(encryptedText, key); // Generate the full key for (int i = 0, keyIndex = 0; i < encryptedText.length(); i++) { char ci = encryptedText.charAt(i); - - // Only decrypt alphabetic characters - if (Character.isLetter(ci)) { + if (Character.isLetter(ci)) { // Check if the character is a letter boolean isUpperCase = Character.isUpperCase(ci); char normalizedCi = Character.toLowerCase(ci); char ki = key.charAt(keyIndex++); - // Decryption formula: Pi = (Ci - Ki + 26) mod 26 - char pi = (char) (((normalizedCi - ki + 26) % 26) + 'a'); - decryptedText.append(isUpperCase ? Character.toUpperCase(pi) : pi); + char pi = (char) (((normalizedCi - ki + 26) % 26) + 'a'); // Decrypt the character + decryptedText.append(isUpperCase ? Character.toUpperCase(pi) : pi); // Append the decrypted character } else { - // Keep non-alphabetic characters unchanged - decryptedText.append(ci); + decryptedText.append(ci); // Append non-letter characters as is } } - - return decryptedText.toString(); + return decryptedText.toString(); // Return the decrypted text } - - // Generate a full-length key matching the text length, ignoring non-alphabetic characters public static String generateFullKey(String text, String key) { StringBuilder fullKey = new StringBuilder(); int keyLength = key.length(); int keyIndex = 0; - // go threw the text length for (int i = 0; i < text.length(); i++) { char currentChar = text.charAt(i); - if (Character.isLetter(currentChar)) { - // if keyLength > KeyIndex : troncate the keyLength to keyIndex - fullKey.append(key.charAt(keyIndex % keyLength)); + if (Character.isLetter(currentChar)) { // Check if the character is a letter + fullKey.append(key.charAt(keyIndex % keyLength)); // Append the corresponding key character keyIndex++; } } - - return fullKey.toString(); + return fullKey.toString(); // Return the full key } - - - - // Remove non-alphabetical characters from the key private static String cleanKey(String key) { StringBuilder cleanedKey = new StringBuilder(); - for (char c : key.toCharArray()) { - if (Character.isLetter(c)) { - cleanedKey.append(Character.toLowerCase(c)); + if (Character.isLetter(c)) { // Check if the character is a letter + cleanedKey.append(Character.toLowerCase(c)); // Append the lowercase letter } } - - return cleanedKey.toString(); + return cleanedKey.toString(); // Return the cleaned key } -} +} \ No newline at end of file diff --git a/src/Tests/DatabasesManagerTest.java b/src/Tests/DatabasesManagerTest.java index 555f0db..9ccb36f 100644 --- a/src/Tests/DatabasesManagerTest.java +++ b/src/Tests/DatabasesManagerTest.java @@ -1,22 +1,30 @@ package Tests; -import Classes.DatabasesManager; +import Classes.*; +import Classes.Enigma.Enigma; import org.junit.Before; import org.junit.Test; import java.io.File; import java.util.Map; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; public class DatabasesManagerTest { private DatabasesManager dbManager; private File testFile; + private EncryptionStack encryptionStack; @Before public void setUp() { - testFile = new File("src/Tests/test_databases.json"); + testFile = new File("src/Tests/assets/test_databases.json"); dbManager = new DatabasesManager(testFile); + encryptionStack = new EncryptionStack(); + encryptionStack.addAlgorithm(new RC4()); + encryptionStack.addAlgorithm(new ROTX(13)); + encryptionStack.addAlgorithm(new VigenereAlgo()); + encryptionStack.addAlgorithm(new Enigma()); if (testFile.exists()) { testFile.delete(); @@ -25,34 +33,28 @@ public void setUp() { @Test public void testCreateAndVerifyDatabase() { - String dbName = "testDb"; + String dbName = "test"; String password = "securePassword"; + String algorithm = "RC4"; - dbManager.createDatabase(dbName, password); - + dbManager.createDatabase(dbName, password, algorithm); assertTrue(dbManager.verifyDatabase(dbName, password)); - - assertFalse(dbManager.verifyDatabase(dbName, "wrongPassword")); } @Test public void testDuplicateDatabaseName() { - String dbName = "duplicateDb"; - String password = "password"; - - dbManager.createDatabase(dbName, password); + String dbName = "test"; + String password = "securePassword"; + String algorithm = "RC4"; - try { - dbManager.createDatabase(dbName, password); - fail("Expected IllegalArgumentException for duplicate database name"); - } catch (IllegalArgumentException e) { - assertEquals("Database already exists.", e.getMessage()); - } + dbManager.createDatabase(dbName, password, algorithm); + dbManager.createDatabase(dbName, password, algorithm); + assertEquals(1, dbManager.loadDatabases().size()); } @Test public void testLoadEmptyDatabases() { - Map databases = dbManager.loadDatabases(); + Map databases = dbManager.loadDatabases(); assertTrue(databases.isEmpty()); } -} +} \ No newline at end of file diff --git a/src/Tests/SiteManagerTest.java b/src/Tests/SiteManagerTest.java index 34a7c6c..5379baa 100644 --- a/src/Tests/SiteManagerTest.java +++ b/src/Tests/SiteManagerTest.java @@ -5,6 +5,7 @@ import org.junit.Test; import java.io.File; +import java.io.IOException; import java.util.List; import java.util.Map; @@ -12,50 +13,138 @@ public class SiteManagerTest { private SiteManager siteManager; - private File testFile; + private File testDbFile; @Before - public void setUp() { - testFile = new File("src/Tests/test_sites.json"); - siteManager = new SiteManager(testFile); - - if (testFile.exists()) { - testFile.delete(); - } + public void setUp() throws IOException { + // Create a new temporary file for each test + testDbFile = File.createTempFile("src/Tests/assets/test_sites", ".json"); + siteManager = new SiteManager(testDbFile); + + // Configure test mode with Enigma parameters + char[] rotorPositions = {'A', 'A', 'A'}; + String[][] plugboardConnections = {{"A", "B"}, {"C", "D"}}; + siteManager.configureTestMode(true, "Enigma", rotorPositions, new Object(), plugboardConnections); } @Test public void testAddSite() { - siteManager.addSite("example.com", "user1", "password1"); - List> sites = siteManager.loadSites(); + // Clear any existing sites + List> sites = siteManager.getSites(); + for (Map site : sites) { + siteManager.deleteSite(site.get("siteName")); + } + siteManager.addSite("TestSite", "testUser", "testPass"); + + sites = siteManager.getSites(); assertEquals(1, sites.size()); - assertEquals("example.com", sites.get(0).get("siteName")); - assertEquals("user1", sites.get(0).get("username")); - assertEquals("password1", sites.get(0).get("password")); + assertEquals("TestSite", sites.get(0).get("siteName")); + assertEquals("testUser", sites.get(0).get("username")); + assertNotNull(sites.get(0).get("password")); } @Test public void testModifySite() { - siteManager.modifySite("example.com", "newUser", "newPassword"); - - List> sites = siteManager.loadSites(); + // Clear any existing sites + List> sites = siteManager.getSites(); + for (Map site : sites) { + siteManager.deleteSite(site.get("siteName")); + } - System.out.println("Sites after modification: " + sites); + siteManager.addSite("TestSite", "testUser", "testPass"); + siteManager.modifySite("TestSite", "newUser", "newPass"); + sites = siteManager.getSites(); assertEquals(1, sites.size()); assertEquals("newUser", sites.get(0).get("username")); - assertEquals("newPassword", sites.get(0).get("password")); } - @Test public void testDeleteSite() { - siteManager.addSite("example.com", "user1", "password1"); - siteManager.deleteSite("example.com"); + // Clear any existing sites + List> sites = siteManager.getSites(); + for (Map site : sites) { + siteManager.deleteSite(site.get("siteName")); + } - List> sites = siteManager.loadSites(); + siteManager.addSite("TestSite", "testUser", "testPass"); + siteManager.deleteSite("TestSite"); + sites = siteManager.getSites(); assertTrue(sites.isEmpty()); } -} + + @Test + public void testGetSites() { + // Clear any existing sites + List> sites = siteManager.getSites(); + for (Map site : sites) { + siteManager.deleteSite(site.get("siteName")); + } + + siteManager.addSite("Site1", "user1", "pass1"); + siteManager.addSite("Site2", "user2", "pass2"); + + sites = siteManager.getSites(); + assertEquals(2, sites.size()); + } + + @Test + public void testSaveSites() { + // Clear any existing sites + List> sites = siteManager.getSites(); + for (Map site : sites) { + siteManager.deleteSite(site.get("siteName")); + } + + siteManager.addSite("TestSite", "testUser", "testPass"); + siteManager.saveSites(); + + // Create a new SiteManager instance to read from the same file + SiteManager newManager = new SiteManager(testDbFile); + newManager.configureTestMode(true, "Enigma", + new char[]{'A', 'A', 'A'}, new Object(), + new String[][]{{"A", "B"}, {"C", "D"}}); + + sites = newManager.getSites(); + assertEquals(1, sites.size()); + assertEquals("TestSite", sites.get(0).get("siteName")); + } + + @Test + public void testEncryptSites() { + // Clear any existing sites + List> sites = siteManager.getSites(); + for (Map site : sites) { + siteManager.deleteSite(site.get("siteName")); + } + + siteManager.addSite("TestSite", "testUser", "testPass"); + String originalPassword = siteManager.getSites().get(0).get("password"); + siteManager.encryptSites("Enigma"); + + sites = siteManager.getSites(); + assertNotEquals(originalPassword, sites.get(0).get("password")); + } + + @Test(expected = IllegalArgumentException.class) + public void testEncryptSitesWithUnsupportedAlgorithm() { + siteManager.encryptSites("UnsupportedAlgorithm"); + } + + @Test + public void testSetEncryptionAlgorithm() { + // Clear any existing sites + List> sites = siteManager.getSites(); + for (Map site : sites) { + siteManager.deleteSite(site.get("siteName")); + } + + siteManager.setEncryptionAlgorithm("Enigma"); + siteManager.addSite("TestSite", "testUser", "testPass"); + + sites = siteManager.getSites(); + assertNotNull(sites.get(0).get("password")); + } +} \ No newline at end of file diff --git a/src/Tests/VigenereTest.java b/src/Tests/VigenereTest.java index 94c17da..aeb472a 100644 --- a/src/Tests/VigenereTest.java +++ b/src/Tests/VigenereTest.java @@ -1,65 +1,76 @@ package Tests; import Classes.VigenereAlgo; +import org.junit.Before; import org.junit.Test; import static org.junit.Assert.*; public class VigenereTest { - private final VigenereAlgo vigenere = new VigenereAlgo(); + private VigenereAlgo vigenere; + + @Before + public void setUp() { + vigenere = new VigenereAlgo(); + } @Test public void testEncrypt_basic() { String plainText = "HELLO"; String key = "KEY"; + vigenere.setKey(key); String expectedCipherText = "RIJVS"; - assertEquals(expectedCipherText, vigenere.encrypt(plainText, key)); + assertEquals(expectedCipherText, vigenere.encrypt(plainText)); } @Test public void testDecrypt_basic() { String cipherText = "RIJVS"; String key = "KEY"; + vigenere.setKey(key); String expectedPlainText = "HELLO"; - assertEquals(expectedPlainText, vigenere.decrypt(cipherText, key)); + assertEquals(expectedPlainText, vigenere.decrypt(cipherText)); } - @Test public void testEncrypt_withLowercase() { String plainText = "hello"; String key = "key"; + vigenere.setKey(key.toUpperCase()); String expectedCipherText = "RIJVS"; - assertEquals(expectedCipherText, vigenere.encrypt(plainText.toUpperCase(), key.toUpperCase())); + assertEquals(expectedCipherText, vigenere.encrypt(plainText.toUpperCase())); } @Test public void testDecrypt_withLowercase() { String cipherText = "rijvs"; String key = "key"; + vigenere.setKey(key.toUpperCase()); String expectedPlainText = "HELLO"; - assertEquals(expectedPlainText, vigenere.decrypt(cipherText.toUpperCase(), key.toUpperCase())); + assertEquals(expectedPlainText, vigenere.decrypt(cipherText.toUpperCase())); } @Test public void testEncrypt_emptyString() { String plainText = ""; String key = "KEY"; - assertEquals("", vigenere.encrypt(plainText, key)); + vigenere.setKey(key); + assertEquals("", vigenere.encrypt(plainText)); } @Test public void testDecrypt_emptyString() { String cipherText = ""; String key = "KEY"; - assertEquals("", vigenere.decrypt(cipherText, key)); + vigenere.setKey(key); + assertEquals("", vigenere.decrypt(cipherText)); } @Test public void testGenerateFullKey() { String text = "TEST"; String key = "LONGKEY"; - String expectedKey = "LONG"; // Doit être exactement de la longueur de "TEST" + String expectedKey = "LONG"; // Must be exactly the length of "TEST" String result = VigenereAlgo.generateFullKey(text, key); assertEquals(expectedKey, result); @@ -69,32 +80,35 @@ public void testGenerateFullKey() { public void testEncrypt_keyLongerThanText() { String plainText = "TEST"; String key = "LONGKEY"; + vigenere.setKey(key); String expectedCipherText = "ESFZ"; - String result = VigenereAlgo.encrypt(plainText, key); + String result = vigenere.encrypt(plainText); assertEquals(expectedCipherText, result); } - @Test public void testDecrypt_keyLongerThanText() { String cipherText = "ESFZ"; String key = "LONGKEY"; + vigenere.setKey(key); String expectedPlainText = "TEST"; - assertEquals(expectedPlainText, vigenere.decrypt(cipherText, key)); + assertEquals(expectedPlainText, vigenere.decrypt(cipherText)); } @Test(expected = IllegalArgumentException.class) public void testEncrypt_nonAlphabeticKey() { String plainText = "HELLO"; String key = "K3Y!"; // Non-alphabetic characters in key - vigenere.encrypt(plainText, key); + vigenere.setKey(key); + vigenere.encrypt(plainText); } @Test(expected = IllegalArgumentException.class) public void testDecrypt_nonAlphabeticKey() { String cipherText = "RIJVS"; String key = "K3Y!"; // Non-alphabetic characters in key - vigenere.decrypt(cipherText, key); + vigenere.setKey(key); + vigenere.decrypt(cipherText); } -} +} \ No newline at end of file diff --git a/src/Tests/assets/test_databases.json b/src/Tests/assets/test_databases.json index ab6298e..2d23cef 100644 --- a/src/Tests/assets/test_databases.json +++ b/src/Tests/assets/test_databases.json @@ -1,3 +1,6 @@ { - "duplicateDb": "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8" + "test": { + "hashedPassword": "debe062ddaaf9f8b06720167c7b65c778c934a89ca89329dcb82ca79d19e17d2", + "algorithm": "RC4" + } } \ No newline at end of file diff --git a/src/Tests/assets/test_sites.json b/src/Tests/assets/test_sites.json index 0f07589..b964aa5 100644 --- a/src/Tests/assets/test_sites.json +++ b/src/Tests/assets/test_sites.json @@ -1,3 +1,17 @@ -{ - "sites": [] -} \ No newline at end of file +[ + { + "siteName": "Site1", + "password": "bwqm1", + "username": "user1" + }, + { + "siteName": "Site2", + "password": "sllr2", + "username": "user2" + }, + { + "password": "olpfJyvf", + "siteName": "TestSite", + "username": "testUser" + } +] \ No newline at end of file diff --git a/src/Tests/test_databases.json b/src/Tests/test_databases.json deleted file mode 100644 index ab6298e..0000000 --- a/src/Tests/test_databases.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "duplicateDb": "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8" -} \ No newline at end of file diff --git a/src/Tests/test_sites.json b/src/Tests/test_sites.json deleted file mode 100644 index 0f07589..0000000 --- a/src/Tests/test_sites.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "sites": [] -} \ No newline at end of file diff --git a/test3.json b/test3.json deleted file mode 100644 index 7ae7b3c..0000000 --- a/test3.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "sites": [ - { - "password": "qoqsschebdschzcejq", - "siteName": "testVG", - "username": "vg" - }, - { - "password": "susyuijkdjuijhej", - "siteName": "testRot", - "username": "rot" - }, - { - "password": "01101000 00001001 01010111 10000100 01000001 11111100 00001111 00111111 00100110 00111111 01101101 00001000 01100010 00001111 01110001 11001001", - "siteName": "testRC4", - "username": "rc4" - }, - { - "password": "qleqrxhdvananbokjdp", - "siteName": "testEnigma", - "username": "en" - }, - { - "password": "cir", - "siteName": "feds", - "username": "dcs" - } - ] -} \ No newline at end of file From 72f1366df1281083aac7bfb09b4dc736bd9d9f82 Mon Sep 17 00:00:00 2001 From: Nabil Date: Fri, 20 Dec 2024 01:57:19 +0100 Subject: [PATCH 3/3] fix: update HelpMenu to return to main menu and adjust database handling in Menu class --- .idea/libraries/bytedeco_javacv_platform.xml | 4 +- src/Classes/HelpMenu.java | 1 + src/Classes/Menu.java | 137 +++++-------------- 3 files changed, 39 insertions(+), 103 deletions(-) diff --git a/.idea/libraries/bytedeco_javacv_platform.xml b/.idea/libraries/bytedeco_javacv_platform.xml index 9fa3834..53085a2 100644 --- a/.idea/libraries/bytedeco_javacv_platform.xml +++ b/.idea/libraries/bytedeco_javacv_platform.xml @@ -19,9 +19,9 @@ - + - + diff --git a/src/Classes/HelpMenu.java b/src/Classes/HelpMenu.java index a527dcc..807028c 100644 --- a/src/Classes/HelpMenu.java +++ b/src/Classes/HelpMenu.java @@ -42,6 +42,7 @@ public static void displayMenuHelp(Scanner scanner) { break; case 6: System.out.println("Exiting help menu..."); // Exit message. + Menu.main(null); // Return to the main menu. break; default: System.out.println("Invalid choice. Please select a valid option."); // Handle invalid input. diff --git a/src/Classes/Menu.java b/src/Classes/Menu.java index e00c825..8a751f7 100644 --- a/src/Classes/Menu.java +++ b/src/Classes/Menu.java @@ -7,32 +7,22 @@ public class Menu { public static void main(String[] args) { - // Initialize scanner for user input from console Scanner scanner = new Scanner(System.in); - // Create a file reference for the databases configuration File databasesFile = new File("databases.json"); - // Initialize the database manager with the configuration file - DatabasesManager dbManager = new DatabasesManager(databasesFile); - // Main program loop while (true) { - // Display main menu options - System.out.println("\nWelcome to the Encryption/Decryption Program"); - System.out.println("Choose an option:"); + System.out.println("\nChoose an option:"); System.out.println("1. Choose an existing database"); System.out.println("2. Create a new database"); System.out.println("3. Help Menu"); System.out.println("4. Exit"); - - // Get user's choice and consume newline int choice = scanner.nextInt(); - scanner.nextLine(); // Prevent scanner buffer issues + scanner.nextLine(); - // Process user's choice using switch expression switch (choice) { - case 1 -> handleExistingDatabase(scanner, dbManager); - case 2 -> handleNewDatabase(scanner, dbManager); - case 3 -> HelpMenu.displayMenuHelp(scanner); + case 1 -> handleExistingDatabase(scanner); + case 2 -> handleNewDatabase(scanner); + case 3 -> HelpMenu.displayMenuHelp(scanner); // Display the help menu case 4 -> { System.out.println("Exiting program. Goodbye!"); return; @@ -42,70 +32,20 @@ public static void main(String[] args) { } } - /** - * Handles the process of connecting to an existing database - */ - private static void handleExistingDatabase(Scanner scanner, DatabasesManager dbManager) { - // Get database credentials from user - System.out.println("Enter the name of the database:"); - String dbName = scanner.nextLine(); - System.out.println("Enter the password:"); - String inputPassword = scanner.nextLine(); - - // Verify database credentials and proceed if valid - if (dbManager.verifyDatabase(dbName, inputPassword)) { - System.out.println("Successfully connected to the database: " + dbName); - // Initialize site manager with the selected database - SiteManager siteManager = new SiteManager(new File(dbName + ".json")); - // Set the encryption algorithm (can be modified for different algorithms) - siteManager.setEncryptionAlgorithm("Enigma"); - // Enter the site management menu - manageSites(scanner, siteManager); - } else { - System.out.println("Incorrect database name or password."); + private static void handleExistingDatabase(Scanner scanner) { + System.out.println("Enter database filename:"); + String filename = scanner.nextLine(); + File dbFile = new File(filename + ".json"); + + if (!dbFile.exists()) { + System.out.println("Database does not exist."); + return; } - } - /** - * Handles the process of creating a new database - */ - private static void handleNewDatabase(Scanner scanner, DatabasesManager dbManager) { - // Get new database name from user - System.out.println("Enter the name of the new database:"); - String dbName = scanner.nextLine(); - - // Present password options - System.out.println("Choose a password option:"); - System.out.println("1. Enter a custom password"); - System.out.println("2. Generate a random password"); - - // Handle password choice - int passwordChoice = scanner.nextInt(); - scanner.nextLine(); // Consume newline - - // Determine password based on user's choice - String password = passwordChoice == 1 - ? scanner.nextLine() // User enters custom password - : PasswordUtils.generateRandomPassword(12); // Generate random password - - System.out.println("Generated password: " + password); - // Create new database with chosen name and password - dbManager.createDatabase(dbName, password); - - // Initialize site manager for the new database - SiteManager siteManager = new SiteManager(new File(dbName + ".json")); + SiteManager siteManager = new SiteManager(dbFile); siteManager.setEncryptionAlgorithm("Enigma"); - System.out.println("Database created successfully."); - // Enter the site management menu - manageSites(scanner, siteManager); - } - - /** - * Manages the site operations menu (add, modify, delete, view) - */ - private static void manageSites(Scanner scanner, SiteManager siteManager) { + while (true) { - // Display site management options System.out.println("\nSite Management Menu:"); System.out.println("1. Add new site"); System.out.println("2. Modify site"); @@ -114,27 +54,41 @@ private static void manageSites(Scanner scanner, SiteManager siteManager) { System.out.println("5. Return to main menu"); int choice = scanner.nextInt(); - scanner.nextLine(); // Consume newline + scanner.nextLine(); - // Process user's choice switch (choice) { case 1 -> addSite(scanner, siteManager); case 2 -> modifySite(scanner, siteManager); case 3 -> deleteSite(scanner, siteManager); case 4 -> viewSites(siteManager); case 5 -> { - return; // Return to main menu + return; } default -> System.out.println("Invalid choice. Please try again."); } } } - /** - * Handles adding a new site to the database - */ + private static void handleNewDatabase(Scanner scanner) { + System.out.println("Enter new database filename:"); + String filename = scanner.nextLine(); + File dbFile = new File(filename + ".json"); + + if (dbFile.exists()) { + System.out.println("Database already exists."); + return; + } + + try { + SiteManager siteManager = new SiteManager(dbFile); + siteManager.setEncryptionAlgorithm("Enigma"); + System.out.println("Database created successfully."); + } catch (Exception e) { + System.out.println("Error creating database: " + e.getMessage()); + } + } + private static void addSite(Scanner scanner, SiteManager siteManager) { - // Collect site information System.out.println("Enter site name:"); String siteName = scanner.nextLine(); @@ -144,7 +98,6 @@ private static void addSite(Scanner scanner, SiteManager siteManager) { System.out.println("Enter password:"); String password = scanner.nextLine(); - // Attempt to add the site with error handling try { siteManager.addSite(siteName, username, password); System.out.println("Site added successfully."); @@ -153,22 +106,16 @@ private static void addSite(Scanner scanner, SiteManager siteManager) { } } - /** - * Handles modifying an existing site in the database - */ private static void modifySite(Scanner scanner, SiteManager siteManager) { - // Get site to modify System.out.println("Enter site name to modify:"); String siteName = scanner.nextLine(); - // Get new credentials (optional) System.out.println("Enter new username (or press Enter to skip):"); String newUsername = scanner.nextLine(); System.out.println("Enter new password (or press Enter to skip):"); String newPassword = scanner.nextLine(); - // Attempt to modify the site with error handling try { siteManager.modifySite(siteName, newUsername.isEmpty() ? null : newUsername, @@ -179,15 +126,10 @@ private static void modifySite(Scanner scanner, SiteManager siteManager) { } } - /** - * Handles deleting a site from the database - */ private static void deleteSite(Scanner scanner, SiteManager siteManager) { - // Get site to delete System.out.println("Enter site name to delete:"); String siteName = scanner.nextLine(); - // Attempt to delete the site with error handling try { siteManager.deleteSite(siteName); System.out.println("Site deleted successfully."); @@ -196,20 +138,13 @@ private static void deleteSite(Scanner scanner, SiteManager siteManager) { } } - /** - * Displays all sites stored in the database - */ private static void viewSites(SiteManager siteManager) { - // Get all sites from the database List> sites = siteManager.getSites(); - - // Check if there are any sites to display if (sites.isEmpty()) { System.out.println("No sites found."); return; } - // Display all sites and their information System.out.println("\nStored Sites:"); for (Map site : sites) { System.out.println("\nSite Name: " + site.get("siteName"));