Password-Manager/password_manager.c
2024-10-19 00:51:55 +00:00

275 lines
8.9 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <openssl/rand.h>
#include <openssl/evp.h>
#include <openssl/sha.h>
#include <openssl/aes.h>
#include <openssl/err.h>
#include <termios.h>
#include <unistd.h>
#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;
}