From a996f78277d5ba5adccb0daa535bc2494350975c Mon Sep 17 00:00:00 2001 From: srdusr Date: Fri, 26 Sep 2025 12:40:58 +0200 Subject: Initial Commit --- main.c | 581 ----------------------------------------------------------------- 1 file changed, 581 deletions(-) delete mode 100644 main.c (limited to 'main.c') diff --git a/main.c b/main.c deleted file mode 100644 index 079a9e7..0000000 --- a/main.c +++ /dev/null @@ -1,581 +0,0 @@ -// TODO: Secret stored in memory must be encrypted with a key derived from the -// user password or consider making password manager stateless (no passwords -// stored locally) - -#include "main.h" - -struct Password passwords[MAX_PASSWORDS]; -int numPasswords = 0; - -FILE *log_file; - -void log_message(const char *message) { - if (log_file == NULL) { - printf("Error: Log file not available.\n"); - return; - } - - time_t current_time; - struct tm *time_info; - char time_string[80]; - - time(¤t_time); - time_info = localtime(¤t_time); - - strftime(time_string, sizeof(time_string), "[%Y-%m-%d %H:%M:%S] ", time_info); - fprintf(log_file, "%s %s\n", time_string, - message); // Print timestamp and message -} - -void initialize_log() { - log_file = fopen("cerberus.log", "a"); - if (log_file == NULL) { - printf("Error: Could not open log file.\n"); - } else { - log_message("=== cerberus log ==="); // Initial log message - } -} - -void close_log() { - if (log_file != NULL) { - fclose(log_file); - } -} - -void error_exit(const char *error_message) { - log_message(error_message); - if (log_file != NULL) { - fclose(log_file); - } - exit(1); -} - -void clear_input_buffer() { - int c; - while ((c = getchar()) != '\n' && c != EOF) - ; -} - -void check_password_policy(const char *password) { - int length = strlen(password); - if (length < 8) { - error_exit("Password must be at least 8 characters long."); - } - - bool has_upper = false, has_lower = false, has_digit = false, - has_special = false; - for (int i = 0; i < length; i++) { - if (isupper(password[i])) { - has_upper = true; - } else if (islower(password[i])) { - has_lower = true; - } else if (isdigit(password[i])) { - has_digit = true; - } else { - has_special = true; - } - } - - if (!has_upper || !has_lower || !has_digit || !has_special) { - error_exit("Password must contain at least one uppercase letter, one " - "lowercase letter, one digit, and one special character."); - } -} - -void generate_password(char *password, int length) { - if (length < 8 || length > MAX_PASSWORD_LENGTH - 1) { - printf("Invalid password length. Please enter a length between 8 and %d.\n", - MAX_PASSWORD_LENGTH - 1); - return; - } - - char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456" - "789!@#$%^&*()-_=+[]{}|;:',.<>?"; - int charset_size = strlen(charset); - - srand(time(NULL)); - - // Initialize flags to check if each required character type is included - bool has_upper = false, has_lower = false, has_digit = false, - has_special = false; - - // Create password with at least one character from each required type - password[0] = charset[rand() % 26]; // at least one uppercase letter - password[1] = charset[26 + rand() % 26]; // at least one lowercase letter - password[2] = charset[52 + rand() % 10]; // at least one digit - password[3] = charset[62 + rand() % 14]; // at least one special character - - // Fill the rest of the password randomly from the character set - for (int i = 4; i < length; i++) { - password[i] = charset[rand() % charset_size]; - } - - password[length] = '\0'; - - // Shuffle the password characters - for (int i = 0; i < length; i++) { - int j = rand() % length; - char temp = password[i]; - password[i] = password[j]; - password[j] = temp; - } - - printf("Generated Password: %s\n", password); -} - -void derive_key(unsigned char *key, const char *password, unsigned char *salt) { - PKCS5_PBKDF2_HMAC(password, strlen(password), salt, SALT_SIZE, - PBKDF2_ITERATIONS, EVP_sha256(), AES_KEY_SIZE, key); -} - -void encrypt_password(struct Password *password, const char *user_password) { - unsigned char iv[AES_BLOCK_SIZE]; - unsigned char encrypted_password[MAX_PASSWORD_LENGTH]; - - RAND_bytes(iv, AES_BLOCK_SIZE); - - unsigned char key[AES_KEY_SIZE]; - derive_key(key, user_password, iv); - - EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); - EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, key, iv); - - int outlen, tmplen; - EVP_EncryptUpdate(ctx, encrypted_password, &outlen, - (unsigned char *)password->password, - strlen(password->password)); - EVP_EncryptFinal_ex(ctx, encrypted_password + outlen, &tmplen); - - memcpy(password->password, encrypted_password, outlen + tmplen); - memcpy(password->username, iv, AES_BLOCK_SIZE); - - EVP_CIPHER_CTX_free(ctx); -} - -void decrypt_password(struct Password *password, const char *user_password) { - unsigned char iv[AES_BLOCK_SIZE]; - unsigned char decrypted_password[MAX_PASSWORD_LENGTH]; - int decrypted_len = 0; - - memcpy(iv, password->username, AES_BLOCK_SIZE); - - unsigned char key[AES_KEY_SIZE]; - derive_key(key, user_password, iv); - - EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); - EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, key, iv); - - int outlen, tmplen; - EVP_DecryptUpdate(ctx, decrypted_password, &outlen, - (unsigned char *)password->password, - strlen(password->password)); - EVP_DecryptFinal_ex(ctx, decrypted_password + outlen, &tmplen); - - decrypted_password[outlen + tmplen] = '\0'; - - strcpy(password->password, (char *)decrypted_password); - - EVP_CIPHER_CTX_free(ctx); -} - -void save_password(struct Password *password, const char *website, - const char *dir, const char *user_password) { - unsigned char iv[AES_BLOCK_SIZE]; - RAND_bytes(iv, AES_BLOCK_SIZE); - - unsigned char key[AES_KEY_SIZE]; - derive_key(key, user_password, iv); - - unsigned char encrypted_password[MAX_PASSWORD_LENGTH]; - EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); - EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, key, iv); - - int outlen, tmplen; - EVP_EncryptUpdate(ctx, encrypted_password, &outlen, - (unsigned char *)password->password, - strlen(password->password)); - EVP_EncryptFinal_ex(ctx, encrypted_password + outlen, &tmplen); - - char filename[256]; - snprintf(filename, sizeof(filename), "%s/%s_%s.dat", dir, website, - password->username); - FILE *fp = fopen(filename, "wb"); - if (fp == NULL) { - printf("Error: could not open file %s for writing.\n", filename); - return; - } - fwrite(iv, sizeof(iv), 1, fp); - fwrite(encrypted_password, outlen + tmplen, 1, fp); - - fclose(fp); - EVP_CIPHER_CTX_free(ctx); -} - -void edit_password(struct Password *password) { - int choice; - printf("\nEdit Password:\n"); - printf("1. Website: %s\n", password->website); - printf("2. Username: %s\n", password->username); - printf("3. Password: %s\n", password->password); - printf("4. Cancel\n"); - printf("Enter your choice: "); - scanf("%d", &choice); - clear_input_buffer(); - - switch (choice) { - case 1: { - char old_filename[256]; - snprintf(old_filename, sizeof(old_filename), "tmp/%s_%s.dat", - password->website, password->username); - if (remove(old_filename) != 0) { - printf("Error deleting old password file.\n"); - } - - printf("Enter new website: "); - fgets(password->website, sizeof(password->website), stdin); - password->website[strcspn(password->website, "\n")] = - 0; // Remove newline character - printf("Website updated.\n"); - save_password(password, password->website, "tmp", "user_password"); - break; - } - case 2: { - char old_filename[256]; - snprintf(old_filename, sizeof(old_filename), "tmp/%s_%s.dat", - password->website, password->username); - if (remove(old_filename) != 0) { - printf("Error deleting old password file.\n"); - } - - printf("Enter new username: "); - fgets(password->username, sizeof(password->username), stdin); - password->username[strcspn(password->username, "\n")] = - 0; // Remove newline character - printf("Username updated.\n"); - save_password(password, password->website, "tmp", "user_password"); - break; - } - case 3: { - int length; - do { - printf("Enter new password length: "); - scanf("%d", &length); - clear_input_buffer(); - if (length < 8 || length > MAX_PASSWORD_LENGTH - 1) { - printf("Invalid password length. Please enter a length between 8 and " - "%d.\n", - MAX_PASSWORD_LENGTH - 1); - } - } while (length < 8 || length > MAX_PASSWORD_LENGTH - 1); - generate_password(password->password, length); - printf("Password updated.\n"); - save_password(password, password->website, "tmp", "user_password"); - break; - } - case 4: - printf("Canceled.\n"); - break; - default: - printf("Invalid choice.\n"); - break; - } -} - -void load_passwords(const char *dir, const char *user_password) { - printf("Available Passwords:\n"); - DIR *d; - struct dirent *dir_entry; - d = opendir(dir); - if (d) { - int count = 0; - while ((dir_entry = readdir(d)) != NULL) { - if (dir_entry->d_type == DT_REG) { // If it's a regular file - char filename[256]; - snprintf(filename, sizeof(filename), "%s/%s", dir, dir_entry->d_name); - FILE *file = fopen(filename, "rb"); - if (file != NULL) { - struct Password password; - - unsigned char iv[AES_BLOCK_SIZE]; - fread(iv, sizeof(iv), 1, file); - - unsigned char encrypted_password[MAX_PASSWORD_LENGTH]; - int len = fread(encrypted_password, 1, MAX_PASSWORD_LENGTH, file); - - unsigned char key[AES_KEY_SIZE]; - derive_key(key, user_password, iv); - - unsigned char decrypted_password[MAX_PASSWORD_LENGTH]; - EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); - EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, key, iv); - - int outlen, tmplen; - EVP_DecryptUpdate(ctx, decrypted_password, &outlen, - encrypted_password, len); - EVP_DecryptFinal_ex(ctx, decrypted_password + outlen, &tmplen); - - decrypted_password[outlen + tmplen] = '\0'; - - fclose(file); - EVP_CIPHER_CTX_free(ctx); - - // Extract website and username from filename - char website[MAX_WEBSITE_LENGTH]; - char username[MAX_USERNAME_LENGTH]; - sscanf(dir_entry->d_name, "%[^_]_%[^.]", website, username); - - // Copy decrypted password to password field - strncpy(password.website, website, MAX_WEBSITE_LENGTH - 1); - password.website[MAX_WEBSITE_LENGTH - 1] = '\0'; - strncpy(password.username, username, MAX_USERNAME_LENGTH - 1); - password.username[MAX_USERNAME_LENGTH - 1] = '\0'; - strncpy(password.password, decrypted_password, - MAX_PASSWORD_LENGTH - 1); - password.password[MAX_PASSWORD_LENGTH - 1] = '\0'; - - passwords[count++] = password; - printf("%d. Website: %s, Username: %s\n", count, password.website, - password.username); - } - } - } - numPasswords = count; - closedir(d); - if (count == 0) { - printf("No passwords found.\n"); - } - } -} - -void copy_to_clipboard(char *text) { - // Use xclip command to copy text to clipboard - FILE *pipe = popen("xclip -selection clipboard", "w"); - if (pipe != NULL) { - fprintf(pipe, "%s", text); - pclose(pipe); - printf("Copied to clipboard: %s\n", text); - } else { - printf("Error: Could not copy to clipboard.\n"); - } -} - -void print_ascii_art(const char *filename) { - FILE *file = fopen(filename, "r"); - if (file == NULL) { - printf("Unable to open ASCII art file.\n"); - return; - } - - // Get console width - struct winsize w; - ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); - int console_width = w.ws_col; - - char line[256]; - while (fgets(line, sizeof(line), file)) { - // Calculate padding for centering - int padding = (console_width - strlen(line)) / 2; - if (padding > 0) { - for (int i = 0; i < padding; i++) { - printf(" "); - } - } - printf("%s", line); - } - - fclose(file); -} - -int main() { - initialize_log(); - - const char *dir = "tmp"; // Directory to store password files - mkdir(dir, 0700); // Create directory if it doesn't exist - - char user_password[MAX_PASSWORD_LENGTH]; - - FILE *key_file = fopen("master.key", "rb"); - if (key_file == NULL) { - printf("Enter your new master password: "); - fgets(user_password, sizeof(user_password), stdin); - user_password[strcspn(user_password, "\n")] = 0; - - // Save master password to file - key_file = fopen("master.key", "wb"); - if (key_file == NULL) { - printf("Error: Could not create master password file.\n"); - return 1; - } - fwrite(user_password, sizeof(user_password), 1, key_file); - fclose(key_file); - } else { - // If master key exists, ask for the password - printf("Enter your master password: "); - fgets(user_password, sizeof(user_password), stdin); - user_password[strcspn(user_password, "\n")] = 0; // Remove newline character - - // Check if the entered password matches the stored master password - char stored_password[MAX_PASSWORD_LENGTH]; - fread(stored_password, sizeof(stored_password), 1, key_file); - fclose(key_file); - if (strcmp(user_password, stored_password) != 0) { - printf("Invalid master password. Exiting...\n"); - return 1; - } - } - - // Print ASCII art - print_ascii_art("ascii-art.txt"); - - int choice; - while (1) { - printf("\n1. Create New Password\n"); - printf("2. Show Passwords\n"); - printf("3. Exit\n"); - printf("Enter your choice: "); - scanf("%d", &choice); - clear_input_buffer(); // Clear input buffer after scanf - - switch (choice) { - case 1: { - struct Password password; - int length; - do { - printf("Enter password length: "); - scanf("%d", &length); - clear_input_buffer(); - if (length < 8 || length > MAX_PASSWORD_LENGTH - 1) { - printf("Invalid password length. Please enter a length between 8 and " - "%d.\n", - MAX_PASSWORD_LENGTH - 1); - } - } while (length < 8 || length > MAX_PASSWORD_LENGTH - 1); - generate_password(password.password, length); - printf("Enter website: "); - fgets(password.website, sizeof(password.website), stdin); - password.website[strcspn(password.website, "\n")] = - 0; // Remove newline character - printf("Enter username: "); - fgets(password.username, sizeof(password.username), stdin); - password.username[strcspn(password.username, "\n")] = - 0; // Remove newline character - save_password(&password, password.website, dir, user_password); - printf("Password information saved to %s\n", password.website); - break; - } - case 2: { - load_passwords(dir, user_password); - printf("Enter the number of the password to view or 0 to cancel: "); - int selection; - scanf("%d", &selection); - clear_input_buffer(); - if (selection > 0 && selection <= numPasswords) { - struct Password selected_password = passwords[selection - 1]; - printf("Selected Password:\n"); - printf("- Website: %s\n", selected_password.website); - printf("- Username: %s\n", selected_password.username); - printf("- Password: %s\n", selected_password.password); - printf("1. Copy Username and/or Password\n"); - printf("2. Edit the Password\n"); - printf("3. Delete the Password\n"); - printf("0. Cancel\n"); - printf("Enter your choice: "); - int copy_choice; - scanf("%d", ©_choice); - clear_input_buffer(); - switch (copy_choice) { - case 1: - // Provide options for copying username and/or password - printf("1. Copy Username and Password\n"); - printf("2. Copy just the Password\n"); - printf("3. Copy just the Username\n"); - printf("0. Cancel\n"); - printf("Enter your choice: "); - int sub_copy_choice; - scanf("%d", &sub_copy_choice); - clear_input_buffer(); - switch (sub_copy_choice) { - case 1: - // Copy both username and password - { - char copy_text[MAX_PASSWORD_LENGTH * 2 + - 2]; // Max length of both plus space - snprintf(copy_text, sizeof(copy_text), - "Username: %s, Password: %s", selected_password.username, - selected_password.password); - copy_to_clipboard(copy_text); - printf("Username and Password copied to clipboard.\n"); - } - break; - case 2: - // Copy just the password - copy_to_clipboard(selected_password.password); - printf("Password copied to clipboard.\n"); - break; - case 3: - // Copy just the username - copy_to_clipboard(selected_password.username); - printf("Username copied to clipboard.\n"); - break; - case 0: - printf("Canceled.\n"); - break; - default: - printf("Invalid choice.\n"); - } - break; - case 2: - edit_password(&selected_password); - save_password(&selected_password, selected_password.website, dir, - user_password); - printf("Password updated.\n"); - break; - case 3: { - struct Password selected_password = passwords[selection - 1]; - printf("Are you sure you want to delete this password? (y/n): "); - char confirm; - scanf(" %c", &confirm); - clear_input_buffer(); - if (confirm == 'y' || confirm == 'Y') { - char filename[256]; - snprintf(filename, sizeof(filename), "%s/%s_%s.dat", dir, - selected_password.website, selected_password.username); - if (remove(filename) != 0) { - printf("Error deleting password file.\n"); - } else { - printf("Password deleted.\n"); - // Shift remaining passwords to fill the gap - for (int i = selection - 1; i < numPasswords - 1; i++) { - passwords[i] = passwords[i + 1]; - } - numPasswords--; - } - } else { - printf("Password not deleted.\n"); - } - break; - } - - case 0: - printf("Canceled.\n"); - break; - default: - printf("Invalid choice.\n"); - } - } else if (selection != 0) { - printf("Invalid selection.\n"); - } - break; - } - case 3: - printf("Exiting program...\n"); - close_log(); - return 0; - default: - printf("Invalid choice. Please enter 1, 2, or 3.\n"); - } - } - - close_log(); - return 0; -} -- cgit v1.2.3