Added stacktrace support with --enable-stack-trace option.
[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 #include "ciphers.h"            /* Includes cipher definitions */
24
25 #ifndef SILC_EPOC
26 /* Dynamically registered list of ciphers. */
27 SilcDList silc_cipher_list = NULL;
28 #endif /* SILC_EPOC */
29
30 /* Static list of ciphers for silc_cipher_register_default(). */
31 const SilcCipherObject silc_default_ciphers[] =
32 {
33   { "aes-256-cbc", 16, 256, silc_aes_set_key, 
34     silc_aes_set_key_with_string, silc_aes_encrypt_cbc,
35     silc_aes_decrypt_cbc, silc_aes_context_len },
36   { "aes-192-cbc", 16, 192, silc_aes_set_key, 
37     silc_aes_set_key_with_string, silc_aes_encrypt_cbc,
38     silc_aes_decrypt_cbc, silc_aes_context_len },
39   { "aes-128-cbc", 16, 128, silc_aes_set_key, 
40     silc_aes_set_key_with_string, silc_aes_encrypt_cbc,
41     silc_aes_decrypt_cbc, silc_aes_context_len },
42   { "twofish-256-cbc", 16, 256, silc_twofish_set_key, 
43     silc_twofish_set_key_with_string,
44     silc_twofish_encrypt_cbc, silc_twofish_decrypt_cbc, 
45     silc_twofish_context_len },
46   { "twofish-192-cbc", 16, 192, silc_twofish_set_key, 
47     silc_twofish_set_key_with_string,
48     silc_twofish_encrypt_cbc, silc_twofish_decrypt_cbc, 
49     silc_twofish_context_len },
50   { "twofish-128-cbc", 16, 128, silc_twofish_set_key, 
51     silc_twofish_set_key_with_string,
52     silc_twofish_encrypt_cbc, silc_twofish_decrypt_cbc, 
53     silc_twofish_context_len },
54   { "rc6-256-cbc", 16, 256, silc_rc6_set_key, silc_rc6_set_key_with_string,
55     silc_rc6_encrypt_cbc, silc_rc6_decrypt_cbc, 
56     silc_rc6_context_len },
57   { "rc6-192-cbc", 16, 192, silc_rc6_set_key, silc_rc6_set_key_with_string,
58     silc_rc6_encrypt_cbc, silc_rc6_decrypt_cbc, 
59     silc_rc6_context_len },
60   { "rc6-128-cbc", 16, 128, silc_rc6_set_key, silc_rc6_set_key_with_string,
61     silc_rc6_encrypt_cbc, silc_rc6_decrypt_cbc, 
62     silc_rc6_context_len },
63   { "mars-256-cbc", 16, 256, silc_mars_set_key, silc_mars_set_key_with_string,
64     silc_mars_encrypt_cbc, silc_mars_decrypt_cbc, 
65     silc_mars_context_len },
66   { "mars-192-cbc", 16, 192, silc_mars_set_key, silc_mars_set_key_with_string,
67     silc_mars_encrypt_cbc, silc_mars_decrypt_cbc, 
68     silc_mars_context_len },
69   { "mars-128-cbc", 16, 128, silc_mars_set_key, silc_mars_set_key_with_string,
70     silc_mars_encrypt_cbc, silc_mars_decrypt_cbc, 
71     silc_mars_context_len },
72   { "cast-256-cbc", 16, 256, silc_cast_set_key, silc_cast_set_key_with_string,
73     silc_cast_encrypt_cbc, silc_cast_decrypt_cbc, 
74     silc_cast_context_len },
75   { "cast-192-cbc", 16, 192, silc_cast_set_key, silc_cast_set_key_with_string,
76     silc_cast_encrypt_cbc, silc_cast_decrypt_cbc, 
77     silc_cast_context_len },
78   { "cast-128-cbc", 16, 128, silc_cast_set_key, silc_cast_set_key_with_string,
79     silc_cast_encrypt_cbc, silc_cast_decrypt_cbc, 
80     silc_cast_context_len },
81   { "none", 0, 0, silc_none_set_key, silc_none_set_key_with_string,
82     silc_none_encrypt_cbc, silc_none_decrypt_cbc, 
83     silc_none_context_len },
84
85   { NULL, 0, 0, NULL, NULL, NULL, NULL, NULL }
86 };
87
88 /* Register a new cipher into SILC. This is used at the initialization of
89    the SILC. This function allocates a new object for the cipher to be
90    registered. Therefore, if memory has been allocated for the object sent
91    as argument it has to be free'd after this function returns succesfully. */
92
93 bool silc_cipher_register(const SilcCipherObject *cipher)
94 {
95 #ifndef SILC_EPOC
96   SilcCipherObject *new;
97
98   SILC_LOG_DEBUG(("Registering new cipher `%s'", cipher->name));
99
100   /* Check if exists already */
101   if (silc_cipher_list) {
102     SilcCipherObject *entry;
103     silc_dlist_start(silc_cipher_list);
104     while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
105       if (!strcmp(entry->name, cipher->name))
106         return FALSE;
107     }
108   }
109
110   new = silc_calloc(1, sizeof(*new));
111   new->name = strdup(cipher->name);
112   new->block_len = cipher->block_len;
113   new->key_len = cipher->key_len;
114   new->set_key = cipher->set_key;
115   new->set_key_with_string = cipher->set_key_with_string;
116   new->encrypt = cipher->encrypt;
117   new->decrypt = cipher->decrypt;
118   new->context_len = cipher->context_len;
119
120   /* Add to list */
121   if (silc_cipher_list == NULL)
122     silc_cipher_list = silc_dlist_init();
123   silc_dlist_add(silc_cipher_list, new);
124
125 #endif /* SILC_EPOC */
126   return TRUE;
127 }
128
129 /* Unregister a cipher from the SILC. */
130
131 bool silc_cipher_unregister(SilcCipherObject *cipher)
132 {
133 #ifndef SILC_EPOC
134   SilcCipherObject *entry;
135
136   SILC_LOG_DEBUG(("Unregistering cipher"));
137
138   if (!silc_cipher_list)
139     return FALSE;
140
141   silc_dlist_start(silc_cipher_list);
142   while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
143     if (cipher == SILC_ALL_CIPHERS || entry == cipher) {
144       silc_dlist_del(silc_cipher_list, entry);
145       silc_free(entry->name);
146       silc_free(entry);
147
148       if (silc_dlist_count(silc_cipher_list) == 0) {
149         silc_dlist_uninit(silc_cipher_list);
150         silc_cipher_list = NULL;
151       }
152
153       return TRUE;
154     }
155   }
156
157 #endif /* SILC_EPOC */
158   return FALSE;
159 }
160
161 /* Function that registers all the default ciphers (all builtin ciphers). 
162    The application may use this to register the default ciphers if specific
163    ciphers in any specific order is not wanted. */
164
165 bool silc_cipher_register_default(void)
166 {
167 #ifndef SILC_EPOC
168   int i;
169
170   for (i = 0; silc_default_ciphers[i].name; i++)
171     silc_cipher_register(&(silc_default_ciphers[i]));
172
173 #endif /* SILC_EPOC */
174   return TRUE;
175 }
176
177 bool silc_cipher_unregister_all(void)
178 {
179 #ifndef SILC_EPOC
180   SilcCipherObject *entry;
181
182   if (!silc_cipher_list)
183     return FALSE;
184
185   silc_dlist_start(silc_cipher_list);
186   while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
187     silc_cipher_unregister(entry);
188     if (!silc_cipher_list)
189       break;
190   }
191 #endif /* SILC_EPOC */
192   return TRUE;
193 }
194
195 /* Allocates a new SILC cipher object. Function returns 1 on succes and 0 
196    on error. The allocated cipher is returned in new_cipher argument. The
197    caller must set the key to the cipher after this function has returned
198    by calling the ciphers set_key function. */
199
200 bool silc_cipher_alloc(const unsigned char *name, SilcCipher *new_cipher)
201 {
202   SilcCipherObject *entry = NULL;
203
204   SILC_LOG_DEBUG(("Allocating new cipher object"));
205   
206 #ifndef SILC_EPOC
207   if (silc_cipher_list) {
208     silc_dlist_start(silc_cipher_list);
209     while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
210       if (!strcmp(entry->name, name))
211         break;
212     }
213   }
214 #else
215   {
216     /* On EPOC which don't have globals we check our constant cipher list. */
217     int i;
218     for (i = 0; silc_default_ciphers[i].name; i++) {
219       if (!strcmp(silc_default_ciphers[i].name, name)) {
220         entry = (SilcCipherObject *)&(silc_default_ciphers[i]);
221         break;
222       }
223     }
224   }
225 #endif /* SILC_EPOC */
226
227   if (entry) {
228     *new_cipher = silc_calloc(1, sizeof(**new_cipher));
229     (*new_cipher)->cipher = entry; 
230     (*new_cipher)->context = silc_calloc(1, entry->context_len());
231     (*new_cipher)->set_iv = silc_cipher_set_iv;
232     (*new_cipher)->get_iv = silc_cipher_get_iv;
233     (*new_cipher)->get_key_len = silc_cipher_get_key_len;
234     (*new_cipher)->get_block_len = silc_cipher_get_block_len;
235     return TRUE;
236   }
237
238   return FALSE;
239 }
240
241 /* Free's the given cipher. */
242
243 void silc_cipher_free(SilcCipher cipher)
244 {
245   if (cipher) {
246     silc_free(cipher->context);
247     silc_free(cipher);
248   }
249 }
250
251 /* Returns TRUE if cipher `name' is supported. */
252
253 bool silc_cipher_is_supported(const unsigned char *name)
254 {
255 #ifndef SILC_EPOC
256   SilcCipherObject *entry;
257
258   if (silc_cipher_list) {
259     silc_dlist_start(silc_cipher_list);
260     while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
261       if (!strcmp(entry->name, name))
262         return TRUE;
263     }
264   }
265 #else
266   {
267     int i;
268     for (i = 0; silc_default_ciphers[i].name; i++)
269       if (!strcmp(silc_default_ciphers[i].name, name))
270         return TRUE;
271   }
272 #endif /* SILC_EPOC */
273   return FALSE;
274 }
275
276 /* Returns comma separated list of supported ciphers. */
277
278 char *silc_cipher_get_supported(void)
279 {
280   SilcCipherObject *entry;
281   char *list = NULL;
282   int len = 0;
283
284 #ifndef SILC_EPOC
285   if (silc_cipher_list) {
286     silc_dlist_start(silc_cipher_list);
287     while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
288       len += strlen(entry->name);
289       list = silc_realloc(list, len + 1);
290       
291       memcpy(list + (len - strlen(entry->name)), 
292              entry->name, strlen(entry->name));
293       memcpy(list + len, ",", 1);
294       len++;
295     }
296   }
297 #else
298   {
299     int i;
300     for (i = 0; silc_default_ciphers[i].name; i++) {
301       entry = (SilcCipherObject *)&(silc_default_ciphers[i]);
302       len += strlen(entry->name);
303       list = silc_realloc(list, len + 1);
304       
305       memcpy(list + (len - strlen(entry->name)), 
306              entry->name, strlen(entry->name));
307       memcpy(list + len, ",", 1);
308       len++;
309     }
310   }
311 #endif /* SILC_EPOC */
312
313   list[len - 1] = 0;
314
315   return list;
316 }
317
318 /* Encrypts */
319
320 bool silc_cipher_encrypt(SilcCipher cipher, const unsigned char *src,
321                          unsigned char *dst, SilcUInt32 len, 
322                          unsigned char *iv)
323 {
324   return cipher->cipher->encrypt(cipher->context, src, dst, len, iv);
325 }
326
327 /* Decrypts */
328
329 bool silc_cipher_decrypt(SilcCipher cipher, const unsigned char *src,
330                          unsigned char *dst, SilcUInt32 len, 
331                          unsigned char *iv)
332 {
333   return cipher->cipher->decrypt(cipher->context, src, dst, len, iv);
334 }
335
336 /* Sets the key for the cipher */
337
338 bool silc_cipher_set_key(SilcCipher cipher, const unsigned char *key,
339                          SilcUInt32 keylen)
340 {
341   return cipher->cipher->set_key(cipher->context, key, keylen);
342 }
343
344 /* Sets the IV (initial vector) for the cipher. */
345
346 void silc_cipher_set_iv(SilcCipher cipher, const unsigned char *iv)
347 {
348   memset(&cipher->iv, 0, sizeof(cipher->iv));
349   memcpy(&cipher->iv, iv, cipher->cipher->block_len);
350 }
351
352 /* Returns the IV (initial vector) of the cipher. The IV is returned 
353    to 'iv' argument. */
354
355 void silc_cipher_get_iv(SilcCipher cipher, unsigned char *iv)
356 {
357   memcpy(iv, &cipher->iv, cipher->cipher->block_len);
358 }
359
360 /* Returns the key length of the cipher. */
361
362 SilcUInt32 silc_cipher_get_key_len(SilcCipher cipher)
363 {
364   return cipher->cipher->key_len;
365 }
366
367 /* Returns the block size of the cipher. */
368
369 SilcUInt32 silc_cipher_get_block_len(SilcCipher cipher)
370 {
371   return cipher->cipher->block_len;
372 }