Moved silc_client_ch[u]mode[_char] to client library from silc/.
[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.5  2000/10/09 11:37:21  priikone
24  *      bugfixes. Made public/private keys protocol compliant.
25  *
26  * Revision 1.4  2000/10/02 18:31:46  priikone
27  *      Added rijndael (AES) to cipher list.
28  *
29  * Revision 1.3  2000/09/28 11:28:20  priikone
30  *      Changed cipher list order.
31  *
32  * Revision 1.2  2000/07/05 06:08:43  priikone
33  *      Global cosmetic change.
34  *
35  * Revision 1.1.1.1  2000/06/27 11:36:54  priikone
36  *      Imported from internal CVS/Added Log headers.
37  *
38  *
39  */
40
41 #include "silcincludes.h"
42
43 #include "ciphers.h"            /* Includes cipher definitions */
44
45 /* List of all ciphers in SILC. You can dynamically add new ciphers
46    into the list. At the initialization of SILC this list is filled with
47    the configured ciphers. */
48 struct SilcCipherListStruct {
49   SilcCipherObject *cipher;
50   struct SilcCipherListStruct *next;
51 };
52
53 /* Dynamically registered list of ciphers. */
54 struct SilcCipherListStruct *silc_cipher_list = NULL;
55
56 /* XXX: add the other good ciphers here as well */
57
58 /* Staticly declared list of ciphers. This is used if system doesn't
59    support SIM's. */
60 SilcCipherObject silc_cipher_builtin_list[] =
61 {
62   { "twofish", 16, 16, silc_twofish_set_key, silc_twofish_set_key_with_string,
63     silc_twofish_encrypt_cbc, silc_twofish_decrypt_cbc, 
64     silc_twofish_context_len },
65   { "aes", 16, 16, silc_rijndael_set_key, 
66     silc_rijndael_set_key_with_string, silc_rijndael_encrypt_cbc,
67     silc_rijndael_decrypt_cbc, silc_rijndael_context_len },
68   { "rc6", 16, 16, silc_rc6_set_key, silc_rc6_set_key_with_string,
69     silc_rc6_encrypt_cbc, silc_rc6_decrypt_cbc, 
70     silc_rc6_context_len },
71   { "mars", 16, 16, silc_mars_set_key, silc_mars_set_key_with_string,
72     silc_mars_encrypt_cbc, silc_mars_decrypt_cbc, 
73     silc_mars_context_len },
74   { "none", 0, 0, silc_none_set_key, silc_none_set_key_with_string,
75     silc_none_encrypt_cbc, silc_none_decrypt_cbc, 
76     silc_none_context_len },
77
78   { NULL, 0, 0, NULL, NULL, NULL, NULL, NULL }
79 };
80
81 /* Register a new cipher into SILC. This is used at the initialization of
82    the SILC. This function allocates a new object for the cipher to be
83    registered. Therefore, if memory has been allocated for the object sent
84    as argument it has to be free'd after this function returns succesfully. */
85
86 int silc_cipher_register(SilcCipherObject *cipher)
87 {
88   struct SilcCipherListStruct *new, *c;
89
90   SILC_LOG_DEBUG(("Registering new cipher"));
91
92   new = silc_calloc(1, sizeof(*new));
93   new->cipher = silc_calloc(1, sizeof(*new->cipher));
94
95   /* Set the pointers */
96   new->cipher->name = strdup(cipher->name);
97   new->cipher->block_len = cipher->block_len;
98   new->cipher->key_len = cipher->key_len;
99   new->cipher->set_key = cipher->set_key;
100   new->cipher->set_key_with_string = cipher->set_key_with_string;
101   new->cipher->encrypt = cipher->encrypt;
102   new->cipher->decrypt = cipher->decrypt;
103   new->cipher->context_len = cipher->context_len;
104   new->next = NULL;
105
106   /* Add the new cipher to the list */
107   if (!silc_cipher_list) {
108     silc_cipher_list = new;
109     return TRUE;
110   }
111
112   c = silc_cipher_list;
113   while (c) {
114     if (!c->next) {
115       c->next = new;
116       break;
117     }
118     c = c->next;
119   }
120
121   return TRUE;
122 }
123
124 /* Unregister a cipher from the SILC. */
125
126 int silc_cipher_unregister(SilcCipherObject *cipher)
127 {
128   struct SilcCipherListStruct *c, *tmp;
129
130   SILC_LOG_DEBUG(("Unregistering cipher"));
131
132   c = silc_cipher_list;
133   
134   if (cipher == SILC_ALL_CIPHERS) {
135     /* Unregister all ciphers */
136     while (c) {
137       tmp = c->next;
138       silc_free(c->cipher->name);
139       silc_free(c);
140       c = tmp;
141     }
142
143     return TRUE;
144   }
145
146   /* Unregister the cipher */
147   if (c->cipher == cipher) {
148     tmp = c->next;
149     silc_free(c->cipher->name);
150     silc_free(c);
151     silc_cipher_list = tmp;
152     
153     return TRUE;
154   }
155
156   while (c) {
157     if (c->next->cipher == cipher) {
158
159       tmp = c->next->next;
160       silc_free(c->cipher->name);
161       silc_free(c);
162       c->next = tmp;
163
164       return TRUE;
165     }
166
167     c = c->next;
168   }
169
170   return FALSE;
171 }
172
173 /* Allocates a new SILC cipher object. Function returns 1 on succes and 0 
174    on error. The allocated cipher is returned in new_cipher argument. The
175    caller must set the key to the cipher after this function has returned
176    by calling the ciphers set_key function. */
177
178 int silc_cipher_alloc(const unsigned char *name, SilcCipher *new_cipher)
179 {
180   struct SilcCipherListStruct *c;
181   int i;
182
183   SILC_LOG_DEBUG(("Allocating new cipher object"));
184
185   /* Allocate the new object */
186   *new_cipher = silc_calloc(1, sizeof(**new_cipher));
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 }