e94a1b7a4ac6d51391748aab629ee960389f7673
[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 all hash functions in SILC. You can dynamically add new hash
28    functions into the list. At the initialization of SILC this list is 
29    filled with the configured hash functions. */
30 struct SilcHashListStruct {
31   SilcHashObject *hash;
32   struct SilcHashListStruct *next;
33 };
34
35 /* List of dynamically registered hash functions. */
36 struct SilcHashListStruct *silc_hash_list = NULL;
37
38 /* Statically declared list of hash functions. */
39 SilcHashObject silc_hash_builtin_list[] = 
40 {
41   { "sha1", 20, 64, silc_sha1_init, silc_sha1_update, silc_sha1_final,
42     silc_sha1_transform, silc_sha1_context_len },
43   { "md5", 16, 64, silc_md5_init, silc_md5_update, silc_md5_final,
44     silc_md5_transform, silc_md5_context_len },
45
46   { NULL, 0, 0, NULL, NULL, NULL, NULL, NULL }
47 };
48
49 /* Registers a new hash function into the SILC. This function is used at
50    the initialization of the SILC. */
51
52 int silc_hash_register(SilcHashObject *hash)
53 {
54   struct SilcHashListStruct *new, *h;
55
56   SILC_LOG_DEBUG(("Registering new hash function `%s'", hash->name));
57
58   new = silc_calloc(1, sizeof(*new));
59   new->hash = silc_calloc(1, sizeof(*new->hash));
60
61   /* Set the pointers */
62   new->hash->name = strdup(hash->name);
63   new->hash->hash_len = hash->hash_len;
64   new->hash->block_len = hash->block_len;
65   new->hash->init = hash->init;
66   new->hash->update = hash->update;
67   new->hash->final = hash->final;
68   new->hash->context_len = hash->context_len;
69   new->next = NULL;
70
71   /* Add the new hash function to the list */
72   if (!silc_hash_list) {
73     silc_hash_list = new;
74     return TRUE;
75   }
76
77   h = silc_hash_list;
78   while (h) {
79     if (!h->next) {
80       h->next = new;
81       break;
82     }
83     h = h->next;
84   }
85
86   return TRUE;
87 }
88
89 /* Unregister a hash function from the SILC. */
90
91 int silc_hash_unregister(SilcHashObject *hash)
92 {
93   struct SilcHashListStruct *h, *tmp;
94
95   SILC_LOG_DEBUG(("Unregistering hash function"));
96
97   h = silc_hash_list;
98
99   /* Unregister all hash functions */
100   if (hash == SILC_ALL_HASH_FUNCTIONS) {
101     /* Unregister all ciphers */
102     while (h) {
103       tmp = h->next;
104       silc_free(h->hash->name);
105       silc_free(h);
106       h = tmp;
107     }
108
109     return TRUE;
110   }
111
112   /* Unregister the hash function */
113   if (h->hash == hash) {
114     tmp = h->next;
115     silc_free(h->hash->name);
116     silc_free(h);
117     silc_hash_list = tmp;
118
119     return TRUE;
120   }
121
122   while (h) {
123     if (h->next->hash == hash) {
124       tmp = h->next->next;
125       silc_free(h->hash->name);
126       silc_free(h);
127       h->next = tmp;
128       return TRUE;
129     }
130
131     h = h->next;
132   }
133
134   return FALSE;
135 }
136
137 /* Allocates a new SilcHash object. New object is returned into new_hash
138    argument. */
139
140 int silc_hash_alloc(const unsigned char *name, SilcHash *new_hash)
141 {
142   struct SilcHashListStruct *h;
143   int i;
144   
145   SILC_LOG_DEBUG(("Allocating new hash object"));
146
147   /* Allocate the new object */
148   *new_hash = silc_calloc(1, sizeof(**new_hash));
149
150   if (silc_hash_list) {
151     h = silc_hash_list;
152     while (h) {
153       if (!strcmp(h->hash->name, name))
154         break;
155       h = h->next;
156     }
157
158     if (!h || !h->hash->context_len)
159       goto check_builtin;
160
161     /* Set the pointers */
162     (*new_hash)->hash = h->hash;
163     (*new_hash)->context = silc_calloc(1, h->hash->context_len());
164     (*new_hash)->make_hash = silc_hash_make;
165
166     return TRUE;
167   }
168
169  check_builtin:
170   for (i = 0; silc_hash_builtin_list[i].name; i++)
171     if (!strcmp(silc_hash_builtin_list[i].name, name))
172       break;
173
174   if (silc_hash_builtin_list[i].name == NULL) {
175     silc_free(*new_hash);
176     *new_hash = NULL;
177     return FALSE;
178   }
179   
180   /* Set the pointers */
181   (*new_hash)->hash = &silc_hash_builtin_list[i];
182   (*new_hash)->context = silc_calloc(1, (*new_hash)->hash->context_len());
183   (*new_hash)->make_hash = silc_hash_make;
184   
185   return TRUE;
186 }
187
188 /* Free's the SilcHash object */
189
190 void silc_hash_free(SilcHash hash)
191 {
192   if (hash) {
193     silc_free(hash->context);
194     silc_free(hash);
195   }
196 }
197
198 /* Returns the length of the hash digest. */
199
200 uint32 silc_hash_len(SilcHash hash)
201 {
202   return hash->hash->hash_len;
203 }
204
205 /* Returns TRUE if hash algorithm `name' is supported. */
206
207 int silc_hash_is_supported(const unsigned char *name)
208 {
209   struct SilcHashListStruct *h;
210   int i;
211
212   if (!name)
213     return FALSE;
214   
215   if (silc_hash_list) {
216     h = silc_hash_list;
217
218     while (h) {
219       if (!strcmp(h->hash->name, name))
220         return TRUE;
221       h = h->next;
222     }
223   }
224
225   for (i = 0; silc_hash_builtin_list[i].name; i++)
226     if (!strcmp(silc_hash_builtin_list[i].name, name))
227       return TRUE;
228
229   return FALSE;
230 }
231
232 /* Returns comma separated list of supported hash functions. */
233
234 char *silc_hash_get_supported()
235 {
236   char *list = NULL;
237   int i, len;
238   struct SilcHashListStruct *h;
239
240   len = 0;
241   if (silc_hash_list) {
242     h = silc_hash_list;
243
244     while (h) {
245       len += strlen(h->hash->name);
246       list = silc_realloc(list, len + 1);
247       
248       memcpy(list + (len - strlen(h->hash->name)), 
249              h->hash->name, strlen(h->hash->name));
250       memcpy(list + len, ",", 1);
251       len++;
252       
253       h = h->next;
254     }
255   }
256
257   for (i = 0; silc_hash_builtin_list[i].name; i++) {
258     len += strlen(silc_hash_builtin_list[i].name);
259     list = silc_realloc(list, len + 1);
260     
261     memcpy(list + (len - strlen(silc_hash_builtin_list[i].name)), 
262            silc_hash_builtin_list[i].name, 
263            strlen(silc_hash_builtin_list[i].name));
264     memcpy(list + len, ",", 1);
265     len++;
266   }
267
268   list[len - 1] = 0;
269
270   return list;
271 }
272
273 /* Creates the hash value and returns it to the return_hash argument. */
274
275 void silc_hash_make(SilcHash hash, const unsigned char *data, 
276                     uint32 len, unsigned char *return_hash)
277 {
278   hash->hash->init(hash->context);
279   hash->hash->update(hash->context, (unsigned char *)data, len);
280   hash->hash->final(hash->context, return_hash);
281 }
282
283 /* Creates fingerprint of the data. If `hash' is NULL SHA1 is used as
284    default hash function. The returned fingerprint must be free's by the
285    caller. */
286
287 char *silc_hash_fingerprint(SilcHash hash, const unsigned char *data,
288                             uint32 data_len)
289 {
290   char fingerprint[64], *cp;
291   unsigned char h[32];
292   int i;
293
294   if (!hash)
295     silc_hash_alloc("sha1", &hash);
296
297   silc_hash_make(hash, data, data_len, h);
298   
299   memset(fingerprint, 0, sizeof(fingerprint));
300   cp = fingerprint;
301   for (i = 0; i < hash->hash->hash_len; i++) {
302     snprintf(cp, sizeof(fingerprint), "%02X", h[i]);
303     cp += 2;
304     
305     if ((i + 1) % 2 == 0)
306       snprintf(cp++, sizeof(fingerprint), " ");
307
308     if ((i + 1) % 10 == 0)
309       snprintf(cp++, sizeof(fingerprint), " ");
310   }
311   
312   return strdup(fingerprint);
313 }