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