Integer type name change.
[silc.git] / lib / silccrypt / silchash.c
1 /*
2
3   silchash.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 2001 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; either version 2 of the License, or
12   (at your option) any later version.
13   
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.
18
19 */
20 /* $Id$ */
21
22 #include "silcincludes.h"
23
24 #include "md5.h"
25 #include "sha1.h"
26
27 /* List of dynamically registered hash functions. */
28 SilcDList silc_hash_list = NULL;
29
30 /* Default hash functions for silc_hash_register_default(). */
31 SilcHashObject silc_default_hash[] = 
32 {
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 },
37
38   { NULL, 0, 0, NULL, NULL, NULL, NULL, NULL }
39 };
40
41 /* Registers a new hash function into the SILC. This function is used at
42    the initialization of the SILC. */
43
44 bool silc_hash_register(SilcHashObject *hash)
45 {
46   SilcHashObject *new;
47
48   SILC_LOG_DEBUG(("Registering new hash function `%s'", hash->name));
49
50   /* Check for existing */
51   if (silc_hash_list) {
52     SilcHashObject *entry;
53     silc_dlist_start(silc_hash_list);
54     while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
55       if (!strcmp(entry->name, hash->name))
56         return FALSE;
57     }
58   }
59
60   new = silc_calloc(1, sizeof(*new));
61   new->name = strdup(hash->name);
62   new->hash_len = hash->hash_len;
63   new->block_len = hash->block_len;
64   new->init = hash->init;
65   new->update = hash->update;
66   new->final = hash->final;
67   new->transform = hash->transform;
68   new->context_len = hash->context_len;
69
70   /* Add to list */
71   if (silc_hash_list == NULL)
72     silc_hash_list = silc_dlist_init();
73   silc_dlist_add(silc_hash_list, new);
74
75   return TRUE;
76 }
77
78 /* Unregister a hash function from the SILC. */
79
80 bool silc_hash_unregister(SilcHashObject *hash)
81 {
82   SilcHashObject *entry;
83
84   SILC_LOG_DEBUG(("Unregistering hash function"));
85
86   if (!silc_hash_list)
87     return FALSE;
88
89   silc_dlist_start(silc_hash_list);
90   while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
91     if (hash == SILC_ALL_HASH_FUNCTIONS || entry == hash) {
92       silc_dlist_del(silc_hash_list, entry);
93
94       if (silc_dlist_count(silc_hash_list) == 0) {
95         silc_dlist_uninit(silc_hash_list);
96         silc_hash_list = NULL;
97       }
98
99       return TRUE;
100     }
101   }
102
103   return FALSE;
104 }
105
106 /* Function that registers all the default hash funcs (all builtin ones). 
107    The application may use this to register the default hash funcs if
108    specific hash funcs in any specific order is not wanted. */
109
110 bool silc_hash_register_default(void)
111 {
112   int i;
113
114   for (i = 0; silc_default_hash[i].name; i++)
115     silc_hash_register(&(silc_default_hash[i]));
116
117   return TRUE;
118 }
119
120 /* Allocates a new SilcHash object. New object is returned into new_hash
121    argument. */
122
123 bool silc_hash_alloc(const unsigned char *name, SilcHash *new_hash)
124 {
125   SilcHashObject *entry;
126   
127   SILC_LOG_DEBUG(("Allocating new hash object"));
128
129   if (silc_hash_list) {
130     silc_dlist_start(silc_hash_list);
131     while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
132       if (!strcmp(entry->name, name)) {
133         *new_hash = silc_calloc(1, sizeof(**new_hash));
134         (*new_hash)->hash = entry;
135         (*new_hash)->context = silc_calloc(1, entry->context_len());
136         (*new_hash)->make_hash = silc_hash_make;
137         return TRUE;
138       }
139     }
140   }
141
142   return FALSE;
143 }
144
145 /* Free's the SilcHash object */
146
147 void silc_hash_free(SilcHash hash)
148 {
149   if (hash) {
150     silc_free(hash->context);
151     silc_free(hash);
152   }
153 }
154
155 /* Returns the length of the hash digest. */
156
157 SilcUInt32 silc_hash_len(SilcHash hash)
158 {
159   return hash->hash->hash_len;
160 }
161
162 /* Returns TRUE if hash algorithm `name' is supported. */
163
164 bool silc_hash_is_supported(const unsigned char *name)
165 {
166   SilcHashObject *entry;
167
168   if (silc_hash_list) {
169     silc_dlist_start(silc_hash_list);
170     while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
171       if (!strcmp(entry->name, name))
172         return TRUE;
173     }
174   }
175
176   return FALSE;
177 }
178
179 /* Returns comma separated list of supported hash functions. */
180
181 char *silc_hash_get_supported(void)
182 {
183   SilcHashObject *entry;
184   char *list = NULL;
185   int len;
186
187   len = 0;
188   if (silc_hash_list) {
189     silc_dlist_start(silc_hash_list);
190     while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
191       len += strlen(entry->name);
192       list = silc_realloc(list, len + 1);
193       
194       memcpy(list + (len - strlen(entry->name)), 
195              entry->name, strlen(entry->name));
196       memcpy(list + len, ",", 1);
197       len++;
198     }
199     list[len - 1] = 0;
200   }
201
202   return list;
203 }
204
205 /* Creates the hash value and returns it to the return_hash argument. */
206
207 void silc_hash_make(SilcHash hash, const unsigned char *data, 
208                     SilcUInt32 len, unsigned char *return_hash)
209 {
210   hash->hash->init(hash->context);
211   hash->hash->update(hash->context, (unsigned char *)data, len);
212   hash->hash->final(hash->context, return_hash);
213 }
214
215 /* Creates fingerprint of the data. If `hash' is NULL SHA1 is used as
216    default hash function. The returned fingerprint must be free's by the
217    caller. */
218
219 char *silc_hash_fingerprint(SilcHash hash, const unsigned char *data,
220                             SilcUInt32 data_len)
221 {
222   SilcHash new_hash = NULL;
223   unsigned char h[32];
224   char *ret;
225
226   if (!hash) {
227     silc_hash_alloc("sha1", &new_hash);
228     hash = new_hash;
229   }
230
231   silc_hash_make(hash, data, data_len, h);
232   ret = silc_fingerprint(h, hash->hash->hash_len);
233
234   if (new_hash != NULL)
235     silc_hash_free(new_hash);
236   return ret;
237 }
238
239 static const char vo[]= "aeiouy";
240 static const char co[]= "bcdfghklmnprstvzx";
241
242 /* Creates a babbleprint (Bubble Babble Encoding, developed by Antti
243    Huima (draft-huima-babble-01.txt)), by first computing real fingerprint
244    using `hash' or if NULL, then using SHA1, and then encoding the
245    fingerprint to the babbleprint. */
246
247 char *silc_hash_babbleprint(SilcHash hash, const unsigned char *data,
248                             SilcUInt32 data_len)
249 {
250   SilcHash new_hash = NULL;
251   char *babbleprint;
252   unsigned char hval[32];
253   unsigned int a, b, c, d, e, check;
254   int i, k, out_len;
255
256   if (!hash) {
257     silc_hash_alloc("sha1", &new_hash);
258     hash = new_hash;
259   }
260
261   /* Take fingerprint */
262   silc_hash_make(hash, data, data_len, hval);
263
264   /* Encode babbleprint */
265   out_len = (((hash->hash->hash_len + 1) / 2) + 1) * 6;
266   babbleprint = silc_calloc(out_len, sizeof(*babbleprint));
267   babbleprint[0] = co[16];
268
269   check = 1;
270   for (i = 0, k = 1; i < hash->hash->hash_len - 1; i += 2, k += 6) { 
271     a = (((hval[i] >> 6) & 3) + check) % 6;
272     b = (hval[i] >> 2) & 15;
273     c = ((hval[i] & 3) + (check / 6)) % 6;
274     d = (hval[i + 1] >> 4) & 15;
275     e = hval[i + 1] & 15;
276     
277     check = ((check * 5) + (hval[i] * 7) + hval[i + 1]) % 36;
278     
279     babbleprint[k + 0] = vo[a];
280     babbleprint[k + 1] = co[b];
281     babbleprint[k + 2] = vo[c];
282     babbleprint[k + 3] = co[d];
283     babbleprint[k + 4] = '-';
284     babbleprint[k + 5] = co[e];
285   }
286
287   if ((hash->hash->hash_len % 2) != 0) {
288     a = (((hval[i] >> 6) & 3) + check) % 6;
289     b = (hval[i] >> 2) & 15;
290     c = ((hval[i] & 3) + (check / 6)) % 6;
291     babbleprint[k + 0] = vo[a];
292     babbleprint[k + 1] = co[b];
293     babbleprint[k + 2] = vo[c];
294   } else { 
295     a = check % 6;
296     b = 16;
297     c = check / 6;
298     babbleprint[k + 0] = vo[a];
299     babbleprint[k + 1] = co[b];
300     babbleprint[k + 2] = vo[c];
301   }
302   babbleprint[k + 3] = co[16];
303
304   if (new_hash != NULL)
305     silc_hash_free(new_hash);
306   return babbleprint;
307 }