Blame egg/egg-hkdf.c

Packit Service f02b19
/*
Packit Service f02b19
 * gnome-keyring
Packit Service f02b19
 *
Packit Service f02b19
 * Copyright (C) 2011 Collabora Ltd.
Packit Service f02b19
 *
Packit Service f02b19
 * This program is free software; you can redistribute it and/or modify
Packit Service f02b19
 * it under the terms of the GNU Lesser General Public License as
Packit Service f02b19
 * published by the Free Software Foundation; either version 2.1 of
Packit Service f02b19
 * the License, or (at your option) any later version.
Packit Service f02b19
 *
Packit Service f02b19
 * This program is distributed in the hope that it will be useful, but
Packit Service f02b19
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service f02b19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service f02b19
 * Lesser General Public License for more details.
Packit Service f02b19
 *
Packit Service f02b19
 * You should have received a copy of the GNU Lesser General Public
Packit Service f02b19
 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
Packit Service f02b19
 *
Packit Service f02b19
 * Author: Stef Walter <stefw@collabora.co.uk>
Packit Service f02b19
 */
Packit Service f02b19
Packit Service f02b19
#include "config.h"
Packit Service f02b19
Packit Service f02b19
#include "egg-hkdf.h"
Packit Service f02b19
#include "egg-secure-memory.h"
Packit Service f02b19
Packit Service f02b19
#include <gcrypt.h>
Packit Service f02b19
Packit Service f02b19
#include <string.h>
Packit Service f02b19
Packit Service f02b19
gboolean
Packit Service f02b19
egg_hkdf_perform (const gchar *hash_algo, gconstpointer input, gsize n_input,
Packit Service f02b19
                  gconstpointer salt, gsize n_salt, gconstpointer info,
Packit Service f02b19
                  gsize n_info, gpointer output, gsize n_output)
Packit Service f02b19
{
Packit Service f02b19
	gpointer alloc = NULL;
Packit Service f02b19
	gpointer buffer = NULL;
Packit Service f02b19
	gcry_md_hd_t md1, md2;
Packit Service f02b19
	guint hash_len;
Packit Service f02b19
	gint i;
Packit Service f02b19
	gint flags, algo;
Packit Service f02b19
	gsize step, n_buffer;
Packit Service f02b19
	guchar *at;
Packit Service f02b19
	gcry_error_t gcry;
Packit Service f02b19
Packit Service f02b19
	algo = gcry_md_map_name (hash_algo);
Packit Service f02b19
	g_return_val_if_fail (algo != 0, FALSE);
Packit Service f02b19
Packit Service f02b19
	hash_len = gcry_md_get_algo_dlen (algo);
Packit Service f02b19
	g_return_val_if_fail (hash_len != 0, FALSE);
Packit Service f02b19
	g_return_val_if_fail (n_output <= 255 * hash_len, FALSE);
Packit Service f02b19
Packit Service f02b19
	/* Buffer we need to for intermediate stuff */
Packit Service f02b19
	if (gcry_is_secure (input)) {
Packit Service f02b19
		flags = GCRY_MD_FLAG_SECURE;
Packit Service f02b19
		buffer = gcry_malloc_secure (hash_len);
Packit Service f02b19
	} else {
Packit Service f02b19
		flags = 0;
Packit Service f02b19
		buffer = gcry_malloc (hash_len);
Packit Service f02b19
	}
Packit Service f02b19
Packit Service f02b19
	g_return_val_if_fail (buffer, FALSE);
Packit Service f02b19
	n_buffer = 0;
Packit Service f02b19
Packit Service f02b19
	/* Salt defaults to hash_len zeros */
Packit Service f02b19
	if (!salt) {
Packit Service f02b19
		salt = alloc = g_malloc0 (hash_len);
Packit Service f02b19
		n_salt = hash_len;
Packit Service f02b19
	}
Packit Service f02b19
Packit Service f02b19
	/* Step 1: Extract */
Packit Service f02b19
	gcry = gcry_md_open (&md1, algo, GCRY_MD_FLAG_HMAC | flags);
Packit Service f02b19
	g_return_val_if_fail (gcry == 0, FALSE);
Packit Service f02b19
	gcry = gcry_md_setkey (md1, salt, n_salt);
Packit Service f02b19
	g_return_val_if_fail (gcry == 0, FALSE);
Packit Service f02b19
	gcry_md_write (md1, input, n_input);
Packit Service f02b19
Packit Service f02b19
	/* Step 2: Expand */
Packit Service f02b19
	gcry = gcry_md_open (&md2, algo, GCRY_MD_FLAG_HMAC | flags);
Packit Service f02b19
	g_return_val_if_fail (gcry == 0, FALSE);
Packit Service f02b19
	gcry = gcry_md_setkey (md2, gcry_md_read (md1, algo), hash_len);
Packit Service f02b19
	g_return_val_if_fail (gcry == 0, FALSE);
Packit Service f02b19
	gcry_md_close (md1);
Packit Service f02b19
Packit Service f02b19
	at = output;
Packit Service f02b19
	for (i = 1; i < 256; ++i) {
Packit Service f02b19
		gcry_md_reset (md2);
Packit Service f02b19
		gcry_md_write (md2, buffer, n_buffer);
Packit Service f02b19
		gcry_md_write (md2, info, n_info);
Packit Service f02b19
		gcry_md_putc (md2, i);
Packit Service f02b19
Packit Service f02b19
		n_buffer = hash_len;
Packit Service f02b19
		memcpy (buffer, gcry_md_read (md2, algo), n_buffer);
Packit Service f02b19
Packit Service f02b19
		step = MIN (n_buffer, n_output);
Packit Service f02b19
		memcpy (at, buffer, step);
Packit Service f02b19
		n_output -= step;
Packit Service f02b19
		at += step;
Packit Service f02b19
Packit Service f02b19
		if (!n_output)
Packit Service f02b19
			break;
Packit Service f02b19
	}
Packit Service f02b19
Packit Service f02b19
	g_free (alloc);
Packit Service f02b19
	gcry_free (buffer);
Packit Service f02b19
	gcry_md_close (md2);
Packit Service f02b19
	return TRUE;
Packit Service f02b19
}