Fix buffer length handling in GnuTLS password encryption and decryption.
authorAndrej Kacian <ticho@claws-mail.org>
Thu, 14 Dec 2017 22:18:50 +0000 (23:18 +0100)
committerAndrej Kacian <ticho@claws-mail.org>
Thu, 14 Dec 2017 22:18:50 +0000 (23:18 +0100)
Also zero out one forgotten copy of plaintext password
before freeing it. Oops!

src/password.c

index 8c17aaffc8fb087d8bd25392cee0deeb0a7ad1b4..9e66a92253fca1acbc2e04bad8251197c143f10f 100644 (file)
@@ -356,7 +356,7 @@ gchar *password_encrypt_gnutls(const gchar *password,
        /* Fill buf with one block of random data, our password, pad the
         * rest with zero bytes. */
        buf = malloc(BUFSIZE + blocklen);
-       memset(buf, 0, BUFSIZE);
+       memset(buf, 0, BUFSIZE + blocklen);
        if (!get_random_bytes(buf, blocklen)) {
                g_free(buf);
                g_free(key.data);
@@ -389,7 +389,7 @@ gchar *password_encrypt_gnutls(const gchar *password,
 
        /* And finally prepare the resulting string:
         * "{algorithm,rounds}base64encodedciphertext" */
-       base = g_base64_encode(encbuf, BUFSIZE);
+       base = g_base64_encode(encbuf, BUFSIZE + blocklen);
        g_free(encbuf);
        output = g_strdup_printf("{%s,%d}%s",
                        gnutls_cipher_get_name(algo), rounds, base);
@@ -479,6 +479,7 @@ gchar *password_decrypt_gnutls(const gchar *password,
                        g_free(tmp);
                return NULL;
        }
+       debug_print("Encrypted password string length: %lu\n", len);
 
        /* Initialize the decryption */
        ret = gnutls_cipher_init(&handle, algo, &key, &iv);
@@ -490,10 +491,13 @@ gchar *password_decrypt_gnutls(const gchar *password,
                return NULL;
        }
 
-       buf = malloc(len + blocklen);
-       memset(buf, 0, len + blocklen);
+       /* Allocate the buffer to store decrypted plaintext in. */
+       buf = malloc(len);
+       memset(buf, 0, len);
+
+       /* Decrypt! */
        ret = gnutls_cipher_decrypt2(handle, tmp, len,
-                       buf, len + blocklen);
+                       buf, len);
        g_free(tmp);
        if (ret < 0) {
                debug_print("Decryption failed: %s\n", gnutls_strerror(ret));
@@ -509,8 +513,12 @@ gchar *password_decrypt_gnutls(const gchar *password,
        g_free(key.data);
        g_free(iv.data);
 
+       /* 'buf+blocklen' should now be pointing to the plaintext
+        * password string. The first block contains random data from the IV. */
        tmp = g_strndup(buf + blocklen, MIN(strlen(buf + blocklen), BUFSIZE));
+       memset(buf, 0, len);
        g_free(buf);
+
        return tmp;
 }