X-Git-Url: http://git.claws-mail.org/?p=claws.git;a=blobdiff_plain;f=src%2Fpassword.c;h=d0025671b20af1a2c77c9cf0a3db854ce0aaebf8;hp=dba5ef20bc3c68da5aa08e7d1e02b64e48fcfd5a;hb=a7a70c6aa50917670ea3897d040457609c4b0242;hpb=f1811794160f215211d17ed164d8d25822545a23 diff --git a/src/password.c b/src/password.c index dba5ef20b..d0025671b 100644 --- a/src/password.c +++ b/src/password.c @@ -30,70 +30,75 @@ #include #include -#ifdef G_OS_UNIX +#if defined G_OS_UNIX #include #include +#elif defined G_OS_WIN32 +#include +#include #endif #include "common/passcrypt.h" +#include "common/plugin.h" #include "common/utils.h" #include "account.h" #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; + gchar *stored_hash = prefs_common_get_prefs()->master_passphrase_hash; const GChecksumType hashtype = G_CHECKSUM_SHA512; const gssize hashlen = g_checksum_type_get_length(hashtype); gssize stored_len; @@ -117,51 +122,47 @@ const gboolean master_password_is_correct(const gchar *input) 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_password = NULL; + _master_passphrase = 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(); - - 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 = + debug_print("Storing hash of new master passphrase\n"); + prefs_common_get_prefs()->master_passphrase_hash = g_compute_checksum_for_string(G_CHECKSUM_SHA512, newp, -1); } 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; @@ -169,48 +170,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; - } - } - } + passwd_store_reencrypt_all(oldp, newp); - /* 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; - } - } - } - } + /* Now reencrypt all plugins passwords fields + * FIXME: Unloaded plugins won't be able to update their stored passwords + */ + plugins_master_passphrase_change(oldp, newp); - master_password_forget(); + master_passphrase_forget(); } #endif @@ -254,7 +221,7 @@ gchar *password_decrypt_old(const gchar *password) #define BUFSIZE 128 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 @@ -265,12 +232,14 @@ gchar *password_encrypt_gnutls(const gchar *password, gnutls_datum_t key, iv; int ivlen, keylen, digestlen, blocklen, ret, i; unsigned char hashbuf[BUFSIZE], *buf, *encbuf, *base, *output; -#ifdef G_OS_UNIX +#if defined G_OS_UNIX int rnd; +#elif defined G_OS_WIN32 + HCRYPTPROV rnd; #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); keylen = gnutls_cipher_get_key_size(algo); @@ -280,8 +249,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; } @@ -293,38 +262,48 @@ gchar *password_encrypt_gnutls(const gchar *password, memcpy(key.data, &hashbuf, keylen); key.size = keylen; -#ifdef G_OS_UNIX /* Prepare our source of random data. */ +#if defined G_OS_UNIX rnd = open("/dev/urandom", O_RDONLY); if (rnd == -1) { perror("fopen on /dev/urandom"); +#elif defined G_OS_WIN32 + if (!CryptAcquireContext(&rnd, NULL, NULL, PROV_RSA_FULL, 0) && + !CryptAcquireContext(&rnd, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)) { + debug_print("Could not acquire a CSP handle.\n"); +#endif g_free(key.data); g_free(iv.data); return NULL; } -#endif /* Prepare random IV for cipher */ iv.data = malloc(ivlen); iv.size = ivlen; -#ifdef G_OS_UNIX +#if defined G_OS_UNIX 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)) { + debug_print("Could not read random data for IV\n"); + CryptReleaseContext(rnd, 0); +#endif g_free(key.data); g_free(iv.data); - close(rnd); return NULL; } -#endif /* Initialize the encryption */ ret = gnutls_cipher_init(&handle, algo, &key, &iv); if (ret < 0) { g_free(key.data); g_free(iv.data); -#ifdef G_OS_UNIX +#if defined G_OS_UNIX close(rnd); +#elif defined G_OS_WIN32 + CryptReleaseContext(rnd, 0); #endif return NULL; } @@ -333,20 +312,28 @@ gchar *password_encrypt_gnutls(const gchar *password, * rest with zero bytes. */ buf = malloc(BUFSIZE + blocklen); memset(buf, 0, BUFSIZE); -#ifdef G_OS_UNIX +#if defined G_OS_UNIX ret = read(rnd, buf, blocklen); if (ret != blocklen) { perror("read into buffer"); + close(rnd); +#elif defined G_OS_WIN32 + if (!CryptGenRandom(rnd, blocklen, buf)) { + debug_print("Could not read random data for IV\n"); + CryptReleaseContext(rnd, 0); +#endif g_free(buf); g_free(key.data); g_free(iv.data); - close(rnd); gnutls_cipher_deinit(handle); return NULL; } /* We don't need any more random data. */ +#if defined G_OS_UNIX close(rnd); +#elif defined G_OS_WIN32 + CryptReleaseContext(rnd, 0); #endif memcpy(buf + blocklen, password, strlen(password)); @@ -382,7 +369,7 @@ 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; @@ -392,12 +379,14 @@ gchar *password_decrypt_gnutls(const gchar *password, int ivlen, keylen, digestlen, blocklen, ret, i; gsize len; unsigned char hashbuf[BUFSIZE], *buf; -#ifdef G_OS_UNIX +#if defined G_OS_UNIX int rnd; +#elif defined G_OS_WIN32 + HCRYPTPROV rnd; #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); @@ -432,8 +421,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; @@ -446,34 +435,46 @@ gchar *password_decrypt_gnutls(const gchar *password, memcpy(key.data, &hashbuf, keylen); key.size = keylen; -#ifdef G_OS_UNIX /* Prepare our source of random data. */ +#if defined G_OS_UNIX rnd = open("/dev/urandom", O_RDONLY); if (rnd == -1) { perror("fopen on /dev/urandom"); +#elif defined G_OS_WIN32 + if (!CryptAcquireContext(&rnd, NULL, NULL, PROV_RSA_FULL, 0) && + !CryptAcquireContext(&rnd, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)) { + debug_print("Could not acquire a CSP handle.\n"); +#endif g_free(key.data); g_free(iv.data); g_strfreev(tokens); return NULL; } -#endif /* Prepare random IV for cipher */ iv.data = malloc(ivlen); iv.size = ivlen; -#ifdef G_OS_UNIX +#if defined G_OS_UNIX 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)) { + debug_print("Could not read random data for IV\n"); + CryptReleaseContext(rnd, 0); +#endif g_free(key.data); g_free(iv.data); g_strfreev(tokens); - close(rnd); return NULL; } /* We don't need any more random data. */ +#if defined G_OS_UNIX close(rnd); +#elif defined G_OS_WIN32 + CryptReleaseContext(rnd, 0); #endif /* Prepare encrypted password string for decryption. */ @@ -517,24 +518,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; @@ -549,12 +550,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