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