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