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(const 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(&(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;
169 /* Free's the SilcHash object */
171 void silc_hash_free(SilcHash hash)
174 silc_free(hash->context);
179 /* Returns the length of the hash digest. */
181 SilcUInt32 silc_hash_len(SilcHash hash)
183 return hash->hash->hash_len;
186 /* Returns TRUE if hash algorithm `name' is supported. */
188 bool silc_hash_is_supported(const unsigned char *name)
191 SilcHashObject *entry;
193 if (silc_hash_list) {
194 silc_dlist_start(silc_hash_list);
195 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
196 if (!strcmp(entry->name, name))
203 for (i = 0; silc_default_hash[i].name; i++)
204 if (!strcmp(silc_default_hash[i].name, name))
207 #endif /* SILC_EPOC */
211 /* Returns comma separated list of supported hash functions. */
213 char *silc_hash_get_supported(void)
215 SilcHashObject *entry;
220 if (silc_hash_list) {
221 silc_dlist_start(silc_hash_list);
222 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
223 len += strlen(entry->name);
224 list = silc_realloc(list, len + 1);
226 memcpy(list + (len - strlen(entry->name)),
227 entry->name, strlen(entry->name));
228 memcpy(list + len, ",", 1);
235 for (i = 0; silc_default_hash[i].name; i++) {
236 entry = (SilcHashObject *)&(silc_default_hash[i]);
237 len += strlen(entry->name);
238 list = silc_realloc(list, len + 1);
240 memcpy(list + (len - strlen(entry->name)),
241 entry->name, strlen(entry->name));
242 memcpy(list + len, ",", 1);
246 #endif /* SILC_EPOC */
253 /* Creates the hash value and returns it to the return_hash argument. */
255 void silc_hash_make(SilcHash hash, const unsigned char *data,
256 SilcUInt32 len, unsigned char *return_hash)
258 hash->hash->init(hash->context);
259 hash->hash->update(hash->context, (unsigned char *)data, len);
260 hash->hash->final(hash->context, return_hash);
263 /* Creates fingerprint of the data. If `hash' is NULL SHA1 is used as
264 default hash function. The returned fingerprint must be free's by the
267 char *silc_hash_fingerprint(SilcHash hash, const unsigned char *data,
270 SilcHash new_hash = NULL;
275 silc_hash_alloc("sha1", &new_hash);
279 silc_hash_make(hash, data, data_len, h);
280 ret = silc_fingerprint(h, hash->hash->hash_len);
282 if (new_hash != NULL)
283 silc_hash_free(new_hash);
287 static const char vo[]= "aeiouy";
288 static const char co[]= "bcdfghklmnprstvzx";
290 /* Creates a babbleprint (Bubble Babble Encoding, developed by Antti
291 Huima (draft-huima-babble-01.txt)), by first computing real fingerprint
292 using `hash' or if NULL, then using SHA1, and then encoding the
293 fingerprint to the babbleprint. */
295 char *silc_hash_babbleprint(SilcHash hash, const unsigned char *data,
298 SilcHash new_hash = NULL;
300 unsigned char hval[32];
301 unsigned int a, b, c, d, e, check;
305 silc_hash_alloc("sha1", &new_hash);
309 /* Take fingerprint */
310 silc_hash_make(hash, data, data_len, hval);
312 /* Encode babbleprint */
313 out_len = (((hash->hash->hash_len + 1) / 2) + 1) * 6;
314 babbleprint = silc_calloc(out_len, sizeof(*babbleprint));
315 babbleprint[0] = co[16];
318 for (i = 0, k = 1; i < hash->hash->hash_len - 1; i += 2, k += 6) {
319 a = (((hval[i] >> 6) & 3) + check) % 6;
320 b = (hval[i] >> 2) & 15;
321 c = ((hval[i] & 3) + (check / 6)) % 6;
322 d = (hval[i + 1] >> 4) & 15;
323 e = hval[i + 1] & 15;
325 check = ((check * 5) + (hval[i] * 7) + hval[i + 1]) % 36;
327 babbleprint[k + 0] = vo[a];
328 babbleprint[k + 1] = co[b];
329 babbleprint[k + 2] = vo[c];
330 babbleprint[k + 3] = co[d];
331 babbleprint[k + 4] = '-';
332 babbleprint[k + 5] = co[e];
335 if ((hash->hash->hash_len % 2) != 0) {
336 a = (((hval[i] >> 6) & 3) + check) % 6;
337 b = (hval[i] >> 2) & 15;
338 c = ((hval[i] & 3) + (check / 6)) % 6;
339 babbleprint[k + 0] = vo[a];
340 babbleprint[k + 1] = co[b];
341 babbleprint[k + 2] = vo[c];
346 babbleprint[k + 0] = vo[a];
347 babbleprint[k + 1] = co[b];
348 babbleprint[k + 2] = vo[c];
350 babbleprint[k + 3] = co[16];
352 if (new_hash != NULL)
353 silc_hash_free(new_hash);