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);
121 silc_free(entry->oid);
124 if (silc_dlist_count(silc_hash_list) == 0) {
125 silc_dlist_uninit(silc_hash_list);
126 silc_hash_list = NULL;
133 #endif /* SILC_SYMBIAN */
137 /* Function that registers all the default hash funcs (all builtin ones).
138 The application may use this to register the default hash funcs if
139 specific hash funcs in any specific order is not wanted. */
141 SilcBool silc_hash_register_default(void)
146 for (i = 0; silc_default_hash[i].name; i++)
147 silc_hash_register(&(silc_default_hash[i]));
149 #endif /* SILC_SYMBIAN */
153 SilcBool silc_hash_unregister_all(void)
156 SilcHashObject *entry;
161 silc_dlist_start(silc_hash_list);
162 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
163 silc_hash_unregister(entry);
167 #endif /* SILC_SYMBIAN */
171 /* Allocates a new SilcHash object. New object is returned into new_hash
174 SilcBool silc_hash_alloc(const unsigned char *name, SilcHash *new_hash)
176 SilcHashObject *entry = NULL;
178 SILC_LOG_DEBUG(("Allocating new hash %s", name));
181 if (silc_hash_list) {
182 silc_dlist_start(silc_hash_list);
183 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
184 if (!strcmp(entry->name, name))
190 /* On EPOC which don't have globals we check our constant hash list. */
192 for (i = 0; silc_default_hash[i].name; i++) {
193 if (!strcmp(silc_default_hash[i].name, name)) {
194 entry = (SilcHashObject *)&(silc_default_hash[i]);
199 #endif /* SILC_SYMBIAN */
202 *new_hash = silc_calloc(1, sizeof(**new_hash));
205 (*new_hash)->hash = entry;
206 (*new_hash)->context = silc_calloc(1, entry->context_len());
207 if (!(*new_hash)->context) {
208 silc_free(*new_hash);
217 /* Allocate hash by OID string */
219 SilcBool silc_hash_alloc_by_oid(const char *oid, SilcHash *new_hash)
221 SilcHashObject *entry = NULL;
223 SILC_LOG_DEBUG(("Allocating new hash %s", oid));
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))
235 /* On EPOC which don't have globals we check our constant hash 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]);
244 #endif /* SILC_SYMBIAN */
247 *new_hash = silc_calloc(1, sizeof(**new_hash));
250 (*new_hash)->hash = entry;
251 (*new_hash)->context = silc_calloc(1, entry->context_len());
252 if (!(*new_hash)->context) {
253 silc_free(*new_hash);
262 /* Free's the SilcHash object */
264 void silc_hash_free(SilcHash hash)
267 silc_free(hash->context);
272 /* Returns the length of the hash digest. */
274 SilcUInt32 silc_hash_len(SilcHash hash)
276 return hash->hash->hash_len;
279 /* Returns the block lenght of the hash. */
281 SilcUInt32 silc_hash_block_len(SilcHash hash)
283 return hash->hash->block_len;
286 /* Returns the name of the hash function */
288 const char *silc_hash_get_name(SilcHash hash)
290 return hash->hash->name;
293 /* Returns hash OID string */
295 const char *silc_hash_get_oid(SilcHash hash)
297 return hash->hash->oid;
300 /* Returns TRUE if hash algorithm `name' is supported. */
302 SilcBool silc_hash_is_supported(const unsigned char *name)
305 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))
317 for (i = 0; silc_default_hash[i].name; i++)
318 if (!strcmp(silc_default_hash[i].name, name))
321 #endif /* SILC_SYMBIAN */
325 /* Returns comma separated list of supported hash functions. */
327 char *silc_hash_get_supported(void)
329 SilcHashObject *entry;
334 if (silc_hash_list) {
335 silc_dlist_start(silc_hash_list);
336 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
337 len += strlen(entry->name);
338 list = silc_realloc(list, len + 1);
340 memcpy(list + (len - strlen(entry->name)),
341 entry->name, strlen(entry->name));
342 memcpy(list + len, ",", 1);
349 for (i = 0; silc_default_hash[i].name; i++) {
350 entry = (SilcHashObject *)&(silc_default_hash[i]);
351 len += strlen(entry->name);
352 list = silc_realloc(list, len + 1);
354 memcpy(list + (len - strlen(entry->name)),
355 entry->name, strlen(entry->name));
356 memcpy(list + len, ",", 1);
360 #endif /* SILC_SYMBIAN */
368 /* Creates the hash value and returns it to the return_hash argument. */
370 void silc_hash_make(SilcHash hash, const unsigned char *data,
371 SilcUInt32 len, unsigned char *return_hash)
373 silc_hash_init(hash);
374 silc_hash_update(hash, data, len);
375 silc_hash_final(hash, return_hash);
378 void silc_hash_init(SilcHash hash)
380 hash->hash->init(hash->context);
383 void silc_hash_update(SilcHash hash, const unsigned char *data,
386 hash->hash->update(hash->context, (unsigned char *)data, data_len);
389 void silc_hash_final(SilcHash hash, unsigned char *return_hash)
391 hash->hash->final(hash->context, return_hash);
394 void silc_hash_transform(SilcHash hash, SilcUInt32 *state,
395 const unsigned char *data)
397 hash->hash->transform(state, data);
400 /* Creates fingerprint of the data. If `hash' is NULL SHA1 is used as
401 default hash function. The returned fingerprint must be freed by the
404 char *silc_hash_fingerprint(SilcHash hash, const unsigned char *data,
407 SilcHash new_hash = NULL;
412 if (!silc_hash_alloc("sha1", &new_hash))
417 silc_hash_make(hash, data, data_len, h);
418 ret = silc_fingerprint(h, hash->hash->hash_len);
420 if (new_hash != NULL)
421 silc_hash_free(new_hash);
425 static const char vo[]= "aeiouy";
426 static const char co[]= "bcdfghklmnprstvzx";
428 /* Creates a babbleprint (Bubble Babble Encoding, developed by Antti
429 Huima (draft-huima-babble-01.txt)), by first computing real fingerprint
430 using `hash' or if NULL, then using SHA1, and then encoding the
431 fingerprint to the babbleprint. */
433 char *silc_hash_babbleprint(SilcHash hash, const unsigned char *data,
436 SilcHash new_hash = NULL;
438 unsigned char hval[32];
439 unsigned int a, b, c, d, e, check;
443 if (!silc_hash_alloc("sha1", &new_hash))
448 /* Take fingerprint */
449 silc_hash_make(hash, data, data_len, hval);
451 /* Encode babbleprint */
452 out_len = (((hash->hash->hash_len + 1) / 2) + 1) * 6;
453 babbleprint = silc_calloc(out_len, sizeof(*babbleprint));
455 silc_hash_free(new_hash);
458 babbleprint[0] = co[16];
461 for (i = 0, k = 1; i < hash->hash->hash_len - 1; i += 2, k += 6) {
462 a = (((hval[i] >> 6) & 3) + check) % 6;
463 b = (hval[i] >> 2) & 15;
464 c = ((hval[i] & 3) + (check / 6)) % 6;
465 d = (hval[i + 1] >> 4) & 15;
466 e = hval[i + 1] & 15;
468 check = ((check * 5) + (hval[i] * 7) + hval[i + 1]) % 36;
470 babbleprint[k + 0] = vo[a];
471 babbleprint[k + 1] = co[b];
472 babbleprint[k + 2] = vo[c];
473 babbleprint[k + 3] = co[d];
474 babbleprint[k + 4] = '-';
475 babbleprint[k + 5] = co[e];
478 if ((hash->hash->hash_len % 2) != 0) {
479 a = (((hval[i] >> 6) & 3) + check) % 6;
480 b = (hval[i] >> 2) & 15;
481 c = ((hval[i] & 3) + (check / 6)) % 6;
482 babbleprint[k + 0] = vo[a];
483 babbleprint[k + 1] = co[b];
484 babbleprint[k + 2] = vo[c];
489 babbleprint[k + 0] = vo[a];
490 babbleprint[k + 1] = co[b];
491 babbleprint[k + 2] = vo[c];
493 babbleprint[k + 3] = co[16];
495 if (new_hash != NULL)
496 silc_hash_free(new_hash);