Initial revision
[silc.git] / lib / silccrypt / silccipher.c
1 /*
2
3   silccipher.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:54  priikone
24  * Initial revision
25  *
26  *
27  */
28
29 #include "silcincludes.h"
30
31 #include "ciphers.h"            /* Includes cipher definitions */
32
33 /* List of all ciphers in SILC. You can dynamically add new ciphers
34    into the list. At the initialization of SILC this list is filled with
35    the configured ciphers. */
36 struct SilcCipherListStruct {
37   SilcCipherObject *cipher;
38   struct SilcCipherListStruct *next;
39 };
40
41 /* Dynamically registered list of ciphers. */
42 struct SilcCipherListStruct *silc_cipher_list = NULL;
43
44 /* XXX: add the other good ciphers here as well */
45
46 /* Staticly declared list of ciphers. This is used if system doesn't
47    support SIM's. */
48 SilcCipherObject silc_cipher_builtin_list[] =
49 {
50   { "none", 0, 0, silc_none_set_key, silc_none_set_key_with_string,
51     silc_none_encrypt_cbc, silc_none_decrypt_cbc, 
52     silc_none_context_len },
53   { "twofish", 16, 16, silc_twofish_set_key, silc_twofish_set_key_with_string,
54     silc_twofish_encrypt_cbc, silc_twofish_decrypt_cbc, 
55     silc_twofish_context_len },
56   { "rc6", 16, 16, silc_rc6_set_key, silc_rc6_set_key_with_string,
57     silc_rc6_encrypt_cbc, silc_rc6_decrypt_cbc, 
58     silc_rc6_context_len },
59   { "mars", 16, 16, silc_mars_set_key, silc_mars_set_key_with_string,
60     silc_mars_encrypt_cbc, silc_mars_decrypt_cbc, 
61     silc_mars_context_len },
62
63   { NULL, 0, 0, NULL, NULL, NULL, NULL, NULL }
64 };
65
66 /* Register a new cipher into SILC. This is used at the initialization of
67    the SILC. This function allocates a new object for the cipher to be
68    registered. Therefore, if memory has been allocated for the object sent
69    as argument it has to be free'd after this function returns succesfully. */
70
71 int silc_cipher_register(SilcCipherObject *cipher)
72 {
73   struct SilcCipherListStruct *new, *c;
74
75   SILC_LOG_DEBUG(("Registering new cipher"));
76
77   new = silc_calloc(1, sizeof(*new));
78   if (!new) {
79     SILC_LOG_ERROR(("Could not allocate new cipher list object: %s",
80                     strerror(errno)));
81     return FALSE;
82   }
83
84   new->cipher = silc_calloc(1, sizeof(*new->cipher));
85   if (!new->cipher) {
86     SILC_LOG_ERROR(("Could not allocate new cipher object: %s",
87                     strerror(errno)));
88     return FALSE;
89   }
90
91   /* Set the pointers */
92   new->cipher->name = strdup(cipher->name);
93   new->cipher->block_len = cipher->block_len;
94   new->cipher->key_len = cipher->key_len;
95   new->cipher->set_key = cipher->set_key;
96   new->cipher->set_key_with_string = cipher->set_key_with_string;
97   new->cipher->encrypt = cipher->encrypt;
98   new->cipher->decrypt = cipher->decrypt;
99   new->cipher->context_len = cipher->context_len;
100   new->next = NULL;
101
102   /* Add the new cipher to the list */
103   if (!silc_cipher_list) {
104     silc_cipher_list = new;
105     return TRUE;
106   }
107
108   c = silc_cipher_list;
109   while (c) {
110     if (!c->next) {
111       c->next = new;
112       break;
113     }
114     c = c->next;
115   }
116
117   return TRUE;
118 }
119
120 /* Unregister a cipher from the SILC. */
121
122 int silc_cipher_unregister(SilcCipherObject *cipher)
123 {
124   struct SilcCipherListStruct *c, *tmp;
125
126   SILC_LOG_DEBUG(("Unregistering cipher"));
127
128   c = silc_cipher_list;
129   
130   if (cipher == SILC_ALL_CIPHERS) {
131     /* Unregister all ciphers */
132     while (c) {
133       tmp = c->next;
134       silc_free(c->cipher->name);
135       silc_free(c);
136       c = tmp;
137     }
138
139     return TRUE;
140   }
141
142   /* Unregister the cipher */
143   if (c->cipher == cipher) {
144     tmp = c->next;
145     silc_free(c->cipher->name);
146     silc_free(c);
147     silc_cipher_list = tmp;
148     
149     return TRUE;
150   }
151
152   while (c) {
153     if (c->next->cipher == cipher) {
154
155       tmp = c->next->next;
156       silc_free(c->cipher->name);
157       silc_free(c);
158       c->next = tmp;
159
160       return TRUE;
161     }
162
163     c = c->next;
164   }
165
166   return FALSE;
167 }
168
169 /* Allocates a new SILC cipher object. Function returns 1 on succes and 0 
170    on error. The allocated cipher is returned in new_cipher argument. The
171    caller must set the key to the cipher after this function has returned
172    by calling the ciphers set_key function. */
173
174 int silc_cipher_alloc(const unsigned char *name, SilcCipher *new_cipher)
175 {
176   struct SilcCipherListStruct *c;
177   int i;
178
179   SILC_LOG_DEBUG(("Allocating new cipher object"));
180
181   /* Allocate the new object */
182   *new_cipher = silc_calloc(1, sizeof(**new_cipher));
183   if (*new_cipher == NULL) {
184     SILC_LOG_ERROR(("Could not allocate new cipher object"));
185     return FALSE;
186   }
187   
188   if (silc_cipher_list) {
189
190     c = silc_cipher_list;
191     while (c) {
192       if (!strcmp(c->cipher->name, name))
193         break;
194       c = c->next;
195     }
196
197     if (!c)
198       goto check_builtin;
199
200     /* Set the pointers */
201     (*new_cipher)->cipher = c->cipher;
202     (*new_cipher)->context = silc_calloc(1, c->cipher->context_len());
203     (*new_cipher)->set_iv = silc_cipher_set_iv;
204     (*new_cipher)->get_iv = silc_cipher_get_iv;
205     (*new_cipher)->get_key_len = silc_cipher_get_key_len;
206     (*new_cipher)->get_block_len = silc_cipher_get_block_len;
207     
208     return TRUE;
209   }
210
211  check_builtin:
212
213   for (i = 0; silc_cipher_builtin_list[i].name; i++)
214     if (!strcmp(silc_cipher_builtin_list[i].name, name))
215       break;
216
217   if (silc_cipher_builtin_list[i].name == NULL) {
218     silc_free(*new_cipher);
219     return FALSE;
220   }
221
222   /* Set the pointers */
223   (*new_cipher)->cipher = &silc_cipher_builtin_list[i];
224   (*new_cipher)->context = 
225     silc_calloc(1, (*new_cipher)->cipher->context_len());
226   (*new_cipher)->set_iv = silc_cipher_set_iv;
227   (*new_cipher)->get_iv = silc_cipher_get_iv;
228   (*new_cipher)->get_key_len = silc_cipher_get_key_len;
229   (*new_cipher)->get_block_len = silc_cipher_get_block_len;
230   memset(&(*new_cipher)->iv, 0, sizeof((*new_cipher)->iv));
231
232   return TRUE;
233 }
234
235 /* Free's the given cipher. */
236
237 void silc_cipher_free(SilcCipher cipher)
238 {
239   if (cipher) {
240     silc_free(cipher->context);
241     silc_free(cipher);
242   }
243 }
244
245 /* Returns TRUE if cipher `name' is supported. */
246
247 int silc_cipher_is_supported(const unsigned char *name)
248 {
249   struct SilcCipherListStruct *c;
250   int i;
251
252   if (silc_cipher_list) {
253     c = silc_cipher_list;
254
255     while (c) {
256       if (!strcmp(c->cipher->name, name))
257         return TRUE;
258       c = c->next;
259     }
260   }
261
262   for (i = 0; silc_cipher_builtin_list[i].name; i++)
263     if (!strcmp(silc_cipher_builtin_list[i].name, name))
264       return TRUE;
265
266   return FALSE;
267 }
268
269 /* Returns comma separated list of supported ciphers. */
270
271 char *silc_cipher_get_supported()
272 {
273   char *list = NULL;
274   int i, len;
275   struct SilcCipherListStruct *c;
276
277   len = 0;
278   if (silc_cipher_list) {
279     c = silc_cipher_list;
280
281     while (c) {
282       len += strlen(c->cipher->name);
283       list = silc_realloc(list, len + 1);
284       
285       memcpy(list + (len - strlen(c->cipher->name)), 
286              c->cipher->name, strlen(c->cipher->name));
287       memcpy(list + len, ",", 1);
288       len++;
289       
290       c = c->next;
291     }
292   }
293
294   for (i = 0; silc_cipher_builtin_list[i].name; i++) {
295     len += strlen(silc_cipher_builtin_list[i].name);
296     list = silc_realloc(list, len + 1);
297     
298     memcpy(list + (len - strlen(silc_cipher_builtin_list[i].name)), 
299            silc_cipher_builtin_list[i].name, 
300            strlen(silc_cipher_builtin_list[i].name));
301     memcpy(list + len, ",", 1);
302     len++;
303   }
304
305   list[len - 1] = 0;
306
307   return list;
308 }
309
310 /* Sets the IV (initial vector) for the cipher. */
311
312 void silc_cipher_set_iv(SilcCipher itself, const unsigned char *iv)
313 {
314   memset(&itself->iv, 0, sizeof(itself->iv));
315   memcpy(&itself->iv, iv, itself->cipher->block_len);
316 }
317
318 /* Returns the IV (initial vector) of the cipher. The IV is returned 
319    to 'iv' argument. */
320
321 void silc_cipher_get_iv(SilcCipher itself, unsigned char *iv)
322 {
323   memcpy(iv, &itself->iv, itself->cipher->block_len);
324 }
325
326 /* Returns the key length of the cipher. */
327 /* XXX */
328
329 unsigned int silc_cipher_get_key_len(SilcCipher itself, 
330                                      const unsigned char *name)
331 {
332
333   return TRUE;
334 }
335
336 /* Returns the block size of the cipher. */
337 /* XXX */
338
339 unsigned int silc_cipher_get_block_len(SilcCipher itself)
340 {
341
342   return TRUE;
343 }