5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2001 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; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
22 #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 { "sha1", 20, 64, silc_sha1_init, silc_sha1_update, silc_sha1_final,
42 silc_sha1_transform, silc_sha1_context_len },
43 { "md5", 16, 64, silc_md5_init, silc_md5_update, silc_md5_final,
44 silc_md5_transform, silc_md5_context_len },
46 { NULL, 0, 0, NULL, NULL, NULL, NULL, NULL }
49 /* Registers a new hash function into the SILC. This function is used at
50 the initialization of the SILC. */
52 bool silc_hash_register(const SilcHashObject *hash)
57 SILC_LOG_DEBUG(("Registering new hash function `%s'", hash->name));
59 /* Check for existing */
61 SilcHashObject *entry;
62 silc_dlist_start(silc_hash_list);
63 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
64 if (!strcmp(entry->name, hash->name))
69 new = silc_calloc(1, sizeof(*new));
70 new->name = strdup(hash->name);
71 new->hash_len = hash->hash_len;
72 new->block_len = hash->block_len;
73 new->init = hash->init;
74 new->update = hash->update;
75 new->final = hash->final;
76 new->transform = hash->transform;
77 new->context_len = hash->context_len;
80 if (silc_hash_list == NULL)
81 silc_hash_list = silc_dlist_init();
82 silc_dlist_add(silc_hash_list, new);
84 #endif /* SILC_EPOC */
88 /* Unregister a hash function from the SILC. */
90 bool silc_hash_unregister(SilcHashObject *hash)
93 SilcHashObject *entry;
95 SILC_LOG_DEBUG(("Unregistering hash function"));
100 silc_dlist_start(silc_hash_list);
101 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
102 if (hash == SILC_ALL_HASH_FUNCTIONS || entry == hash) {
103 silc_dlist_del(silc_hash_list, entry);
105 if (silc_dlist_count(silc_hash_list) == 0) {
106 silc_dlist_uninit(silc_hash_list);
107 silc_hash_list = NULL;
114 #endif /* SILC_EPOC */
118 /* Function that registers all the default hash funcs (all builtin ones).
119 The application may use this to register the default hash funcs if
120 specific hash funcs in any specific order is not wanted. */
122 bool silc_hash_register_default(void)
127 for (i = 0; silc_default_hash[i].name; i++)
128 silc_hash_register(&(silc_default_hash[i]));
130 #endif /* SILC_EPOC */
134 /* Allocates a new SilcHash object. New object is returned into new_hash
137 bool silc_hash_alloc(const unsigned char *name, SilcHash *new_hash)
139 SilcHashObject *entry = NULL;
141 SILC_LOG_DEBUG(("Allocating new hash object"));
144 if (silc_hash_list) {
145 silc_dlist_start(silc_hash_list);
146 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
147 if (!strcmp(entry->name, name))
153 /* On EPOC which don't have globals we check our constant hash list. */
155 for (i = 0; silc_default_hash[i].name; i++) {
156 if (!strcmp(silc_default_hash[i].name, name)) {
157 entry = (SilcHashObject *)&(silc_default_hash[i]);
162 #endif /* SILC_EPOC */
165 *new_hash = silc_calloc(1, sizeof(**new_hash));
166 (*new_hash)->hash = entry;
167 (*new_hash)->context = silc_calloc(1, entry->context_len());
174 /* Free's the SilcHash object */
176 void silc_hash_free(SilcHash hash)
179 silc_free(hash->context);
184 /* Returns the length of the hash digest. */
186 SilcUInt32 silc_hash_len(SilcHash hash)
188 return hash->hash->hash_len;
191 /* Returns the block lenght of the hash. */
193 SilcUInt32 silc_hash_block_len(SilcHash hash)
195 return hash->hash->block_len;
198 /* Returns the name of the hash function */
200 const char *silc_hash_get_name(SilcHash hash)
202 return hash->hash->name;
205 /* Returns TRUE if hash algorithm `name' is supported. */
207 bool silc_hash_is_supported(const unsigned char *name)
210 SilcHashObject *entry;
212 if (silc_hash_list) {
213 silc_dlist_start(silc_hash_list);
214 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
215 if (!strcmp(entry->name, name))
222 for (i = 0; silc_default_hash[i].name; i++)
223 if (!strcmp(silc_default_hash[i].name, name))
226 #endif /* SILC_EPOC */
230 /* Returns comma separated list of supported hash functions. */
232 char *silc_hash_get_supported(void)
234 SilcHashObject *entry;
239 if (silc_hash_list) {
240 silc_dlist_start(silc_hash_list);
241 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
242 len += strlen(entry->name);
243 list = silc_realloc(list, len + 1);
245 memcpy(list + (len - strlen(entry->name)),
246 entry->name, strlen(entry->name));
247 memcpy(list + len, ",", 1);
254 for (i = 0; silc_default_hash[i].name; i++) {
255 entry = (SilcHashObject *)&(silc_default_hash[i]);
256 len += strlen(entry->name);
257 list = silc_realloc(list, len + 1);
259 memcpy(list + (len - strlen(entry->name)),
260 entry->name, strlen(entry->name));
261 memcpy(list + len, ",", 1);
265 #endif /* SILC_EPOC */
272 /* Creates the hash value and returns it to the return_hash argument. */
274 void silc_hash_make(SilcHash hash, const unsigned char *data,
275 SilcUInt32 len, unsigned char *return_hash)
277 silc_hash_init(hash);
278 silc_hash_update(hash, data, len);
279 silc_hash_final(hash, return_hash);
282 void silc_hash_init(SilcHash hash)
284 hash->hash->init(hash->context);
287 void silc_hash_update(SilcHash hash, const unsigned char *data,
290 hash->hash->update(hash->context, (unsigned char *)data, data_len);
293 void silc_hash_final(SilcHash hash, unsigned char *return_hash)
295 hash->hash->final(hash->context, return_hash);
298 void silc_hash_transform(SilcHash hash, SilcUInt32 *state,
299 const unsigned char *data)
301 hash->hash->transform(state, data);
304 /* Creates fingerprint of the data. If `hash' is NULL SHA1 is used as
305 default hash function. The returned fingerprint must be freed by the
308 char *silc_hash_fingerprint(SilcHash hash, const unsigned char *data,
311 SilcHash new_hash = NULL;
316 silc_hash_alloc("sha1", &new_hash);
320 silc_hash_make(hash, data, data_len, h);
321 ret = silc_fingerprint(h, hash->hash->hash_len);
323 if (new_hash != NULL)
324 silc_hash_free(new_hash);
328 static const char vo[]= "aeiouy";
329 static const char co[]= "bcdfghklmnprstvzx";
331 /* Creates a babbleprint (Bubble Babble Encoding, developed by Antti
332 Huima (draft-huima-babble-01.txt)), by first computing real fingerprint
333 using `hash' or if NULL, then using SHA1, and then encoding the
334 fingerprint to the babbleprint. */
336 char *silc_hash_babbleprint(SilcHash hash, const unsigned char *data,
339 SilcHash new_hash = NULL;
341 unsigned char hval[32];
342 unsigned int a, b, c, d, e, check;
346 silc_hash_alloc("sha1", &new_hash);
350 /* Take fingerprint */
351 silc_hash_make(hash, data, data_len, hval);
353 /* Encode babbleprint */
354 out_len = (((hash->hash->hash_len + 1) / 2) + 1) * 6;
355 babbleprint = silc_calloc(out_len, sizeof(*babbleprint));
356 babbleprint[0] = co[16];
359 for (i = 0, k = 1; i < hash->hash->hash_len - 1; i += 2, k += 6) {
360 a = (((hval[i] >> 6) & 3) + check) % 6;
361 b = (hval[i] >> 2) & 15;
362 c = ((hval[i] & 3) + (check / 6)) % 6;
363 d = (hval[i + 1] >> 4) & 15;
364 e = hval[i + 1] & 15;
366 check = ((check * 5) + (hval[i] * 7) + hval[i + 1]) % 36;
368 babbleprint[k + 0] = vo[a];
369 babbleprint[k + 1] = co[b];
370 babbleprint[k + 2] = vo[c];
371 babbleprint[k + 3] = co[d];
372 babbleprint[k + 4] = '-';
373 babbleprint[k + 5] = co[e];
376 if ((hash->hash->hash_len % 2) != 0) {
377 a = (((hval[i] >> 6) & 3) + check) % 6;
378 b = (hval[i] >> 2) & 15;
379 c = ((hval[i] & 3) + (check / 6)) % 6;
380 babbleprint[k + 0] = vo[a];
381 babbleprint[k + 1] = co[b];
382 babbleprint[k + 2] = vo[c];
387 babbleprint[k + 0] = vo[a];
388 babbleprint[k + 1] = co[b];
389 babbleprint[k + 2] = vo[c];
391 babbleprint[k + 3] = co[16];
393 if (new_hash != NULL)
394 silc_hash_free(new_hash);