X-Git-Url: http://git.claws-mail.org/?p=claws.git;a=blobdiff_plain;f=src%2Fpassword.c;h=826d3167545842f72f7491840e715afabece6ddf;hp=7e37e28750b92a7a98c899ab70799775dce60a35;hb=d643604a31ead1f9767fbde96e8a24b13b80def8;hpb=5bef3aecedf1f062cc9ddf9a3b819841a5d989f8 diff --git a/src/password.c b/src/password.c index 7e37e2875..826d31675 100644 --- a/src/password.c +++ b/src/password.c @@ -45,60 +45,62 @@ #include "alertpanel.h" #include "inputdialog.h" #include "password.h" +#include "passwordstore.h" #include "prefs_common.h" #ifndef PASSWORD_CRYPTO_OLD -static gchar *_master_password = NULL; +static gchar *_master_passphrase = NULL; -static const gchar *master_password() +static const gchar *master_passphrase() { gchar *input; gboolean end = FALSE; - if (!prefs_common_get_prefs()->use_master_password) { + if (!prefs_common_get_prefs()->use_master_passphrase) { return PASSCRYPT_KEY; } - if (_master_password != NULL) { - debug_print("Master password is in memory, offering it.\n"); - return _master_password; + if (_master_passphrase != NULL) { + debug_print("Master passphrase is in memory, offering it.\n"); + return _master_passphrase; } while (!end) { - input = input_dialog_with_invisible(_("Input master password"), - _("Input master password"), NULL); + input = input_dialog_with_invisible(_("Input master passphrase"), + _("Input master passphrase"), NULL); if (input == NULL) { - debug_print("Cancel pressed at master password dialog.\n"); + debug_print("Cancel pressed at master passphrase dialog.\n"); break; } - if (master_password_is_correct(input)) { - debug_print("Entered master password seems to be correct, remembering it.\n"); - _master_password = input; + if (master_passphrase_is_correct(input)) { + debug_print("Entered master passphrase seems to be correct, remembering it.\n"); + _master_passphrase = input; end = TRUE; } else { - alertpanel_error(_("Incorrect master password.")); + alertpanel_error(_("Incorrect master passphrase.")); } } - return _master_password; + return _master_passphrase; } -const gboolean master_password_is_set() +const gboolean master_passphrase_is_set() { - if (prefs_common_get_prefs()->master_password_hash == NULL - || strlen(prefs_common_get_prefs()->master_password_hash) == 0) + if (prefs_common_get_prefs()->master_passphrase_hash == NULL + || strlen(prefs_common_get_prefs()->master_passphrase_hash) == 0) return FALSE; return TRUE; } -const gboolean master_password_is_correct(const gchar *input) +const gboolean master_passphrase_is_correct(const gchar *input) { gchar *hash; - gchar *stored_hash = prefs_common_get_prefs()->master_password_hash; - const GChecksumType hashtype = G_CHECKSUM_SHA512; + gchar **tokens; + gchar *stored_hash = prefs_common_get_prefs()->master_passphrase_hash; + const GChecksumType hashtype = G_CHECKSUM_SHA256; const gssize hashlen = g_checksum_type_get_length(hashtype); gssize stored_len; @@ -107,6 +109,16 @@ const gboolean master_password_is_correct(const gchar *input) if (stored_hash == NULL) return FALSE; + tokens = g_strsplit_set(stored_hash, "{}", 3); + if (strlen(tokens[0]) != 0 || + strcmp(tokens[1], "SHA-256") || + strlen(tokens[2]) == 0) { + debug_print("Mangled master_passphrase_hash in config, can not use it.\n"); + g_strfreev(tokens); + return FALSE; + } + + stored_hash = tokens[2]; stored_len = strlen(stored_hash); g_return_val_if_fail(stored_len == 2*hashlen, FALSE); @@ -114,58 +126,61 @@ const gboolean master_password_is_correct(const gchar *input) if (!strncasecmp(hash, stored_hash, stored_len)) { g_free(hash); + g_strfreev(tokens); return TRUE; } + g_strfreev(tokens); g_free(hash); return FALSE; } -gboolean master_password_is_entered() +gboolean master_passphrase_is_entered() { - return (_master_password == NULL) ? FALSE : TRUE; + return (_master_passphrase == NULL) ? FALSE : TRUE; } -void master_password_forget() +void master_passphrase_forget() { - /* If master password is currently in memory (entered by user), + /* If master passphrase is currently in memory (entered by user), * get rid of it. User will have to enter the new one again. */ - if (_master_password != NULL) { - memset(_master_password, 0, strlen(_master_password)); - g_free(_master_password); + if (_master_passphrase != NULL) { + memset(_master_passphrase, 0, strlen(_master_passphrase)); + g_free(_master_passphrase); + _master_passphrase = NULL; } - _master_password = NULL; } -void master_password_change(const gchar *newp) +void master_passphrase_change(const gchar *oldp, const gchar *newp) { - gchar *pwd, *newpwd; - const gchar *oldp; - GList *cur; - PrefsAccount *acc; - - /* Make sure the user has to enter the master password before - * being able to change it. */ - master_password_forget(); + const GChecksumType hashtype = G_CHECKSUM_SHA256; + gchar *hash; - oldp = master_password(); + if (oldp == NULL) { + /* If oldp is NULL, make sure the user has to enter the + * current master passphrase before being able to change it. */ + master_passphrase_forget(); + oldp = master_passphrase(); + } g_return_if_fail(oldp != NULL); - /* Update master password hash in prefs */ - if (prefs_common_get_prefs()->master_password_hash != NULL) - g_free(prefs_common_get_prefs()->master_password_hash); + /* Update master passphrase hash in prefs */ + if (prefs_common_get_prefs()->master_passphrase_hash != NULL) + g_free(prefs_common_get_prefs()->master_passphrase_hash); if (newp != NULL) { - debug_print("Storing hash of new master password\n"); - prefs_common_get_prefs()->master_password_hash = - g_compute_checksum_for_string(G_CHECKSUM_SHA512, newp, -1); + debug_print("Storing hash of new master passphrase\n"); + hash = g_compute_checksum_for_string(hashtype, newp, -1); + prefs_common_get_prefs()->master_passphrase_hash = + g_strconcat("{SHA-256}", hash, NULL); + g_free(hash); } else { - debug_print("Setting master_password_hash to NULL\n"); - prefs_common_get_prefs()->master_password_hash = NULL; + debug_print("Setting master_passphrase_hash to NULL\n"); + prefs_common_get_prefs()->master_passphrase_hash = NULL; } /* Now go over all accounts, reencrypting their passwords using - * the new master password. */ + * the new master passphrase. */ if (oldp == NULL) oldp = PASSCRYPT_KEY; @@ -173,53 +188,14 @@ void master_password_change(const gchar *newp) newp = PASSCRYPT_KEY; debug_print("Reencrypting all account passwords...\n"); - for (cur = account_get_list(); cur != NULL; cur = cur->next) { - acc = (PrefsAccount *)cur->data; - debug_print("account %s\n", acc->account_name); - - /* Password for receiving */ - if (acc->passwd != NULL && strlen(acc->passwd) > 0) { - pwd = password_decrypt(acc->passwd, oldp); - if (pwd == NULL) { - debug_print("failed to decrypt recv password with old master password\n"); - } else { - newpwd = password_encrypt(pwd, newp); - memset(pwd, 0, strlen(pwd)); - g_free(pwd); - if (newpwd == NULL) { - debug_print("failed to encrypt recv password with new master password\n"); - } else { - g_free(acc->passwd); - acc->passwd = newpwd; - } - } - } - - /* Password for sending */ - if (acc->smtp_passwd != NULL && strlen(acc->smtp_passwd) > 0) { - pwd = password_decrypt(acc->smtp_passwd, oldp); - if (pwd == NULL) { - debug_print("failed to decrypt smtp password with old master password\n"); - } else { - newpwd = password_encrypt(pwd, newp); - memset(pwd, 0, strlen(pwd)); - g_free(pwd); - if (newpwd == NULL) { - debug_print("failed to encrypt smtp password with new master password\n"); - } else { - g_free(acc->smtp_passwd); - acc->smtp_passwd = newpwd; - } - } - } - } + passwd_store_reencrypt_all(oldp, newp); /* Now reencrypt all plugins passwords fields * FIXME: Unloaded plugins won't be able to update their stored passwords */ - plugins_master_password_change(oldp, newp); + plugins_master_passphrase_change(oldp, newp); - master_password_forget(); + master_passphrase_forget(); } #endif @@ -262,8 +238,12 @@ gchar *password_decrypt_old(const gchar *password) #ifdef PASSWORD_CRYPTO_GNUTLS #define BUFSIZE 128 +/* Since we can't count on having GnuTLS new enough to have + * gnutls_cipher_get_iv_size(), we hardcode the IV length for now. */ +#define IVLEN 16 + gchar *password_encrypt_gnutls(const gchar *password, - const gchar *encryption_password) + const gchar *encryption_passphrase) { /* Another, slightly inferior combination is AES-128-CBC + SHA-256. * Any block cipher in CBC mode with keysize N and a hash algo with @@ -272,7 +252,7 @@ gchar *password_encrypt_gnutls(const gchar *password, gnutls_digest_algorithm_t digest = GNUTLS_DIG_SHA512; gnutls_cipher_hd_t handle; gnutls_datum_t key, iv; - int ivlen, keylen, digestlen, blocklen, ret, i; + int keylen, digestlen, blocklen, ret, i; unsigned char hashbuf[BUFSIZE], *buf, *encbuf, *base, *output; #if defined G_OS_UNIX int rnd; @@ -281,9 +261,9 @@ gchar *password_encrypt_gnutls(const gchar *password, #endif g_return_val_if_fail(password != NULL, NULL); - g_return_val_if_fail(encryption_password != NULL, NULL); + g_return_val_if_fail(encryption_passphrase != NULL, NULL); - ivlen = gnutls_cipher_get_iv_size(algo); +/* ivlen = gnutls_cipher_get_iv_size(algo);*/ keylen = gnutls_cipher_get_key_size(algo); blocklen = gnutls_cipher_get_block_size(algo); digestlen = gnutls_hash_get_len(digest); @@ -291,8 +271,8 @@ gchar *password_encrypt_gnutls(const gchar *password, /* Prepare key for cipher - first half of hash of passkey XORed with * the second. */ memset(&hashbuf, 0, BUFSIZE); - if ((ret = gnutls_hash_fast(digest, encryption_password, - strlen(encryption_password), &hashbuf)) < 0) { + if ((ret = gnutls_hash_fast(digest, encryption_passphrase, + strlen(encryption_passphrase), &hashbuf)) < 0) { debug_print("Hashing passkey failed: %s\n", gnutls_strerror(ret)); return NULL; } @@ -320,15 +300,15 @@ gchar *password_encrypt_gnutls(const gchar *password, } /* Prepare random IV for cipher */ - iv.data = malloc(ivlen); - iv.size = ivlen; + iv.data = malloc(IVLEN); + iv.size = IVLEN; #if defined G_OS_UNIX - ret = read(rnd, iv.data, ivlen); - if (ret != ivlen) { + ret = read(rnd, iv.data, IVLEN); + if (ret != IVLEN) { perror("read into iv"); close(rnd); #elif defined G_OS_WIN32 - if (!CryptGenRandom(rnd, ivlen, iv.data)) { + if (!CryptGenRandom(rnd, IVLEN, iv.data)) { debug_print("Could not read random data for IV\n"); CryptReleaseContext(rnd, 0); #endif @@ -411,14 +391,14 @@ gchar *password_encrypt_gnutls(const gchar *password, } gchar *password_decrypt_gnutls(const gchar *password, - const gchar *decryption_password) + const gchar *decryption_passphrase) { gchar **tokens, *tmp; gnutls_cipher_algorithm_t algo; gnutls_digest_algorithm_t digest = GNUTLS_DIG_UNKNOWN; gnutls_cipher_hd_t handle; gnutls_datum_t key, iv; - int ivlen, keylen, digestlen, blocklen, ret, i; + int keylen, digestlen, blocklen, ret, i; gsize len; unsigned char hashbuf[BUFSIZE], *buf; #if defined G_OS_UNIX @@ -428,7 +408,7 @@ gchar *password_decrypt_gnutls(const gchar *password, #endif g_return_val_if_fail(password != NULL, NULL); - g_return_val_if_fail(decryption_password != NULL, NULL); + g_return_val_if_fail(decryption_passphrase != NULL, NULL); tokens = g_strsplit_set(password, "{}", 3); @@ -454,7 +434,7 @@ gchar *password_decrypt_gnutls(const gchar *password, return NULL; } - ivlen = gnutls_cipher_get_iv_size(algo); +/* ivlen = gnutls_cipher_get_iv_size(algo); */ keylen = gnutls_cipher_get_key_size(algo); blocklen = gnutls_cipher_get_block_size(algo); digestlen = gnutls_hash_get_len(digest); @@ -463,8 +443,8 @@ gchar *password_decrypt_gnutls(const gchar *password, * the second. AES-256 has key length 32 and length of SHA-512 hash * is exactly twice that, 64. */ memset(&hashbuf, 0, BUFSIZE); - if ((ret = gnutls_hash_fast(digest, decryption_password, - strlen(decryption_password), &hashbuf)) < 0) { + if ((ret = gnutls_hash_fast(digest, decryption_passphrase, + strlen(decryption_passphrase), &hashbuf)) < 0) { debug_print("Hashing passkey failed: %s\n", gnutls_strerror(ret)); g_strfreev(tokens); return NULL; @@ -494,15 +474,15 @@ gchar *password_decrypt_gnutls(const gchar *password, } /* Prepare random IV for cipher */ - iv.data = malloc(ivlen); - iv.size = ivlen; + iv.data = malloc(IVLEN); + iv.size = IVLEN; #if defined G_OS_UNIX - ret = read(rnd, iv.data, ivlen); - if (ret != ivlen) { + ret = read(rnd, iv.data, IVLEN); + if (ret != IVLEN) { perror("read into iv"); close(rnd); #elif defined G_OS_WIN32 - if (!CryptGenRandom(rnd, ivlen, iv.data)) { + if (!CryptGenRandom(rnd, IVLEN, iv.data)) { debug_print("Could not read random data for IV\n"); CryptReleaseContext(rnd, 0); #endif @@ -560,24 +540,24 @@ gchar *password_decrypt_gnutls(const gchar *password, #endif gchar *password_encrypt(const gchar *password, - const gchar *encryption_password) + const gchar *encryption_passphrase) { if (password == NULL || strlen(password) == 0) { return NULL; } #ifndef PASSWORD_CRYPTO_OLD - if (encryption_password == NULL) - encryption_password = master_password(); + if (encryption_passphrase == NULL) + encryption_passphrase = master_passphrase(); - return password_encrypt_real(password, encryption_password); + return password_encrypt_real(password, encryption_passphrase); #endif return password_encrypt_old(password); } gchar *password_decrypt(const gchar *password, - const gchar *decryption_password) + const gchar *decryption_passphrase) { if (password == NULL || strlen(password) == 0) { return NULL; @@ -592,12 +572,12 @@ gchar *password_decrypt(const gchar *password, /* Try available crypto backend */ #ifndef PASSWORD_CRYPTO_OLD - if (decryption_password == NULL) - decryption_password = master_password(); + if (decryption_passphrase == NULL) + decryption_passphrase = master_passphrase(); if (*password == '{') { debug_print("Trying to decrypt password...\n"); - return password_decrypt_real(password, decryption_password); + return password_decrypt_real(password, decryption_passphrase); } #endif