1 /*
2 
3   silchash.c
4 
5   Author: Pekka Riikonen <priikone@silcnet.org>
6 
7   Copyright (C) 1997 - 2007 Pekka Riikonen
8 
9   The contents of this file are subject to one of the Licenses specified
10   in the COPYING file;  You may not use this file except in compliance
11   with the License.
12 
13   The software distributed under the License is distributed on an "AS IS"
14   basis, in the hope that it will be useful, but WITHOUT WARRANTY OF ANY
15   KIND, either expressed or implied.  See the COPYING file for more
16   information.
17 
18 */
19 /* $Id$ */
20 
21 #include "silc.h"
22 
23 #include "md5.h"
24 #include "sha1.h"
25 #include "sha256.h"
26 
27 /* The main SILC hash structure. */
28 struct SilcHashStruct {
29   SilcHashObject *hash;
30   void *context;
31 };
32 
33 #ifndef SILC_SYMBIAN
34 /* List of dynamically registered hash functions. */
35 SilcDList silc_hash_list = NULL;
36 #endif /* SILC_SYMBIAN */
37 
38 /* Default hash functions for silc_hash_register_default(). */
39 const SilcHashObject silc_default_hash[] =
40 {
41   { "sha256", "2.16.840.1.101.3.4.2.1",
42     32, 64, silc_sha256_init, silc_sha256_update, silc_sha256_final,
43     silc_sha256_transform, silc_sha256_context_len },
44   { "sha1", "1.3.14.3.2.26",
45     20, 64, silc_sha1_init, silc_sha1_update, silc_sha1_final,
46     silc_sha1_transform, silc_sha1_context_len },
47   { "md5", "1.2.840.113549.2.5",
48     16, 64, silc_md5_init, silc_md5_update, silc_md5_final,
49     silc_md5_transform, silc_md5_context_len },
50 
51   { NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL }
52 };
53 
54 /* Registers a new hash function into the SILC. This function is used at
55    the initialization of the SILC. */
56 
silc_hash_register(const SilcHashObject * hash)57 SilcBool silc_hash_register(const SilcHashObject *hash)
58 {
59 #ifndef SILC_SYMBIAN
60   SilcHashObject *new;
61 
62   SILC_LOG_DEBUG(("Registering new hash function `%s'", hash->name));
63 
64   /* Check for existing */
65   if (silc_hash_list) {
66     SilcHashObject *entry;
67     silc_dlist_start(silc_hash_list);
68     while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
69       if (!strcmp(entry->name, hash->name))
70 	return FALSE;
71     }
72   }
73 
74   new = silc_calloc(1, sizeof(*new));
75   if (!new)
76     return FALSE;
77   new->name = strdup(hash->name);
78   if (!new->name) {
79     silc_free(new);
80     return FALSE;
81   }
82   new->oid = strdup(hash->oid);
83   if (!new->oid) {
84     silc_free(new);
85     return FALSE;
86   }
87   new->hash_len = hash->hash_len;
88   new->block_len = hash->block_len;
89   new->init = hash->init;
90   new->update = hash->update;
91   new->final = hash->final;
92   new->transform = hash->transform;
93   new->context_len = hash->context_len;
94 
95   /* Add to list */
96   if (silc_hash_list == NULL)
97     silc_hash_list = silc_dlist_init();
98   silc_dlist_add(silc_hash_list, new);
99 
100 #endif /* SILC_SYMBIAN */
101   return TRUE;
102 }
103 
104 /* Unregister a hash function from the SILC. */
105 
silc_hash_unregister(SilcHashObject * hash)106 SilcBool silc_hash_unregister(SilcHashObject *hash)
107 {
108 #ifndef SILC_SYMBIAN
109   SilcHashObject *entry;
110 
111   SILC_LOG_DEBUG(("Unregistering hash function"));
112 
113   if (!silc_hash_list)
114     return FALSE;
115 
116   silc_dlist_start(silc_hash_list);
117   while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
118     if (hash == SILC_ALL_HASH_FUNCTIONS || entry == hash) {
119       silc_dlist_del(silc_hash_list, entry);
120       silc_free(entry->name);
121       silc_free(entry->oid);
122       silc_free(entry);
123 
124       if (silc_dlist_count(silc_hash_list) == 0) {
125 	silc_dlist_uninit(silc_hash_list);
126 	silc_hash_list = NULL;
127       }
128 
129       return TRUE;
130     }
131   }
132 
133 #endif /* SILC_SYMBIAN */
134   return FALSE;
135 }
136 
137 /* Function that registers all the default hash funcs (all builtin ones).
138    The application may use this to register the default hash funcs if
139    specific hash funcs in any specific order is not wanted. */
140 
silc_hash_register_default(void)141 SilcBool silc_hash_register_default(void)
142 {
143 #ifndef SILC_SYMBIAN
144   int i;
145 
146   for (i = 0; silc_default_hash[i].name; i++)
147     silc_hash_register(&(silc_default_hash[i]));
148 
149 #endif /* SILC_SYMBIAN */
150   return TRUE;
151 }
152 
silc_hash_unregister_all(void)153 SilcBool silc_hash_unregister_all(void)
154 {
155 #ifndef SILC_SYMBIAN
156   SilcHashObject *entry;
157 
158   if (!silc_hash_list)
159     return FALSE;
160 
161   silc_dlist_start(silc_hash_list);
162   while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
163     silc_hash_unregister(entry);
164     if (!silc_hash_list)
165       break;
166   }
167 #endif /* SILC_SYMBIAN */
168   return TRUE;
169 }
170 
171 /* Allocates a new SilcHash object. New object is returned into new_hash
172    argument. */
173 
silc_hash_alloc(const unsigned char * name,SilcHash * new_hash)174 SilcBool silc_hash_alloc(const unsigned char *name, SilcHash *new_hash)
175 {
176   SilcHashObject *entry = NULL;
177 
178   SILC_LOG_DEBUG(("Allocating new hash %s", name));
179 
180 #ifndef SILC_SYMBIAN
181   if (silc_hash_list) {
182     silc_dlist_start(silc_hash_list);
183     while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
184       if (!strcmp(entry->name, name))
185 	break;
186     }
187   }
188 #else
189   {
190     /* On EPOC which don't have globals we check our constant hash list. */
191     int i;
192     for (i = 0; silc_default_hash[i].name; i++) {
193       if (!strcmp(silc_default_hash[i].name, name)) {
194 	entry = (SilcHashObject *)&(silc_default_hash[i]);
195 	break;
196       }
197     }
198   }
199 #endif /* SILC_SYMBIAN */
200 
201   if (entry) {
202     *new_hash = silc_calloc(1, sizeof(**new_hash));
203     if (!(*new_hash))
204       return FALSE;
205     (*new_hash)->hash = entry;
206     (*new_hash)->context = silc_calloc(1, entry->context_len());
207     if (!(*new_hash)->context) {
208       silc_free(*new_hash);
209       return FALSE;
210     }
211     return TRUE;
212   }
213 
214   return FALSE;
215 }
216 
217 /* Allocate hash by OID string */
218 
silc_hash_alloc_by_oid(const char * oid,SilcHash * new_hash)219 SilcBool silc_hash_alloc_by_oid(const char *oid, SilcHash *new_hash)
220 {
221   SilcHashObject *entry = NULL;
222 
223   SILC_LOG_DEBUG(("Allocating new hash %s", oid));
224 
225 #ifndef SILC_SYMBIAN
226   if (silc_hash_list) {
227     silc_dlist_start(silc_hash_list);
228     while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
229       if (!strcmp(entry->oid, oid))
230 	break;
231     }
232   }
233 #else
234   {
235     /* On EPOC which don't have globals we check our constant hash list. */
236     int i;
237     for (i = 0; silc_default_hash[i].oid; i++) {
238       if (!strcmp(silc_default_hash[i].oid, oid)) {
239 	entry = (SilcHashObject *)&(silc_default_hash[i]);
240 	break;
241       }
242     }
243   }
244 #endif /* SILC_SYMBIAN */
245 
246   if (entry) {
247     *new_hash = silc_calloc(1, sizeof(**new_hash));
248     if (!(*new_hash))
249       return FALSE;
250     (*new_hash)->hash = entry;
251     (*new_hash)->context = silc_calloc(1, entry->context_len());
252     if (!(*new_hash)->context) {
253       silc_free(*new_hash);
254       return FALSE;
255     }
256     return TRUE;
257   }
258 
259   return FALSE;
260 }
261 
262 /* Free's the SilcHash object */
263 
silc_hash_free(SilcHash hash)264 void silc_hash_free(SilcHash hash)
265 {
266   if (hash) {
267     silc_free(hash->context);
268     silc_free(hash);
269   }
270 }
271 
272 /* Returns the length of the hash digest. */
273 
silc_hash_len(SilcHash hash)274 SilcUInt32 silc_hash_len(SilcHash hash)
275 {
276   return hash->hash->hash_len;
277 }
278 
279 /* Returns the block lenght of the hash. */
280 
silc_hash_block_len(SilcHash hash)281 SilcUInt32 silc_hash_block_len(SilcHash hash)
282 {
283   return hash->hash->block_len;
284 }
285 
286 /* Returns the name of the hash function */
287 
silc_hash_get_name(SilcHash hash)288 const char *silc_hash_get_name(SilcHash hash)
289 {
290   return hash->hash->name;
291 }
292 
293 /* Returns hash OID string */
294 
silc_hash_get_oid(SilcHash hash)295 const char *silc_hash_get_oid(SilcHash hash)
296 {
297   return hash->hash->oid;
298 }
299 
300 /* Returns TRUE if hash algorithm `name' is supported. */
301 
silc_hash_is_supported(const unsigned char * name)302 SilcBool silc_hash_is_supported(const unsigned char *name)
303 {
304 #ifndef SILC_SYMBIAN
305   SilcHashObject *entry;
306 
307   if (silc_hash_list) {
308     silc_dlist_start(silc_hash_list);
309     while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
310       if (!strcmp(entry->name, name))
311 	return TRUE;
312     }
313   }
314 #else
315   {
316     int i;
317     for (i = 0; silc_default_hash[i].name; i++)
318       if (!strcmp(silc_default_hash[i].name, name))
319 	return TRUE;
320   }
321 #endif /* SILC_SYMBIAN */
322   return FALSE;
323 }
324 
325 /* Returns comma separated list of supported hash functions. */
326 
silc_hash_get_supported(void)327 char *silc_hash_get_supported(void)
328 {
329   SilcHashObject *entry;
330   char *list = NULL;
331   int len = 0;
332 
333 #ifndef SILC_SYMBIAN
334   if (silc_hash_list) {
335     silc_dlist_start(silc_hash_list);
336     while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
337       len += strlen(entry->name);
338       list = silc_realloc(list, len + 1);
339 
340       memcpy(list + (len - strlen(entry->name)),
341 	     entry->name, strlen(entry->name));
342       memcpy(list + len, ",", 1);
343       len++;
344     }
345   }
346 #else
347   {
348     int i;
349     for (i = 0; silc_default_hash[i].name; i++) {
350       entry = (SilcHashObject *)&(silc_default_hash[i]);
351       len += strlen(entry->name);
352       list = silc_realloc(list, len + 1);
353 
354       memcpy(list + (len - strlen(entry->name)),
355 	     entry->name, strlen(entry->name));
356       memcpy(list + len, ",", 1);
357       len++;
358     }
359   }
360 #endif /* SILC_SYMBIAN */
361 
362   if (list)
363     list[len - 1] = 0;
364 
365   return list;
366 }
367 
368 /* Creates the hash value and returns it to the return_hash argument. */
369 
silc_hash_make(SilcHash hash,const unsigned char * data,SilcUInt32 len,unsigned char * return_hash)370 void silc_hash_make(SilcHash hash, const unsigned char *data,
371 		    SilcUInt32 len, unsigned char *return_hash)
372 {
373   silc_hash_init(hash);
374   silc_hash_update(hash, data, len);
375   silc_hash_final(hash, return_hash);
376 }
377 
silc_hash_init(SilcHash hash)378 void silc_hash_init(SilcHash hash)
379 {
380   hash->hash->init(hash->context);
381 }
382 
silc_hash_update(SilcHash hash,const unsigned char * data,SilcUInt32 data_len)383 void silc_hash_update(SilcHash hash, const unsigned char *data,
384 		      SilcUInt32 data_len)
385 {
386   hash->hash->update(hash->context, (unsigned char *)data, data_len);
387 }
388 
silc_hash_final(SilcHash hash,unsigned char * return_hash)389 void silc_hash_final(SilcHash hash, unsigned char *return_hash)
390 {
391   hash->hash->final(hash->context, return_hash);
392 }
393 
silc_hash_transform(SilcHash hash,SilcUInt32 * state,const unsigned char * data)394 void silc_hash_transform(SilcHash hash, SilcUInt32 *state,
395 			 const unsigned char *data)
396 {
397   hash->hash->transform(state, data);
398 }
399 
400 /* Creates fingerprint of the data. If `hash' is NULL SHA1 is used as
401    default hash function. The returned fingerprint must be freed by the
402    caller. */
403 
silc_hash_fingerprint(SilcHash hash,const unsigned char * data,SilcUInt32 data_len)404 char *silc_hash_fingerprint(SilcHash hash, const unsigned char *data,
405 			    SilcUInt32 data_len)
406 {
407   SilcHash new_hash = NULL;
408   unsigned char h[32];
409   char *ret;
410 
411   if (!hash) {
412     if (!silc_hash_alloc("sha1", &new_hash))
413       return NULL;
414     hash = new_hash;
415   }
416 
417   silc_hash_make(hash, data, data_len, h);
418   ret = silc_fingerprint(h, hash->hash->hash_len);
419 
420   if (new_hash != NULL)
421     silc_hash_free(new_hash);
422   return ret;
423 }
424 
425 static const char vo[]= "aeiouy";
426 static const char co[]= "bcdfghklmnprstvzx";
427 
428 /* Creates a babbleprint (Bubble Babble Encoding, developed by Antti
429    Huima (draft-huima-babble-01.txt)), by first computing real fingerprint
430    using `hash' or if NULL, then using SHA1, and then encoding the
431    fingerprint to the babbleprint. */
432 
silc_hash_babbleprint(SilcHash hash,const unsigned char * data,SilcUInt32 data_len)433 char *silc_hash_babbleprint(SilcHash hash, const unsigned char *data,
434 			    SilcUInt32 data_len)
435 {
436   SilcHash new_hash = NULL;
437   char *babbleprint;
438   unsigned char hval[32];
439   unsigned int a, b, c, d, e, check;
440   int i, k, out_len;
441 
442   if (!hash) {
443     if (!silc_hash_alloc("sha1", &new_hash))
444       return NULL;
445     hash = new_hash;
446   }
447 
448   /* Take fingerprint */
449   silc_hash_make(hash, data, data_len, hval);
450 
451   /* Encode babbleprint */
452   out_len = (((hash->hash->hash_len + 1) / 2) + 1) * 6;
453   babbleprint = silc_calloc(out_len, sizeof(*babbleprint));
454   if (!babbleprint) {
455     silc_hash_free(new_hash);
456     return NULL;
457   }
458   babbleprint[0] = co[16];
459 
460   check = 1;
461   for (i = 0, k = 1; i < hash->hash->hash_len - 1; i += 2, k += 6) {
462     a = (((hval[i] >> 6) & 3) + check) % 6;
463     b = (hval[i] >> 2) & 15;
464     c = ((hval[i] & 3) + (check / 6)) % 6;
465     d = (hval[i + 1] >> 4) & 15;
466     e = hval[i + 1] & 15;
467 
468     check = ((check * 5) + (hval[i] * 7) + hval[i + 1]) % 36;
469 
470     babbleprint[k + 0] = vo[a];
471     babbleprint[k + 1] = co[b];
472     babbleprint[k + 2] = vo[c];
473     babbleprint[k + 3] = co[d];
474     babbleprint[k + 4] = '-';
475     babbleprint[k + 5] = co[e];
476   }
477 
478   if ((hash->hash->hash_len % 2) != 0) {
479     a = (((hval[i] >> 6) & 3) + check) % 6;
480     b = (hval[i] >> 2) & 15;
481     c = ((hval[i] & 3) + (check / 6)) % 6;
482     babbleprint[k + 0] = vo[a];
483     babbleprint[k + 1] = co[b];
484     babbleprint[k + 2] = vo[c];
485   } else {
486     a = check % 6;
487     b = 16;
488     c = check / 6;
489     babbleprint[k + 0] = vo[a];
490     babbleprint[k + 1] = co[b];
491     babbleprint[k + 2] = vo[c];
492   }
493   babbleprint[k + 3] = co[16];
494 
495   if (new_hash != NULL)
496     silc_hash_free(new_hash);
497   return babbleprint;
498 }
499