Added SILC Server library.
[silc.git] / lib / silccrypt / silchash.c
index f508c836e3bfa87898cd59ad7bbe0a87f96461b1..34aff02bb6adabed5f90f37855471eef3722963d 100644 (file)
@@ -2,15 +2,14 @@
 
   silchash.c
 
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+  Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2001 Pekka Riikonen
+  Copyright (C) 1997 - 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
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-  
+  the Free Software Foundation; version 2 of the License.
+
   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
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 #include "md5.h"
 #include "sha1.h"
+#include "sha256.h"
+
+/* The main SILC hash structure. */
+struct SilcHashStruct {
+  SilcHashObject *hash;
+  void *context;
+};
 
+#ifndef SILC_EPOC
 /* List of dynamically registered hash functions. */
 SilcDList silc_hash_list = NULL;
+#endif /* SILC_EPOC */
 
 /* Default hash functions for silc_hash_register_default(). */
-SilcHashObject silc_default_hash[] = 
+const SilcHashObject silc_default_hash[] =
 {
+  { "sha256", 32, 64, silc_sha256_init, silc_sha256_update, silc_sha256_final,
+    silc_sha256_transform, silc_sha256_context_len },
   { "sha1", 20, 64, silc_sha1_init, silc_sha1_update, silc_sha1_final,
     silc_sha1_transform, silc_sha1_context_len },
   { "md5", 16, 64, silc_md5_init, silc_md5_update, silc_md5_final,
@@ -41,12 +51,23 @@ SilcHashObject silc_default_hash[] =
 /* Registers a new hash function into the SILC. This function is used at
    the initialization of the SILC. */
 
-bool silc_hash_register(SilcHashObject *hash)
+SilcBool silc_hash_register(const SilcHashObject *hash)
 {
+#ifndef SILC_EPOC
   SilcHashObject *new;
 
   SILC_LOG_DEBUG(("Registering new hash function `%s'", hash->name));
 
+  /* Check for existing */
+  if (silc_hash_list) {
+    SilcHashObject *entry;
+    silc_dlist_start(silc_hash_list);
+    while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
+      if (!strcmp(entry->name, hash->name))
+       return FALSE;
+    }
+  }
+
   new = silc_calloc(1, sizeof(*new));
   new->name = strdup(hash->name);
   new->hash_len = hash->hash_len;
@@ -62,13 +83,15 @@ bool silc_hash_register(SilcHashObject *hash)
     silc_hash_list = silc_dlist_init();
   silc_dlist_add(silc_hash_list, new);
 
+#endif /* SILC_EPOC */
   return TRUE;
 }
 
 /* Unregister a hash function from the SILC. */
 
-bool silc_hash_unregister(SilcHashObject *hash)
+SilcBool silc_hash_unregister(SilcHashObject *hash)
 {
+#ifndef SILC_EPOC
   SilcHashObject *entry;
 
   SILC_LOG_DEBUG(("Unregistering hash function"));
@@ -80,6 +103,8 @@ bool silc_hash_unregister(SilcHashObject *hash)
   while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
     if (hash == SILC_ALL_HASH_FUNCTIONS || entry == hash) {
       silc_dlist_del(silc_hash_list, entry);
+      silc_free(entry->name);
+      silc_free(entry);
 
       if (silc_dlist_count(silc_hash_list) == 0) {
        silc_dlist_uninit(silc_hash_list);
@@ -90,44 +115,80 @@ bool silc_hash_unregister(SilcHashObject *hash)
     }
   }
 
+#endif /* SILC_EPOC */
   return FALSE;
 }
 
-/* Function that registers all the default hash funcs (all builtin ones). 
+/* Function that registers all the default hash funcs (all builtin ones).
    The application may use this to register the default hash funcs if
    specific hash funcs in any specific order is not wanted. */
 
-bool silc_hash_register_default(void)
+SilcBool silc_hash_register_default(void)
 {
+#ifndef SILC_EPOC
   int i;
 
   for (i = 0; silc_default_hash[i].name; i++)
     silc_hash_register(&(silc_default_hash[i]));
 
+#endif /* SILC_EPOC */
+  return TRUE;
+}
+
+SilcBool silc_hash_unregister_all(void)
+{
+#ifndef SILC_EPOC
+  SilcHashObject *entry;
+
+  if (!silc_hash_list)
+    return FALSE;
+
+  silc_dlist_start(silc_hash_list);
+  while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
+    silc_hash_unregister(entry);
+    if (!silc_hash_list)
+      break;
+  }
+#endif /* SILC_EPOC */
   return TRUE;
 }
 
 /* Allocates a new SilcHash object. New object is returned into new_hash
    argument. */
 
-bool silc_hash_alloc(const unsigned char *name, SilcHash *new_hash)
+SilcBool silc_hash_alloc(const unsigned char *name, SilcHash *new_hash)
 {
-  SilcHashObject *entry;
-  
+  SilcHashObject *entry = NULL;
+
   SILC_LOG_DEBUG(("Allocating new hash object"));
 
+#ifndef SILC_EPOC
   if (silc_hash_list) {
     silc_dlist_start(silc_hash_list);
     while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
-      if (!strcmp(entry->name, name)) {
-       *new_hash = silc_calloc(1, sizeof(**new_hash));
-       (*new_hash)->hash = entry;
-       (*new_hash)->context = silc_calloc(1, entry->context_len());
-       (*new_hash)->make_hash = silc_hash_make;
-       return TRUE;
+      if (!strcmp(entry->name, name))
+       break;
+    }
+  }
+#else
+  {
+    /* On EPOC which don't have globals we check our constant hash list. */
+    int i;
+    for (i = 0; silc_default_hash[i].name; i++) {
+      if (!strcmp(silc_default_hash[i].name, name)) {
+       entry = (SilcHashObject *)&(silc_default_hash[i]);
+       break;
       }
     }
   }
+#endif /* SILC_EPOC */
+
+  if (entry) {
+    *new_hash = silc_calloc(1, sizeof(**new_hash));
+    (*new_hash)->hash = entry;
+    (*new_hash)->context = silc_calloc(1, entry->context_len());
+    return TRUE;
+  }
 
   return FALSE;
 }
