diff --git a/password_manager.c b/password_manager.c new file mode 100644 index 0000000..53d65b9 --- /dev/null +++ b/password_manager.c @@ -0,0 +1,274 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SALT_SIZE 16 +#define IV_SIZE 16 +#define BLOCK_SIZE 16 +#define KEY_SIZE 32 +#define MAX_CIPHERTEXT_LENGTH 256 + +const char *defaultCharSet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!@#$%^&*()-_=+[]{};:,.<>?/\\|"; +const char *noSymbolsCharSet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +int passwordLength = 16; +int useSymbols = 1; +char masterPassword[256]; // Master password for encryption + +void getMasterPassword(char *password) { + struct termios oldt, newt; + printf("Enter master password: "); + tcgetattr(STDIN_FILENO, &oldt); + newt = oldt; + newt.c_lflag &= ~(ECHO); + tcsetattr(STDIN_FILENO, TCSANOW, &newt); + fgets(password, sizeof(masterPassword), stdin); + password[strcspn(password, "\n")] = '\0'; + tcsetattr(STDIN_FILENO, TCSANOW, &oldt); + printf("\n"); +} + +void printHelp() { + printf("Password Manager Usage:\n"); + printf(" --add SERVICE --username USERNAME [--password PASSWORD] Add a new service with optional password (randomly generated if not provided)\n"); + printf(" --get SERVICE Retrieve the username and password for a given service\n"); + printf(" --list List all services stored in the vault\n"); + printf(" --length LENGTH Specify the length of generated passwords (default: 16)\n"); + printf(" --no-symbols Generate passwords without symbols\n"); + printf(" --help Display this help message\n"); +} + +void parseArgs(int argc, char **argv, char **operation, char **service, char **username, char **password) { + int c; + while (1) { + static struct option long_options[] = { + {"length", required_argument, 0, 'l'}, + {"no-symbols", no_argument, 0, 'n'}, + {"add", required_argument, 0, 'a'}, + {"get", required_argument, 0, 'g'}, + {"list", no_argument, 0, 'L'}, + {"username", required_argument, 0, 'u'}, + {"password", required_argument, 0, 'p'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0} + }; + + c = getopt_long(argc, argv, "l:na:g:L:u:p:h", long_options, NULL); + if (c == -1) break; + + switch (c) { + case 'l': + passwordLength = atoi(optarg); + break; + case 'n': + useSymbols = 0; + break; + case 'a': + *operation = "add"; + *service = optarg; + break; + case 'g': + *operation = "get"; + *service = optarg; + break; + case 'L': + *operation = "list"; + break; + case 'u': + *username = optarg; + break; + case 'p': + *password = optarg; + break; + case 'h': + printHelp(); + exit(0); + default: + printf("Invalid option %c\n", c); + exit(1); + } + } +} + +void generatePassword(char *password) { + const char *charSet = useSymbols ? defaultCharSet : noSymbolsCharSet; + for (int i = 0; i < passwordLength; ++i) { + unsigned char randomByte; + RAND_bytes(&randomByte, sizeof(randomByte)); + int randomIndex = randomByte % (int)strlen(charSet); + password[i] = charSet[randomIndex]; + } + password[passwordLength] = '\0'; +} + +void handleErrors() { + ERR_print_errors_fp(stderr); + abort(); +} + +void deriveKey(unsigned char *key, unsigned char *salt) { + if (!PKCS5_PBKDF2_HMAC(masterPassword, strlen(masterPassword), salt, SALT_SIZE, 10000, EVP_sha256(), KEY_SIZE, key)) { + handleErrors(); + } +} + +void encryptPassword(const char *plaintext, unsigned char *ciphertext, unsigned char *salt, int *ciphertext_len) { + unsigned char key[KEY_SIZE], iv[IV_SIZE]; + deriveKey(key, salt); + + // Generate random IV + RAND_bytes(iv, sizeof(iv)); + + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + int len; + + // Prepend salt and IV to the ciphertext + memcpy(ciphertext, salt, SALT_SIZE); + memcpy(ciphertext + SALT_SIZE, iv, IV_SIZE); + + if (!EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv)) handleErrors(); + + if (!EVP_EncryptUpdate(ctx, ciphertext + SALT_SIZE + IV_SIZE, &len, (unsigned char *)plaintext, strlen(plaintext))) handleErrors(); + *ciphertext_len = len; + + if (!EVP_EncryptFinal_ex(ctx, ciphertext + SALT_SIZE + IV_SIZE + len, &len)) handleErrors(); + *ciphertext_len += len; + + EVP_CIPHER_CTX_free(ctx); +} + +void decryptPassword(const unsigned char *ciphertext, char *plaintext, int ciphertext_len) { + unsigned char key[KEY_SIZE], iv[IV_SIZE], salt[SALT_SIZE]; + memcpy(salt, ciphertext, SALT_SIZE); + memcpy(iv, ciphertext + SALT_SIZE, IV_SIZE); + + deriveKey(key, salt); + + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + int len, plaintext_len; + + if (!EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv)) handleErrors(); + + if (!EVP_DecryptUpdate(ctx, (unsigned char *)plaintext, &len, ciphertext + SALT_SIZE + IV_SIZE, ciphertext_len - SALT_SIZE - IV_SIZE)) handleErrors(); + plaintext_len = len; + + if (!EVP_DecryptFinal_ex(ctx, (unsigned char *)plaintext + len, &len)) handleErrors(); + plaintext_len += len; + plaintext[plaintext_len] = '\0'; + + EVP_CIPHER_CTX_free(ctx); +} + +void savePassword(const char *service, const char *username, const char *password) { + FILE *vault = fopen("vault.csv", "a"); + if (!vault) { + printf("Error opening vault file.\n"); + return; + } + + unsigned char ciphertext[MAX_CIPHERTEXT_LENGTH]; + int ciphertext_len; + unsigned char salt[SALT_SIZE]; + RAND_bytes(salt, sizeof(salt)); + + encryptPassword(password, ciphertext, salt, &ciphertext_len); + + // Convert to hex string for storage + char hexCiphertext[MAX_CIPHERTEXT_LENGTH * 2 + 1]; // Enough space for hex representation + for (int i = 0; i < ciphertext_len + SALT_SIZE + IV_SIZE; i++) { + sprintf(hexCiphertext + i * 2, "%02x", ciphertext[i]); + } + + fprintf(vault, "%s,%s,%s\n", service, username, hexCiphertext); + fclose(vault); +} + +void getPassword(const char *service) { + FILE *vault = fopen("vault.csv", "r"); + if (!vault) { + printf("Error opening vault file.\n"); + return; + } + + char line[512]; + while (fgets(line, sizeof(line), vault)) { + char *storedService = strtok(line, ","); + char *storedUsername = strtok(NULL, ","); + char *encryptedPassword = strtok(NULL, "\n"); + + if (strcmp(service, storedService) == 0) { + unsigned char ciphertext[MAX_CIPHERTEXT_LENGTH]; + int ciphertext_len = strlen(encryptedPassword) / 2; // Each byte is represented by 2 hex characters + for (int i = 0; i < ciphertext_len; i++) { + sscanf(encryptedPassword + 2 * i, "%2hhx", &ciphertext[i]); + } + + char decryptedPassword[MAX_CIPHERTEXT_LENGTH]; + decryptPassword(ciphertext, decryptedPassword, ciphertext_len); + printf("Service: %s\nUsername: %s\nPassword: %s\n", storedService, storedUsername, decryptedPassword); + fclose(vault); + return; + } + } + + printf("Service not found.\n"); + fclose(vault); +} + +void listServices() { + FILE *vault = fopen("vault.csv", "r"); + if (!vault) { + printf("Error opening vault file.\n"); + return; + } + + printf("Services in the vault:\n"); + char line[512]; + while (fgets(line, sizeof(line), vault)) { + char *storedService = strtok(line, ","); + // Check if storedService exists + if (storedService != NULL) { + printf("%s\n", storedService); + } + } + + fclose(vault); +} + +int main(int argc, char **argv) { + char *operation = NULL; + char *service = NULL; + char *username = NULL; + char *password = NULL; + + parseArgs(argc, argv, &operation, &service, &username, &password); + getMasterPassword(masterPassword); // Get the master password + + if (operation != NULL) { + if (strcmp(operation, "add") == 0) { + char generatedPassword[256]; + if (password == NULL) { + generatePassword(generatedPassword); + savePassword(service, username, generatedPassword); + } else { + savePassword(service, username, password); + } + } else if (strcmp(operation, "get") == 0) { + getPassword(service); + } else if (strcmp(operation, "list") == 0) { + listServices(); + } + } else { + printf("No valid operation specified.\n"); + } + + return 0; +}