updates.
[silc.git] / lib / silccrypt / silchash.c
1 /*
2
3   silchash.c 
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2002 Pekka Riikonen
8
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.
12
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.
17
18 */
19 /* $Id$ */
20
21 #include "silcincludes.h"
22
23 #include "md5.h"
24 #include "sha1.h"
25
26 /* The main SILC hash structure. */
27 struct SilcHashStruct {
28   SilcHashObject *hash;
29   void *context;
30 };
31
32 #ifndef SILC_EPOC
33 /* List of dynamically registered hash functions. */
34 SilcDList silc_hash_list = NULL;
35 #endif /* SILC_EPOC */
36
37 /* Default hash functions for silc_hash_register_default(). */
38 const SilcHashObject silc_default_hash[] = 
39 {
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 },
44
45   { NULL, 0, 0, NULL, NULL, NULL, NULL, NULL }
46 };
47
48 /* Registers a new hash function into the SILC. This function is used at
49    the initialization of the SILC. */
50
51 bool silc_hash_register(const SilcHashObject *hash)
52 {
53 #ifndef SILC_EPOC
54   SilcHashObject *new;
55
56   SILC_LOG_DEBUG(("Registering new hash function `%s'", hash->name));
57
58   /* Check for existing */
59   if (silc_hash_list) {
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))
64         return FALSE;
65     }
66   }
67
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;
77
78   /* Add to list */
79   if (silc_hash_list == NULL)
80     silc_hash_list = silc_dlist_init();
81   silc_dlist_add(silc_hash_list, new);
82
83 #endif /* SILC_EPOC */
84   return TRUE;
85 }
86
87 /* Unregister a hash function from the SILC. */
88
89 bool silc_hash_unregister(SilcHashObject *hash)
90 {
91 #ifndef SILC_EPOC
92   SilcHashObject *entry;
93
94   SILC_LOG_DEBUG(("Unregistering hash function"));
95
96   if (!silc_hash_list)
97     return FALSE;
98
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);
103
104       if (silc_dlist_count(silc_hash_list) == 0) {
105         silc_dlist_uninit(silc_hash_list);
106         silc_hash_list = NULL;
107       }
108
109       return TRUE;
110     }
111   }
112
113 #endif /* SILC_EPOC */
114   return FALSE;
115 }
116
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. */
120
121 bool silc_hash_register_default(void)
122 {
123 #ifndef SILC_EPOC
124   int i;
125
126   for (i = 0; silc_default_hash[i].name; i++)
127     silc_hash_register(&(silc_default_hash[i]));
128
129 #endif /* SILC_EPOC */
130   return TRUE;
131 }
132
133 /* Allocates a new SilcHash object. New object is returned into new_hash
134    argument. */
135
136 bool silc_hash_alloc(const unsigned char *name, SilcHash *new_hash)
137 {
138   SilcHashObject *entry = NULL;
139   
140   SILC_LOG_DEBUG(("Allocating new hash object"));
141
142 #ifndef SILC_EPOC
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))
147         break;
148     }
149   }
150 #else
151   {
152     /* On EPOC which don't have globals we check our constant hash list. */
153     int i;
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]);
157         break;
158       }
159     }
160   }
161 #endif /* SILC_EPOC */
162
163   if (entry) {
164     *new_hash = silc_calloc(1, sizeof(**new_hash));
165     (*new_hash)->hash = entry;
166     (*new_hash)->context = silc_calloc(1, entry->context_len());
167     return TRUE;
168   }
169
170   return FALSE;
171 }
172
173 /* Free's the SilcHash object */
174
175 void silc_hash_free(SilcHash hash)
176 {
177   if (hash) {
178     silc_free(hash->context);
179     silc_free(hash);
180   }
181 }
182
183 /* Returns the length of the hash digest. */
184
185 SilcUInt32 silc_hash_len(SilcHash hash)
186 {
187   return hash->hash->hash_len;
188 }
189
190 /* Returns the block lenght of the hash. */
191
192 SilcUInt32 silc_hash_block_len(SilcHash hash)
193 {
194   return hash->hash->block_len;
195 }
196
197 /* Returns the name of the hash function */
198
199 const char *silc_hash_get_name(SilcHash hash)
200 {
201   return hash->hash->name;
202 }
203
204 /* Returns TRUE if hash algorithm `name' is supported. */
205
206 bool silc_hash_is_supported(const unsigned char *name)
207 {
208 #ifndef SILC_EPOC
209   SilcHashObject *entry;
210
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))
215         return TRUE;
216     }
217   }
218 #else
219   {
220     int i;
221     for (i = 0; silc_default_hash[i].name; i++)
222       if (!strcmp(silc_default_hash[i].name, name))
223         return TRUE;
224   }
225 #endif /* SILC_EPOC */
226   return FALSE;
227 }
228
229 /* Returns comma separated list of supported hash functions. */
230
231 char *silc_hash_get_supported(void)
232 {
233   SilcHashObject *entry;
234   char *list = NULL;
235   int len = 0;
236
237 #ifndef SILC_EPOC
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);
243       
244       memcpy(list + (len - strlen(entry->name)), 
245              entry->name, strlen(entry->name));
246       memcpy(list + len, ",", 1);
247       len++;
248     }
249   }
250 #else
251   {
252     int i;
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);
257       
258       memcpy(list + (len - strlen(entry->name)), 
259              entry->name, strlen(entry->name));
260       memcpy(list + len, ",", 1);
261       len++;
262     }
263   }
264 #endif /* SILC_EPOC */
265
266   list[len - 1] = 0;
267
268   return list;
269 }
270
271 /* Creates the hash value and returns it to the return_hash argument. */
272
273 void silc_hash_make(SilcHash hash, const unsigned char *data, 
274                     SilcUInt32 len, unsigned char *return_hash)
275 {
276   silc_hash_init(hash);
277   silc_hash_update(hash, data, len);
278   silc_hash_final(hash, return_hash);
279 }
280
281 void silc_hash_init(SilcHash hash)
282 {
283   hash->hash->init(hash->context);
284 }
285
286 void silc_hash_update(SilcHash hash, const unsigned char *data,
287                       SilcUInt32 data_len)
288 {
289   hash->hash->update(hash->context, (unsigned char *)data, data_len);
290 }
291
292 void silc_hash_final(SilcHash hash, unsigned char *return_hash)
293 {
294   hash->hash->final(hash->context, return_hash);
295 }
296
297 void silc_hash_transform(SilcHash hash, SilcUInt32 *state,
298                          const unsigned char *data)
299 {
300   hash->hash->transform(state, data);
301 }
302
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
305    caller. */
306
307 char *silc_hash_fingerprint(SilcHash hash, const unsigned char *data,
308                             SilcUInt32 data_len)
309 {
310   SilcHash new_hash = NULL;
311   unsigned char h[32];
312   char *ret;
313
314   if (!hash) {
315     silc_hash_alloc("sha1", &new_hash);
316     hash = new_hash;
317   }
318
319   silc_hash_make(hash, data, data_len, h);
320   ret = silc_fingerprint(h, hash->hash->hash_len);
321
322   if (new_hash != NULL)
323     silc_hash_free(new_hash);
324   return ret;
325 }
326
327 static const char vo[]= "aeiouy";
328 static const char co[]= "bcdfghklmnprstvzx";
329
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. */
334
335 char *silc_hash_babbleprint(SilcHash hash, const unsigned char *data,
336                             SilcUInt32 data_len)
337 {
338   SilcHash new_hash = NULL;
339   char *babbleprint;
340   unsigned char hval[32];
341   unsigned int a, b, c, d, e, check;
342   int i, k, out_len;
343
344   if (!hash) {
345     silc_hash_alloc("sha1", &new_hash);
346     hash = new_hash;
347   }
348
349   /* Take fingerprint */
350   silc_hash_make(hash, data, data_len, hval);
351
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];
356
357   check = 1;
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;
364     
365     check = ((check * 5) + (hval[i] * 7) + hval[i + 1]) % 36;
366     
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];
373   }
374
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];
382   } else { 
383     a = check % 6;
384     b = 16;
385     c = check / 6;
386     babbleprint[k + 0] = vo[a];
387     babbleprint[k + 1] = co[b];
388     babbleprint[k + 2] = vo[c];
389   }
390   babbleprint[k + 3] = co[16];
391
392   if (new_hash != NULL)
393     silc_hash_free(new_hash);
394   return babbleprint;
395 }