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