return NULL;
}
-static const gchar *master_passphrase()
+const gchar *master_passphrase()
{
gchar *input;
gboolean end = FALSE;
return _master_passphrase;
}
-const gboolean master_passphrase_is_set()
+gboolean master_passphrase_is_set()
{
if (prefs_common_get_prefs()->master_passphrase == NULL
|| strlen(prefs_common_get_prefs()->master_passphrase) == 0)
return TRUE;
}
-const gboolean master_passphrase_is_correct(const gchar *input)
+gboolean master_passphrase_is_correct(const gchar *input)
{
guchar *kd, *input_kd;
gchar **tokens;
g_strfreev(tokens);
if (kd_len != KD_LENGTH) {
- debug_print("master_passphrase is %ld bytes long, should be %d.\n",
+ debug_print("master_passphrase is %"G_GSIZE_FORMAT" bytes long, should be %d.\n",
kd_len, KD_LENGTH);
g_free(kd);
return FALSE;
gnutls_cipher_algorithm_t algo = GNUTLS_CIPHER_AES_256_CBC;
gnutls_cipher_hd_t handle;
gnutls_datum_t key, iv;
- int keylen, blocklen, ret;
+ int keylen, blocklen, ret, len, i;
unsigned char *buf, *encbuf, *base, *output;
guint rounds = prefs_common_get_prefs()->master_passphrase_pbkdf2_rounds;
return NULL;
}
+ /* Find out how big buffer (in multiples of BUFSIZE)
+ * we need to store the password. */
+ i = 1;
+ len = strlen(password);
+ while(len >= i * BUFSIZE)
+ i++;
+ len = i * BUFSIZE;
+
/* Fill buf with one block of random data, our password, pad the
* rest with zero bytes. */
- buf = malloc(BUFSIZE + blocklen);
- memset(buf, 0, BUFSIZE);
+ buf = malloc(len + blocklen);
+ memset(buf, 0, len + blocklen);
if (!get_random_bytes(buf, blocklen)) {
g_free(buf);
g_free(key.data);
memcpy(buf + blocklen, password, strlen(password));
/* Encrypt into encbuf */
- encbuf = malloc(BUFSIZE + blocklen);
- memset(encbuf, 0, BUFSIZE + blocklen);
- ret = gnutls_cipher_encrypt2(handle, buf, BUFSIZE + blocklen,
- encbuf, BUFSIZE + blocklen);
+ encbuf = malloc(len + blocklen);
+ memset(encbuf, 0, len + blocklen);
+ ret = gnutls_cipher_encrypt2(handle, buf, len + blocklen,
+ encbuf, len + blocklen);
if (ret < 0) {
g_free(key.data);
g_free(iv.data);
/* And finally prepare the resulting string:
* "{algorithm,rounds}base64encodedciphertext" */
- base = g_base64_encode(encbuf, BUFSIZE);
+ base = g_base64_encode(encbuf, len + blocklen);
g_free(encbuf);
output = g_strdup_printf("{%s,%d}%s",
gnutls_cipher_get_name(algo), rounds, base);
unsigned char *buf;
guint rounds;
size_t commapos;
+ gboolean valid_utf8;
g_return_val_if_fail(password != NULL, NULL);
g_return_val_if_fail(decryption_passphrase != NULL, NULL);
/* Prepare encrypted password string for decryption. */
tmp = g_base64_decode(tokens[2], &len);
g_strfreev(tokens);
+ if (tmp == NULL || len == 0) {
+ debug_print("Failed base64-decoding of stored password string\n");
+ g_free(key.data);
+ g_free(iv.data);
+ if (tmp != NULL)
+ g_free(tmp);
+ return NULL;
+ }
+ debug_print("Encrypted password string length: %"G_GSIZE_FORMAT"\n", len);
/* Initialize the decryption */
ret = gnutls_cipher_init(&handle, algo, &key, &iv);
debug_print("Cipher init failed: %s\n", gnutls_strerror(ret));
g_free(key.data);
g_free(iv.data);
+ g_free(tmp);
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));
g_free(key.data);
g_free(key.data);
g_free(iv.data);
- tmp = g_strndup(buf + blocklen, MIN(strlen(buf + blocklen), BUFSIZE));
+ /* 'buf+blocklen' should now be pointing to the plaintext
+ * password string.
+ * (The first block contains random data from the IV.)
+ *
+ * At this point, it should be a valid UTF-8 string. Let's make sure. */
+
+ /* First, let's assume there's just garbage and play it safe
+ * by looking for a first NULL byte within the decrypted range.
+ * (We could really use g_strchr_len() here instead, but Glib
+ * doesn't have that.) */
+ if (!g_strstr_len(buf + blocklen, len - blocklen, "\0")) {
+ debug_print("Could not find a NULL byte in the decrypted password.\n");
+ valid_utf8 = FALSE;
+ } else {
+ /* There is a NULL byte, we can rely on strlen() returning
+ * a sane value, so we don't read past the end of the allocated
+ * buffer. */
+ valid_utf8 = g_utf8_validate(buf + blocklen, strlen(buf + blocklen), NULL);
+ }
+
+ if (!valid_utf8)
+ debug_print("Decrypted password is not a valid UTF-8 string!\n");
+ cm_return_val_if_fail(valid_utf8, NULL);
+
+ tmp = g_strndup(buf + blocklen, strlen(buf + blocklen));
+ memset(buf, 0, len);
g_free(buf);
+
return tmp;
}