5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2002 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.
21 #include "silcincludes.h"
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_EPOC */
38 /* Default hash functions for silc_hash_register_default(). */
39 const SilcHashObject silc_default_hash[] =
41 { "sha256", 32, 64, silc_sha256_init, silc_sha256_update, silc_sha256_final,
42 silc_sha256_transform, silc_sha256_context_len },
43 { "sha1", 20, 64, silc_sha1_init, silc_sha1_update, silc_sha1_final,
44 silc_sha1_transform, silc_sha1_context_len },
45 { "md5", 16, 64, silc_md5_init, silc_md5_update, silc_md5_final,
46 silc_md5_transform, silc_md5_context_len },
48 { NULL, 0, 0, NULL, NULL, NULL, NULL, NULL }
51 /* Registers a new hash function into the SILC. This function is used at
52 the initialization of the SILC. */
54 SilcBool silc_hash_register(const SilcHashObject *hash)
59 SILC_LOG_DEBUG(("Registering new hash function `%s'", hash->name));
61 /* Check for existing */
63 SilcHashObject *entry;
64 silc_dlist_start(silc_hash_list);
65 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
66 if (!strcmp(entry->name, hash->name))
71 new = silc_calloc(1, sizeof(*new));
72 new->name = strdup(hash->name);
73 new->hash_len = hash->hash_len;
74 new->block_len = hash->block_len;
75 new->init = hash->init;
76 new->update = hash->update;
77 new->final = hash->final;
78 new->transform = hash->transform;
79 new->context_len = hash->context_len;
82 if (silc_hash_list == NULL)
83 silc_hash_list = silc_dlist_init();
84 silc_dlist_add(silc_hash_list, new);
86 #endif /* SILC_EPOC */
90 /* Unregister a hash function from the SILC. */
92 SilcBool silc_hash_unregister(SilcHashObject *hash)
95 SilcHashObject *entry;
97 SILC_LOG_DEBUG(("Unregistering hash function"));
102 silc_dlist_start(silc_hash_list);
103 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
104 if (hash == SILC_ALL_HASH_FUNCTIONS || entry == hash) {
105 silc_dlist_del(silc_hash_list, entry);
106 silc_free(entry->name);
109 if (silc_dlist_count(silc_hash_list) == 0) {
110 silc_dlist_uninit(silc_hash_list);
111 silc_hash_list = NULL;
118 #endif /* SILC_EPOC */
122 /* Function that registers all the default hash funcs (all builtin ones).
123 The application may use this to register the default hash funcs if
124 specific hash funcs in any specific order is not wanted. */
126 SilcBool silc_hash_register_default(void)
131 for (i = 0; silc_default_hash[i].name; i++)
132 silc_hash_register(&(silc_default_hash[i]));
134 #endif /* SILC_EPOC */
138 SilcBool silc_hash_unregister_all(void)
141 SilcHashObject *entry;
146 silc_dlist_start(silc_hash_list);
147 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
148 silc_hash_unregister(entry);
152 #endif /* SILC_EPOC */
156 /* Allocates a new SilcHash object. New object is returned into new_hash
159 SilcBool silc_hash_alloc(const unsigned char *name, SilcHash *new_hash)
161 SilcHashObject *entry = NULL;
163 SILC_LOG_DEBUG(("Allocating new hash object"));
166 if (silc_hash_list) {
167 silc_dlist_start(silc_hash_list);
168 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
169 if (!strcmp(entry->name, name))
175 /* On EPOC which don't have globals we check our constant hash list. */
177 for (i = 0; silc_default_hash[i].name; i++) {
178 if (!strcmp(silc_default_hash[i].name, name)) {
179 entry = (SilcHashObject *)&(silc_default_hash[i]);
184 #endif /* SILC_EPOC */
187 *new_hash = silc_calloc(1, sizeof(**new_hash));
188 (*new_hash)->hash = entry;
189 (*new_hash)->context = silc_calloc(1, entry->context_len());
196 /* Free's the SilcHash object */
198 void silc_hash_free(SilcHash hash)
201 silc_free(hash->context);
206 /* Returns the length of the hash digest. */
208 SilcUInt32 silc_hash_len(SilcHash hash)
210 return hash->hash->hash_len;
213 /* Returns the block lenght of the hash. */
215 SilcUInt32 silc_hash_block_len(SilcHash hash)
217 return hash->hash->block_len;
220 /* Returns the name of the hash function */
222 const char *silc_hash_get_name(SilcHash hash)
224 return hash->hash->name;
227 /* Returns TRUE if hash algorithm `name' is supported. */
229 SilcBool silc_hash_is_supported(const unsigned char *name)
232 SilcHashObject *entry;
234 if (silc_hash_list) {
235 silc_dlist_start(silc_hash_list);
236 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
237 if (!strcmp(entry->name, name))
244 for (i = 0; silc_default_hash[i].name; i++)
245 if (!strcmp(silc_default_hash[i].name, name))
248 #endif /* SILC_EPOC */
252 /* Returns comma separated list of supported hash functions. */
254 char *silc_hash_get_supported(void)
256 SilcHashObject *entry;
261 if (silc_hash_list) {
262 silc_dlist_start(silc_hash_list);
263 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
264 len += strlen(entry->name);
265 list = silc_realloc(list, len + 1);
267 memcpy(list + (len - strlen(entry->name)),
268 entry->name, strlen(entry->name));
269 memcpy(list + len, ",", 1);
276 for (i = 0; silc_default_hash[i].name; i++) {
277 entry = (SilcHashObject *)&(silc_default_hash[i]);
278 len += strlen(entry->name);
279 list = silc_realloc(list, len + 1);
281 memcpy(list + (len - strlen(entry->name)),
282 entry->name, strlen(entry->name));
283 memcpy(list + len, ",", 1);
287 #endif /* SILC_EPOC */
294 /* Creates the hash value and returns it to the return_hash argument. */
296 void silc_hash_make(SilcHash hash, const unsigned char *data,
297 SilcUInt32 len, unsigned char *return_hash)
299 silc_hash_init(hash);
300 silc_hash_update(hash, data, len);
301 silc_hash_final(hash, return_hash);
304 void silc_hash_init(SilcHash hash)
306 hash->hash->init(hash->context);
309 void silc_hash_update(SilcHash hash, const unsigned char *data,
312 hash->hash->update(hash->context, (unsigned char *)data, data_len);
315 void silc_hash_final(SilcHash hash, unsigned char *return_hash)
317 hash->hash->final(hash->context, return_hash);
320 void silc_hash_transform(SilcHash hash, SilcUInt32 *state,
321 const unsigned char *data)
323 hash->hash->transform(state, data);
326 /* Creates fingerprint of the data. If `hash' is NULL SHA1 is used as
327 default hash function. The returned fingerprint must be freed by the
330 char *silc_hash_fingerprint(SilcHash hash, const unsigned char *data,
333 SilcHash new_hash = NULL;
338 silc_hash_alloc("sha1", &new_hash);
342 silc_hash_make(hash, data, data_len, h);
343 ret = silc_fingerprint(h, hash->hash->hash_len);
345 if (new_hash != NULL)
346 silc_hash_free(new_hash);
350 static const char vo[]= "aeiouy";
351 static const char co[]= "bcdfghklmnprstvzx";
353 /* Creates a babbleprint (Bubble Babble Encoding, developed by Antti
354 Huima (draft-huima-babble-01.txt)), by first computing real fingerprint
355 using `hash' or if NULL, then using SHA1, and then encoding the
356 fingerprint to the babbleprint. */
358 char *silc_hash_babbleprint(SilcHash hash, const unsigned char *data,
361 SilcHash new_hash = NULL;
363 unsigned char hval[32];
364 unsigned int a, b, c, d, e, check;
368 silc_hash_alloc("sha1", &new_hash);
372 /* Take fingerprint */
373 silc_hash_make(hash, data, data_len, hval);
375 /* Encode babbleprint */
376 out_len = (((hash->hash->hash_len + 1) / 2) + 1) * 6;
377 babbleprint = silc_calloc(out_len, sizeof(*babbleprint));
378 babbleprint[0] = co[16];
381 for (i = 0, k = 1; i < hash->hash->hash_len - 1; i += 2, k += 6) {
382 a = (((hval[i] >> 6) & 3) + check) % 6;
383 b = (hval[i] >> 2) & 15;
384 c = ((hval[i] & 3) + (check / 6)) % 6;
385 d = (hval[i + 1] >> 4) & 15;
386 e = hval[i + 1] & 15;
388 check = ((check * 5) + (hval[i] * 7) + hval[i + 1]) % 36;
390 babbleprint[k + 0] = vo[a];
391 babbleprint[k + 1] = co[b];
392 babbleprint[k + 2] = vo[c];
393 babbleprint[k + 3] = co[d];
394 babbleprint[k + 4] = '-';
395 babbleprint[k + 5] = co[e];
398 if ((hash->hash->hash_len % 2) != 0) {
399 a = (((hval[i] >> 6) & 3) + check) % 6;
400 b = (hval[i] >> 2) & 15;
401 c = ((hval[i] & 3) + (check / 6)) % 6;
402 babbleprint[k + 0] = vo[a];
403 babbleprint[k + 1] = co[b];
404 babbleprint[k + 2] = vo[c];
409 babbleprint[k + 0] = vo[a];
410 babbleprint[k + 1] = co[b];
411 babbleprint[k + 2] = vo[c];
413 babbleprint[k + 3] = co[16];
415 if (new_hash != NULL)
416 silc_hash_free(new_hash);