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 */
56 SilcBool silc_hash_register(const SilcHashObject *hash)
61 SILC_LOG_DEBUG(("Registering new hash function `%s'", hash->name));
63 /* Check for existing */
65 SilcHashObject *entry;
66 silc_dlist_start(silc_hash_list);
67 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
68 if (!strcmp(entry->name, hash->name))
73 new = silc_calloc(1, sizeof(*new));
76 new->name = strdup(hash->name);
81 new->oid = strdup(hash->oid);
86 new->hash_len = hash->hash_len;
87 new->block_len = hash->block_len;
88 new->init = hash->init;
89 new->update = hash->update;
90 new->final = hash->final;
91 new->transform = hash->transform;
92 new->context_len = hash->context_len;
95 if (silc_hash_list == NULL)
96 silc_hash_list = silc_dlist_init();
97 silc_dlist_add(silc_hash_list, new);
99 #endif /* SILC_SYMBIAN */
103 /* Unregister a hash function */
105 SilcBool silc_hash_unregister(SilcHashObject *hash)
108 SilcHashObject *entry;
110 SILC_LOG_DEBUG(("Unregistering hash function"));
115 silc_dlist_start(silc_hash_list);
116 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
117 if (hash == SILC_ALL_HASH_FUNCTIONS || entry == hash) {
118 silc_dlist_del(silc_hash_list, entry);
119 silc_free(entry->name);
120 silc_free(entry->oid);
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 /* Register default hash functions */
138 SilcBool silc_hash_register_default(void)
140 /* We use builtin hash functions */
144 /* Unregister all hash functions */
146 SilcBool silc_hash_unregister_all(void)
149 SilcHashObject *entry;
154 silc_dlist_start(silc_hash_list);
155 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
156 silc_hash_unregister(entry);
160 #endif /* SILC_SYMBIAN */
164 /* Allocates a new SilcHash object. New object is returned into new_hash
167 SilcBool silc_hash_alloc(const char *name, SilcHash *new_hash)
169 SilcHashObject *entry = NULL;
172 SILC_LOG_DEBUG(("Allocating new hash %s", name));
175 /* Check list of registered hash functions */
176 if (silc_hash_list) {
177 silc_dlist_start(silc_hash_list);
178 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
179 if (!strcmp(entry->name, name))
183 #endif /* SILC_SYMBIAN */
186 /* Check builtin hash function list */
187 for (i = 0; silc_default_hash[i].name; i++) {
188 if (!strcmp(silc_default_hash[i].name, name)) {
189 entry = (SilcHashObject *)&(silc_default_hash[i]);
196 *new_hash = silc_calloc(1, sizeof(**new_hash));
199 (*new_hash)->hash = entry;
200 (*new_hash)->context = silc_calloc(1, entry->context_len());
201 if (!(*new_hash)->context) {
202 silc_free(*new_hash);
211 /* Allocate hash by OID string */
213 SilcBool silc_hash_alloc_by_oid(const char *oid, SilcHash *new_hash)
215 SilcHashObject *entry = NULL;
218 SILC_LOG_DEBUG(("Allocating new hash %s", oid));
221 /* Check list of registered hash functions */
222 if (silc_hash_list) {
223 silc_dlist_start(silc_hash_list);
224 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
225 if (!strcmp(entry->oid, oid))
229 #endif /* SILC_SYMBIAN */
232 /* Check builtin hash function list */
233 for (i = 0; silc_default_hash[i].oid; i++) {
234 if (!strcmp(silc_default_hash[i].oid, oid)) {
235 entry = (SilcHashObject *)&(silc_default_hash[i]);
242 *new_hash = silc_calloc(1, sizeof(**new_hash));
245 (*new_hash)->hash = entry;
246 (*new_hash)->context = silc_calloc(1, entry->context_len());
247 if (!(*new_hash)->context) {
248 silc_free(*new_hash);
257 /* Free's the SilcHash object */
259 void silc_hash_free(SilcHash hash)
262 silc_free(hash->context);
267 /* Returns the length of the hash digest. */
269 SilcUInt32 silc_hash_len(SilcHash hash)
271 return hash->hash->hash_len;
274 /* Returns the block lenght of the hash. */
276 SilcUInt32 silc_hash_block_len(SilcHash hash)
278 return hash->hash->block_len;
281 /* Returns the name of the hash function */
283 const char *silc_hash_get_name(SilcHash hash)
285 return hash->hash->name;
288 /* Returns hash OID string */
290 const char *silc_hash_get_oid(SilcHash hash)
292 return hash->hash->oid;
295 /* Returns TRUE if hash algorithm `name' is supported. */
297 SilcBool silc_hash_is_supported(const char *name)
299 SilcHashObject *entry;
303 if (silc_hash_list) {
304 silc_dlist_start(silc_hash_list);
305 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
306 if (!strcmp(entry->name, name))
310 #endif /* SILC_SYMBIAN */
312 for (i = 0; silc_default_hash[i].name; i++)
313 if (!strcmp(silc_default_hash[i].name, name))
319 /* Returns comma separated list of supported hash functions. */
321 char *silc_hash_get_supported(void)
323 SilcHashObject *entry, *entry2;
328 if (silc_hash_list) {
329 silc_dlist_start(silc_hash_list);
330 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
331 len += strlen(entry->name);
332 list = silc_realloc(list, len + 1);
334 memcpy(list + (len - strlen(entry->name)),
335 entry->name, strlen(entry->name));
336 memcpy(list + len, ",", 1);
340 #endif /* SILC_SYMBIAN */
342 for (i = 0; silc_default_hash[i].name; i++) {
343 entry = (SilcHashObject *)&(silc_default_hash[i]);
345 if (silc_hash_list) {
346 silc_dlist_start(silc_hash_list);
347 while ((entry2 = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
348 if (!strcmp(entry2->name, entry->name))
355 len += strlen(entry->name);
356 list = silc_realloc(list, len + 1);
358 memcpy(list + (len - strlen(entry->name)),
359 entry->name, strlen(entry->name));
360 memcpy(list + len, ",", 1);
369 /* Creates the hash value and returns it to the return_hash argument. */
371 void silc_hash_make(SilcHash hash, const unsigned char *data,
372 SilcUInt32 len, unsigned char *return_hash)
374 silc_hash_init(hash);
375 silc_hash_update(hash, data, len);
376 silc_hash_final(hash, return_hash);
379 void silc_hash_init(SilcHash hash)
381 hash->hash->init(hash->context);
384 void silc_hash_update(SilcHash hash, const unsigned char *data,
387 hash->hash->update(hash->context, (unsigned char *)data, data_len);
390 void silc_hash_final(SilcHash hash, unsigned char *return_hash)
392 hash->hash->final(hash->context, return_hash);
395 void silc_hash_transform(SilcHash hash, SilcUInt32 *state,
396 const unsigned char *data)
398 hash->hash->transform(state, data);
401 /* Creates fingerprint of the data. If `hash' is NULL SHA1 is used as
402 default hash function. The returned fingerprint must be freed by the
405 char *silc_hash_fingerprint(SilcHash hash, const unsigned char *data,
408 SilcHash new_hash = NULL;
413 if (!silc_hash_alloc("sha1", &new_hash))
418 silc_hash_make(hash, data, data_len, h);
419 ret = silc_fingerprint(h, hash->hash->hash_len);
421 if (new_hash != NULL)
422 silc_hash_free(new_hash);
426 static const char vo[]= "aeiouy";
427 static const char co[]= "bcdfghklmnprstvzx";
429 /* Creates a babbleprint (Bubble Babble Encoding, developed by Antti
430 Huima (draft-huima-babble-01.txt)), by first computing real fingerprint
431 using `hash' or if NULL, then using SHA1, and then encoding the
432 fingerprint to the babbleprint. */
434 char *silc_hash_babbleprint(SilcHash hash, const unsigned char *data,
437 SilcHash new_hash = NULL;
439 unsigned char hval[32];
440 unsigned int a, b, c, d, e, check;
444 if (!silc_hash_alloc("sha1", &new_hash))
449 /* Take fingerprint */
450 silc_hash_make(hash, data, data_len, hval);
452 /* Encode babbleprint */
453 out_len = (((hash->hash->hash_len + 1) / 2) + 1) * 6;
454 babbleprint = silc_calloc(out_len, sizeof(*babbleprint));
456 silc_hash_free(new_hash);
459 babbleprint[0] = co[16];
462 for (i = 0, k = 1; i < hash->hash->hash_len - 1; i += 2, k += 6) {
463 a = (((hval[i] >> 6) & 3) + check) % 6;
464 b = (hval[i] >> 2) & 15;
465 c = ((hval[i] & 3) + (check / 6)) % 6;
466 d = (hval[i + 1] >> 4) & 15;
467 e = hval[i + 1] & 15;
469 check = ((check * 5) + (hval[i] * 7) + hval[i + 1]) % 36;
471 babbleprint[k + 0] = vo[a];
472 babbleprint[k + 1] = co[b];
473 babbleprint[k + 2] = vo[c];
474 babbleprint[k + 3] = co[d];
475 babbleprint[k + 4] = '-';
476 babbleprint[k + 5] = co[e];
479 if ((hash->hash->hash_len % 2) != 0) {
480 a = (((hval[i] >> 6) & 3) + check) % 6;
481 b = (hval[i] >> 2) & 15;
482 c = ((hval[i] & 3) + (check / 6)) % 6;
483 babbleprint[k + 0] = vo[a];
484 babbleprint[k + 1] = co[b];
485 babbleprint[k + 2] = vo[c];
490 babbleprint[k + 0] = vo[a];
491 babbleprint[k + 1] = co[b];
492 babbleprint[k + 2] = vo[c];
494 babbleprint[k + 3] = co[16];
496 if (new_hash != NULL)
497 silc_hash_free(new_hash);