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"
28 /* List of dynamically registered hash functions. */
29 SilcDList silc_hash_list = NULL;
30 #endif /* SILC_EPOC */
32 /* Default hash functions for silc_hash_register_default(). */
33 const SilcHashObject silc_default_hash[] =
35 { "sha1", 20, 64, silc_sha1_init, silc_sha1_update, silc_sha1_final,
36 silc_sha1_transform, silc_sha1_context_len },
37 { "md5", 16, 64, silc_md5_init, silc_md5_update, silc_md5_final,
38 silc_md5_transform, silc_md5_context_len },
40 { NULL, 0, 0, NULL, NULL, NULL, NULL, NULL }
43 /* Registers a new hash function into the SILC. This function is used at
44 the initialization of the SILC. */
46 bool silc_hash_register(SilcHashObject *hash)
51 SILC_LOG_DEBUG(("Registering new hash function `%s'", hash->name));
53 /* Check for existing */
55 SilcHashObject *entry;
56 silc_dlist_start(silc_hash_list);
57 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
58 if (!strcmp(entry->name, hash->name))
63 new = silc_calloc(1, sizeof(*new));
64 new->name = strdup(hash->name);
65 new->hash_len = hash->hash_len;
66 new->block_len = hash->block_len;
67 new->init = hash->init;
68 new->update = hash->update;
69 new->final = hash->final;
70 new->transform = hash->transform;
71 new->context_len = hash->context_len;
74 if (silc_hash_list == NULL)
75 silc_hash_list = silc_dlist_init();
76 silc_dlist_add(silc_hash_list, new);
78 #endif /* SILC_EPOC */
82 /* Unregister a hash function from the SILC. */
84 bool silc_hash_unregister(SilcHashObject *hash)
87 SilcHashObject *entry;
89 SILC_LOG_DEBUG(("Unregistering hash function"));
94 silc_dlist_start(silc_hash_list);
95 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
96 if (hash == SILC_ALL_HASH_FUNCTIONS || entry == hash) {
97 silc_dlist_del(silc_hash_list, entry);
99 if (silc_dlist_count(silc_hash_list) == 0) {
100 silc_dlist_uninit(silc_hash_list);
101 silc_hash_list = NULL;
108 #endif /* SILC_EPOC */
112 /* Function that registers all the default hash funcs (all builtin ones).
113 The application may use this to register the default hash funcs if
114 specific hash funcs in any specific order is not wanted. */
116 bool silc_hash_register_default(void)
121 for (i = 0; silc_default_hash[i].name; i++)
122 silc_hash_register((SilcHashObject *)&(silc_default_hash[i]));
124 #endif /* SILC_EPOC */
128 /* Allocates a new SilcHash object. New object is returned into new_hash
131 bool silc_hash_alloc(const unsigned char *name, SilcHash *new_hash)
133 SilcHashObject *entry = NULL;
135 SILC_LOG_DEBUG(("Allocating new hash object"));
138 if (silc_hash_list) {
139 silc_dlist_start(silc_hash_list);
140 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
141 if (!strcmp(entry->name, name))
147 /* On EPOC which don't have globals we check our constant hash list. */
149 for (i = 0; silc_default_hash[i].name; i++) {
150 if (!strcmp(silc_default_hash[i].name, name)) {
151 entry = (SilcHashObject *)&(silc_default_hash[i]);
156 #endif /* SILC_EPOC */
159 *new_hash = silc_calloc(1, sizeof(**new_hash));
160 (*new_hash)->hash = entry;
161 (*new_hash)->context = silc_calloc(1, entry->context_len());
162 (*new_hash)->make_hash = silc_hash_make;
168 /* Free's the SilcHash object */
170 void silc_hash_free(SilcHash hash)
173 silc_free(hash->context);
178 /* Returns the length of the hash digest. */
180 SilcUInt32 silc_hash_len(SilcHash hash)
182 return hash->hash->hash_len;
185 /* Returns TRUE if hash algorithm `name' is supported. */
187 bool silc_hash_is_supported(const unsigned char *name)
190 SilcHashObject *entry;
192 if (silc_hash_list) {
193 silc_dlist_start(silc_hash_list);
194 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
195 if (!strcmp(entry->name, name))
202 for (i = 0; silc_default_hash[i].name; i++)
203 if (!strcmp(silc_default_hash[i].name, name))
206 #endif /* SILC_EPOC */
210 /* Returns comma separated list of supported hash functions. */
212 char *silc_hash_get_supported(void)
214 SilcHashObject *entry;
219 if (silc_hash_list) {
220 silc_dlist_start(silc_hash_list);
221 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
222 len += strlen(entry->name);
223 list = silc_realloc(list, len + 1);
225 memcpy(list + (len - strlen(entry->name)),
226 entry->name, strlen(entry->name));
227 memcpy(list + len, ",", 1);
234 for (i = 0; silc_default_hash[i].name; i++) {
235 entry = (SilcHashObject *)&(silc_default_hash[i]);
236 len += strlen(entry->name);
237 list = silc_realloc(list, len + 1);
239 memcpy(list + (len - strlen(entry->name)),
240 entry->name, strlen(entry->name));
241 memcpy(list + len, ",", 1);
245 #endif /* SILC_EPOC */
252 /* Creates the hash value and returns it to the return_hash argument. */
254 void silc_hash_make(SilcHash hash, const unsigned char *data,
255 SilcUInt32 len, unsigned char *return_hash)
257 hash->hash->init(hash->context);
258 hash->hash->update(hash->context, (unsigned char *)data, len);
259 hash->hash->final(hash->context, return_hash);
262 /* Creates fingerprint of the data. If `hash' is NULL SHA1 is used as
263 default hash function. The returned fingerprint must be free's by the
266 char *silc_hash_fingerprint(SilcHash hash, const unsigned char *data,
269 SilcHash new_hash = NULL;
274 silc_hash_alloc("sha1", &new_hash);
278 silc_hash_make(hash, data, data_len, h);
279 ret = silc_fingerprint(h, hash->hash->hash_len);
281 if (new_hash != NULL)
282 silc_hash_free(new_hash);
286 static const char vo[]= "aeiouy";
287 static const char co[]= "bcdfghklmnprstvzx";
289 /* Creates a babbleprint (Bubble Babble Encoding, developed by Antti
290 Huima (draft-huima-babble-01.txt)), by first computing real fingerprint
291 using `hash' or if NULL, then using SHA1, and then encoding the
292 fingerprint to the babbleprint. */
294 char *silc_hash_babbleprint(SilcHash hash, const unsigned char *data,
297 SilcHash new_hash = NULL;
299 unsigned char hval[32];
300 unsigned int a, b, c, d, e, check;
304 silc_hash_alloc("sha1", &new_hash);
308 /* Take fingerprint */
309 silc_hash_make(hash, data, data_len, hval);
311 /* Encode babbleprint */
312 out_len = (((hash->hash->hash_len + 1) / 2) + 1) * 6;
313 babbleprint = silc_calloc(out_len, sizeof(*babbleprint));
314 babbleprint[0] = co[16];
317 for (i = 0, k = 1; i < hash->hash->hash_len - 1; i += 2, k += 6) {
318 a = (((hval[i] >> 6) & 3) + check) % 6;
319 b = (hval[i] >> 2) & 15;
320 c = ((hval[i] & 3) + (check / 6)) % 6;
321 d = (hval[i + 1] >> 4) & 15;
322 e = hval[i + 1] & 15;
324 check = ((check * 5) + (hval[i] * 7) + hval[i + 1]) % 36;
326 babbleprint[k + 0] = vo[a];
327 babbleprint[k + 1] = co[b];
328 babbleprint[k + 2] = vo[c];
329 babbleprint[k + 3] = co[d];
330 babbleprint[k + 4] = '-';
331 babbleprint[k + 5] = co[e];
334 if ((hash->hash->hash_len % 2) != 0) {
335 a = (((hval[i] >> 6) & 3) + check) % 6;
336 b = (hval[i] >> 2) & 15;
337 c = ((hval[i] & 3) + (check / 6)) % 6;
338 babbleprint[k + 0] = vo[a];
339 babbleprint[k + 1] = co[b];
340 babbleprint[k + 2] = vo[c];
345 babbleprint[k + 0] = vo[a];
346 babbleprint[k + 1] = co[b];
347 babbleprint[k + 2] = vo[c];
349 babbleprint[k + 3] = co[16];
351 if (new_hash != NULL)
352 silc_hash_free(new_hash);