X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilccrypt%2Fsilchash.c;h=34aff02bb6adabed5f90f37855471eef3722963d;hb=40f8443d8d3a6577336ee66d18e04d9ac4d956bb;hp=18cf81bc4720f815b21464e1c0a5225a1eb22e29;hpb=318d79b391bf6288e3e28c840217a7097f3d0392;p=silc.git diff --git a/lib/silccrypt/silchash.c b/lib/silccrypt/silchash.c index 18cf81bc..34aff02b 100644 --- a/lib/silccrypt/silchash.c +++ b/lib/silccrypt/silchash.c @@ -2,200 +2,195 @@ silchash.c - Author: Pekka Riikonen + Author: Pekka Riikonen - Copyright (C) 1997 - 2000 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 GNU General Public License for more details. */ -/* - * $Id$ - * $Log$ - * Revision 1.3 2000/07/10 05:35:43 priikone - * Added fingerprint functions. - * - * Revision 1.2 2000/07/05 06:08:43 priikone - * Global cosmetic change. - * - * Revision 1.1.1.1 2000/06/27 11:36:55 priikone - * Imported from internal CVS/Added Log headers. - * - * - */ - -#include "silcincludes.h" +/* $Id$ */ + +#include "silc.h" #include "md5.h" #include "sha1.h" +#include "sha256.h" -/* List of all hash functions in SILC. You can dynamically add new hash - functions into the list. At the initialization of SILC this list is - filled with the configured hash functions. */ -struct SilcHashListStruct { +/* The main SILC hash structure. */ +struct SilcHashStruct { SilcHashObject *hash; - struct SilcHashListStruct *next; + void *context; }; +#ifndef SILC_EPOC /* List of dynamically registered hash functions. */ -struct SilcHashListStruct *silc_hash_list = NULL; +SilcDList silc_hash_list = NULL; +#endif /* SILC_EPOC */ -/* Statically declared list of hash functions. */ -SilcHashObject silc_hash_builtin_list[] = +/* Default hash functions for silc_hash_register_default(). */ +const SilcHashObject silc_default_hash[] = { - { "md5", 16, 64, silc_md5_init, silc_md5_update, silc_md5_final, - silc_md5_transform, silc_md5_context_len }, + { "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, + silc_md5_transform, silc_md5_context_len }, { NULL, 0, 0, NULL, NULL, NULL, NULL, NULL } }; -/* Registers a ned hash function into the SILC. This function is used at +/* Registers a new hash function into the SILC. This function is used at the initialization of the SILC. */ -int silc_hash_register(SilcHashObject *hash) +SilcBool silc_hash_register(const SilcHashObject *hash) { - struct SilcHashListStruct *new, *h; +#ifndef SILC_EPOC + SilcHashObject *new; - SILC_LOG_DEBUG(("Registering new hash function")); + SILC_LOG_DEBUG(("Registering new hash function `%s'", hash->name)); - new = silc_calloc(1, sizeof(*new)); - new->hash = silc_calloc(1, sizeof(*new->hash)); - - /* Set the pointers */ - new->hash->name = silc_calloc(1, strlen(hash->name)); - memcpy(new->hash->name, hash->name, strlen(hash->name)); - new->hash->hash_len = hash->hash_len; - new->hash->block_len = hash->block_len; - new->hash->init = hash->init; - new->hash->update = hash->update; - new->hash->final = hash->final; - new->hash->context_len = hash->context_len; - new->next = NULL; - - /* Add the new hash function to the list */ - if (!silc_hash_list) { - silc_hash_list = new; - return TRUE; - } - - h = silc_hash_list; - while (h) { - if (!h->next) { - h->next = new; - break; + /* 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; } - h = h->next; } + new = silc_calloc(1, sizeof(*new)); + new->name = strdup(hash->name); + new->hash_len = hash->hash_len; + new->block_len = hash->block_len; + new->init = hash->init; + new->update = hash->update; + new->final = hash->final; + new->transform = hash->transform; + new->context_len = hash->context_len; + + /* Add to list */ + if (silc_hash_list == NULL) + 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. */ -int silc_hash_unregister(SilcHashObject *hash) +SilcBool silc_hash_unregister(SilcHashObject *hash) { - struct SilcHashListStruct *h, *tmp; +#ifndef SILC_EPOC + SilcHashObject *entry; SILC_LOG_DEBUG(("Unregistering hash function")); - h = silc_hash_list; + if (!silc_hash_list) + return FALSE; - /* Unregister all hash functions */ - if (hash == SILC_ALL_HASH_FUNCTIONS) { - /* Unregister all ciphers */ - while (h) { - tmp = h->next; - silc_free(h->hash->name); - silc_free(h); - h = tmp; - } + silc_dlist_start(silc_hash_list); + 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); - return TRUE; - } + if (silc_dlist_count(silc_hash_list) == 0) { + silc_dlist_uninit(silc_hash_list); + silc_hash_list = NULL; + } - /* Unregister the hash function */ - if (h->hash == hash) { - tmp = h->next; - silc_free(h->hash->name); - silc_free(h); - silc_hash_list = tmp; - - return TRUE; - } - - while (h) { - if (h->next->hash == hash) { - tmp = h->next->next; - silc_free(h->hash->name); - silc_free(h); - h->next = tmp; return TRUE; } - - h = h->next; } +#endif /* SILC_EPOC */ 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. */ + +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. */ -int silc_hash_alloc(const unsigned char *name, SilcHash *new_hash) +SilcBool silc_hash_alloc(const unsigned char *name, SilcHash *new_hash) { - struct SilcHashListStruct *h; - int i; - - SILC_LOG_DEBUG(("Allocating new hash object")); + SilcHashObject *entry = NULL; - /* Allocate the new object */ - *new_hash = silc_calloc(1, sizeof(**new_hash)); + SILC_LOG_DEBUG(("Allocating new hash object")); +#ifndef SILC_EPOC if (silc_hash_list) { - h = silc_hash_list; - while (h) { - if (!strcmp(h->hash->name, name)) + silc_dlist_start(silc_hash_list); + while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) { + if (!strcmp(entry->name, name)) break; - h = h->next; } + } +#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 (!h) - goto check_builtin; - - /* Set the pointers */ - (*new_hash)->hash = h->hash; - (*new_hash)->context = silc_calloc(1, h->hash->context_len()); - (*new_hash)->make_hash = silc_hash_make; - + 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; } - check_builtin: - for (i = 0; silc_hash_builtin_list[i].name; i++) - if (!strcmp(silc_hash_builtin_list[i].name, name)) - break; - - if (silc_hash_builtin_list[i].name == NULL) { - silc_free(*new_hash); - return FALSE; - } - - /* Set the pointers */ - (*new_hash)->hash = &silc_hash_builtin_list[i]; - (*new_hash)->context = silc_calloc(1, (*new_hash)->hash->context_len()); - (*new_hash)->make_hash = silc_hash_make; - - return TRUE; + return FALSE; } /* Free's the SilcHash object */ @@ -208,65 +203,88 @@ void silc_hash_free(SilcHash hash) } } +/* Returns the length of the hash digest. */ + +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. */ -int silc_hash_is_supported(const unsigned char *name) +SilcBool silc_hash_is_supported(const unsigned char *name) { - struct SilcHashListStruct *h; - int i; - - if (silc_hash_list) { - h = silc_hash_list; +#ifndef SILC_EPOC + SilcHashObject *entry; - while (h) { - if (!strcmp(h->hash->name, name)) + 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)) return TRUE; - h = h->next; } } - - for (i = 0; silc_hash_builtin_list[i].name; i++) - if (!strcmp(silc_hash_builtin_list[i].name, 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; } /* Returns comma separated list of supported hash functions. */ -char *silc_hash_get_supported() +char *silc_hash_get_supported(void) { + SilcHashObject *entry; char *list = NULL; - int i, len; - struct SilcHashListStruct *h; + int len = 0; - len = 0; +#ifndef SILC_EPOC if (silc_hash_list) { - h = silc_hash_list; - - while (h) { - len += strlen(h->hash->name); + 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(h->hash->name)), - h->hash->name, strlen(h->hash->name)); + + memcpy(list + (len - strlen(entry->name)), + entry->name, strlen(entry->name)); memcpy(list + len, ",", 1); len++; - - h = h->next; } } +#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); - for (i = 0; silc_hash_builtin_list[i].name; i++) { - len += strlen(silc_hash_builtin_list[i].name); - list = silc_realloc(list, len + 1); - - memcpy(list + (len - strlen(silc_hash_builtin_list[i].name)), - silc_hash_builtin_list[i].name, - strlen(silc_hash_builtin_list[i].name)); - memcpy(list + len, ",", 1); - len++; + memcpy(list + (len - strlen(entry->name)), + entry->name, strlen(entry->name)); + memcpy(list + len, ",", 1); + len++; + } } +#endif /* SILC_EPOC */ list[len - 1] = 0; @@ -275,42 +293,126 @@ char *silc_hash_get_supported() /* Creates the hash value and returns it to the return_hash argument. */ -void silc_hash_make(SilcHash hash, const unsigned char *data, - unsigned int 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, - unsigned int data_len) + SilcUInt32 data_len) { - char fingerprint[64], *cp; + SilcHash new_hash = NULL; unsigned char h[32]; - int i; + char *ret; - if (!hash) - silc_hash_alloc("sha1", &hash); + if (!hash) { + silc_hash_alloc("sha1", &new_hash); + hash = new_hash; + } silc_hash_make(hash, data, data_len, h); - - memset(fingerprint, 0, sizeof(fingerprint)); - cp = fingerprint; - for (i = 0; i < hash->hash->hash_len; i++) { - snprintf(cp, sizeof(fingerprint), "%02X", h[i]); - cp += 2; - - if ((i + 1) % 2 == 0) - snprintf(cp++, sizeof(fingerprint), " "); - - if ((i + 1) % 10 == 0) - snprintf(cp++, sizeof(fingerprint), " "); + ret = silc_fingerprint(h, hash->hash->hash_len); + + if (new_hash != NULL) + silc_hash_free(new_hash); + return ret; +} + +static const char vo[]= "aeiouy"; +static const char co[]= "bcdfghklmnprstvzx"; + +/* Creates a babbleprint (Bubble Babble Encoding, developed by Antti + Huima (draft-huima-babble-01.txt)), by first computing real fingerprint + using `hash' or if NULL, then using SHA1, and then encoding the + fingerprint to the babbleprint. */ + +char *silc_hash_babbleprint(SilcHash hash, const unsigned char *data, + SilcUInt32 data_len) +{ + SilcHash new_hash = NULL; + char *babbleprint; + unsigned char hval[32]; + unsigned int a, b, c, d, e, check; + int i, k, out_len; + + if (!hash) { + silc_hash_alloc("sha1", &new_hash); + hash = new_hash; + } + + /* Take fingerprint */ + silc_hash_make(hash, data, data_len, hval); + + /* Encode babbleprint */ + out_len = (((hash->hash->hash_len + 1) / 2) + 1) * 6; + babbleprint = silc_calloc(out_len, sizeof(*babbleprint)); + babbleprint[0] = co[16]; + + check = 1; + 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]; + babbleprint[k + 3] = co[d]; + babbleprint[k + 4] = '-'; + babbleprint[k + 5] = co[e]; } - - return strdup(fingerprint); + + if ((hash->hash->hash_len % 2) != 0) { + a = (((hval[i] >> 6) & 3) + check) % 6; + b = (hval[i] >> 2) & 15; + c = ((hval[i] & 3) + (check / 6)) % 6; + babbleprint[k + 0] = vo[a]; + babbleprint[k + 1] = co[b]; + babbleprint[k + 2] = vo[c]; + } else { + a = check % 6; + b = 16; + c = check / 6; + babbleprint[k + 0] = vo[a]; + babbleprint[k + 1] = co[b]; + babbleprint[k + 2] = vo[c]; + } + babbleprint[k + 3] = co[16]; + + if (new_hash != NULL) + silc_hash_free(new_hash); + return babbleprint; }