fix CID 1596595: Resource leaks, and CID 1596594: (CHECKED_RETURN)
[claws.git] / src / password.c
1 /*
2  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 2016 The Claws Mail Team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  *
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #include "claws-features.h"
23 #endif
24
25 #ifdef PASSWORD_CRYPTO_GNUTLS
26 # include <gnutls/gnutls.h>
27 # include <gnutls/crypto.h>
28 #endif
29
30 #include <glib.h>
31 #include <glib/gi18n.h>
32
33 #if defined G_OS_UNIX
34 #include <fcntl.h>
35 #include <unistd.h>
36 #elif defined G_OS_WIN32
37 #include <windows.h>
38 #include <wincrypt.h>
39 #endif
40
41 #include "common/passcrypt.h"
42 #include "common/plugin.h"
43 #include "common/pkcs5_pbkdf2.h"
44 #include "common/timing.h"
45 #include "common/utils.h"
46 #include "account.h"
47 #include "alertpanel.h"
48 #include "inputdialog.h"
49 #include "password.h"
50 #include "passwordstore.h"
51 #include "prefs_common.h"
52
53 #ifndef PASSWORD_CRYPTO_OLD
54 static gchar *_master_passphrase = NULL;
55
56 /* Length of stored key derivation, before base64. */
57 #define KD_LENGTH 64
58
59 /* Length of randomly generated and saved salt, used for key derivation.
60  * Also before base64. */
61 #define KD_SALT_LENGTH 64
62
63 static void _generate_salt()
64 {
65         guchar salt[KD_SALT_LENGTH];
66
67         if (prefs_common_get_prefs()->master_passphrase_salt != NULL) {
68                 g_free(prefs_common_get_prefs()->master_passphrase_salt);
69         }
70
71         if (!get_random_bytes(salt, KD_SALT_LENGTH)) {
72                 debug_print("Could not get random bytes for kd salt.\n");
73                 return;
74         }
75
76         prefs_common_get_prefs()->master_passphrase_salt =
77                 g_base64_encode(salt, KD_SALT_LENGTH);
78 }
79
80 #undef KD_SALT_LENGTH
81
82 static guchar *_make_key_deriv(const gchar *passphrase, guint rounds,
83                 guint length)
84 {
85         guchar *kd, *salt;
86         gchar *saltpref = prefs_common_get_prefs()->master_passphrase_salt;
87         gsize saltlen;
88         gint ret;
89
90         /* Grab our salt, generating and saving a new random one if needed. */
91         if (saltpref == NULL || strlen(saltpref) == 0) {
92                 _generate_salt();
93                 saltpref = prefs_common_get_prefs()->master_passphrase_salt;
94         }
95         salt = g_base64_decode(saltpref, &saltlen);
96         kd = g_malloc0(length);
97
98         START_TIMING("PBKDF2");
99         ret = pkcs5_pbkdf2(passphrase, strlen(passphrase), salt, saltlen,
100                         kd, length, rounds);
101         END_TIMING();
102
103         g_free(salt);
104
105         if (ret == 0) {
106                 return kd;
107         }
108
109         g_free(kd);
110         return NULL;
111 }
112
113 const gchar *master_passphrase()
114 {
115         gchar *input;
116         gboolean end = FALSE;
117
118         if (!prefs_common_get_prefs()->use_master_passphrase) {
119                 return PASSCRYPT_KEY;
120         }
121
122         if (_master_passphrase != NULL) {
123                 debug_print("Master passphrase is in memory, offering it.\n");
124                 return _master_passphrase;
125         }
126
127         while (!end) {
128                 input = input_dialog_with_invisible(_("Input master passphrase"),
129                                 _("Input master passphrase"), NULL);
130
131                 if (input == NULL) {
132                         debug_print("Cancel pressed at master passphrase dialog.\n");
133                         break;
134                 }
135
136                 if (master_passphrase_is_correct(input)) {
137                         debug_print("Entered master passphrase seems to be correct, remembering it.\n");
138                         _master_passphrase = input;
139                         end = TRUE;
140                 } else {
141                         alertpanel_error(_("Incorrect master passphrase."));
142                 }
143         }
144
145         return _master_passphrase;
146 }
147
148 gboolean master_passphrase_is_set()
149 {
150         if (prefs_common_get_prefs()->master_passphrase == NULL
151                         || strlen(prefs_common_get_prefs()->master_passphrase) == 0)
152                 return FALSE;
153
154         return TRUE;
155 }
156
157 gboolean master_passphrase_is_correct(const gchar *input)
158 {
159         guchar *kd, *input_kd;
160         gchar **tokens;
161         gchar *stored_kd = prefs_common_get_prefs()->master_passphrase;
162         gsize kd_len;
163         guint rounds = 0;
164         gint ret;
165
166         g_return_val_if_fail(stored_kd != NULL && strlen(stored_kd) > 0, FALSE);
167         g_return_val_if_fail(input != NULL, FALSE);
168
169         tokens = g_strsplit_set(stored_kd, "{}", 3);
170         if (tokens[0] == NULL ||
171                         strlen(tokens[0]) != 0 || /* nothing before { */
172                         tokens[1] == NULL ||
173                         strncmp(tokens[1], "PBKDF2-HMAC-SHA1,", 17) || /* correct tag */
174                         strlen(tokens[1]) <= 17 || /* something after , */
175                         (rounds = atoi(tokens[1] + 17)) <= 0 || /* valid rounds # */
176                         tokens[2] == NULL ||
177                         strlen(tokens[2]) == 0) { /* string continues after } */
178                 debug_print("Mangled master_passphrase format in config, can not use it.\n");
179                 g_strfreev(tokens);
180                 return FALSE;
181         }
182
183         stored_kd = tokens[2];
184         kd = g_base64_decode(stored_kd, &kd_len); /* should be 64 */
185         g_strfreev(tokens);
186
187         if (kd_len != KD_LENGTH) {
188                 debug_print("master_passphrase is %"G_GSIZE_FORMAT" bytes long, should be %d.\n",
189                                 kd_len, KD_LENGTH);
190                 g_free(kd);
191                 return FALSE;
192         }
193
194         input_kd = _make_key_deriv(input, rounds, KD_LENGTH);
195         ret = memcmp(kd, input_kd, kd_len);
196
197         g_free(input_kd);
198         g_free(kd);
199
200         if (ret == 0)
201                 return TRUE;
202
203         return FALSE;
204 }
205
206 gboolean master_passphrase_is_entered()
207 {
208         return (_master_passphrase == NULL) ? FALSE : TRUE;
209 }
210
211 void master_passphrase_forget()
212 {
213         /* If master passphrase is currently in memory (entered by user),
214          * get rid of it. User will have to enter the new one again. */
215         if (_master_passphrase != NULL) {
216                 memset(_master_passphrase, 0, strlen(_master_passphrase));
217                 g_free(_master_passphrase);
218                 _master_passphrase = NULL;
219         }
220 }
221
222 void master_passphrase_change(const gchar *oldp, const gchar *newp)
223 {
224         guchar *kd;
225         gchar *base64_kd;
226         guint rounds = prefs_common_get_prefs()->master_passphrase_pbkdf2_rounds;
227
228         g_return_if_fail(rounds > 0);
229
230         if (oldp == NULL) {
231                 /* If oldp is NULL, make sure the user has to enter the
232                  * current master passphrase before being able to change it. */
233                 master_passphrase_forget();
234                 oldp = master_passphrase();
235         }
236         g_return_if_fail(oldp != NULL);
237
238         /* Update master passphrase hash in prefs */
239         if (prefs_common_get_prefs()->master_passphrase != NULL)
240                 g_free(prefs_common_get_prefs()->master_passphrase);
241
242         if (newp != NULL) {
243                 debug_print("Storing key derivation of new master passphrase\n");
244                 kd = _make_key_deriv(newp, rounds, KD_LENGTH);
245                 base64_kd = g_base64_encode(kd, 64);
246                 prefs_common_get_prefs()->master_passphrase =
247                         g_strdup_printf("{PBKDF2-HMAC-SHA1,%d}%s", rounds, base64_kd);
248                 g_free(kd);
249                 g_free(base64_kd);
250         } else {
251                 debug_print("Setting master_passphrase to NULL\n");
252                 prefs_common_get_prefs()->master_passphrase = NULL;
253         }
254
255         /* Now go over all accounts, reencrypting their passwords using
256          * the new master passphrase. */
257
258         if (oldp == NULL)
259                 oldp = PASSCRYPT_KEY;
260         if (newp == NULL)
261                 newp = PASSCRYPT_KEY;
262
263         debug_print("Reencrypting all account passwords...\n");
264         passwd_store_reencrypt_all(oldp, newp);
265
266         master_passphrase_forget();
267 }
268 #endif
269
270 gchar *password_encrypt_old(const gchar *password)
271 {
272         if (!password || strlen(password) == 0) {
273                 return NULL;
274         }
275
276         gchar *encrypted = g_strdup(password);
277         gchar *encoded, *result;
278         gsize len = strlen(password);
279
280         passcrypt_encrypt(encrypted, len);
281         encoded = g_base64_encode(encrypted, len);
282         g_free(encrypted);
283         result = g_strconcat("!", encoded, NULL);
284         g_free(encoded);
285
286         return result;
287 }
288
289 gchar *password_decrypt_old(const gchar *password)
290 {
291         if (!password || strlen(password) == 0) {
292                 return NULL;
293         }
294
295         if (*password != '!' || strlen(password) < 2) {
296                 return NULL;
297         }
298
299         gsize len;
300         gchar *decrypted = g_base64_decode(password + 1, &len);
301
302         passcrypt_decrypt(decrypted, len);
303         return decrypted;
304 }
305
306 #ifdef PASSWORD_CRYPTO_GNUTLS
307 #define BUFSIZE 128
308
309 /* Since we can't count on having GnuTLS new enough to have
310  * gnutls_cipher_get_iv_size(), we hardcode the IV length for now. */
311 #define IVLEN 16
312
313 gchar *password_encrypt_gnutls(const gchar *password,
314                 const gchar *encryption_passphrase)
315 {
316         gnutls_cipher_algorithm_t algo = GNUTLS_CIPHER_AES_256_CBC;
317         gnutls_cipher_hd_t handle;
318         gnutls_datum_t key, iv;
319         int keylen, blocklen, ret, len, i;
320         unsigned char *buf, *encbuf, *base, *output;
321         guint rounds = prefs_common_get_prefs()->master_passphrase_pbkdf2_rounds;
322
323         g_return_val_if_fail(password != NULL, NULL);
324         g_return_val_if_fail(encryption_passphrase != NULL, NULL);
325
326 /*      ivlen = gnutls_cipher_get_iv_size(algo);*/
327         keylen = gnutls_cipher_get_key_size(algo);
328         blocklen = gnutls_cipher_get_block_size(algo);
329 /*      digestlen = gnutls_hash_get_len(digest); */
330
331         /* Take the passphrase and compute a key derivation of suitable
332          * length to be used as encryption key for our block cipher. */
333         key.data = _make_key_deriv(encryption_passphrase, rounds, keylen);
334         key.size = keylen;
335
336         /* Prepare random IV for cipher */
337         iv.data = malloc(IVLEN);
338         iv.size = IVLEN;
339         if (!get_random_bytes(iv.data, IVLEN)) {
340                 g_free(key.data);
341                 g_free(iv.data);
342                 return NULL;
343         }
344
345         /* Initialize the encryption */
346         ret = gnutls_cipher_init(&handle, algo, &key, &iv);
347         if (ret < 0) {
348                 g_free(key.data);
349                 g_free(iv.data);
350                 return NULL;
351         }
352
353         /* Find out how big buffer (in multiples of BUFSIZE)
354          * we need to store the password. */
355         i = 1;
356         len = strlen(password);
357         while(len >= i * BUFSIZE)
358                 i++;
359         len = i * BUFSIZE;
360
361         /* Fill buf with one block of random data, our password, pad the
362          * rest with zero bytes. */
363         buf = malloc(len + blocklen);
364         memset(buf, 0, len + blocklen);
365         if (!get_random_bytes(buf, blocklen)) {
366                 g_free(buf);
367                 g_free(key.data);
368                 g_free(iv.data);
369                 gnutls_cipher_deinit(handle);
370                 return NULL;
371         }
372
373         memcpy(buf + blocklen, password, strlen(password));
374
375         /* Encrypt into encbuf */
376         encbuf = malloc(len + blocklen);
377         memset(encbuf, 0, len + blocklen);
378         ret = gnutls_cipher_encrypt2(handle, buf, len + blocklen,
379                         encbuf, len + blocklen);
380         if (ret < 0) {
381                 g_free(key.data);
382                 g_free(iv.data);
383                 g_free(buf);
384                 g_free(encbuf);
385                 gnutls_cipher_deinit(handle);
386                 return NULL;
387         }
388
389         /* Cleanup */
390         gnutls_cipher_deinit(handle);
391         g_free(key.data);
392         g_free(iv.data);
393         g_free(buf);
394
395         /* And finally prepare the resulting string:
396          * "{algorithm,rounds}base64encodedciphertext" */
397         base = g_base64_encode(encbuf, len + blocklen);
398         g_free(encbuf);
399         output = g_strdup_printf("{%s,%d}%s",
400                         gnutls_cipher_get_name(algo), rounds, base);
401         g_free(base);
402
403         return output;
404 }
405
406 gchar *password_decrypt_gnutls(const gchar *password,
407                 const gchar *decryption_passphrase)
408 {
409         gchar **tokens, *tmp;
410         gnutls_cipher_algorithm_t algo;
411         gnutls_cipher_hd_t handle;
412         gnutls_datum_t key, iv;
413         int keylen, blocklen, ret;
414         gsize len;
415         unsigned char *buf;
416         guint rounds;
417         size_t commapos;
418         gboolean valid_utf8;
419
420         g_return_val_if_fail(password != NULL, NULL);
421         g_return_val_if_fail(decryption_passphrase != NULL, NULL);
422
423         tokens = g_strsplit_set(password, "{}", 3);
424
425         /* Parse the string, retrieving algorithm and encrypted data.
426          * We expect "{algorithm,rounds}base64encodedciphertext". */
427         if (tokens[0] == NULL || strlen(tokens[0]) != 0 ||
428                         tokens[1] == NULL || strlen(tokens[1]) == 0 ||
429                         tokens[2] == NULL || strlen(tokens[2]) == 0) {
430                 debug_print("Garbled password string.\n");
431                 g_strfreev(tokens);
432                 return NULL;
433         }
434
435         commapos = strcspn(tokens[1], ",");
436         if (commapos == strlen(tokens[1]) || commapos == 0) {
437                 debug_print("Garbled algorithm substring.\n");
438                 g_strfreev(tokens);
439                 return NULL;
440         }
441
442         buf = g_strndup(tokens[1], commapos);
443         if ((algo = gnutls_cipher_get_id(buf)) == GNUTLS_CIPHER_UNKNOWN) {
444                 debug_print("Password string has unknown algorithm: '%s'\n", buf);
445                 g_free(buf);
446                 g_strfreev(tokens);
447                 return NULL;
448         }
449         g_free(buf);
450
451         if ((rounds = atoi(tokens[1] + commapos + 1)) <= 0) {
452                 debug_print("Invalid number of rounds: %d\n", rounds);
453                 g_strfreev(tokens);
454                 return NULL;
455         }
456
457 /*      ivlen = gnutls_cipher_get_iv_size(algo); */
458         keylen = gnutls_cipher_get_key_size(algo);
459         blocklen = gnutls_cipher_get_block_size(algo);
460 /*      digestlen = gnutls_hash_get_len(digest); */
461
462         /* Take the passphrase and compute a key derivation of suitable
463          * length to be used as encryption key for our block cipher. */
464         key.data = _make_key_deriv(decryption_passphrase, rounds, keylen);
465         key.size = keylen;
466
467         /* Prepare random IV for cipher */
468         iv.data = malloc(IVLEN);
469         iv.size = IVLEN;
470         if (!get_random_bytes(iv.data, IVLEN)) {
471                 g_free(key.data);
472                 g_free(iv.data);
473                 g_strfreev(tokens);
474                 return NULL;
475         }
476
477         /* Prepare encrypted password string for decryption. */
478         tmp = g_base64_decode(tokens[2], &len);
479         g_strfreev(tokens);
480         if (tmp == NULL || len == 0) {
481                 debug_print("Failed base64-decoding of stored password string\n");
482                 g_free(key.data);
483                 g_free(iv.data);
484                 if (tmp != NULL)
485                         g_free(tmp);
486                 return NULL;
487         }
488         debug_print("Encrypted password string length: %"G_GSIZE_FORMAT"\n", len);
489
490         /* Initialize the decryption */
491         ret = gnutls_cipher_init(&handle, algo, &key, &iv);
492         if (ret < 0) {
493                 debug_print("Cipher init failed: %s\n", gnutls_strerror(ret));
494                 g_free(key.data);
495                 g_free(iv.data);
496                 g_free(tmp);
497                 return NULL;
498         }
499
500         /* Allocate the buffer to store decrypted plaintext in. */
501         buf = malloc(len);
502         memset(buf, 0, len);
503
504         /* Decrypt! */
505         ret = gnutls_cipher_decrypt2(handle, tmp, len,
506                         buf, len);
507         g_free(tmp);
508         if (ret < 0) {
509                 debug_print("Decryption failed: %s\n", gnutls_strerror(ret));
510                 g_free(key.data);
511                 g_free(iv.data);
512                 g_free(buf);
513                 gnutls_cipher_deinit(handle);
514                 return NULL;
515         }
516
517         /* Cleanup */
518         gnutls_cipher_deinit(handle);
519         g_free(key.data);
520         g_free(iv.data);
521
522         /* 'buf+blocklen' should now be pointing to the plaintext
523          * password string.
524          * (The first block contains random data from the IV.)
525          *
526          * At this point, it should be a valid UTF-8 string. Let's make sure. */
527
528         /* First, let's assume there's just garbage and play it safe
529          * by looking for a first NULL byte within the decrypted range.
530          * (We could really use g_strchr_len() here instead, but Glib
531          * doesn't have that.) */
532         if (!g_strstr_len(buf + blocklen, len - blocklen, "\0")) {
533                 debug_print("Could not find a NULL byte in the decrypted password.\n");
534                 valid_utf8 = FALSE;
535         } else {
536                 /* There is a NULL byte, we can rely on strlen() returning
537                  * a sane value, so we don't read past the end of the allocated
538                  * buffer. */
539                 valid_utf8 = g_utf8_validate(buf + blocklen, strlen(buf + blocklen), NULL);
540         }
541
542         if (!valid_utf8)
543                 debug_print("Decrypted password is not a valid UTF-8 string!\n");
544         cm_return_val_if_fail(valid_utf8, NULL);
545
546         tmp = g_strndup(buf + blocklen, strlen(buf + blocklen));
547         memset(buf, 0, len);
548         g_free(buf);
549
550         return tmp;
551 }
552
553 #undef BUFSIZE
554
555 #endif
556
557 gchar *password_encrypt(const gchar *password,
558                 const gchar *encryption_passphrase)
559 {
560         if (password == NULL || strlen(password) == 0) {
561                 return NULL;
562         }
563
564 #ifndef PASSWORD_CRYPTO_OLD
565         if (encryption_passphrase == NULL)
566                 encryption_passphrase = master_passphrase();
567
568         return password_encrypt_real(password, encryption_passphrase);
569 #else
570         return password_encrypt_old(password);
571 #endif
572 }
573
574 gchar *password_decrypt(const gchar *password,
575                 const gchar *decryption_passphrase)
576 {
577         if (password == NULL || strlen(password) == 0) {
578                 return NULL;
579         }
580
581         /* First, check if the password was possibly decrypted using old,
582          * obsolete method */
583         if (*password == '!') {
584                 debug_print("Trying to decrypt password using the old method...\n");
585                 return password_decrypt_old(password);
586         }
587
588         /* Try available crypto backend */
589 #ifndef PASSWORD_CRYPTO_OLD
590         if (decryption_passphrase == NULL)
591                 decryption_passphrase = master_passphrase();
592
593         if (*password == '{') {
594                 debug_print("Trying to decrypt password...\n");
595                 return password_decrypt_real(password, decryption_passphrase);
596         }
597 #endif
598
599         /* Fallback, in case the configuration is really old and
600          * stored password in plaintext */
601         debug_print("Assuming password was stored plaintext, returning it unchanged\n");
602         return g_strdup(password);
603 }