@@ -144,15 +205,30 @@ void silc_hash_free(SilcHash hash)
 
 /* Returns the length of the hash digest. */
 
-uint32 silc_hash_len(SilcHash hash)
+SilcUInt32 silc_hash_len(SilcHash hash)
 {
   return hash->hash->hash_len;
 }
 
+/* Returns the block lenght of the hash. */
+
+SilcUInt32 silc_hash_block_len(SilcHash hash)
+{
+  return hash->hash->block_len;
+}
+
+/* Returns the name of the hash function */
+
+const char *silc_hash_get_name(SilcHash hash)
+{
+  return hash->hash->name;
+}
+
 /* Returns TRUE if hash algorithm `name' is supported. */
 
-bool silc_hash_is_supported(const unsigned char *name)
+SilcBool silc_hash_is_supported(const unsigned char *name)
 {
+#ifndef SILC_EPOC
   SilcHashObject *entry;
 
   if (silc_hash_list) {
@@ -162,7 +238,14 @@ bool silc_hash_is_supported(const unsigned char *name)
        return TRUE;
     }
   }
-
+#else
+  {
+    int i;
+    for (i = 0; silc_default_hash[i].name; i++)
+      if (!strcmp(silc_default_hash[i].name, name))
+       return TRUE;
+  }
+#endif /* SILC_EPOC */
   return FALSE;
 }
 
@@ -172,42 +255,80 @@ char *silc_hash_get_supported(void)
 {
   SilcHashObject *entry;
   char *list = NULL;
-  int len;
+  int len = 0;
 
-  len = 0;
+#ifndef SILC_EPOC
   if (silc_hash_list) {
     silc_dlist_start(silc_hash_list);
     while ((entry = silc_dlist_get(silc_hash_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++;
+    }
+  }
+#else
+  {
+    int i;
+    for (i = 0; silc_default_hash[i].name; i++) {
+      entry = (SilcHashObject *)&(silc_default_hash[i]);
+      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;
   }
+#endif /* SILC_EPOC */
+
+  list[len - 1] = 0;
 
   return list;
 }
 
 /* Creates the hash value and returns it to the return_hash argument. */
 
-void silc_hash_make(SilcHash hash, const unsigned char *data, 
-                   uint32 len, unsigned char *return_hash)
+void silc_hash_make(SilcHash hash, const unsigned char *data,
+                   SilcUInt32 len, unsigned char *return_hash)
+{
+  silc_hash_init(hash);
+  silc_hash_update(hash, data, len);
+  silc_hash_final(hash, return_hash);
+}
+
+void silc_hash_init(SilcHash hash)
 {
   hash->hash->init(hash->context);
-  hash->hash->update(hash->context, (unsigned char *)data, len);
+}
+
+void silc_hash_update(SilcHash hash, const unsigned char *data,
+                     SilcUInt32 data_len)
+{
+  hash->hash->update(hash->context, (unsigned char *)data, data_len);
+}
+
+void silc_hash_final(SilcHash hash, unsigned char *return_hash)
+{
   hash->hash->final(hash->context, return_hash);
 }
 
+void silc_hash_transform(SilcHash hash, SilcUInt32 *state,
+                        const unsigned char *data)
+{
+  hash->hash->transform(state, data);
+}
+
 /* Creates fingerprint of the data. If `hash' is NULL SHA1 is used as
-   default hash function. The returned fingerprint must be free's by the
+   default hash function. The returned fingerprint must be freed by the
    caller. */
 
 char *silc_hash_fingerprint(SilcHash hash, const unsigned char *data,
-                           uint32 data_len)
+                           SilcUInt32 data_len)
 {
   SilcHash new_hash = NULL;
   unsigned char h[32];
@@ -235,7 +356,7 @@ static const char co[]= "bcdfghklmnprstvzx";
    fingerprint to the babbleprint. */
 
 char *silc_hash_babbleprint(SilcHash hash, const unsigned char *data,
-                           uint32 data_len)
+                           SilcUInt32 data_len)
 {
   SilcHash new_hash = NULL;
   char *babbleprint;
@@ -257,15 +378,15 @@ char *silc_hash_babbleprint(SilcHash hash, const unsigned char *data,
   babbleprint[0] = co[16];
 
   check = 1;
-  for (i = 0, k = 1; i < hash->hash->hash_len - 1; i += 2, k += 6) { 
+  for (i = 0, k = 1; i < hash->hash->hash_len - 1; i += 2, k += 6) {
     a = (((hval[i] >> 6) & 3) + check) % 6;
     b = (hval[i] >> 2) & 15;
     c = ((hval[i] & 3) + (check / 6)) % 6;
     d = (hval[i + 1] >> 4) & 15;
     e = hval[i + 1] & 15;
-    
+
     check = ((check * 5) + (hval[i] * 7) + hval[i + 1]) % 36;
-    
+
     babbleprint[k + 0] = vo[a];
     babbleprint[k + 1] = co[b];
     babbleprint[k + 2] = vo[c];
@@ -281,7 +402,7 @@ char *silc_hash_babbleprint(SilcHash hash, const unsigned char *data,
     babbleprint[k + 0] = vo[a];
     babbleprint[k + 1] = co[b];
     babbleprint[k + 2] = vo[c];
-  } else { 
+  } else {
     a = check % 6;
     b = 16;
     c = check / 6;