addition of silc.css
[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   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;
59
60   /* Add to list */
61   if (silc_hash_list == NULL)
62     silc_hash_list = silc_dlist_init();
63   silc_dlist_add(silc_hash_list, new);
64
65   return TRUE;
66 }
67
68 /* Unregister a hash function from the SILC. */
69
70 bool silc_hash_unregister(SilcHashObject *hash)
71 {
72   SilcHashObject *entry;
73
74   SILC_LOG_DEBUG(("Unregistering hash function"));
75
76   if (!silc_hash_list)
77     return FALSE;
78
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);
83
84       if (silc_dlist_count(silc_hash_list) == 0) {
85         silc_dlist_uninit(silc_hash_list);
86         silc_hash_list = NULL;
87       }
88
89       return TRUE;
90     }
91   }
92
93   return FALSE;
94 }
95
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. */
99
100 bool silc_hash_register_default(void)
101 {
102   int i;
103
104   for (i = 0; silc_default_hash[i].name; i++)
105     silc_hash_register(&(silc_default_hash[i]));
106
107   return TRUE;
108 }
109
110 /* Allocates a new SilcHash object. New object is returned into new_hash
111    argument. */
112
113 bool silc_hash_alloc(const unsigned char *name, SilcHash *new_hash)
114 {
115   SilcHashObject *entry;
116   
117   SILC_LOG_DEBUG(("Allocating new hash object"));
118
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;
127         return TRUE;
128       }
129     }
130   }
131
132   return FALSE;
133 }
134
135 /* Free's the SilcHash object */
136
137 void silc_hash_free(SilcHash hash)
138 {
139   if (hash) {
140     silc_free(hash->context);
141     silc_free(hash);
142   }
143 }
144
145 /* Returns the length of the hash digest. */
146
147 uint32 silc_hash_len(SilcHash hash)
148 {
149   return hash->hash->hash_len;
150 }
151
152 /* Returns TRUE if hash algorithm `name' is supported. */
153
154 bool silc_hash_is_supported(const unsigned char *name)
155 {
156   SilcHashObject *entry;
157
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))
162         return TRUE;
163     }
164   }
165
166   return FALSE;
167 }
168
169 /* Returns comma separated list of supported hash functions. */
170
171 char *silc_hash_get_supported(void)
172 {
173   SilcHashObject *entry;
174   char *list = NULL;
175   int len;
176
177   len = 0;
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);
183       
184       memcpy(list + (len - strlen(entry->name)), 
185              entry->name, strlen(entry->name));
186       memcpy(list + len, ",", 1);
187       len++;
188     }
189     list[len - 1] = 0;
190   }
191
192   return list;
193 }
194
195 /* Creates the hash value and returns it to the return_hash argument. */
196
197 void silc_hash_make(SilcHash hash, const unsigned char *data, 
198                     uint32 len, unsigned char *return_hash)
199 {
200   hash->hash->init(hash->context);
201   hash->hash->update(hash->context, (unsigned char *)data, len);
202   hash->hash->final(hash->context, return_hash);
203 }
204
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
207    caller. */
208
209 char *silc_hash_fingerprint(SilcHash hash, const unsigned char *data,
210                             uint32 data_len)
211 {
212   char fingerprint[64], *cp;
213   unsigned char h[32];
214   int i;
215
216   if (!hash)
217     silc_hash_alloc("sha1", &hash);
218
219   silc_hash_make(hash, data, data_len, h);
220   
221   memset(fingerprint, 0, sizeof(fingerprint));
222   cp = fingerprint;
223   for (i = 0; i < hash->hash->hash_len; i++) {
224     snprintf(cp, sizeof(fingerprint), "%02X", h[i]);
225     cp += 2;
226     
227     if ((i + 1) % 2 == 0)
228       snprintf(cp++, sizeof(fingerprint), " ");
229
230     if ((i + 1) % 10 == 0)
231       snprintf(cp++, sizeof(fingerprint), " ");
232   }
233   i--;
234   if ((i + 1) % 2 == 0)
235     cp[-2] = 0;
236   if ((i + 1) % 10 == 0)
237     cp[-1] = 0;
238   
239   return strdup(fingerprint);
240 }
241
242 static const char vo[]= "aeiouy";
243 static const char co[]= "bcdfghklmnprstvzx";
244
245 /* Creates a babbleprint (Bubble Babble Encoding, developed by Antti
246    Huima (draft-huima-babble-01.txt)), by first computing real fingerprint
247    using `hash' or if NULL, then using SHA1, and then encoding the
248    fingerprint to the babbleprint. */
249
250 char *silc_hash_babbleprint(SilcHash hash, const unsigned char *data,
251                             uint32 data_len)
252 {
253   char *babbleprint;
254   unsigned char hval[32];
255   unsigned int a, b, c, d, e, check;
256   int i, k, out_len;
257
258   if (!hash)
259     silc_hash_alloc("sha1", &hash);
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   return babbleprint;
305 }