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 */
367 /* Creates the hash value and returns it to the return_hash argument. */
369 void silc_hash_make(SilcHash hash, const unsigned char *data,
370 SilcUInt32 len, unsigned char *return_hash)
372 silc_hash_init(hash);
373 silc_hash_update(hash, data, len);
374 silc_hash_final(hash, return_hash);
377 void silc_hash_init(SilcHash hash)
379 hash->hash->init(hash->context);
382 void silc_hash_update(SilcHash hash, const unsigned char *data,
385 hash->hash->update(hash->context, (unsigned char *)data, data_len);
388 void silc_hash_final(SilcHash hash, unsigned char *return_hash)
390 hash->hash->final(hash->context, return_hash);
393 void silc_hash_transform(SilcHash hash, SilcUInt32 *state,
394 const unsigned char *data)
396 hash->hash->transform(state, data);
399 /* Creates fingerprint of the data. If `hash' is NULL SHA1 is used as
400 default hash function. The returned fingerprint must be freed by the
403 char *silc_hash_fingerprint(SilcHash hash, const unsigned char *data,
406 SilcHash new_hash = NULL;
411 if (!silc_hash_alloc("sha1", &new_hash))
416 silc_hash_make(hash, data, data_len, h);
417 ret = silc_fingerprint(h, hash->hash->hash_len);
419 if (new_hash != NULL)
420 silc_hash_free(new_hash);
424 static const char vo[]= "aeiouy";
425 static const char co[]= "bcdfghklmnprstvzx";
427 /* Creates a babbleprint (Bubble Babble Encoding, developed by Antti
428 Huima (draft-huima-babble-01.txt)), by first computing real fingerprint
429 using `hash' or if NULL, then using SHA1, and then encoding the
430 fingerprint to the babbleprint. */
432 char *silc_hash_babbleprint(SilcHash hash, const unsigned char *data,
435 SilcHash new_hash = NULL;
437 unsigned char hval[32];
438 unsigned int a, b, c, d, e, check;
442 if (!silc_hash_alloc("sha1", &new_hash))
447 /* Take fingerprint */
448 silc_hash_make(hash, data, data_len, hval);
450 /* Encode babbleprint */
451 out_len = (((hash->hash->hash_len + 1) / 2) + 1) * 6;
452 babbleprint = silc_calloc(out_len, sizeof(*babbleprint));
454 silc_hash_free(new_hash);
457 babbleprint[0] = co[16];
460 for (i = 0, k = 1; i < hash->hash->hash_len - 1; i += 2, k += 6) {
461 a = (((hval[i] >> 6) & 3) + check) % 6;
462 b = (hval[i] >> 2) & 15;
463 c = ((hval[i] & 3) + (check / 6)) % 6;
464 d = (hval[i + 1] >> 4) & 15;
465 e = hval[i + 1] & 15;
467 check = ((check * 5) + (hval[i] * 7) + hval[i + 1]) % 36;
469 babbleprint[k + 0] = vo[a];
470 babbleprint[k + 1] = co[b];
471 babbleprint[k + 2] = vo[c];
472 babbleprint[k + 3] = co[d];
473 babbleprint[k + 4] = '-';
474 babbleprint[k + 5] = co[e];
477 if ((hash->hash->hash_len % 2) != 0) {
478 a = (((hval[i] >> 6) & 3) + check) % 6;
479 b = (hval[i] >> 2) & 15;
480 c = ((hval[i] & 3) + (check / 6)) % 6;
481 babbleprint[k + 0] = vo[a];
482 babbleprint[k + 1] = co[b];
483 babbleprint[k + 2] = vo[c];
488 babbleprint[k + 0] = vo[a];
489 babbleprint[k + 1] = co[b];
490 babbleprint[k + 2] = vo[c];
492 babbleprint[k + 3] = co[16];
494 if (new_hash != NULL)
495 silc_hash_free(new_hash);