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);
104 if (silc_dlist_count(silc_hash_list) == 0) {
105 silc_dlist_uninit(silc_hash_list);
106 silc_hash_list = NULL;
113 #endif /* SILC_EPOC */
117 /* Function that registers all the default hash funcs (all builtin ones).
118 The application may use this to register the default hash funcs if
119 specific hash funcs in any specific order is not wanted. */
121 bool silc_hash_register_default(void)
126 for (i = 0; silc_default_hash[i].name; i++)
127 silc_hash_register(&(silc_default_hash[i]));
129 #endif /* SILC_EPOC */
133 /* Allocates a new SilcHash object. New object is returned into new_hash
136 bool silc_hash_alloc(const unsigned char *name, SilcHash *new_hash)
138 SilcHashObject *entry = NULL;
140 SILC_LOG_DEBUG(("Allocating new hash object"));
143 if (silc_hash_list) {
144 silc_dlist_start(silc_hash_list);
145 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
146 if (!strcmp(entry->name, name))
152 /* On EPOC which don't have globals we check our constant hash list. */
154 for (i = 0; silc_default_hash[i].name; i++) {
155 if (!strcmp(silc_default_hash[i].name, name)) {
156 entry = (SilcHashObject *)&(silc_default_hash[i]);
161 #endif /* SILC_EPOC */
164 *new_hash = silc_calloc(1, sizeof(**new_hash));
165 (*new_hash)->hash = entry;
166 (*new_hash)->context = silc_calloc(1, entry->context_len());
173 /* Free's the SilcHash object */
175 void silc_hash_free(SilcHash hash)
178 silc_free(hash->context);
183 /* Returns the length of the hash digest. */
185 SilcUInt32 silc_hash_len(SilcHash hash)
187 return hash->hash->hash_len;
190 /* Returns the block lenght of the hash. */
192 SilcUInt32 silc_hash_block_len(SilcHash hash)
194 return hash->hash->block_len;
197 /* Returns the name of the hash function */
199 const char *silc_hash_get_name(SilcHash hash)
201 return hash->hash->name;
204 /* Returns TRUE if hash algorithm `name' is supported. */
206 bool silc_hash_is_supported(const unsigned char *name)
209 SilcHashObject *entry;
211 if (silc_hash_list) {
212 silc_dlist_start(silc_hash_list);
213 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
214 if (!strcmp(entry->name, name))
221 for (i = 0; silc_default_hash[i].name; i++)
222 if (!strcmp(silc_default_hash[i].name, name))
225 #endif /* SILC_EPOC */
229 /* Returns comma separated list of supported hash functions. */
231 char *silc_hash_get_supported(void)
233 SilcHashObject *entry;
238 if (silc_hash_list) {
239 silc_dlist_start(silc_hash_list);
240 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
241 len += strlen(entry->name);
242 list = silc_realloc(list, len + 1);
244 memcpy(list + (len - strlen(entry->name)),
245 entry->name, strlen(entry->name));
246 memcpy(list + len, ",", 1);
253 for (i = 0; silc_default_hash[i].name; i++) {
254 entry = (SilcHashObject *)&(silc_default_hash[i]);
255 len += strlen(entry->name);
256 list = silc_realloc(list, len + 1);
258 memcpy(list + (len - strlen(entry->name)),
259 entry->name, strlen(entry->name));
260 memcpy(list + len, ",", 1);
264 #endif /* SILC_EPOC */
271 /* Creates the hash value and returns it to the return_hash argument. */
273 void silc_hash_make(SilcHash hash, const unsigned char *data,
274 SilcUInt32 len, unsigned char *return_hash)
276 silc_hash_init(hash);
277 silc_hash_update(hash, data, len);
278 silc_hash_final(hash, return_hash);
281 void silc_hash_init(SilcHash hash)
283 hash->hash->init(hash->context);
286 void silc_hash_update(SilcHash hash, const unsigned char *data,
289 hash->hash->update(hash->context, (unsigned char *)data, data_len);
292 void silc_hash_final(SilcHash hash, unsigned char *return_hash)
294 hash->hash->final(hash->context, return_hash);
297 void silc_hash_transform(SilcHash hash, SilcUInt32 *state,
298 const unsigned char *data)
300 hash->hash->transform(state, data);
303 /* Creates fingerprint of the data. If `hash' is NULL SHA1 is used as
304 default hash function. The returned fingerprint must be freed by the
307 char *silc_hash_fingerprint(SilcHash hash, const unsigned char *data,
310 SilcHash new_hash = NULL;
315 silc_hash_alloc("sha1", &new_hash);
319 silc_hash_make(hash, data, data_len, h);
320 ret = silc_fingerprint(h, hash->hash->hash_len);
322 if (new_hash != NULL)
323 silc_hash_free(new_hash);
327 static const char vo[]= "aeiouy";
328 static const char co[]= "bcdfghklmnprstvzx";
330 /* Creates a babbleprint (Bubble Babble Encoding, developed by Antti
331 Huima (draft-huima-babble-01.txt)), by first computing real fingerprint
332 using `hash' or if NULL, then using SHA1, and then encoding the
333 fingerprint to the babbleprint. */
335 char *silc_hash_babbleprint(SilcHash hash, const unsigned char *data,
338 SilcHash new_hash = NULL;
340 unsigned char hval[32];
341 unsigned int a, b, c, d, e, check;
345 silc_hash_alloc("sha1", &new_hash);
349 /* Take fingerprint */
350 silc_hash_make(hash, data, data_len, hval);
352 /* Encode babbleprint */
353 out_len = (((hash->hash->hash_len + 1) / 2) + 1) * 6;
354 babbleprint = silc_calloc(out_len, sizeof(*babbleprint));
355 babbleprint[0] = co[16];
358 for (i = 0, k = 1; i < hash->hash->hash_len - 1; i += 2, k += 6) {
359 a = (((hval[i] >> 6) & 3) + check) % 6;
360 b = (hval[i] >> 2) & 15;
361 c = ((hval[i] & 3) + (check / 6)) % 6;
362 d = (hval[i + 1] >> 4) & 15;
363 e = hval[i + 1] & 15;
365 check = ((check * 5) + (hval[i] * 7) + hval[i + 1]) % 36;
367 babbleprint[k + 0] = vo[a];
368 babbleprint[k + 1] = co[b];
369 babbleprint[k + 2] = vo[c];
370 babbleprint[k + 3] = co[d];
371 babbleprint[k + 4] = '-';
372 babbleprint[k + 5] = co[e];
375 if ((hash->hash->hash_len % 2) != 0) {
376 a = (((hval[i] >> 6) & 3) + check) % 6;
377 b = (hval[i] >> 2) & 15;
378 c = ((hval[i] & 3) + (check / 6)) % 6;
379 babbleprint[k + 0] = vo[a];
380 babbleprint[k + 1] = co[b];
381 babbleprint[k + 2] = vo[c];
386 babbleprint[k + 0] = vo[a];
387 babbleprint[k + 1] = co[b];
388 babbleprint[k + 2] = vo[c];
390 babbleprint[k + 3] = co[16];
392 if (new_hash != NULL)
393 silc_hash_free(new_hash);