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