5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2007 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
27 /* The main SILC hash structure. */
28 struct SilcHashStruct {
34 /* List of dynamically registered hash functions. */
35 SilcDList silc_hash_list = NULL;
36 #endif /* SILC_SYMBIAN */
38 /* Default hash functions for silc_hash_register_default(). */
39 const SilcHashObject silc_default_hash[] =
41 { "sha256", "2.16.840.1.101.3.4.2.1",
42 32, 64, silc_sha256_init, silc_sha256_update, silc_sha256_final,
43 silc_sha256_transform, silc_sha256_context_len },
44 { "sha1", "1.3.14.3.2.26",
45 20, 64, silc_sha1_init, silc_sha1_update, silc_sha1_final,
46 silc_sha1_transform, silc_sha1_context_len },
47 { "md5", "1.2.840.113549.2.5",
48 16, 64, silc_md5_init, silc_md5_update, silc_md5_final,
49 silc_md5_transform, silc_md5_context_len },
51 { NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL }
54 /* Registers a new hash function into the SILC. This function is used at
55 the initialization of the SILC. */
57 SilcBool silc_hash_register(const SilcHashObject *hash)
62 SILC_LOG_DEBUG(("Registering new hash function `%s'", hash->name));
64 /* Check for existing */
66 SilcHashObject *entry;
67 silc_dlist_start(silc_hash_list);
68 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
69 if (!strcmp(entry->name, hash->name))
74 new = silc_calloc(1, sizeof(*new));
77 new->name = strdup(hash->name);
82 new->oid = strdup(hash->oid);
87 new->hash_len = hash->hash_len;
88 new->block_len = hash->block_len;
89 new->init = hash->init;
90 new->update = hash->update;
91 new->final = hash->final;
92 new->transform = hash->transform;
93 new->context_len = hash->context_len;
96 if (silc_hash_list == NULL)
97 silc_hash_list = silc_dlist_init();
98 silc_dlist_add(silc_hash_list, new);
100 #endif /* SILC_SYMBIAN */
104 /* Unregister a hash function from the SILC. */
106 SilcBool silc_hash_unregister(SilcHashObject *hash)
109 SilcHashObject *entry;
111 SILC_LOG_DEBUG(("Unregistering hash function"));
116 silc_dlist_start(silc_hash_list);
117 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
118 if (hash == SILC_ALL_HASH_FUNCTIONS || entry == hash) {
119 silc_dlist_del(silc_hash_list, entry);
120 silc_free(entry->name);
123 if (silc_dlist_count(silc_hash_list) == 0) {
124 silc_dlist_uninit(silc_hash_list);
125 silc_hash_list = NULL;
132 #endif /* SILC_SYMBIAN */
136 /* Function that registers all the default hash funcs (all builtin ones).
137 The application may use this to register the default hash funcs if
138 specific hash funcs in any specific order is not wanted. */
140 SilcBool silc_hash_register_default(void)
145 for (i = 0; silc_default_hash[i].name; i++)
146 silc_hash_register(&(silc_default_hash[i]));
148 #endif /* SILC_SYMBIAN */
152 SilcBool silc_hash_unregister_all(void)
155 SilcHashObject *entry;
160 silc_dlist_start(silc_hash_list);
161 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
162 silc_hash_unregister(entry);
166 #endif /* SILC_SYMBIAN */
170 /* Allocates a new SilcHash object. New object is returned into new_hash
173 SilcBool silc_hash_alloc(const unsigned char *name, SilcHash *new_hash)
175 SilcHashObject *entry = NULL;
177 SILC_LOG_DEBUG(("Allocating new hash %s", name));
180 if (silc_hash_list) {
181 silc_dlist_start(silc_hash_list);
182 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
183 if (!strcmp(entry->name, name))
189 /* On EPOC which don't have globals we check our constant hash list. */
191 for (i = 0; silc_default_hash[i].name; i++) {
192 if (!strcmp(silc_default_hash[i].name, name)) {
193 entry = (SilcHashObject *)&(silc_default_hash[i]);
198 #endif /* SILC_SYMBIAN */
201 *new_hash = silc_calloc(1, sizeof(**new_hash));
204 (*new_hash)->hash = entry;
205 (*new_hash)->context = silc_calloc(1, entry->context_len());
206 if (!(*new_hash)->context) {
207 silc_free(*new_hash);
216 /* Allocate hash by OID string */
218 SilcBool silc_hash_alloc_by_oid(const char *oid, SilcHash *new_hash)
220 SilcHashObject *entry = NULL;
222 SILC_LOG_DEBUG(("Allocating new hash %s", oid));
225 if (silc_hash_list) {
226 silc_dlist_start(silc_hash_list);
227 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
228 if (!strcmp(entry->oid, oid))
234 /* On EPOC which don't have globals we check our constant hash list. */
236 for (i = 0; silc_default_hash[i].oid; i++) {
237 if (!strcmp(silc_default_hash[i].oid, oid)) {
238 entry = (SilcHashObject *)&(silc_default_hash[i]);
243 #endif /* SILC_SYMBIAN */
246 *new_hash = silc_calloc(1, sizeof(**new_hash));
249 (*new_hash)->hash = entry;
250 (*new_hash)->context = silc_calloc(1, entry->context_len());
251 if (!(*new_hash)->context) {
252 silc_free(*new_hash);
261 /* Free's the SilcHash object */
263 void silc_hash_free(SilcHash hash)
266 silc_free(hash->context);
271 /* Returns the length of the hash digest. */
273 SilcUInt32 silc_hash_len(SilcHash hash)
275 return hash->hash->hash_len;
278 /* Returns the block lenght of the hash. */
280 SilcUInt32 silc_hash_block_len(SilcHash hash)
282 return hash->hash->block_len;
285 /* Returns the name of the hash function */
287 const char *silc_hash_get_name(SilcHash hash)
289 return hash->hash->name;
292 /* Returns hash OID string */
294 const char *silc_hash_get_oid(SilcHash hash)
296 return hash->hash->oid;
299 /* Returns TRUE if hash algorithm `name' is supported. */
301 SilcBool silc_hash_is_supported(const unsigned char *name)
304 SilcHashObject *entry;
306 if (silc_hash_list) {
307 silc_dlist_start(silc_hash_list);
308 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
309 if (!strcmp(entry->name, name))
316 for (i = 0; silc_default_hash[i].name; i++)
317 if (!strcmp(silc_default_hash[i].name, name))
320 #endif /* SILC_SYMBIAN */
324 /* Returns comma separated list of supported hash functions. */
326 char *silc_hash_get_supported(void)
328 SilcHashObject *entry;
333 if (silc_hash_list) {
334 silc_dlist_start(silc_hash_list);
335 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
336 len += strlen(entry->name);
337 list = silc_realloc(list, len + 1);
339 memcpy(list + (len - strlen(entry->name)),
340 entry->name, strlen(entry->name));
341 memcpy(list + len, ",", 1);
348 for (i = 0; silc_default_hash[i].name; i++) {
349 entry = (SilcHashObject *)&(silc_default_hash[i]);
350 len += strlen(entry->name);
351 list = silc_realloc(list, len + 1);
353 memcpy(list + (len - strlen(entry->name)),
354 entry->name, strlen(entry->name));
355 memcpy(list + len, ",", 1);
359 #endif /* SILC_SYMBIAN */
366 /* Creates the hash value and returns it to the return_hash argument. */
368 void silc_hash_make(SilcHash hash, const unsigned char *data,
369 SilcUInt32 len, unsigned char *return_hash)
371 silc_hash_init(hash);
372 silc_hash_update(hash, data, len);
373 silc_hash_final(hash, return_hash);
376 void silc_hash_init(SilcHash hash)
378 hash->hash->init(hash->context);
381 void silc_hash_update(SilcHash hash, const unsigned char *data,
384 hash->hash->update(hash->context, (unsigned char *)data, data_len);
387 void silc_hash_final(SilcHash hash, unsigned char *return_hash)
389 hash->hash->final(hash->context, return_hash);
392 void silc_hash_transform(SilcHash hash, SilcUInt32 *state,
393 const unsigned char *data)
395 hash->hash->transform(state, data);
398 /* Creates fingerprint of the data. If `hash' is NULL SHA1 is used as
399 default hash function. The returned fingerprint must be freed by the
402 char *silc_hash_fingerprint(SilcHash hash, const unsigned char *data,
405 SilcHash new_hash = NULL;
410 if (!silc_hash_alloc("sha1", &new_hash))
415 silc_hash_make(hash, data, data_len, h);
416 ret = silc_fingerprint(h, hash->hash->hash_len);
418 if (new_hash != NULL)
419 silc_hash_free(new_hash);
423 static const char vo[]= "aeiouy";
424 static const char co[]= "bcdfghklmnprstvzx";
426 /* Creates a babbleprint (Bubble Babble Encoding, developed by Antti
427 Huima (draft-huima-babble-01.txt)), by first computing real fingerprint
428 using `hash' or if NULL, then using SHA1, and then encoding the
429 fingerprint to the babbleprint. */
431 char *silc_hash_babbleprint(SilcHash hash, const unsigned char *data,
434 SilcHash new_hash = NULL;
436 unsigned char hval[32];
437 unsigned int a, b, c, d, e, check;
441 if (!silc_hash_alloc("sha1", &new_hash))
446 /* Take fingerprint */
447 silc_hash_make(hash, data, data_len, hval);
449 /* Encode babbleprint */
450 out_len = (((hash->hash->hash_len + 1) / 2) + 1) * 6;
451 babbleprint = silc_calloc(out_len, sizeof(*babbleprint));
453 silc_hash_free(new_hash);
456 babbleprint[0] = co[16];
459 for (i = 0, k = 1; i < hash->hash->hash_len - 1; i += 2, k += 6) {
460 a = (((hval[i] >> 6) & 3) + check) % 6;
461 b = (hval[i] >> 2) & 15;
462 c = ((hval[i] & 3) + (check / 6)) % 6;
463 d = (hval[i + 1] >> 4) & 15;
464 e = hval[i + 1] & 15;
466 check = ((check * 5) + (hval[i] * 7) + hval[i + 1]) % 36;
468 babbleprint[k + 0] = vo[a];
469 babbleprint[k + 1] = co[b];
470 babbleprint[k + 2] = vo[c];
471 babbleprint[k + 3] = co[d];
472 babbleprint[k + 4] = '-';
473 babbleprint[k + 5] = co[e];
476 if ((hash->hash->hash_len % 2) != 0) {
477 a = (((hval[i] >> 6) & 3) + check) % 6;
478 b = (hval[i] >> 2) & 15;
479 c = ((hval[i] & 3) + (check / 6)) % 6;
480 babbleprint[k + 0] = vo[a];
481 babbleprint[k + 1] = co[b];
482 babbleprint[k + 2] = vo[c];
487 babbleprint[k + 0] = vo[a];
488 babbleprint[k + 1] = co[b];
489 babbleprint[k + 2] = vo[c];
491 babbleprint[k + 3] = co[16];
493 if (new_hash != NULL)
494 silc_hash_free(new_hash);