Added SILC Server library.
[silc.git] / lib / silccrypt / silchmac.c
index dfde14da034cb6333c9da80c2863d9c6cf0759c5..6b3abed3dc6376663c76592ccf48b813dccea4a0 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  silchmac.c 
+  silchmac.c
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1999 - 2001 Pekka Riikonen
+  Copyright (C) 1999 - 2005 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
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 /* HMAC context */
 struct SilcHmacStruct {
   SilcHmacObject *hmac;
   SilcHash hash;
-  bool allocated_hash;         /* TRUE if the hash was allocated */
-
-  unsigned char *key;
-  SilcUInt32 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_EPOC
@@ -42,8 +39,10 @@ SilcDList silc_hmac_list = NULL;
 /* Default hmacs for silc_hmac_register_default(). */
 const SilcHmacObject silc_default_hmacs[] =
 {
+  { "hmac-sha256-96", 12 },
   { "hmac-sha1-96", 12 },
   { "hmac-md5-96", 12 },
+  { "hmac-sha256", 32 },
   { "hmac-sha1", 20 },
   { "hmac-md5", 16 },
 
@@ -54,18 +53,21 @@ static void silc_hmac_init_internal(SilcHmac hmac, unsigned char *key,
                                    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 */
@@ -73,7 +75,7 @@ static void silc_hmac_init_internal(SilcHmac hmac, unsigned char *key,
   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;
   }
@@ -82,7 +84,7 @@ static void silc_hmac_init_internal(SilcHmac hmac, unsigned char *key,
 /* Registers a new HMAC into the SILC. This function is used at the
    initialization of the SILC. */
 
-bool silc_hmac_register(const SilcHmacObject *hmac)
+SilcBool silc_hmac_register(const SilcHmacObject *hmac)
 {
 #ifndef SILC_EPOC
   SilcHmacObject *new;
@@ -114,7 +116,7 @@ bool silc_hmac_register(const SilcHmacObject *hmac)
 
 /* Unregister a HMAC from the SILC. */
 
-bool silc_hmac_unregister(SilcHmacObject *hmac)
+SilcBool silc_hmac_unregister(SilcHmacObject *hmac)
 {
 #ifndef SILC_EPOC
   SilcHmacObject *entry;
@@ -128,6 +130,8 @@ bool silc_hmac_unregister(SilcHmacObject *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);
@@ -142,11 +146,11 @@ bool silc_hmac_unregister(SilcHmacObject *hmac)
   return FALSE;
 }
 
-/* Function that registers all the default hmacs (all builtin ones). 
+/* 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. */
 
-bool silc_hmac_register_default(void)
+SilcBool silc_hmac_register_default(void)
 {
 #ifndef SILC_EPOC
   int i;
@@ -158,12 +162,30 @@ bool silc_hmac_register_default(void)
   return TRUE;
 }
 
+SilcBool silc_hmac_unregister_all(void)
+{
+#ifndef SILC_EPOC
+  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_EPOC */
+  return TRUE;
+}
+
 /* Allocates a new SilcHmac object of name of `name'.  The `hash' may
    be provided as argument.  If provided it is used as the hash function
    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)
 {
   SILC_LOG_DEBUG(("Allocating new HMAC"));
 
@@ -198,7 +220,7 @@ bool silc_hmac_alloc(char *name, SilcHash hash, SilcHmac *new_hmac)
     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;
       }
     }
@@ -234,7 +256,6 @@ void silc_hmac_free(SilcHmac hmac)
       silc_free(hmac->key);
     }
 
-    silc_free(hmac->hash_context);
     silc_free(hmac);
   }
 }
@@ -262,14 +283,14 @@ const char *silc_hmac_get_name(SilcHmac hmac)
 
 /* Returns TRUE if HMAC `name' is supported. */
 
-bool silc_hmac_is_supported(const char *name)
+SilcBool silc_hmac_is_supported(const char *name)
 {
 #ifndef SILC_EPOC
   SilcHmacObject *entry;
 
   if (!name)
     return FALSE;
-  
+
   if (silc_hmac_list) {
     silc_dlist_start(silc_hmac_list);
     while ((entry = silc_dlist_get(silc_hmac_list)) != SILC_LIST_END) {
@@ -302,8 +323,8 @@ char *silc_hmac_get_supported()
     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++;
@@ -316,8 +337,8 @@ char *silc_hmac_get_supported()
       entry = (SilcHmacObject *)&(silc_default_hmacs[i]);
       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++;
@@ -362,7 +383,7 @@ void silc_hmac_make(SilcHmac hmac, unsigned char *data,
    key. The key is sent as argument to the function. */
 
 void silc_hmac_make_with_key(SilcHmac hmac, unsigned char *data,
-                            SilcUInt32 data_len, 
+                            SilcUInt32 data_len,
                             unsigned char *key, SilcUInt32 key_len,
                             unsigned char *return_hash,
                             SilcUInt32 *return_len)
@@ -376,7 +397,7 @@ void silc_hmac_make_with_key(SilcHmac hmac, unsigned char *data,
 
 /* 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,
@@ -384,7 +405,7 @@ void silc_hmac_make_truncated(SilcHmac hmac, unsigned char *data,
                              SilcUInt32 truncated_len,
                              unsigned char *return_hash)
 {
-  unsigned char hvalue[20];
+  unsigned char hvalue[SILC_HASH_MAXLEN];
 
   SILC_LOG_DEBUG(("Making HMAC for message"));
 
@@ -408,15 +429,9 @@ void silc_hmac_init_with_key(SilcHmac hmac, const unsigned char *key,
                             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. */
@@ -425,7 +440,7 @@ void silc_hmac_update(SilcHmac hmac, const unsigned char *data,
                      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. */
@@ -434,14 +449,13 @@ void silc_hmac_final(SilcHmac hmac, unsigned char *return_hash,
                     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));