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 /* List of dynamically registered hash functions. */
28 SilcDList silc_hash_list = NULL;
30 /* Default hash functions for silc_hash_register_default(). */
31 SilcHashObject silc_default_hash[] =
33 { "sha1", 20, 64, silc_sha1_init, silc_sha1_update, silc_sha1_final,
34 silc_sha1_transform, silc_sha1_context_len },
35 { "md5", 16, 64, silc_md5_init, silc_md5_update, silc_md5_final,
36 silc_md5_transform, silc_md5_context_len },
38 { NULL, 0, 0, NULL, NULL, NULL, NULL, NULL }
41 /* Registers a new hash function into the SILC. This function is used at
42 the initialization of the SILC. */
44 bool silc_hash_register(SilcHashObject *hash)
48 SILC_LOG_DEBUG(("Registering new hash function `%s'", hash->name));
50 new = silc_calloc(1, sizeof(*new));
51 new->name = strdup(hash->name);
52 new->hash_len = hash->hash_len;
53 new->block_len = hash->block_len;
54 new->init = hash->init;
55 new->update = hash->update;
56 new->final = hash->final;
57 new->transform = hash->transform;
58 new->context_len = hash->context_len;
61 if (silc_hash_list == NULL)
62 silc_hash_list = silc_dlist_init();
63 silc_dlist_add(silc_hash_list, new);
68 /* Unregister a hash function from the SILC. */
70 bool silc_hash_unregister(SilcHashObject *hash)
72 SilcHashObject *entry;
74 SILC_LOG_DEBUG(("Unregistering hash function"));
79 silc_dlist_start(silc_hash_list);
80 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
81 if (hash == SILC_ALL_HASH_FUNCTIONS || entry == hash) {
82 silc_dlist_del(silc_hash_list, entry);
84 if (silc_dlist_count(silc_hash_list) == 0) {
85 silc_dlist_uninit(silc_hash_list);
86 silc_hash_list = NULL;
96 /* Function that registers all the default hash funcs (all builtin ones).
97 The application may use this to register the default hash funcs if
98 specific hash funcs in any specific order is not wanted. */
100 bool silc_hash_register_default(void)
104 for (i = 0; silc_default_hash[i].name; i++)
105 silc_hash_register(&(silc_default_hash[i]));
110 /* Allocates a new SilcHash object. New object is returned into new_hash
113 bool silc_hash_alloc(const unsigned char *name, SilcHash *new_hash)
115 SilcHashObject *entry;
117 SILC_LOG_DEBUG(("Allocating new hash object"));
119 if (silc_hash_list) {
120 silc_dlist_start(silc_hash_list);
121 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
122 if (!strcmp(entry->name, name)) {
123 *new_hash = silc_calloc(1, sizeof(**new_hash));
124 (*new_hash)->hash = entry;
125 (*new_hash)->context = silc_calloc(1, entry->context_len());
126 (*new_hash)->make_hash = silc_hash_make;
135 /* Free's the SilcHash object */
137 void silc_hash_free(SilcHash hash)
140 silc_free(hash->context);
145 /* Returns the length of the hash digest. */
147 uint32 silc_hash_len(SilcHash hash)
149 return hash->hash->hash_len;
152 /* Returns TRUE if hash algorithm `name' is supported. */
154 bool silc_hash_is_supported(const unsigned char *name)
156 SilcHashObject *entry;
158 if (silc_hash_list) {
159 silc_dlist_start(silc_hash_list);
160 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
161 if (!strcmp(entry->name, name))
169 /* Returns comma separated list of supported hash functions. */
171 char *silc_hash_get_supported(void)
173 SilcHashObject *entry;
178 if (silc_hash_list) {
179 silc_dlist_start(silc_hash_list);
180 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
181 len += strlen(entry->name);
182 list = silc_realloc(list, len + 1);
184 memcpy(list + (len - strlen(entry->name)),
185 entry->name, strlen(entry->name));
186 memcpy(list + len, ",", 1);
195 /* Creates the hash value and returns it to the return_hash argument. */
197 void silc_hash_make(SilcHash hash, const unsigned char *data,
198 uint32 len, unsigned char *return_hash)
200 hash->hash->init(hash->context);
201 hash->hash->update(hash->context, (unsigned char *)data, len);
202 hash->hash->final(hash->context, return_hash);
205 /* Creates fingerprint of the data. If `hash' is NULL SHA1 is used as
206 default hash function. The returned fingerprint must be free's by the
209 char *silc_hash_fingerprint(SilcHash hash, const unsigned char *data,
212 SilcHash new_hash = NULL;
217 silc_hash_alloc("sha1", &new_hash);
221 silc_hash_make(hash, data, data_len, h);
222 ret = silc_fingerprint(h, hash->hash->hash_len);
224 if (new_hash != NULL)
225 silc_hash_free(new_hash);
229 static const char vo[]= "aeiouy";
230 static const char co[]= "bcdfghklmnprstvzx";
232 /* Creates a babbleprint (Bubble Babble Encoding, developed by Antti
233 Huima (draft-huima-babble-01.txt)), by first computing real fingerprint
234 using `hash' or if NULL, then using SHA1, and then encoding the
235 fingerprint to the babbleprint. */
237 char *silc_hash_babbleprint(SilcHash hash, const unsigned char *data,
240 SilcHash new_hash = NULL;
242 unsigned char hval[32];
243 unsigned int a, b, c, d, e, check;
247 silc_hash_alloc("sha1", &new_hash);
251 /* Take fingerprint */
252 silc_hash_make(hash, data, data_len, hval);
254 /* Encode babbleprint */
255 out_len = (((hash->hash->hash_len + 1) / 2) + 1) * 6;
256 babbleprint = silc_calloc(out_len, sizeof(*babbleprint));
257 babbleprint[0] = co[16];
260 for (i = 0, k = 1; i < hash->hash->hash_len - 1; i += 2, k += 6) {
261 a = (((hval[i] >> 6) & 3) + check) % 6;
262 b = (hval[i] >> 2) & 15;
263 c = ((hval[i] & 3) + (check / 6)) % 6;
264 d = (hval[i + 1] >> 4) & 15;
265 e = hval[i + 1] & 15;
267 check = ((check * 5) + (hval[i] * 7) + hval[i + 1]) % 36;
269 babbleprint[k + 0] = vo[a];
270 babbleprint[k + 1] = co[b];
271 babbleprint[k + 2] = vo[c];
272 babbleprint[k + 3] = co[d];
273 babbleprint[k + 4] = '-';
274 babbleprint[k + 5] = co[e];
277 if ((hash->hash->hash_len % 2) != 0) {
278 a = (((hval[i] >> 6) & 3) + check) % 6;
279 b = (hval[i] >> 2) & 15;
280 c = ((hval[i] & 3) + (check / 6)) % 6;
281 babbleprint[k + 0] = vo[a];
282 babbleprint[k + 1] = co[b];
283 babbleprint[k + 2] = vo[c];
288 babbleprint[k + 0] = vo[a];
289 babbleprint[k + 1] = co[b];
290 babbleprint[k + 2] = vo[c];
292 babbleprint[k + 3] = co[16];
294 if (new_hash != NULL)
295 silc_hash_free(new_hash);