From f1babd48f5259186cd1233288992f942d4b5b0bb Mon Sep 17 00:00:00 2001 From: Simeon Simeonov Date: Fri, 9 Mar 2018 14:02:34 +0100 Subject: Complete rewrite of the master password implementation --- libsylph/account.c | 24 -- libsylph/imap.c | 18 +- libsylph/masterpassword.c | 159 ++++++--- libsylph/masterpassword.h | 6 +- libsylph/news.c | 7 +- libsylph/pop.c | 11 +- libsylph/prefs_account.c | 1 - libsylph/prefs_account.h | 2 - libsylph/ssl.c | 844 +++++++++++++++++++++++----------------------- 9 files changed, 560 insertions(+), 512 deletions(-) (limited to 'libsylph') diff --git a/libsylph/account.c b/libsylph/account.c index 7440434..2431bf3 100644 --- a/libsylph/account.c +++ b/libsylph/account.c @@ -36,9 +36,6 @@ #include "procheader.h" #include "utils.h" #include "sylmain.h" -#include "prefs_common.h" -#include "masterpassword.h" - PrefsAccount *cur_account; @@ -54,24 +51,6 @@ void account_read_config_all(void) FILE *fp; gchar buf[PREFSBUFSIZE]; PrefsAccount *ac_prefs; -#if USE_SSL - if (prefs_common.use_master_password) { - if (prefs_common.master_password_hash != NULL) { - /* allow 3 attempts to enter the master password */ - if (check_master_password_interactively(3) != 0) { - /* master password does not match the hash */ - g_free(master_password); - master_password = NULL; - } - } else { - /* No master password set (no master_password_hash) */ - set_master_password_interactively(3); - } - /* TODO: Warning if password is NULL */ - } else { - master_password = NULL; - } -#endif debug_print(_("Reading all config for each account...\n")); @@ -100,9 +79,6 @@ void account_read_config_all(void) for (cur = ac_label_list; cur != NULL; cur = cur->next) { ac_prefs = prefs_account_new(); prefs_account_read_config(ac_prefs, (gchar *)cur->data); -#if USE_SSL - ac_prefs->master_password = master_password; -#endif account_list = g_list_append(account_list, ac_prefs); if (ac_prefs->is_default) cur_account = ac_prefs; diff --git a/libsylph/imap.c b/libsylph/imap.c index 0cd4409..9ee4b15 100644 --- a/libsylph/imap.c +++ b/libsylph/imap.c @@ -52,6 +52,7 @@ #include "utils.h" #include "prefs_common.h" #include "virtual.h" +#include "masterpassword.h" #define IMAP4_PORT 143 #if USE_SSL @@ -705,19 +706,9 @@ static gint imap_session_connect(IMAPSession *session) account = (PrefsAccount *)(SESSION(session)->data); log_message(_("creating IMAP4 connection to %s:%d ...\n"), - SESSION(session)->server, SESSION(session)->port); - - if (prefs_common.use_master_password && account->master_password != NULL) { - if (decrypt_data(&pass, - account->passwd, - account->master_password, - strlen(account->passwd) + 1) != RC_OK) { - session_destroy(session); - return -1; - } - } else { - pass = account->passwd; - } + SESSION(session)->server, SESSION(session)->port); + + pass = decrypt_with_master_password(account->passwd); if (!pass) pass = account->tmp_pass; if (!pass) { @@ -731,6 +722,7 @@ static gint imap_session_connect(IMAPSession *session) account->tmp_pass = tmp_pass; pass = account->tmp_pass; } + if (account->use_socks && account->use_socks_for_recv && account->proxy_host) { socks_info = socks_info_new(account->socks_type, account->proxy_host, account->proxy_port, account->use_proxy_auth ? account->proxy_name : NULL, account->use_proxy_auth ? account->proxy_pass : NULL); diff --git a/libsylph/masterpassword.c b/libsylph/masterpassword.c index ee443aa..4cef644 100644 --- a/libsylph/masterpassword.c +++ b/libsylph/masterpassword.c @@ -21,6 +21,8 @@ #include "config.h" #endif +#include + #include "prefs_common.h" #include "ssl.h" #include "utils.h" @@ -29,72 +31,141 @@ gchar *master_password; void set_master_password(const char *password) { - master_password = password; + master_password = password; } gchar *get_master_password(void) { - return master_password; + return master_password; } +void unload_master_password(void) { + #if USE_SSL + OPENSSL_cleanse(master_password, strlen(master_password)); +#endif + g_free(master_password); + master_password = NULL; -gint set_master_password_interactively(guint max_attempts) { +} - if (master_password != NULL) - return 0; /* master_password already set */ +gboolean master_password_active(void) { - master_password = input_set_new_password(max_attempts); +#if USE_SSL + return ((master_password != NULL) && + prefs_common.use_master_password); +#else + return FALSE; +#endif - if (master_password == NULL) - return 1; +} - if (generate_password_hash( - &prefs_common.master_password_hash, - master_password, - NULL) != RC_OK) { - /* should not really happen unless buggy code / library */ - g_free(prefs_common.master_password_hash); - prefs_common.master_password_hash = NULL; - debug_print(_("Could not generate master password hash")); - return 1; - } +gchar *decrypt_with_master_password(gchar *str) { - prefs_common_write_config(); - return 0; +#if USE_SSL + gchar *new_str; + + if ((!str) || (!master_password_active())) + return str; /* do nothing */ + + if (decrypt_data(&new_str, + str, + master_password, + strlen(str)) != RC_OK) { + OPENSSL_cleanse(new_str, strlen(new_str)); + g_free(new_str); + return str; + } + + return new_str; +#else + return str; /* do nothing */ +#endif } -gint check_master_password_interactively(guint max_attempts) { +gchar *encrypt_with_master_password(gchar *str) { + +#if USE_SSL + gchar *new_str; + gint length_encrypted; + + if ((!str) || (!master_password_active())) + return str; /* do nothing */ + + if (encrypt_data(&new_str, + &length_encrypted, + str, + master_password, + strlen(str), + 32, /* TODO: to be set in prefs_common */ + TRUE) != RC_OK) { + OPENSSL_cleanse(new_str, strlen(new_str)); + g_free(new_str); + return str; + } + + return new_str; +#else + return str; /* do nothing */ +#endif - guint cnt; +} - if (max_attempts < 1) - return 1; +#if USE_SSL +gint set_master_password_interactively(guint max_attempts) { - if (prefs_common.master_password_hash != NULL) { - return 1; - } + if (master_password == NULL) + master_password = input_set_new_password(max_attempts); - if (master_password != NULL) { - /* password already cached */ - return check_password(master_password, - prefs_common.master_password_hash); - } + if (master_password == NULL) + return 1; - for (cnt = 0; cnt < max_attempts; ++cnt) { - master_password = input_query_master_password(); - if (check_password(master_password, - prefs_common.master_password_hash) == RC_OK) { - return RC_OK; /* match */ - } - debug_print(_("Wrong master password entered (%d)\n"), cnt); - /* TODO: clear before free? */ - g_free(master_password); - master_password = NULL; - } + if (generate_password_hash( + &prefs_common.master_password_hash, + master_password, + NULL) != RC_OK) { + /* should not really happen unless buggy code / library */ + g_free(prefs_common.master_password_hash); + prefs_common.master_password_hash = NULL; + debug_print(_("Could not generate master password hash")); + return 1; + } - return 1; /* no match */ + prefs_common_write_config(); + return 0; } +gint check_master_password_interactively(guint max_attempts) { + + guint cnt; + + if (max_attempts < 1) + return 1; + + if (prefs_common.master_password_hash != NULL) { + return 1; + } + + if (master_password != NULL) { + /* password already cached */ + return check_password(master_password, + prefs_common.master_password_hash); + } + + for (cnt = 0; cnt < max_attempts; ++cnt) { + master_password = input_query_master_password(); + if (check_password(master_password, + prefs_common.master_password_hash) == RC_OK) { + return RC_OK; /* match */ + } + debug_print(_("Wrong master password entered (%d)\n"), cnt); + OPENSSL_cleanse(master_password, strlen(master_password)); + g_free(master_password); + master_password = NULL; + } + + return 1; /* no match */ + +} #endif /* USE_SSL */ diff --git a/libsylph/masterpassword.h b/libsylph/masterpassword.h index b2798ce..9d00384 100644 --- a/libsylph/masterpassword.h +++ b/libsylph/masterpassword.h @@ -27,12 +27,14 @@ extern gchar *master_password; void set_master_password(const char *password); gchar *get_master_password(void); +void unload_master_password(void); +gboolean master_password_active(void); +gchar *decrypt_with_master_password(gchar *str); +gchar *encrypt_with_master_password(gchar *str); #if USE_SSL - gint set_master_password_interactively(guint max_attempts); gint check_master_password_interactively(guint max_attempts); - #endif /* USE_SSL */ #endif /* __MASTERPASSWORD_H__ */ diff --git a/libsylph/news.c b/libsylph/news.c index ffff9f9..b7a922a 100644 --- a/libsylph/news.c +++ b/libsylph/news.c @@ -44,6 +44,7 @@ #include "utils.h" #include "prefs_common.h" #include "prefs_account.h" +#include "masterpassword.h" #if USE_SSL # include "ssl.h" #endif @@ -250,7 +251,11 @@ static Session *news_session_new_for_folder(Folder *folder) if (ac->use_nntp_auth && ac->userid && ac->userid[0]) { userid = ac->userid; if (ac->passwd && ac->passwd[0]) - passwd = g_strdup(ac->passwd); + if (master_password_active()) { + passwd = decrypt_with_master_password(ac->passwd); + } else { + passwd = g_strdup(ac->passwd); + } else passwd = input_query_password(ac->nntp_server, userid); } diff --git a/libsylph/pop.c b/libsylph/pop.c index 8cb7f5c..a387f5e 100644 --- a/libsylph/pop.c +++ b/libsylph/pop.c @@ -39,6 +39,7 @@ #include "prefs_account.h" #include "utils.h" #include "recv.h" +#include "masterpassword.h" gint pop3_greeting_recv (Pop3Session *session, const gchar *msg); @@ -437,8 +438,14 @@ Session *pop3_session_new(PrefsAccount *account) session->error_msg = NULL; session->user = g_strdup(account->userid); - session->pass = account->passwd ? g_strdup(account->passwd) : - account->tmp_pass ? g_strdup(account->tmp_pass) : NULL; + if (master_password_active()) { + session->pass = account->passwd ? decrypt_with_master_password( + account->passwd) : account->tmp_pass ? g_strdup( + account->tmp_pass) : NULL; + } else { + session->pass = account->passwd ? g_strdup(account->passwd) : + account->tmp_pass ? g_strdup(account->tmp_pass) : NULL; + } SESSION(session)->server = g_strdup(account->recv_server); diff --git a/libsylph/prefs_account.c b/libsylph/prefs_account.c index 07605fb..1aecba9 100644 --- a/libsylph/prefs_account.c +++ b/libsylph/prefs_account.c @@ -218,7 +218,6 @@ void prefs_account_read_config(PrefsAccount *ac_prefs, const gchar *label) g_free(rcpath); *ac_prefs = tmp_ac_prefs; - ac_prefs->master_password = NULL; while (*p && !g_ascii_isdigit(*p)) p++; id = atoi(p); if (id < 0) g_warning("wrong account id: %d\n", id); diff --git a/libsylph/prefs_account.h b/libsylph/prefs_account.h index 68badd8..ad899f8 100644 --- a/libsylph/prefs_account.h +++ b/libsylph/prefs_account.h @@ -187,8 +187,6 @@ struct _PrefsAccount /* Compose */ gchar *sig_names[10]; gchar *sig_texts[10]; - - gchar *master_password; }; PrefsAccount *prefs_account_new (void); diff --git a/libsylph/ssl.c b/libsylph/ssl.c index 5042f74..44b2935 100644 --- a/libsylph/ssl.c +++ b/libsylph/ssl.c @@ -411,467 +411,465 @@ void ssl_set_verify_func(SSLVerifyFunc func) /* master password related functions */ static gint secure_derive_key(guchar *key, - gint length_key, - const gchar *passphrase, - const guchar *salt) { + gint length_key, + const gchar *passphrase, + const guchar *salt) { - guint length_buffer, length_hash; - guchar *buffer, *ptr_hash; + guint length_buffer, length_hash; + guchar *buffer, *ptr_hash; - EVP_MD_CTX *mdctx; + EVP_MD_CTX *mdctx; - OPENSSL_cleanse(key, length_key); + OPENSSL_cleanse(key, length_key); - length_buffer = SALT_SIZE + strlen(passphrase); - buffer = OPENSSL_malloc(length_buffer); - OPENSSL_cleanse(buffer, length_buffer); + length_buffer = SALT_SIZE + strlen(passphrase); + buffer = OPENSSL_malloc(length_buffer); + OPENSSL_cleanse(buffer, length_buffer); memcpy(buffer, salt, SALT_SIZE); memcpy(buffer + SALT_SIZE, passphrase, strlen(passphrase)); - mdctx = EVP_MD_CTX_create(); - EVP_DigestInit_ex(mdctx, KEY_HASH, NULL); - EVP_DigestUpdate(mdctx, buffer, length_buffer); - OPENSSL_cleanse(buffer, length_buffer); + mdctx = EVP_MD_CTX_create(); + EVP_DigestInit_ex(mdctx, KEY_HASH, NULL); + EVP_DigestUpdate(mdctx, buffer, length_buffer); + OPENSSL_cleanse(buffer, length_buffer); - ptr_hash = OPENSSL_malloc(EVP_MD_size(KEY_HASH)); - EVP_DigestFinal_ex(mdctx, ptr_hash, &length_hash); + ptr_hash = OPENSSL_malloc(EVP_MD_size(KEY_HASH)); + EVP_DigestFinal_ex(mdctx, ptr_hash, &length_hash); - memcpy(key, - ptr_hash, - (length_hash > length_key) ? length_key : length_hash); + memcpy(key, + ptr_hash, + (length_hash > length_key) ? length_key : length_hash); - OPENSSL_cleanse(ptr_hash, length_hash); - OPENSSL_free(ptr_hash); - OPENSSL_free(buffer); - EVP_MD_CTX_destroy(mdctx); + OPENSSL_cleanse(ptr_hash, length_hash); + OPENSSL_free(ptr_hash); + OPENSSL_free(buffer); + EVP_MD_CTX_destroy(mdctx); - return RC_OK; + return RC_OK; } - gint encrypt_data(gchar **encrypted, - gint *length_encrypted, - const gchar *data, - const gchar *passphrase, - gint length_data, - guint min_data_length, - gboolean rnd_salt) { - - gint crypt_buffer_cnt, rc; - guint key_size, length_hash; - guint length_cleartext, length_ciphertext, length_total; - guchar salt[SALT_SIZE]; - guchar *ciphertext_buffer, *total_buffer; - /* sensitive buffers and counters */ - guint length_data_payload, length_padding; - gchar str_data_size[3]; - guchar *data_payload_buffer, *hash_buffer, *padding_buffer, *key; - guchar *cleartext_buffer; - - EVP_CIPHER_CTX *ctx; - EVP_MD_CTX *mdctx; - - rc = RC_ERROR; - - if (length_data < 1) { - return -1; - } - if (rnd_salt) { - if (RAND_bytes(salt, SALT_SIZE) != 1) { - debug_print("Random problems...\n"); - goto cleanup; - } - } else { - strncpy((gchar *)salt, "FOR TESTING ONLY", SALT_SIZE); - } - - key_size = EVP_CIPHER_key_length(CIPHER); - key = OPENSSL_malloc(key_size); - OPENSSL_cleanse(key, key_size); - if (secure_derive_key(key, - key_size, - passphrase, - salt) != RC_OK) { - OPENSSL_cleanse(key, key_size); - debug_print("Could not generate secure key\n"); - goto cleanup; - } - - /* prepare the data-buffer */ - length_padding = 0; - if (length_data < min_data_length) { - g_snprintf(str_data_size, 3, "%02d", length_data); - length_padding = min_data_length - length_data; - padding_buffer = OPENSSL_malloc(length_padding); - OPENSSL_cleanse(padding_buffer, length_padding); - if (RAND_bytes(padding_buffer, length_padding) != 1) { - debug_print("Random problems...\n"); - goto cleanup; - } - } else { - g_snprintf(str_data_size, 3, "-1"); - } - - length_data_payload = 2 + length_data + length_padding; - data_payload_buffer = OPENSSL_malloc(length_data_payload); - OPENSSL_cleanse(data_payload_buffer, length_data_payload); - - memcpy(data_payload_buffer, str_data_size, 2); - memcpy(data_payload_buffer + 2, data, length_data); - if (length_padding > 0) { - memcpy(data_payload_buffer + (2 + length_data), - padding_buffer, - length_padding); - } - - mdctx = EVP_MD_CTX_create(); - EVP_DigestInit_ex(mdctx, DIGEST_HASH, NULL); - EVP_DigestUpdate(mdctx, data_payload_buffer, length_data_payload); - - length_hash = EVP_MD_size(DIGEST_HASH); - hash_buffer = OPENSSL_malloc(length_hash); - OPENSSL_cleanse(hash_buffer, length_hash); - EVP_DigestFinal_ex(mdctx, hash_buffer, NULL); - - length_cleartext = length_hash + length_data_payload; - - cleartext_buffer = OPENSSL_malloc(length_cleartext); - OPENSSL_cleanse(cleartext_buffer, length_cleartext); - - /* assemble cleartext-buffer */ - memcpy(cleartext_buffer, hash_buffer, length_hash); - memcpy(cleartext_buffer + length_hash, - data_payload_buffer, - length_data_payload); - OPENSSL_cleanse(data_payload_buffer, length_data_payload); /* sensitive */ - - /* encryption */ - if (!(ctx = EVP_CIPHER_CTX_new())) { - debug_print("New ctx failed\n"); - goto cleanup; - } - - length_ciphertext = 0; - if (EVP_EncryptInit_ex(ctx, CIPHER, NULL, key, salt) != 1) { - debug_print("EVP_EncryptInit_ex failed\n"); - goto cleanup; - } - - ciphertext_buffer = OPENSSL_malloc(length_cleartext); - - crypt_buffer_cnt = 0; - while(1) { - if (EVP_EncryptUpdate(ctx, - ciphertext_buffer + length_ciphertext, - &crypt_buffer_cnt, - cleartext_buffer + length_ciphertext, - 1) != 1) { /* one byte at a time */ - debug_print("EVP_EncryptUpdate failed\n"); - goto cleanup; - } - - if (crypt_buffer_cnt != 1) { /* paranoia */ - debug_print("The sizes of enc and dec text do not correspond\n"); - goto cleanup; - } - - ++length_ciphertext; - - if (length_ciphertext >= length_cleartext) { - break; - } - } - /* No padding required for the CFB mode */ - - OPENSSL_cleanse(cleartext_buffer, length_cleartext); /* sensitive */ - length_total = SALT_SIZE + length_ciphertext; - total_buffer = OPENSSL_malloc(length_total); - - memcpy(total_buffer, salt, SALT_SIZE); - memcpy(total_buffer + SALT_SIZE, ciphertext_buffer, length_ciphertext); - - *encrypted = g_base64_encode(total_buffer, length_total); - *length_encrypted = strlen(*encrypted); - - rc = RC_OK; + gint *length_encrypted, + const gchar *data, + const gchar *passphrase, + gint length_data, + guint min_data_length, + gboolean rnd_salt) { + + gint crypt_buffer_cnt, rc; + guint key_size, length_hash; + guint length_cleartext, length_ciphertext, length_total; + guchar salt[SALT_SIZE]; + guchar *ciphertext_buffer, *total_buffer; + /* sensitive buffers and counters */ + guint length_data_payload, length_padding; + gchar str_data_size[3]; + guchar *data_payload_buffer, *hash_buffer, *padding_buffer, *key; + guchar *cleartext_buffer; + + EVP_CIPHER_CTX *ctx; + EVP_MD_CTX *mdctx; + + rc = RC_ERROR; + + if (length_data < 1) { + return -1; + } + if (rnd_salt) { + if (RAND_bytes(salt, SALT_SIZE) != 1) { + debug_print("Random problems...\n"); + goto cleanup; + } + } else { + strncpy((gchar *)salt, "FOR TESTING ONLY", SALT_SIZE); + } + + key_size = EVP_CIPHER_key_length(CIPHER); + key = OPENSSL_malloc(key_size); + OPENSSL_cleanse(key, key_size); + if (secure_derive_key(key, + key_size, + passphrase, + salt) != RC_OK) { + OPENSSL_cleanse(key, key_size); + debug_print("Could not generate secure key\n"); + goto cleanup; + } + + /* prepare the data-buffer */ + length_padding = 0; + if (length_data < min_data_length) { + g_snprintf(str_data_size, 3, "%02d", length_data); + length_padding = min_data_length - length_data; + padding_buffer = OPENSSL_malloc(length_padding); + OPENSSL_cleanse(padding_buffer, length_padding); + if (RAND_bytes(padding_buffer, length_padding) != 1) { + debug_print("Random problems...\n"); + goto cleanup; + } + } else { + g_snprintf(str_data_size, 3, "-1"); + } + + length_data_payload = 2 + length_data + length_padding; + data_payload_buffer = OPENSSL_malloc(length_data_payload); + OPENSSL_cleanse(data_payload_buffer, length_data_payload); + + memcpy(data_payload_buffer, str_data_size, 2); + memcpy(data_payload_buffer + 2, data, length_data); + if (length_padding > 0) { + memcpy(data_payload_buffer + (2 + length_data), + padding_buffer, + length_padding); + } + + mdctx = EVP_MD_CTX_create(); + EVP_DigestInit_ex(mdctx, DIGEST_HASH, NULL); + EVP_DigestUpdate(mdctx, data_payload_buffer, length_data_payload); + + length_hash = EVP_MD_size(DIGEST_HASH); + hash_buffer = OPENSSL_malloc(length_hash); + OPENSSL_cleanse(hash_buffer, length_hash); + EVP_DigestFinal_ex(mdctx, hash_buffer, NULL); + + length_cleartext = length_hash + length_data_payload; + + cleartext_buffer = OPENSSL_malloc(length_cleartext); + OPENSSL_cleanse(cleartext_buffer, length_cleartext); + + /* assemble cleartext-buffer */ + memcpy(cleartext_buffer, hash_buffer, length_hash); + memcpy(cleartext_buffer + length_hash, + data_payload_buffer, + length_data_payload); + OPENSSL_cleanse(data_payload_buffer, length_data_payload); /* sensitive */ + + /* encryption */ + if (!(ctx = EVP_CIPHER_CTX_new())) { + debug_print("New ctx failed\n"); + goto cleanup; + } + + length_ciphertext = 0; + if (EVP_EncryptInit_ex(ctx, CIPHER, NULL, key, salt) != 1) { + debug_print("EVP_EncryptInit_ex failed\n"); + goto cleanup; + } + + ciphertext_buffer = OPENSSL_malloc(length_cleartext); + + crypt_buffer_cnt = 0; + while(1) { + if (EVP_EncryptUpdate(ctx, + ciphertext_buffer + length_ciphertext, + &crypt_buffer_cnt, + cleartext_buffer + length_ciphertext, + 1) != 1) { /* one byte at a time */ + debug_print("EVP_EncryptUpdate failed\n"); + goto cleanup; + } + + if (crypt_buffer_cnt != 1) { /* paranoia */ + debug_print("The sizes of enc and dec text do not correspond\n"); + goto cleanup; + } + + ++length_ciphertext; + + if (length_ciphertext >= length_cleartext) { + break; + } + } + /* No padding required for the CFB mode */ + + OPENSSL_cleanse(cleartext_buffer, length_cleartext); /* sensitive */ + length_total = SALT_SIZE + length_ciphertext; + total_buffer = OPENSSL_malloc(length_total); + + memcpy(total_buffer, salt, SALT_SIZE); + memcpy(total_buffer + SALT_SIZE, ciphertext_buffer, length_ciphertext); + + *encrypted = g_base64_encode(total_buffer, length_total); + *length_encrypted = strlen(*encrypted); + + rc = RC_OK; cleanup: - /* key */ - OPENSSL_cleanse(key, key_size); - OPENSSL_free(key); - /* cleartext buffer */ - OPENSSL_cleanse(cleartext_buffer, length_cleartext); - OPENSSL_free(cleartext_buffer); - /* payload buffer */ - OPENSSL_cleanse(data_payload_buffer, length_data_payload); - OPENSSL_free(data_payload_buffer); - /* hash */ - OPENSSL_cleanse(hash_buffer, length_hash); - OPENSSL_free(hash_buffer); - /* padding */ - if (length_padding > 0) { - OPENSSL_cleanse(padding_buffer, length_padding); - OPENSSL_free(padding_buffer); - } - - OPENSSL_cleanse(str_data_size, 3); /* paranoia */ - - /* ciphertext buffer */ - OPENSSL_free(ciphertext_buffer); - - /* total buffer */ - OPENSSL_free(total_buffer); - - length_data_payload = 0; - length_padding = 0; - - EVP_CIPHER_CTX_free(ctx); - EVP_MD_CTX_destroy(mdctx); - - return rc; + /* key */ + OPENSSL_cleanse(key, key_size); + OPENSSL_free(key); + /* cleartext buffer */ + OPENSSL_cleanse(cleartext_buffer, length_cleartext); + OPENSSL_free(cleartext_buffer); + /* payload buffer */ + OPENSSL_cleanse(data_payload_buffer, length_data_payload); + OPENSSL_free(data_payload_buffer); + /* hash */ + OPENSSL_cleanse(hash_buffer, length_hash); + OPENSSL_free(hash_buffer); + /* padding */ + if (length_padding > 0) { + OPENSSL_cleanse(padding_buffer, length_padding); + OPENSSL_free(padding_buffer); + } -} + OPENSSL_cleanse(str_data_size, 3); /* paranoia */ + + /* ciphertext buffer */ + OPENSSL_free(ciphertext_buffer); + + /* total buffer */ + OPENSSL_free(total_buffer); + + length_data_payload = 0; + length_padding = 0; + EVP_CIPHER_CTX_free(ctx); + EVP_MD_CTX_destroy(mdctx); + + return rc; + +} gint decrypt_data(gchar **decrypted, - const gchar *data, - const gchar *passphrase, - gint length_data) { - - gint rc; /* return code */ - gint decrypt_buffer_cnt, length_ciphertext, length_decrypted; - guint key_size, length_hash, length_cleartext; - gsize length_total; - guchar salt[SALT_SIZE]; - guchar *ciphertext_buffer, *total_buffer; - /* sensitive buffers and counters */ - gint data_size; - guint length_data_payload; - gchar str_data_size[3]; - guchar *data_payload_buffer, *hash_buffer, *key; - guchar *cleartext_buffer; - - EVP_CIPHER_CTX *ctx; - EVP_MD_CTX *mdctx; - - rc = -1; - - if (length_data < 1) { - return -1; - } - - total_buffer = g_base64_decode(data, &length_total); - length_ciphertext = length_total - SALT_SIZE; - ciphertext_buffer = OPENSSL_malloc(length_ciphertext); - OPENSSL_cleanse(ciphertext_buffer, length_ciphertext); - - memcpy(salt, total_buffer, SALT_SIZE); - memcpy(ciphertext_buffer, total_buffer + SALT_SIZE, length_ciphertext); - - key_size = EVP_CIPHER_key_length(CIPHER); - - /* decryption */ - if(!(ctx = EVP_CIPHER_CTX_new())) { - debug_print("New ctx failed\n"); - goto cleanup; - } - - key = OPENSSL_malloc(key_size); - OPENSSL_cleanse(key, key_size); - if (secure_derive_key(key, - key_size, - passphrase, - salt) != 0) { - OPENSSL_cleanse(key, key_size); - debug_print("Could not generate secure key\n"); - goto cleanup; - } - - if (EVP_DecryptInit_ex(ctx, CIPHER, NULL, key, salt) != 1) { - debug_print("EVP_DecryptInit_ex failed\n"); - goto cleanup; - } - OPENSSL_cleanse(key, key_size); /* highly sensitive */ - cleartext_buffer = OPENSSL_malloc(length_ciphertext); - OPENSSL_cleanse(cleartext_buffer, length_ciphertext); - - length_cleartext = 0; - decrypt_buffer_cnt = 0; - - while(1) { - if (EVP_DecryptUpdate(ctx, - cleartext_buffer + length_cleartext, - &decrypt_buffer_cnt, - ciphertext_buffer + length_cleartext, - 1) != 1) { /* one byte at a time */ - debug_print("EVP_EncryptUpdate failed\n"); - goto cleanup; - } - - if (decrypt_buffer_cnt != 1) { /* paranoia */ - debug_print("The sizes of enc and dec text do not correspond"); - goto cleanup; - } - - ++length_cleartext; - - if (length_cleartext >= length_ciphertext) { - break; - } - } - - - length_hash = EVP_MD_size(DIGEST_HASH); - hash_buffer = OPENSSL_malloc(length_hash); - length_data_payload = length_cleartext - length_hash; - data_payload_buffer = OPENSSL_malloc(length_data_payload); - OPENSSL_cleanse(data_payload_buffer, length_data_payload); - - memcpy(data_payload_buffer, - cleartext_buffer + length_hash, - length_data_payload); - - mdctx = EVP_MD_CTX_create(); - EVP_DigestInit_ex(mdctx, DIGEST_HASH, NULL); - EVP_DigestUpdate(mdctx, data_payload_buffer, length_data_payload); - EVP_DigestFinal_ex(mdctx, hash_buffer, &length_hash); - - if (strncmp((const gchar*) hash_buffer, - (const gchar*) cleartext_buffer, - length_hash) != 0) { - debug_print("Invalid hash\n"); - rc = RC_WRONG_HASH_OR_KEY; - goto cleanup; - } - - memcpy(str_data_size, cleartext_buffer + length_hash, 2); - data_size = atoi(str_data_size); - - if (data_size < 0) { - length_decrypted = length_data_payload - 2; - } else { - length_decrypted = data_size; - } - *decrypted = OPENSSL_malloc(length_decrypted); - memcpy(*decrypted, data_payload_buffer + 2, length_decrypted); - - rc = RC_OK; + const gchar *data, + const gchar *passphrase, + gint length_data) { + + gint rc; /* return code */ + gint decrypt_buffer_cnt, length_ciphertext, length_decrypted; + guint key_size, length_hash, length_cleartext; + gsize length_total; + guchar salt[SALT_SIZE]; + guchar *ciphertext_buffer, *total_buffer; + /* sensitive buffers and counters */ + gint data_size; + guint length_data_payload; + gchar str_data_size[3]; + guchar *data_payload_buffer, *hash_buffer, *key; + guchar *cleartext_buffer; + + EVP_CIPHER_CTX *ctx; + EVP_MD_CTX *mdctx; + + rc = -1; + + if (length_data < 1) { + return -1; + } + + total_buffer = g_base64_decode(data, &length_total); + length_ciphertext = length_total - SALT_SIZE; + ciphertext_buffer = OPENSSL_malloc(length_ciphertext); + OPENSSL_cleanse(ciphertext_buffer, length_ciphertext); + + memcpy(salt, total_buffer, SALT_SIZE); + memcpy(ciphertext_buffer, total_buffer + SALT_SIZE, length_ciphertext); + + key_size = EVP_CIPHER_key_length(CIPHER); + + /* decryption */ + if(!(ctx = EVP_CIPHER_CTX_new())) { + debug_print("New ctx failed\n"); + goto cleanup; + } + + key = OPENSSL_malloc(key_size); + OPENSSL_cleanse(key, key_size); + if (secure_derive_key(key, + key_size, + passphrase, + salt) != 0) { + OPENSSL_cleanse(key, key_size); + debug_print("Could not generate secure key\n"); + goto cleanup; + } + + if (EVP_DecryptInit_ex(ctx, CIPHER, NULL, key, salt) != 1) { + debug_print("EVP_DecryptInit_ex failed\n"); + goto cleanup; + } + OPENSSL_cleanse(key, key_size); /* highly sensitive */ + cleartext_buffer = OPENSSL_malloc(length_ciphertext); + OPENSSL_cleanse(cleartext_buffer, length_ciphertext); + + length_cleartext = 0; + decrypt_buffer_cnt = 0; + + while(1) { + if (EVP_DecryptUpdate(ctx, + cleartext_buffer + length_cleartext, + &decrypt_buffer_cnt, + ciphertext_buffer + length_cleartext, + 1) != 1) { /* one byte at a time */ + debug_print("EVP_EncryptUpdate failed\n"); + goto cleanup; + } + + if (decrypt_buffer_cnt != 1) { /* paranoia */ + debug_print("The sizes of enc and dec text do not correspond"); + goto cleanup; + } + + ++length_cleartext; + + if (length_cleartext >= length_ciphertext) { + break; + } + } + + + length_hash = EVP_MD_size(DIGEST_HASH); + hash_buffer = OPENSSL_malloc(length_hash); + length_data_payload = length_cleartext - length_hash; + data_payload_buffer = OPENSSL_malloc(length_data_payload); + OPENSSL_cleanse(data_payload_buffer, length_data_payload); + + memcpy(data_payload_buffer, + cleartext_buffer + length_hash, + length_data_payload); + + mdctx = EVP_MD_CTX_create(); + EVP_DigestInit_ex(mdctx, DIGEST_HASH, NULL); + EVP_DigestUpdate(mdctx, data_payload_buffer, length_data_payload); + EVP_DigestFinal_ex(mdctx, hash_buffer, &length_hash); + + if (strncmp((const gchar*) hash_buffer, + (const gchar*) cleartext_buffer, + length_hash) != 0) { + debug_print("Invalid hash\n"); + rc = RC_WRONG_HASH_OR_KEY; + goto cleanup; + } + + memcpy(str_data_size, cleartext_buffer + length_hash, 2); + data_size = atoi(str_data_size); + + if (data_size < 0) { + length_decrypted = length_data_payload - 2; + } else { + length_decrypted = data_size; + } + *decrypted = OPENSSL_malloc(length_decrypted); + memcpy(*decrypted, data_payload_buffer + 2, length_decrypted); + + rc = RC_OK; cleanup: - /* key */ - OPENSSL_cleanse(key, key_size); - OPENSSL_free(key); - /* payload buffer */ - OPENSSL_cleanse(data_payload_buffer, length_data_payload); - OPENSSL_free(data_payload_buffer); - /* hash */ - OPENSSL_cleanse(hash_buffer, length_hash); - OPENSSL_free(hash_buffer); - /* ciphertext */ - OPENSSL_free(ciphertext_buffer); - OPENSSL_free(total_buffer); + /* key */ + OPENSSL_cleanse(key, key_size); + OPENSSL_free(key); + /* payload buffer */ + OPENSSL_cleanse(data_payload_buffer, length_data_payload); + OPENSSL_free(data_payload_buffer); + /* hash */ + OPENSSL_cleanse(hash_buffer, length_hash); + OPENSSL_free(hash_buffer); + /* ciphertext */ + OPENSSL_free(ciphertext_buffer); + OPENSSL_free(total_buffer); - EVP_CIPHER_CTX_free(ctx); - EVP_MD_CTX_destroy(mdctx); + EVP_CIPHER_CTX_free(ctx); + EVP_MD_CTX_destroy(mdctx); - return rc; + return rc; } gint generate_password_hash(gchar **password_hash, - const gchar *password, - const guchar *salt) { - /* - * Hashes 'password' using PKCS5_PBKDF2_HMAC with SHA512 and 'salt', - * and assigns a string to 'password_hash' with the following format: - * pbkdf2_sha512$iterations$base64(salt)$base64(password_hash) - */ - guchar lsalt[SALT_SIZE]; - gchar *PBKDF2_digest, *salt_b64, *digest_b64; - - if (salt == NULL) { - if (RAND_bytes(lsalt, SALT_SIZE) != 1) { - debug_print("Random problems...\n"); - return RC_ERROR; - } - } else { - memcpy(lsalt, salt, SALT_SIZE); - } - - PBKDF2_digest = OPENSSL_malloc(PBKDF2_DIGEST_SIZE); - OPENSSL_cleanse(PBKDF2_digest, PBKDF2_DIGEST_SIZE); - - PKCS5_PBKDF2_HMAC(password, - strlen(password), - lsalt, - SALT_SIZE, - PBKDF2_ITERATIONS, - EVP_sha512(), - PBKDF2_DIGEST_SIZE, - (guchar *) PBKDF2_digest); - digest_b64 = g_base64_encode((guchar *) PBKDF2_digest, PBKDF2_DIGEST_SIZE); - OPENSSL_cleanse(PBKDF2_digest, PBKDF2_DIGEST_SIZE); - OPENSSL_free(PBKDF2_digest); - - salt_b64 = g_base64_encode(lsalt, SALT_SIZE); - - *password_hash = g_strdup_printf("pbkdf2_sha512$%d$%s$%s", - PBKDF2_ITERATIONS, - salt_b64, - digest_b64); - - OPENSSL_cleanse(digest_b64, strlen(digest_b64)); - OPENSSL_free(digest_b64); - - OPENSSL_cleanse(salt_b64, strlen(salt_b64)); - OPENSSL_free(salt_b64); - - return RC_OK; + const gchar *password, + const guchar *salt) { + /* + * Hashes 'password' using PKCS5_PBKDF2_HMAC with SHA512 and 'salt', + * and assigns a string to 'password_hash' with the following format: + * pbkdf2_sha512$iterations$base64(salt)$base64(password_hash) + */ + guchar lsalt[SALT_SIZE]; + gchar *PBKDF2_digest, *salt_b64, *digest_b64; + + if (salt == NULL) { + if (RAND_bytes(lsalt, SALT_SIZE) != 1) { + debug_print("Random problems...\n"); + return RC_ERROR; + } + } else { + memcpy(lsalt, salt, SALT_SIZE); + } + + PBKDF2_digest = OPENSSL_malloc(PBKDF2_DIGEST_SIZE); + OPENSSL_cleanse(PBKDF2_digest, PBKDF2_DIGEST_SIZE); + + PKCS5_PBKDF2_HMAC(password, + strlen(password), + lsalt, + SALT_SIZE, + PBKDF2_ITERATIONS, + EVP_sha512(), + PBKDF2_DIGEST_SIZE, + (guchar *) PBKDF2_digest); + digest_b64 = g_base64_encode((guchar *) PBKDF2_digest, PBKDF2_DIGEST_SIZE); + OPENSSL_cleanse(PBKDF2_digest, PBKDF2_DIGEST_SIZE); + OPENSSL_free(PBKDF2_digest); + + salt_b64 = g_base64_encode(lsalt, SALT_SIZE); + + *password_hash = g_strdup_printf("pbkdf2_sha512$%d$%s$%s", + PBKDF2_ITERATIONS, + salt_b64, + digest_b64); + + OPENSSL_cleanse(digest_b64, strlen(digest_b64)); + OPENSSL_free(digest_b64); + + OPENSSL_cleanse(salt_b64, strlen(salt_b64)); + OPENSSL_free(salt_b64); + + return RC_OK; } gint check_password(const gchar *password, const gchar *password_hash) { - gint token_counter, rc; - guchar *salt; - gchar **tokens, *new_hash; - gsize salt_length; - - rc = RC_ERROR; - tokens = g_strsplit(password_hash, - "$", - -1); - token_counter = 0; - while (*(tokens + token_counter) != NULL) { - ++token_counter; - } - - if (token_counter != 4) { - debug_print("Invalid password hash...\n"); - goto cleanup; - } - - salt = g_base64_decode(*(tokens + 2), &salt_length); - if (salt_length != SALT_SIZE) { - debug_print("Salt size does not match\n"); - goto cleanup; - } - - if (generate_password_hash(&new_hash, password, salt) != RC_OK) { - debug_print("Password hash generation failed\n"); - goto cleanup; - } - - rc = g_strcmp0(password_hash, new_hash); + gint token_counter, rc; + guchar *salt; + gchar **tokens, *new_hash; + gsize salt_length; + + rc = RC_ERROR; + tokens = g_strsplit(password_hash, + "$", + -1); + token_counter = 0; + while (*(tokens + token_counter) != NULL) { + ++token_counter; + } + + if (token_counter != 4) { + debug_print("Invalid password hash...\n"); + goto cleanup; + } + + salt = g_base64_decode(*(tokens + 2), &salt_length); + if (salt_length != SALT_SIZE) { + debug_print("Salt size does not match\n"); + goto cleanup; + } + + if (generate_password_hash(&new_hash, password, salt) != RC_OK) { + debug_print("Password hash generation failed\n"); + goto cleanup; + } + + rc = g_strcmp0(password_hash, new_hash); cleanup: - g_free(salt); - g_free(new_hash); - g_strfreev(tokens); - return rc; + g_free(salt); + g_free(new_hash); + g_strfreev(tokens); + return rc; } -- cgit v1.3