/*
- silchmac.c
+ silchmac.c
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1999 - 2001 Pekka Riikonen
+ Copyright (C) 1999 - 2008 Pekka Riikonen
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
GNU General Public License for more details.
*/
-/* $Id$ */
-#include "silcincludes.h"
+#include "silccrypto.h"
/* HMAC context */
struct SilcHmacStruct {
SilcHmacObject *hmac;
SilcHash hash;
- bool allocated_hash; /* TRUE if the hash was allocated */
-
- unsigned char *key;
- uint32 key_len;
-
unsigned char inner_pad[64];
unsigned char outer_pad[64];
- void *hash_context;
+ unsigned char *key;
+ unsigned int key_len : 31;
+ unsigned int allocated_hash : 1; /* TRUE if the hash was allocated */
};
+#ifndef SILC_SYMBIAN
/* List of dynamically registered HMACs. */
SilcDList silc_hmac_list = NULL;
+#endif /* SILC_SYMBIAN */
/* Default hmacs for silc_hmac_register_default(). */
-SilcHmacObject silc_default_hmacs[] =
+const SilcHmacObject silc_default_hmacs[] =
{
+ { "hmac-sha256-96", 12 },
+ { "hmac-sha512-96", 12 },
{ "hmac-sha1-96", 12 },
{ "hmac-md5-96", 12 },
+ { "hmac-sha256", 32 },
+ { "hmac-sha512", 64 },
{ "hmac-sha1", 20 },
{ "hmac-md5", 16 },
};
static void silc_hmac_init_internal(SilcHmac hmac, unsigned char *key,
- uint32 key_len)
+ SilcUInt32 key_len)
{
SilcHash hash = hmac->hash;
- unsigned char hvalue[20];
+ SilcUInt32 block_len;
+ unsigned char hvalue[SILC_HASH_MAXLEN];
int i;
memset(hmac->inner_pad, 0, sizeof(hmac->inner_pad));
memset(hmac->outer_pad, 0, sizeof(hmac->outer_pad));
+ block_len = silc_hash_block_len(hash);
+
/* If the key length is more than block size of the hash function, the
key is hashed. */
- if (key_len > hash->hash->block_len) {
+ if (key_len > block_len) {
silc_hash_make(hash, key, key_len, hvalue);
key = hvalue;
- key_len = hash->hash->hash_len;
+ key_len = silc_hash_len(hash);
}
/* Copy the key into the pads */
memcpy(hmac->outer_pad, key, key_len);
/* XOR the key with pads */
- for (i = 0; i < hash->hash->block_len; i++) {
+ for (i = 0; i < block_len; i++) {
hmac->inner_pad[i] ^= 0x36;
hmac->outer_pad[i] ^= 0x5c;
}
}
-/* Registers a new HMAC into the SILC. This function is used at the
- initialization of the SILC. */
+/* Registers a new HMAC */
-bool silc_hmac_register(SilcHmacObject *hmac)
+SilcBool silc_hmac_register(const SilcHmacObject *hmac)
{
+#ifndef SILC_SYMBIAN
SilcHmacObject *new;
SILC_LOG_DEBUG(("Registering new HMAC `%s'", hmac->name));
}
new = silc_calloc(1, sizeof(*new));
+ if (!new)
+ return FALSE;
new->name = strdup(hmac->name);
new->len = hmac->len;
silc_hmac_list = silc_dlist_init();
silc_dlist_add(silc_hmac_list, new);
+#endif /* SILC_SYMBIAN */
return TRUE;
}
-/* Unregister a HMAC from the SILC. */
+/* Unregister a HMAC */
-bool silc_hmac_unregister(SilcHmacObject *hmac)
+SilcBool silc_hmac_unregister(SilcHmacObject *hmac)
{
+#ifndef SILC_SYMBIAN
SilcHmacObject *entry;
SILC_LOG_DEBUG(("Unregistering HMAC"));
while ((entry = silc_dlist_get(silc_hmac_list)) != SILC_LIST_END) {
if (hmac == SILC_ALL_HMACS || entry == hmac) {
silc_dlist_del(silc_hmac_list, entry);
+ silc_free(entry->name);
+ silc_free(entry);
if (silc_dlist_count(silc_hmac_list) == 0) {
silc_dlist_uninit(silc_hmac_list);
}
}
+#endif /* SILC_SYMBIAN */
return FALSE;
}
-/* Function that registers all the default hmacs (all builtin ones).
- The application may use this to register the default hmacs if
- specific hmacs in any specific order is not wanted. */
+/* Register default HMACs */
-bool silc_hmac_register_default(void)
+SilcBool silc_hmac_register_default(void)
{
- int i;
+ /* We use builtin HMACs */
+ return TRUE;
+}
- for (i = 0; silc_default_hmacs[i].name; i++)
- silc_hmac_register(&(silc_default_hmacs[i]));
+/* Unregister all HMACs */
+
+SilcBool silc_hmac_unregister_all(void)
+{
+#ifndef SILC_SYMBIAN
+ SilcHmacObject *entry;
+ if (!silc_hmac_list)
+ return FALSE;
+
+ silc_dlist_start(silc_hmac_list);
+ while ((entry = silc_dlist_get(silc_hmac_list)) != SILC_LIST_END) {
+ silc_hmac_unregister(entry);
+ if (!silc_hmac_list)
+ break;
+ }
+#endif /* SILC_SYMBIAN */
return TRUE;
}
of the HMAC. If it is NULL then the hash function is allocated and
the name of the hash algorithm is derived from the `name'. */
-bool silc_hmac_alloc(char *name, SilcHash hash, SilcHmac *new_hmac)
+SilcBool silc_hmac_alloc(const char *name, SilcHash hash, SilcHmac *new_hmac)
{
- SilcHmacObject *entry;
+ SilcHmacObject *entry = NULL;
+ int i;
SILC_LOG_DEBUG(("Allocating new HMAC"));
/* Allocate the new object */
*new_hmac = silc_calloc(1, sizeof(**new_hmac));
+ if (!(*new_hmac))
+ return FALSE;
if (!hash) {
char *tmp = strdup(name), *hname;
(*new_hmac)->hash = hash;
+#ifndef SILC_SYMBIAN
+ /* Check registered list of HMACs */
if (silc_hmac_list) {
silc_dlist_start(silc_hmac_list);
while ((entry = silc_dlist_get(silc_hmac_list)) != SILC_LIST_END) {
if (!strcmp(entry->name, name)) {
- (*new_hmac)->hmac = entry;
+ (*new_hmac)->hmac = entry;
+ return TRUE;
+ }
+ }
+ }
+#endif /* SILC_SYMBIAN */
+
+ if (!entry) {
+ /* Check builtin list of HMACs */
+ for (i = 0; silc_default_hmacs[i].name; i++) {
+ if (!strcmp(silc_default_hmacs[i].name, name)) {
+ (*new_hmac)->hmac = (SilcHmacObject *)&(silc_default_hmacs[i]);
return TRUE;
}
}
silc_free(hmac->key);
}
- silc_free(hmac->hash_context);
silc_free(hmac);
}
}
/* Returns the length of the MAC that the HMAC will produce. */
-uint32 silc_hmac_len(SilcHmac hmac)
+SilcUInt32 silc_hmac_len(SilcHmac hmac)
{
return hmac->hmac->len;
}
/* Returns TRUE if HMAC `name' is supported. */
-bool silc_hmac_is_supported(const char *name)
+SilcBool silc_hmac_is_supported(const char *name)
{
SilcHmacObject *entry;
+ int i;
if (!name)
return FALSE;
-
+
+#ifndef SILC_SYMBIAN
if (silc_hmac_list) {
silc_dlist_start(silc_hmac_list);
while ((entry = silc_dlist_get(silc_hmac_list)) != SILC_LIST_END) {
return TRUE;
}
}
+#endif /* SILC_SYMBIAN */
+
+ for (i = 0; silc_default_hmacs[i].name; i++)
+ if (!strcmp(silc_default_hmacs[i].name, name))
+ return TRUE;
return FALSE;
}
char *silc_hmac_get_supported()
{
- SilcHmacObject *entry;
+ SilcHmacObject *entry, *entry2;
char *list = NULL;
- int len;
+ int len = 0, i;
- len = 0;
+#ifndef SILC_SYMBIAN
if (silc_hmac_list) {
silc_dlist_start(silc_hmac_list);
while ((entry = silc_dlist_get(silc_hmac_list)) != SILC_LIST_END) {
len += strlen(entry->name);
list = silc_realloc(list, len + 1);
-
- memcpy(list + (len - strlen(entry->name)),
+
+ memcpy(list + (len - strlen(entry->name)),
entry->name, strlen(entry->name));
memcpy(list + len, ",", 1);
len++;
}
- list[len - 1] = 0;
}
+#endif /* SILC_SYMBIAN */
+
+
+ for (i = 0; silc_default_hmacs[i].name; i++) {
+ entry = (SilcHmacObject *)&(silc_default_hmacs[i]);
+
+ if (silc_hmac_list) {
+ silc_dlist_start(silc_hmac_list);
+ while ((entry2 = silc_dlist_get(silc_hmac_list)) != SILC_LIST_END) {
+ if (!strcmp(entry2->name, entry->name))
+ break;
+ }
+ if (entry2)
+ continue;
+ }
+
+ len += strlen(entry->name);
+ list = silc_realloc(list, len + 1);
+
+ memcpy(list + (len - strlen(entry->name)),
+ entry->name, strlen(entry->name));
+ memcpy(list + len, ",", 1);
+ len++;
+ }
+
+ list[len - 1] = 0;
return list;
}
/* Sets the HMAC key used in the HMAC creation */
void silc_hmac_set_key(SilcHmac hmac, const unsigned char *key,
- uint32 key_len)
+ SilcUInt32 key_len)
{
if (hmac->key) {
memset(hmac->key, 0, hmac->key_len);
silc_free(hmac->key);
}
- hmac->key = silc_calloc(key_len, sizeof(unsigned char));
+ hmac->key = silc_malloc(key_len);
+ if (!hmac->key)
+ return;
hmac->key_len = key_len;
memcpy(hmac->key, key, key_len);
}
+/* Return HMAC key */
+
+const unsigned char *silc_hmac_get_key(SilcHmac hmac, SilcUInt32 *key_len)
+{
+ if (key_len)
+ *key_len = hmac->key_len;
+ return (const unsigned char *)hmac->key;
+}
+
/* Create the HMAC. This is thee make_hmac function pointer. This
uses the internal key set with silc_hmac_set_key. */
void silc_hmac_make(SilcHmac hmac, unsigned char *data,
- uint32 data_len, unsigned char *return_hash,
- uint32 *return_len)
+ SilcUInt32 data_len, unsigned char *return_hash,
+ SilcUInt32 *return_len)
{
SILC_LOG_DEBUG(("Making HMAC for message"));
key. The key is sent as argument to the function. */
void silc_hmac_make_with_key(SilcHmac hmac, unsigned char *data,
- uint32 data_len,
- unsigned char *key, uint32 key_len,
+ SilcUInt32 data_len,
+ unsigned char *key, SilcUInt32 key_len,
unsigned char *return_hash,
- uint32 *return_len)
+ SilcUInt32 *return_len)
{
SILC_LOG_DEBUG(("Making HMAC for message"));
/* Creates the HMAC just as above except that the hash value is truncated
to the truncated_len sent as argument. NOTE: One should not truncate to
- less than half of the length of original hash value. However, this
+ less than half of the length of original hash value. However, this
routine allows these dangerous truncations. */
void silc_hmac_make_truncated(SilcHmac hmac, unsigned char *data,
- uint32 data_len,
- uint32 truncated_len,
+ SilcUInt32 data_len,
+ SilcUInt32 truncated_len,
unsigned char *return_hash)
{
- unsigned char hvalue[20];
+ unsigned char hvalue[SILC_HASH_MAXLEN];
SILC_LOG_DEBUG(("Making HMAC for message"));
/* Same as above but with specific key */
void silc_hmac_init_with_key(SilcHmac hmac, const unsigned char *key,
- uint32 key_len)
+ SilcUInt32 key_len)
{
SilcHash hash = hmac->hash;
-
- silc_hmac_init_internal(hmac, hmac->key, hmac->key_len);
-
- if (!hmac->hash_context)
- hmac->hash_context = silc_calloc(1, hash->hash->context_len());
-
- hash->hash->init(hmac->hash_context);
- hash->hash->update(hmac->hash_context, hmac->inner_pad,
- hash->hash->block_len);
+ silc_hmac_init_internal(hmac, (unsigned char *)key, key_len);
+ silc_hash_init(hash);
+ silc_hash_update(hash, hmac->inner_pad, silc_hash_block_len(hash));
}
/* Add data to be used in the MAC computation. */
void silc_hmac_update(SilcHmac hmac, const unsigned char *data,
- uint32 data_len)
+ SilcUInt32 data_len)
{
SilcHash hash = hmac->hash;
- hash->hash->update(hmac->hash_context, (unsigned char *)data, data_len);
+ silc_hash_update(hash, data, data_len);
}
/* Compute the final MAC. */
void silc_hmac_final(SilcHmac hmac, unsigned char *return_hash,
- uint32 *return_len)
+ SilcUInt32 *return_len)
{
SilcHash hash = hmac->hash;
- unsigned char mac[20];
-
- hash->hash->final(hmac->hash_context, mac);
- hash->hash->init(hmac->hash_context);
- hash->hash->update(hmac->hash_context, hmac->outer_pad,
- hash->hash->block_len);
- hash->hash->update(hmac->hash_context, mac, hash->hash->hash_len);
- hash->hash->final(hmac->hash_context, mac);
+ unsigned char mac[SILC_HASH_MAXLEN];
+
+ silc_hash_final(hash, mac);
+ silc_hash_init(hash);
+ silc_hash_update(hash, hmac->outer_pad, silc_hash_block_len(hash));
+ silc_hash_update(hash, mac, silc_hash_len(hash));
+ silc_hash_final(hash, mac);
memcpy(return_hash, mac, hmac->hmac->len);
memset(mac, 0, sizeof(mac));