view libpurple/ciphers/hmac.c @ 32533:e091c8ea292e

Pluck all MSNP18 changes. This is pretty much to fix sending OIMs. *** Plucked rev b8b574c4d6f6c05105b372191ca5259b4ae0ad41 (qulogic@pidgin.im): Add a function for parsing a network:username for MSNP18. *** Plucked rev 86bb401efa33f02ca5d28fea216a39a3cf29b5b4 (qulogic@pidgin.im): Fix UBX on MSNP18. *** Plucked rev ba2513694e6abcbdfddc66820f1df20540a36847 (qulogic@pidgin.im): Fix NLN on MSNP18. *** Plucked rev 83a617670da618f4dbdeeebbdb5e2813a4ad2c0c (qulogic@pidgin.im): Switch to ABFindContactsPaged instead of ABFindAll. *** Plucked rev b6bd214d29db885c6d28628c163fa144bdf4a76d (qulogic@pidgin.im): Send circle authentication on the notification server on MSNP18. *** Plucked rev 2ca50146aa67469313579cea414e4a2b660939aa (qulogic@pidgin.im): Make a small name change. *** Plucked rev 2c13bf358104060d6713317e18e03b434862cb38 (qulogic@pidgin.im): Add a missing function. *** Plucked rev a8deb3f73726f4148e8f36f317a88fedcb051c34 (qulogic@pidgin.im): Update UUM to allow sending to users on any network. *** Plucked rev dddff988e830a7a2fa0e40aad200f0e908b9231e (qulogic@pidgin.im): Switch to MSNP18. *** Plucked rev 9fe45819000c530c509c07b7feb29ce9d4ea13b0 (qulogic@pidgin.im): Send offline messages using UUM. *** Plucked rev c1584182b85f99fa3507ea3f76b07865ee7e43f7 (qulogic@pidgin.im): Drop support for protocols below 18. *** Plucked rev f0388e54998489dbe4b6133796f77459f20fe884 (qulogic@pidgin.im): Fix indices for client capabilities and display pics.
author Elliott Sales de Andrade <qulogic@pidgin.im>
date Wed, 22 Feb 2012 05:52:30 +0000
parents ca94413ccd0e
children
line wrap: on
line source

/*
 * purple
 *
 * Purple is the legal property of its developers, whose names are too numerous
 * to list here.  Please refer to the COPYRIGHT file distributed with this
 * source distribution.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
 */
#include <cipher.h>

#include <util.h>

struct HMAC_Context {
	PurpleCipherContext *hash;
	char *name;
	int blocksize;
	guchar *opad;
};

	static void
hmac_init(PurpleCipherContext *context, gpointer extra)
{
	struct HMAC_Context *hctx;
	hctx = g_new0(struct HMAC_Context, 1);
	purple_cipher_context_set_data(context, hctx);
	purple_cipher_context_reset(context, extra);
}

	static void
hmac_reset(PurpleCipherContext *context, gpointer extra)
{
	struct HMAC_Context *hctx;

	hctx = purple_cipher_context_get_data(context);

	g_free(hctx->name);
	hctx->name = NULL;
	if (hctx->hash)
		purple_cipher_context_destroy(hctx->hash);
	hctx->hash = NULL;
	hctx->blocksize = 0;
	g_free(hctx->opad);
	hctx->opad = NULL;
}

	static void
hmac_set_opt(PurpleCipherContext *context, const gchar *name, void *value)
{
	struct HMAC_Context *hctx;

	hctx = purple_cipher_context_get_data(context);

	if (purple_strequal(name, "hash")) {
		g_free(hctx->name);
		if (hctx->hash)
			purple_cipher_context_destroy(hctx->hash);
		hctx->name = g_strdup((char*)value);
		hctx->hash = purple_cipher_context_new_by_name((char *)value, NULL);
		hctx->blocksize = purple_cipher_context_get_block_size(hctx->hash);
	}
}

	static void *
hmac_get_opt(PurpleCipherContext *context, const gchar *name)
{
	struct HMAC_Context *hctx;

	hctx = purple_cipher_context_get_data(context);

	if (purple_strequal(name, "hash")) {
		return hctx->name;
	}

	return NULL;
}

	static void
