X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=blobdiff_plain;f=lib%2Fsilccrypt%2Fsilchash.c;h=67c149522d4eef9606930d792f9b081234cfb47f;hp=819a2fab377fdeadafa1d54fd7597f63d9df93db;hb=e7b6c157b80152bf9fb9266e6bdd93f9fb0db776;hpb=d8d491f554988814894c0573211e31cfeca0a4e5 diff --git a/lib/silccrypt/silchash.c b/lib/silccrypt/silchash.c index 819a2fab..67c14952 100644 --- a/lib/silccrypt/silchash.c +++ b/lib/silccrypt/silchash.c @@ -2,15 +2,14 @@ silchash.c - Author: Pekka Riikonen + Author: Pekka Riikonen - Copyright (C) 1997 - 2001 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 - 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 @@ -19,36 +18,75 @@ */ /* $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 { + SilcHashObject *hash; + void *context; +}; +#ifndef SILC_SYMBIAN /* List of dynamically registered hash functions. */ SilcDList silc_hash_list = NULL; +#endif /* SILC_SYMBIAN */ /* Default hash functions for silc_hash_register_default(). */ -SilcHashObject silc_default_hash[] = +const SilcHashObject silc_default_hash[] = { - { "sha1", 20, 64, silc_sha1_init, silc_sha1_update, silc_sha1_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 }, + { "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", 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 - the initialization of the SILC. */ +/* Registers a new hash function */ -bool silc_hash_register(SilcHashObject *hash) +SilcBool silc_hash_register(const SilcHashObject *hash) { +#ifndef SILC_SYMBIAN 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)); + 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; @@ -62,13 +100,15 @@ bool silc_hash_register(SilcHashObject *hash) silc_hash_list = silc_dlist_init(); silc_dlist_add(silc_hash_list, new); +#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_SYMBIAN SilcHashObject *entry; SILC_LOG_DEBUG(("Unregistering hash function")); @@ -80,6 +120,9 @@ 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->oid); + silc_free(entry); if (silc_dlist_count(silc_hash_list) == 0) { silc_dlist_uninit(silc_hash_list); @@ -90,45 +133,128 @@ bool silc_hash_unregister(SilcHashObject *hash) } } +#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) { - int i; + /* We use builtin hash functions */ + return TRUE; +} - for (i = 0; silc_default_hash[i].name; i++) - silc_hash_register(&(silc_default_hash[i])); +/* Unregister all hash functions */ + +SilcBool silc_hash_unregister_all(void) +{ +#ifndef SILC_SYMBIAN + 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_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; - - SILC_LOG_DEBUG(("Allocating new hash object")); + SilcHashObject *entry = NULL; + int i; + + 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) { - 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; + } + } +#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]); + 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; + } + + 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; + } + return FALSE; } @@ -144,17 +270,40 @@ 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 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) { 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) { @@ -162,6 +311,11 @@ bool silc_hash_is_supported(const unsigned char *name) return TRUE; } } +#endif /* SILC_SYMBIAN */ + + for (i = 0; silc_default_hash[i].name; i++) + if (!strcmp(silc_default_hash[i].name, name)) + return TRUE; return FALSE; } @@ -170,71 +324,180 @@ 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; + int i, len = 0; - len = 0; +#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++; } - list[len - 1] = 0; } +#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++; + } + + 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, void *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) { - 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) { + if (!silc_hash_alloc("sha1", &new_hash)) + return NULL; + 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), " "); - } - i--; - if ((i + 1) % 2 == 0) - cp[-2] = 0; - if ((i + 1) % 10 == 0) - cp[-1] = 0; - - return strdup(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) { + if (!silc_hash_alloc("sha1", &new_hash)) + return NULL; + 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)); + 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) { + 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]; + } + + 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; }