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"
26 /* The main SILC hash structure. */
27 struct SilcHashStruct {
33 /* List of dynamically registered hash functions. */
34 SilcDList silc_hash_list = NULL;
35 #endif /* SILC_EPOC */
37 /* Default hash functions for silc_hash_register_default(). */
38 const SilcHashObject silc_default_hash[] =
40 { "sha1", 20, 64, silc_sha1_init, silc_sha1_update, silc_sha1_final,
41 silc_sha1_transform, silc_sha1_context_len },
42 { "md5", 16, 64, silc_md5_init, silc_md5_update, silc_md5_final,
43 silc_md5_transform, silc_md5_context_len },
45 { NULL, 0, 0, NULL, NULL, NULL, NULL, NULL }
48 /* Registers a new hash function into the SILC. This function is used at
49 the initialization of the SILC. */
51 bool silc_hash_register(const SilcHashObject *hash)
56 SILC_LOG_DEBUG(("Registering new hash function `%s'", hash->name));
58 /* Check for existing */
60 SilcHashObject *entry;
61 silc_dlist_start(silc_hash_list);
62 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
63 if (!strcmp(entry->name, hash->name))
68 new = silc_calloc(1, sizeof(*new));
69 new->name = strdup(hash->name);
70 new->hash_len = hash->hash_len;
71 new->block_len = hash->block_len;
72 new->init = hash->init;
73 new->update = hash->update;
74 new->final = hash->final;
75 new->transform = hash->transform;
76 new->context_len = hash->context_len;
79 if (silc_hash_list == NULL)
80 silc_hash_list = silc_dlist_init();
81 silc_dlist_add(silc_hash_list, new);
83 #endif /* SILC_EPOC */
87 /* Unregister a hash function from the SILC. */
89 bool silc_hash_unregister(SilcHashObject *hash)
92 SilcHashObject *entry;
94 SILC_LOG_DEBUG(("Unregistering hash function"));
99 silc_dlist_start(silc_hash_list);
100 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
101 if (hash == SILC_ALL_HASH_FUNCTIONS || entry == hash) {
102 silc_dlist_del(silc_hash_list, entry);
103 silc_free(entry->name);
106 if (silc_dlist_count(silc_hash_list) == 0) {
107 silc_dlist_uninit(silc_hash_list);
108 silc_hash_list = NULL;
115 #endif /* SILC_EPOC */
119 /* Function that registers all the default hash funcs (all builtin ones).
120 The application may use this to register the default hash funcs if
121 specific hash funcs in any specific order is not wanted. */
123 bool silc_hash_register_default(void)
128 for (i = 0; silc_default_hash[i].name; i++)
129 silc_hash_register(&(silc_default_hash[i]));
131 #endif /* SILC_EPOC */
135 bool silc_hash_unregister_all(void)
138 SilcHashObject *entry;
143 silc_dlist_start(silc_hash_list);
144 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
145 silc_hash_unregister(entry);
149 #endif /* SILC_EPOC */
153 /* Allocates a new SilcHash object. New object is returned into new_hash
156 bool silc_hash_alloc(const unsigned char *name, SilcHash *new_hash)
158 SilcHashObject *entry = NULL;
160 SILC_LOG_DEBUG(("Allocating new hash object"));
163 if (silc_hash_list) {
164 silc_dlist_start(silc_hash_list);
165 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
166 if (!strcmp(entry->name, name))
172 /* On EPOC which don't have globals we check our constant hash list. */
174 for (i = 0; silc_default_hash[i].name; i++) {
175 if (!strcmp(silc_default_hash[i].name, name)) {
176 entry = (SilcHashObject *)&(silc_default_hash[i]);
181 #endif /* SILC_EPOC */
184 *new_hash = silc_calloc(1, sizeof(**new_hash));
185 (*new_hash)->hash = entry;
186 (*new_hash)->context = silc_calloc(1, entry->context_len());
193 /* Free's the SilcHash object */
195 void silc_hash_free(SilcHash hash)
198 silc_free(hash->context);
203 /* Returns the length of the hash digest. */
205 SilcUInt32 silc_hash_len(SilcHash hash)
207 return hash->hash->hash_len;
210 /* Returns the block lenght of the hash. */
212 SilcUInt32 silc_hash_block_len(SilcHash hash)
214 return hash->hash->block_len;
217 /* Returns the name of the hash function */
219 const char *silc_hash_get_name(SilcHash hash)
221 return hash->hash->name;
224 /* Returns TRUE if hash algorithm `name' is supported. */
226 bool silc_hash_is_supported(const unsigned char *name)
229 SilcHashObject *entry;
231 if (silc_hash_list) {
232 silc_dlist_start(silc_hash_list);
233 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
234 if (!strcmp(entry->name, name))
241 for (i = 0; silc_default_hash[i].name; i++)
242 if (!strcmp(silc_default_hash[i].name, name))
245 #endif /* SILC_EPOC */
249 /* Returns comma separated list of supported hash functions. */
251 char *silc_hash_get_supported(void)
253 SilcHashObject *entry;
258 if (silc_hash_list) {
259 silc_dlist_start(silc_hash_list);
260 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
261 len += strlen(entry->name);
262 list = silc_realloc(list, len + 1);
264 memcpy(list + (len - strlen(entry->name)),
265 entry->name, strlen(entry->name));
266 memcpy(list + len, ",", 1);
273 for (i = 0; silc_default_hash[i].name; i++) {
274 entry = (SilcHashObject *)&(silc_default_hash[i]);
275 len += strlen(entry->name);
276 list = silc_realloc(list, len + 1);
278 memcpy(list + (len - strlen(entry->name)),
279 entry->name, strlen(entry->name));
280 memcpy(list + len, ",", 1);
284 #endif /* SILC_EPOC */
291 /* Creates the hash value and returns it to the return_hash argument. */
293 void silc_hash_make(SilcHash hash, const unsigned char *data,
294 SilcUInt32 len, unsigned char *return_hash)
296 silc_hash_init(hash);
297 silc_hash_update(hash, data, len);
298 silc_hash_final(hash, return_hash);
301 void silc_hash_init(SilcHash hash)
303 hash->hash->init(hash->context);
306 void silc_hash_update(SilcHash hash, const unsigned char *data,
309 hash->hash->update(hash->context, (unsigned char *)data, data_len);
312 void silc_hash_final(SilcHash hash, unsigned char *return_hash)
314 hash->hash->final(hash->context, return_hash);
317 void silc_hash_transform(SilcHash hash, SilcUInt32 *state,
318 const unsigned char *data)
320 hash->hash->transform(state, data);
323 /* Creates fingerprint of the data. If `hash' is NULL SHA1 is used as
324 default hash function. The returned fingerprint must be freed by the
327 char *silc_hash_fingerprint(SilcHash hash, const unsigned char *data,
330 SilcHash new_hash = NULL;
335 silc_hash_alloc("sha1", &new_hash);
339 silc_hash_make(hash, data, data_len, h);
340 ret = silc_fingerprint(h, hash->hash->hash_len);
342 if (new_hash != NULL)
343 silc_hash_free(new_hash);
347 static const char vo[]= "aeiouy";
348 static const char co[]= "bcdfghklmnprstvzx";
350 /* Creates a babbleprint (Bubble Babble Encoding, developed by Antti
351 Huima (draft-huima-babble-01.txt)), by first computing real fingerprint
352 using `hash' or if NULL, then using SHA1, and then encoding the
353 fingerprint to the babbleprint. */
355 char *silc_hash_babbleprint(SilcHash hash, const unsigned char *data,
358 SilcHash new_hash = NULL;
360 unsigned char hval[32];
361 unsigned int a, b, c, d, e, check;
365 silc_hash_alloc("sha1", &new_hash);
369 /* Take fingerprint */
370 silc_hash_make(hash, data, data_len, hval);
372 /* Encode babbleprint */
373 out_len = (((hash->hash->hash_len + 1) / 2) + 1) * 6;
374 babbleprint = silc_calloc(out_len, sizeof(*babbleprint));
375 babbleprint[0] = co[16];
378 for (i = 0, k = 1; i < hash->hash->hash_len - 1; i += 2, k += 6) {
379 a = (((hval[i] >> 6) & 3) + check) % 6;
380 b = (hval[i] >> 2) & 15;
381 c = ((hval[i] & 3) + (check / 6)) % 6;
382 d = (hval[i + 1] >> 4) & 15;
383 e = hval[i + 1] & 15;
385 check = ((check * 5) + (hval[i] * 7) + hval[i + 1]) % 36;
387 babbleprint[k + 0] = vo[a];
388 babbleprint[k + 1] = co[b];
389 babbleprint[k + 2] = vo[c];
390 babbleprint[k + 3] = co[d];
391 babbleprint[k + 4] = '-';
392 babbleprint[k + 5] = co[e];
395 if ((hash->hash->hash_len % 2) != 0) {
396 a = (((hval[i] >> 6) & 3) + check) % 6;
397 b = (hval[i] >> 2) & 15;
398 c = ((hval[i] & 3) + (check / 6)) % 6;
399 babbleprint[k + 0] = vo[a];
400 babbleprint[k + 1] = co[b];
401 babbleprint[k + 2] = vo[c];
406 babbleprint[k + 0] = vo[a];
407 babbleprint[k + 1] = co[b];
408 babbleprint[k + 2] = vo[c];
410 babbleprint[k + 3] = co[16];
412 if (new_hash != NULL)
413 silc_hash_free(new_hash);