hmac_append(PurpleCipherContext *context, const guchar *data, size_t len)
{
	struct HMAC_Context *hctx = purple_cipher_context_get_data(context);

	g_return_if_fail(hctx->hash != NULL);

	purple_cipher_context_append(hctx->hash, data, len);
}

	static gboolean
hmac_digest(PurpleCipherContext *context, size_t in_len, guchar *out, size_t *out_len)
{
	struct HMAC_Context *hctx = purple_cipher_context_get_data(context);
	PurpleCipherContext *hash = hctx->hash;
	guchar *inner_hash;
	size_t hash_len;
	gboolean result;

	g_return_val_if_fail(hash != NULL, FALSE);

	inner_hash = g_malloc(100); /* TODO: Should be enough for now... */
	result = purple_cipher_context_digest(hash, 100, inner_hash, &hash_len);

	purple_cipher_context_reset(hash, NULL);

	purple_cipher_context_append(hash, hctx->opad, hctx->blocksize);
	purple_cipher_context_append(hash, inner_hash, hash_len);

	g_free(inner_hash);

	result = result && purple_cipher_context_digest(hash, in_len, out, out_len);

	return result;
}

	static void
hmac_uninit(PurpleCipherContext *context)
{
	struct HMAC_Context *hctx;

	purple_cipher_context_reset(context, NULL);

	hctx = purple_cipher_context_get_data(context);

	g_free(hctx);
}

	static void
hmac_set_key_with_len(PurpleCipherContext *context, const guchar * key, size_t key_len)
{
	struct HMAC_Context *hctx = purple_cipher_context_get_data(context);
	int blocksize, i;
	guchar *ipad;
	guchar *full_key;

	g_return_if_fail(hctx->hash != NULL);

	g_free(hctx->opad);

	blocksize = hctx->blocksize;
	ipad = g_malloc(blocksize);
	hctx->opad = g_malloc(blocksize);

	if (key_len > blocksize) {
		purple_cipher_context_reset(hctx->hash, NULL);
		purple_cipher_context_append(hctx->hash, key, key_len);
		full_key = g_malloc(100); /* TODO: Should be enough for now... */
		purple_cipher_context_digest(hctx->hash, 100, full_key, &key_len);
	} else
		full_key = g_memdup(key, key_len);

	if (key_len < blocksize) {
		full_key = g_realloc(full_key, blocksize);
		memset(full_key + key_len, 0, blocksize - key_len);
	}

	for(i = 0; i < blocksize; i++) {
		ipad[i] = 0x36 ^ full_key[i];
		hctx->opad[i] = 0x5c ^ full_key[i];
	}

	g_free(full_key);

	purple_cipher_context_reset(hctx->hash, NULL);
	purple_cipher_context_append(hctx->hash, ipad, blocksize);
	g_free(ipad);
}

	static void
hmac_set_key(PurpleCipherContext *context, const guchar * key)
{
	hmac_set_key_with_len(context, key, strlen((char *)key));
}

	static size_t
hmac_get_block_size(PurpleCipherContext *context)
{
	struct HMAC_Context *hctx = purple_cipher_context_get_data(context);

	return hctx->blocksize;
}

static PurpleCipherOps HMACOps = {
	hmac_set_opt,           /* Set option */
	hmac_get_opt,           /* Get option */
	hmac_init,               /* init */
	hmac_reset,              /* reset */
	hmac_uninit,             /* uninit */
	NULL,                   /* set iv */
	hmac_append,             /* append */
	hmac_digest,             /* digest */
	NULL,                   /* encrypt */
	NULL,                   /* decrypt */
	NULL,                   /* set salt */
	NULL,                   /* get salt size */
	hmac_set_key,           /* set key */
	NULL,                   /* get key size */
	NULL,                   /* set batch mode */
	NULL,                   /* get batch mode */
	hmac_get_block_size,    /* get block size */
	hmac_set_key_with_len   /* set key with len */
};

PurpleCipherOps *
purple_hmac_cipher_get_ops(void) {
	return &HMACOps;
}