X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilccrypt%2Fsilchash.c;h=67c149522d4eef9606930d792f9b081234cfb47f;hb=e7b6c157b80152bf9fb9266e6bdd93f9fb0db776;hp=7fcbf4411ef72aa1eec1e91fc4a7b08459053516;hpb=f1753017d02b95b2ba29c3a3953dead09005eff3;p=silc.git diff --git a/lib/silccrypt/silchash.c b/lib/silccrypt/silchash.c index 7fcbf441..67c14952 100644 --- a/lib/silccrypt/silchash.c +++ b/lib/silccrypt/silchash.c @@ -1,10 +1,10 @@ /* - silchash.c + silchash.c Author: Pekka Riikonen - 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,11 +18,12 @@ */ /* $Id$ */ -#include "silcincludes.h" +#include "silc.h" #include "md5.h" #include "sha1.h" #include "sha256.h" +#include "sha512.h" /* The main SILC hash structure. */ struct SilcHashStruct { @@ -30,30 +31,35 @@ 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[] = { - { "sha1", 20, 64, silc_sha1_init, silc_sha1_update, silc_sha1_final, - silc_sha1_transform, silc_sha1_context_len }, - { "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 }, - { "md5", 16, 64, silc_md5_init, silc_md5_update, silc_md5_final, + { "sha512", "2.16.840.1.101.3.4.2.3", + 32, 64, silc_sha512_init, silc_sha512_update, silc_sha512_final, + silc_sha512_transform, silc_sha512_context_len }, + { "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", "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 - the initialization of the SILC. */ +/* Registers a new hash function */ -bool silc_hash_register(const SilcHashObject *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 +75,18 @@ bool 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,15 +100,15 @@ bool 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; } -/* Unregister a hash function from the SILC. */ +/* Unregister a hash function */ -bool silc_hash_unregister(SilcHashObject *hash) +SilcBool silc_hash_unregister(SilcHashObject *hash) { -#ifndef SILC_EPOC +#ifndef SILC_SYMBIAN SilcHashObject *entry; SILC_LOG_DEBUG(("Unregistering hash function")); @@ -104,6 +121,7 @@ bool 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 +133,23 @@ bool silc_hash_unregister(SilcHashObject *hash) } } -#endif /* SILC_EPOC */ +#endif /* SILC_SYMBIAN */ return FALSE; } -/* 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. */ +/* Register default hash functions */ -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 */ + /* We use builtin hash functions */ return TRUE; } -bool silc_hash_unregister_all(void) +/* Unregister all hash functions */ + +SilcBool silc_hash_unregister_all(void) { -#ifndef SILC_EPOC +#ifndef SILC_SYMBIAN SilcHashObject *entry; if (!silc_hash_list) @@ -149,20 +161,22 @@ bool silc_hash_unregister_all(void) if (!silc_hash_list) break; } -#endif /* SILC_EPOC */ +#endif /* SILC_SYMBIAN */ 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 char *name, SilcHash *new_hash) { SilcHashObject *entry = NULL; - - SILC_LOG_DEBUG(("Allocating new hash object")); + int i; -#ifndef SILC_EPOC + SILC_LOG_DEBUG(("Allocating new hash %s", name)); + +#ifndef SILC_SYMBIAN + /* Check list of registered hash functions */ if (silc_hash_list) { silc_dlist_start(silc_hash_list); while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) { @@ -170,10 +184,10 @@ bool silc_hash_alloc(const unsigned char *name, SilcHash *new_hash) break; } } -#else - { - /* On EPOC which don't have globals we check our constant hash list. */ - int i; +#endif /* SILC_SYMBIAN */ + + if (!entry) { + /* Check builtin hash function list */ for (i = 0; silc_default_hash[i].name; i++) { if (!strcmp(silc_default_hash[i].name, name)) { entry = (SilcHashObject *)&(silc_default_hash[i]); @@ -181,12 +195,63 @@ bool silc_hash_alloc(const unsigned char *name, SilcHash *new_hash) } } } -#endif /* SILC_EPOC */ 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; + int i; + + SILC_LOG_DEBUG(("Allocating new hash %s", oid)); + +#ifndef SILC_SYMBIAN + /* Check list of registered hash functions */ + 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; + } + } +#endif /* SILC_SYMBIAN */ + + if (!entry) { + /* Check builtin hash function list */ + for (i = 0; silc_default_hash[i].oid; i++) { + if (!strcmp(silc_default_hash[i].oid, oid)) { + entry = (SilcHashObject *)&(silc_default_hash[i]); + break; + } + } + } + + 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,13 +289,21 @@ 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. */ -bool silc_hash_is_supported(const unsigned char *name) +SilcBool silc_hash_is_supported(const char *name) { -#ifndef SILC_EPOC SilcHashObject *entry; + int i; +#ifndef SILC_SYMBIAN if (silc_hash_list) { silc_dlist_start(silc_hash_list); while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) { @@ -238,14 +311,12 @@ 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 */ +#endif /* SILC_SYMBIAN */ + + for (i = 0; silc_default_hash[i].name; i++) + if (!strcmp(silc_default_hash[i].name, name)) + return TRUE; + return FALSE; } @@ -253,38 +324,46 @@ bool silc_hash_is_supported(const unsigned char *name) char *silc_hash_get_supported(void) { - SilcHashObject *entry; + SilcHashObject *entry, *entry2; char *list = NULL; - int len = 0; + int i, 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++; } } -#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++; +#endif /* SILC_SYMBIAN */ + + for (i = 0; silc_default_hash[i].name; i++) { + entry = (SilcHashObject *)&(silc_default_hash[i]); + + if (silc_hash_list) { + silc_dlist_start(silc_hash_list); + while ((entry2 = silc_dlist_get(silc_hash_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++; } -#endif /* SILC_EPOC */ list[len - 1] = 0; @@ -293,7 +372,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); @@ -317,7 +396,7 @@ 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, +void silc_hash_transform(SilcHash hash, void *state, const unsigned char *data) { hash->hash->transform(state, data); @@ -335,7 +414,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 +445,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 +456,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 +487,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;