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.
28 /* The main SILC hash structure. */
29 struct SilcHashStruct {
35 /* List of dynamically registered hash functions. */
36 SilcDList silc_hash_list = NULL;
37 #endif /* SILC_SYMBIAN */
39 /* Default hash functions for silc_hash_register_default(). */
40 const SilcHashObject silc_default_hash[] =
42 { "sha256", "2.16.840.1.101.3.4.2.1",
43 32, 64, silc_sha256_init, silc_sha256_update, silc_sha256_final,
44 silc_sha256_transform, silc_sha256_context_len },
45 { "sha512", "2.16.840.1.101.3.4.2.3",
46 32, 64, silc_sha512_init, silc_sha512_update, silc_sha512_final,
47 silc_sha512_transform, silc_sha512_context_len },
48 { "sha1", "1.3.14.3.2.26",
49 20, 64, silc_sha1_init, silc_sha1_update, silc_sha1_final,
50 silc_sha1_transform, silc_sha1_context_len },
51 { "md5", "1.2.840.113549.2.5",
52 16, 64, silc_md5_init, silc_md5_update, silc_md5_final,
53 silc_md5_transform, silc_md5_context_len },
55 { NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL }
58 /* Registers a new hash function */
60 SilcBool silc_hash_register(const SilcHashObject *hash)
65 SILC_LOG_DEBUG(("Registering new hash function `%s'", hash->name));
67 /* Check for existing */
69 SilcHashObject *entry;
70 silc_dlist_start(silc_hash_list);
71 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
72 if (!strcmp(entry->name, hash->name))
77 new = silc_calloc(1, sizeof(*new));
80 new->name = strdup(hash->name);
85 new->oid = strdup(hash->oid);
90 new->hash_len = hash->hash_len;
91 new->block_len = hash->block_len;
92 new->init = hash->init;
93 new->update = hash->update;
94 new->final = hash->final;
95 new->transform = hash->transform;
96 new->context_len = hash->context_len;
99 if (silc_hash_list == NULL)
100 silc_hash_list = silc_dlist_init();
101 silc_dlist_add(silc_hash_list, new);
103 #endif /* SILC_SYMBIAN */
107 /* Unregister a hash function */
109 SilcBool silc_hash_unregister(SilcHashObject *hash)
112 SilcHashObject *entry;
114 SILC_LOG_DEBUG(("Unregistering hash function"));
119 silc_dlist_start(silc_hash_list);
120 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
121 if (hash == SILC_ALL_HASH_FUNCTIONS || entry == hash) {
122 silc_dlist_del(silc_hash_list, entry);
123 silc_free(entry->name);
124 silc_free(entry->oid);
127 if (silc_dlist_count(silc_hash_list) == 0) {
128 silc_dlist_uninit(silc_hash_list);
129 silc_hash_list = NULL;
136 #endif /* SILC_SYMBIAN */
140 /* Register default hash functions */
142 SilcBool silc_hash_register_default(void)
144 /* We use builtin hash functions */
148 /* Unregister all hash functions */
150 SilcBool silc_hash_unregister_all(void)
153 SilcHashObject *entry;
158 silc_dlist_start(silc_hash_list);
159 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
160 silc_hash_unregister(entry);
164 #endif /* SILC_SYMBIAN */
168 /* Allocates a new SilcHash object. New object is returned into new_hash
171 SilcBool silc_hash_alloc(const char *name, SilcHash *new_hash)
173 SilcHashObject *entry = NULL;
176 SILC_LOG_DEBUG(("Allocating new hash %s", name));
179 /* Check list of registered hash functions */
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))
187 #endif /* SILC_SYMBIAN */
190 /* Check builtin hash function 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]);
200 *new_hash = silc_calloc(1, sizeof(**new_hash));
203 (*new_hash)->hash = entry;
204 (*new_hash)->context = silc_calloc(1, entry->context_len());
205 if (!(*new_hash)->context) {
206 silc_free(*new_hash);
215 /* Allocate hash by OID string */
217 SilcBool silc_hash_alloc_by_oid(const char *oid, SilcHash *new_hash)
219 SilcHashObject *entry = NULL;
222 SILC_LOG_DEBUG(("Allocating new hash %s", oid));
225 /* Check list of registered hash functions */
226 if (silc_hash_list) {
227 silc_dlist_start(silc_hash_list);
228 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
229 if (!strcmp(entry->oid, oid))
233 #endif /* SILC_SYMBIAN */
236 /* Check builtin hash function list */
237 for (i = 0; silc_default_hash[i].oid; i++) {
238 if (!strcmp(silc_default_hash[i].oid, oid)) {
239 entry = (SilcHashObject *)&(silc_default_hash[i]);
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 char *name)
303 SilcHashObject *entry;
307 if (silc_hash_list) {
308 silc_dlist_start(silc_hash_list);
309 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
310 if (!strcmp(entry->name, name))
314 #endif /* SILC_SYMBIAN */
316 for (i = 0; silc_default_hash[i].name; i++)
317 if (!strcmp(silc_default_hash[i].name, name))
323 /* Returns comma separated list of supported hash functions. */
325 char *silc_hash_get_supported(void)
327 SilcHashObject *entry, *entry2;
332 if (silc_hash_list) {
333 silc_dlist_start(silc_hash_list);
334 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
335 len += strlen(entry->name);
336 list = silc_realloc(list, len + 1);
338 memcpy(list + (len - strlen(entry->name)),
339 entry->name, strlen(entry->name));
340 memcpy(list + len, ",", 1);
344 #endif /* SILC_SYMBIAN */
346 for (i = 0; silc_default_hash[i].name; i++) {
347 entry = (SilcHashObject *)&(silc_default_hash[i]);
349 if (silc_hash_list) {
350 silc_dlist_start(silc_hash_list);
351 while ((entry2 = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
352 if (!strcmp(entry2->name, entry->name))
359 len += strlen(entry->name);
360 list = silc_realloc(list, len + 1);
362 memcpy(list + (len - strlen(entry->name)),
363 entry->name, strlen(entry->name));
364 memcpy(list + len, ",", 1);
373 /* Creates the hash value and returns it to the return_hash argument. */
375 void silc_hash_make(SilcHash hash, const unsigned char *data,
376 SilcUInt32 len, unsigned char *return_hash)
378 silc_hash_init(hash);
379 silc_hash_update(hash, data, len);
380 silc_hash_final(hash, return_hash);
383 void silc_hash_init(SilcHash hash)
385 hash->hash->init(hash->context);
388 void silc_hash_update(SilcHash hash, const unsigned char *data,
391 hash->hash->update(hash->context, (unsigned char *)data, data_len);
394 void silc_hash_final(SilcHash hash, unsigned char *return_hash)
396 hash->hash->final(hash->context, return_hash);
399 void silc_hash_transform(SilcHash hash, void *state,
400 const unsigned char *data)
402 hash->hash->transform(state, data);
405 /* Creates fingerprint of the data. If `hash' is NULL SHA1 is used as
406 default hash function. The returned fingerprint must be freed by the
409 char *silc_hash_fingerprint(SilcHash hash, const unsigned char *data,
412 SilcHash new_hash = NULL;
417 if (!silc_hash_alloc("sha1", &new_hash))
422 silc_hash_make(hash, data, data_len, h);
423 ret = silc_fingerprint(h, hash->hash->hash_len);
425 if (new_hash != NULL)
426 silc_hash_free(new_hash);
430 static const char vo[]= "aeiouy";
431 static const char co[]= "bcdfghklmnprstvzx";
433 /* Creates a babbleprint (Bubble Babble Encoding, developed by Antti
434 Huima (draft-huima-babble-01.txt)), by first computing real fingerprint
435 using `hash' or if NULL, then using SHA1, and then encoding the
436 fingerprint to the babbleprint. */
438 char *silc_hash_babbleprint(SilcHash hash, const unsigned char *data,
441 SilcHash new_hash = NULL;
443 unsigned char hval[32];
444 unsigned int a, b, c, d, e, check;
448 if (!silc_hash_alloc("sha1", &new_hash))
453 /* Take fingerprint */
454 silc_hash_make(hash, data, data_len, hval);
456 /* Encode babbleprint */
457 out_len = (((hash->hash->hash_len + 1) / 2) + 1) * 6;
458 babbleprint = silc_calloc(out_len, sizeof(*babbleprint));
460 silc_hash_free(new_hash);
463 babbleprint[0] = co[16];
466 for (i = 0, k = 1; i < hash->hash->hash_len - 1; i += 2, k += 6) {
467 a = (((hval[i] >> 6) & 3) + check) % 6;
468 b = (hval[i] >> 2) & 15;
469 c = ((hval[i] & 3) + (check / 6)) % 6;
470 d = (hval[i + 1] >> 4) & 15;
471 e = hval[i + 1] & 15;
473 check = ((check * 5) + (hval[i] * 7) + hval[i + 1]) % 36;
475 babbleprint[k + 0] = vo[a];
476 babbleprint[k + 1] = co[b];
477 babbleprint[k + 2] = vo[c];
478 babbleprint[k + 3] = co[d];
479 babbleprint[k + 4] = '-';
480 babbleprint[k + 5] = co[e];
483 if ((hash->hash->hash_len % 2) != 0) {
484 a = (((hval[i] >> 6) & 3) + check) % 6;
485 b = (hval[i] >> 2) & 15;
486 c = ((hval[i] & 3) + (check / 6)) % 6;
487 babbleprint[k + 0] = vo[a];
488 babbleprint[k + 1] = co[b];
489 babbleprint[k + 2] = vo[c];
494 babbleprint[k + 0] = vo[a];
495 babbleprint[k + 1] = co[b];
496 babbleprint[k + 2] = vo[c];
498 babbleprint[k + 3] = co[16];
500 if (new_hash != NULL)
501 silc_hash_free(new_hash);