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