Merge branch 'topic/mm-fixes' of git://208.110.73.182/silc into silc.1.1.branch
[silc.git] / lib / silccrypt / silchash.c
index f486c26dad5fc0f4b1e937d89e98bd5fb107ade5..59cdf7f94eb88d07efc93792a791f3f79e3a516a 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  silchash.c 
+  silchash.c
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2002 Pekka Riikonen
+  Copyright (C) 1997 - 2007 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
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 #include "md5.h"
 #include "sha1.h"
@@ -30,22 +30,25 @@ struct SilcHashStruct {
   void *context;
 };
 
-#ifndef SILC_EPOC
+#ifndef SILC_SYMBIAN
 /* List of dynamically registered hash functions. */
 SilcDList silc_hash_list = NULL;
-#endif /* SILC_EPOC */
+#endif /* SILC_SYMBIAN */
 
 /* Default hash functions for silc_hash_register_default(). */
-const SilcHashObject silc_default_hash[] = 
+const SilcHashObject silc_default_hash[] =
 {
-  { "sha256", 32, 64, silc_sha256_init, silc_sha256_update, silc_sha256_final,
+  { "sha256", "2.16.840.1.101.3.4.2.1",
+    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,
+  { "sha1", "1.3.14.3.2.26",
+    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,
+  { "md5", "1.2.840.113549.2.5",
+    16, 64, silc_md5_init, silc_md5_update, silc_md5_final,
     silc_md5_transform, silc_md5_context_len },
 
-  { NULL, 0, 0, NULL, NULL, NULL, NULL, NULL }
+  { NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL }
 };
 
 /* Registers a new hash function into the SILC. This function is used at
@@ -53,7 +56,7 @@ const SilcHashObject silc_default_hash[] =
 
 SilcBool silc_hash_register(const SilcHashObject *hash)
 {
-#ifndef SILC_EPOC
+#ifndef SILC_SYMBIAN
   SilcHashObject *new;
 
   SILC_LOG_DEBUG(("Registering new hash function `%s'", hash->name));
@@ -69,7 +72,18 @@ SilcBool silc_hash_register(const SilcHashObject *hash)
   }
 
   new = silc_calloc(1, sizeof(*new));
+  if (!new)
+    return FALSE;
   new->name = strdup(hash->name);
+  if (!new->name) {
+    silc_free(new);
+    return FALSE;
+  }
+  new->oid = strdup(hash->oid);
+  if (!new->oid) {
+    silc_free(new);
+    return FALSE;
+  }
   new->hash_len = hash->hash_len;
   new->block_len = hash->block_len;
   new->init = hash->init;
@@ -83,7 +97,7 @@ SilcBool silc_hash_register(const SilcHashObject *hash)
     silc_hash_list = silc_dlist_init();
   silc_dlist_add(silc_hash_list, new);
 
-#endif /* SILC_EPOC */
+#endif /* SILC_SYMBIAN */
   return TRUE;
 }
 
@@ -91,7 +105,7 @@ SilcBool silc_hash_register(const SilcHashObject *hash)
 
 SilcBool silc_hash_unregister(SilcHashObject *hash)
 {
-#ifndef SILC_EPOC
+#ifndef SILC_SYMBIAN
   SilcHashObject *entry;
 
   SILC_LOG_DEBUG(("Unregistering hash function"));
@@ -104,6 +118,7 @@ SilcBool silc_hash_unregister(SilcHashObject *hash)
     if (hash == SILC_ALL_HASH_FUNCTIONS || entry == hash) {
       silc_dlist_del(silc_hash_list, entry);
       silc_free(entry->name);
+      silc_free(entry->oid);
       silc_free(entry);
 
       if (silc_dlist_count(silc_hash_list) == 0) {
@@ -115,29 +130,29 @@ SilcBool silc_hash_unregister(SilcHashObject *hash)
     }
   }
 
-#endif /* SILC_EPOC */
+#endif /* SILC_SYMBIAN */
   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. */
 
 SilcBool silc_hash_register_default(void)
 {
-#ifndef SILC_EPOC
+#ifndef SILC_SYMBIAN
   int i;
 
   for (i = 0; silc_default_hash[i].name; i++)
     silc_hash_register(&(silc_default_hash[i]));
 
-#endif /* SILC_EPOC */
+#endif /* SILC_SYMBIAN */
   return TRUE;
 }
 
 SilcBool silc_hash_unregister_all(void)
 {
-#ifndef SILC_EPOC
+#ifndef SILC_SYMBIAN
   SilcHashObject *entry;
 
   if (!silc_hash_list)
@@ -149,7 +164,7 @@ SilcBool silc_hash_unregister_all(void)
     if (!silc_hash_list)
       break;
   }
-#endif /* SILC_EPOC */
+#endif /* SILC_SYMBIAN */
   return TRUE;
 }
 
@@ -159,10 +174,10 @@ SilcBool silc_hash_unregister_all(void)
 SilcBool silc_hash_alloc(const unsigned char *name, SilcHash *new_hash)
 {
   SilcHashObject *entry = NULL;
-  
-  SILC_LOG_DEBUG(("Allocating new hash object"));
 
-#ifndef SILC_EPOC
+  SILC_LOG_DEBUG(("Allocating new hash %s", name));
+
+#ifndef SILC_SYMBIAN
   if (silc_hash_list) {
     silc_dlist_start(silc_hash_list);
     while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
@@ -181,12 +196,63 @@ SilcBool silc_hash_alloc(const unsigned char *name, SilcHash *new_hash)
       }
     }
   }
-#endif /* SILC_EPOC */
+#endif /* SILC_SYMBIAN */
 
   if (entry) {
     *new_hash = silc_calloc(1, sizeof(**new_hash));
+    if (!(*new_hash))
+      return FALSE;
     (*new_hash)->hash = entry;
     (*new_hash)->context = silc_calloc(1, entry->context_len());
+    if (!(*new_hash)->context) {
+      silc_free(*new_hash);
+      return FALSE;
+    }
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+/* Allocate hash by OID string */
+
+SilcBool silc_hash_alloc_by_oid(const char *oid, SilcHash *new_hash)
+{
+  SilcHashObject *entry = NULL;
+
+  SILC_LOG_DEBUG(("Allocating new hash %s", oid));
+
+#ifndef SILC_SYMBIAN
+  if (silc_hash_list) {
+    silc_dlist_start(silc_hash_list);
+    while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
+      if (!strcmp(entry->oid, oid))
+       break;
+    }
+  }
+#else
+  {
+    /* On EPOC which don't have globals we check our constant hash list. */
+    int i;
+    for (i = 0; silc_default_hash[i].oid; i++) {
+      if (!strcmp(silc_default_hash[i].oid, oid)) {
+       entry = (SilcHashObject *)&(silc_default_hash[i]);
+       break;
+      }
+    }
+  }
+#endif /* SILC_SYMBIAN */
+
+  if (entry) {
+    *new_hash = silc_calloc(1, sizeof(**new_hash));
+    if (!(*new_hash))
+      return FALSE;
+    (*new_hash)->hash = entry;
+    (*new_hash)->context = silc_calloc(1, entry->context_len());
+    if (!(*new_hash)->context) {
+      silc_free(*new_hash);
+      return FALSE;
+    }
     return TRUE;
   }
 
@@ -224,11 +290,18 @@ const char *silc_hash_get_name(SilcHash hash)
   return hash->hash->name;
 }
 
+/* Returns hash OID string */
+
+const char *silc_hash_get_oid(SilcHash hash)
+{
+  return hash->hash->oid;
+}
+
 /* Returns TRUE if hash algorithm `name' is supported. */
 
 SilcBool silc_hash_is_supported(const unsigned char *name)
 {
-#ifndef SILC_EPOC
+#ifndef SILC_SYMBIAN
   SilcHashObject *entry;
 
   if (silc_hash_list) {
@@ -245,7 +318,7 @@ SilcBool silc_hash_is_supported(const unsigned char *name)
       if (!strcmp(silc_default_hash[i].name, name))
        return TRUE;
   }
-#endif /* SILC_EPOC */
+#endif /* SILC_SYMBIAN */
   return FALSE;
 }
 
@@ -257,14 +330,14 @@ char *silc_hash_get_supported(void)
   char *list = NULL;
   int len = 0;
 
-#ifndef SILC_EPOC
+#ifndef SILC_SYMBIAN
   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++;
@@ -277,14 +350,14 @@ char *silc_hash_get_supported(void)
       entry = (SilcHashObject *)&(silc_default_hash[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++;
     }
   }
-#endif /* SILC_EPOC */
+#endif /* SILC_SYMBIAN */
 
   list[len - 1] = 0;
 
@@ -293,7 +366,7 @@ char *silc_hash_get_supported(void)
 
 /* Creates the hash value and returns it to the return_hash argument. */
 
-void silc_hash_make(SilcHash hash, const unsigned char *data, 
+void silc_hash_make(SilcHash hash, const unsigned char *data,
                    SilcUInt32 len, unsigned char *return_hash)
 {
   silc_hash_init(hash);
@@ -335,7 +408,8 @@ char *silc_hash_fingerprint(SilcHash hash, const unsigned char *data,
   char *ret;
 
   if (!hash) {
-    silc_hash_alloc("sha1", &new_hash);
+    if (!silc_hash_alloc("sha1", &new_hash))
+      return NULL;
     hash = new_hash;
   }
 
@@ -365,7 +439,8 @@ char *silc_hash_babbleprint(SilcHash hash, const unsigned char *data,
   int i, k, out_len;
 
   if (!hash) {
-    silc_hash_alloc("sha1", &new_hash);
+    if (!silc_hash_alloc("sha1", &new_hash))
+      return NULL;
     hash = new_hash;
   }
 
@@ -375,18 +450,22 @@ char *silc_hash_babbleprint(SilcHash hash, const unsigned char *data,
   /* Encode babbleprint */
   out_len = (((hash->hash->hash_len + 1) / 2) + 1) * 6;
   babbleprint = silc_calloc(out_len, sizeof(*babbleprint));
+  if (!babbleprint) {
+    silc_hash_free(new_hash);
+    return NULL;
+  }
   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];
@@ -402,7 +481,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;