Static analyzer bug fixes
[silc.git] / lib / silccrypt / silccipher.c
1 /*
2
3   silccipher.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2007 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; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19 /* $Id$ */
20
21 #include "silc.h"
22 #include "ciphers.h"            /* Includes cipher definitions */
23
24 /* The SilcCipher context */
25 struct SilcCipherStruct {
26   SilcCipherObject *cipher;
27   void *context;
28   unsigned char iv[SILC_CIPHER_MAX_IV_SIZE];
29 };
30
31 #ifndef SILC_SYMBIAN
32 /* Dynamically registered list of ciphers. */
33 SilcDList silc_cipher_list = NULL;
34 #endif /* SILC_SYMBIAN */
35
36 /* Macro to define cipher to cipher list */
37 #define SILC_CIPHER_API_DEF(name, cipher, keylen, blocklen, ivlen, mode) \
38 { name, silc_##cipher##_set_key, silc_##cipher##_set_iv,                \
39   silc_##cipher##_encrypt, silc_##cipher##_decrypt,                     \
40   silc_##cipher##_context_len, keylen, blocklen, ivlen, mode }
41
42 /* Static list of ciphers for silc_cipher_register_default(). */
43 const SilcCipherObject silc_default_ciphers[] =
44 {
45   SILC_CIPHER_API_DEF("aes-256-ctr", aes_ctr, 256, 16, 16,
46                       SILC_CIPHER_MODE_CTR),
47   SILC_CIPHER_API_DEF("aes-192-ctr", aes_ctr, 192, 16, 16,
48                       SILC_CIPHER_MODE_CTR),
49   SILC_CIPHER_API_DEF("aes-128-ctr", aes_ctr, 128, 16, 16,
50                       SILC_CIPHER_MODE_CTR),
51   SILC_CIPHER_API_DEF("aes-256-cbc", aes_cbc, 256, 16, 16,
52                       SILC_CIPHER_MODE_CBC),
53   SILC_CIPHER_API_DEF("aes-192-cbc", aes_cbc, 192, 16, 16,
54                       SILC_CIPHER_MODE_CBC),
55   SILC_CIPHER_API_DEF("aes-128-cbc", aes_cbc, 128, 16, 16,
56                       SILC_CIPHER_MODE_CBC),
57   SILC_CIPHER_API_DEF("twofish-256-cbc", twofish_cbc, 256, 16, 16,
58                       SILC_CIPHER_MODE_CBC),
59   SILC_CIPHER_API_DEF("twofish-192-cbc", twofish_cbc, 192, 16, 16,
60                       SILC_CIPHER_MODE_CBC),
61   SILC_CIPHER_API_DEF("twofish-128-cbc", twofish_cbc, 128, 16, 16,
62                       SILC_CIPHER_MODE_CBC),
63 #ifdef SILC_DEBUG
64   SILC_CIPHER_API_DEF("none", none, 0, 0, 0, 0),
65 #endif /* SILC_DEBUG */
66   { NULL, NULL, 0, 0, 0, 0 }
67 };
68
69 /* Register a new cipher into SILC. This is used at the initialization of
70    the SILC. This function allocates a new object for the cipher to be
71    registered. Therefore, if memory has been allocated for the object sent
72    as argument it has to be free'd after this function returns succesfully. */
73
74 SilcBool silc_cipher_register(const SilcCipherObject *cipher)
75 {
76 #ifndef SILC_SYMBIAN
77   SilcCipherObject *new;
78
79   SILC_LOG_DEBUG(("Registering new cipher `%s'", cipher->name));
80
81   /* Check if exists already */
82   if (silc_cipher_list) {
83     SilcCipherObject *entry;
84     silc_dlist_start(silc_cipher_list);
85     while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
86       if (!strcmp(entry->name, cipher->name))
87         return FALSE;
88     }
89   }
90
91   new = silc_calloc(1, sizeof(*new));
92   if (!new)
93     return FALSE;
94   new->name = strdup(cipher->name);
95   if (!new->name) {
96     silc_free(new);
97     return FALSE;
98   }
99   new->key_len = cipher->key_len;
100   new->block_len = cipher->block_len;
101   new->iv_len = cipher->iv_len;
102   new->set_key = cipher->set_key;
103   new->set_iv = cipher->set_iv;
104   new->encrypt = cipher->encrypt;
105   new->decrypt = cipher->decrypt;
106   new->context_len = cipher->context_len;
107   new->mode = cipher->mode;
108
109   /* Add to list */
110   if (silc_cipher_list == NULL)
111     silc_cipher_list = silc_dlist_init();
112   silc_dlist_add(silc_cipher_list, new);
113
114 #endif /* SILC_SYMBIAN */
115   return TRUE;
116 }
117
118 /* Unregister a cipher from the SILC. */
119
120 SilcBool silc_cipher_unregister(SilcCipherObject *cipher)
121 {
122 #ifndef SILC_SYMBIAN
123   SilcCipherObject *entry;
124
125   SILC_LOG_DEBUG(("Unregistering cipher"));
126
127   if (!silc_cipher_list)
128     return FALSE;
129
130   silc_dlist_start(silc_cipher_list);
131   while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
132     if (cipher == SILC_ALL_CIPHERS || entry == cipher) {
133       silc_dlist_del(silc_cipher_list, entry);
134       silc_free(entry->name);
135       silc_free(entry);
136
137       if (silc_dlist_count(silc_cipher_list) == 0) {
138         silc_dlist_uninit(silc_cipher_list);
139         silc_cipher_list = NULL;
140       }
141
142       return TRUE;
143     }
144   }
145
146 #endif /* SILC_SYMBIAN */
147   return FALSE;
148 }
149
150 /* Function that registers all the default ciphers (all builtin ciphers).
151    The application may use this to register the default ciphers if specific
152    ciphers in any specific order is not wanted. */
153
154 SilcBool silc_cipher_register_default(void)
155 {
156 #ifndef SILC_SYMBIAN
157   int i;
158
159   for (i = 0; silc_default_ciphers[i].name; i++)
160     silc_cipher_register(&(silc_default_ciphers[i]));
161
162 #endif /* SILC_SYMBIAN */
163   return TRUE;
164 }
165
166 SilcBool silc_cipher_unregister_all(void)
167 {
168 #ifndef SILC_SYMBIAN
169   SilcCipherObject *entry;
170
171   if (!silc_cipher_list)
172     return FALSE;
173
174   silc_dlist_start(silc_cipher_list);
175   while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
176     silc_cipher_unregister(entry);
177     if (!silc_cipher_list)
178       break;
179   }
180 #endif /* SILC_SYMBIAN */
181   return TRUE;
182 }
183
184 /* Allocates a new SILC cipher object. Function returns 1 on succes and 0
185    on error. The allocated cipher is returned in new_cipher argument. The
186    caller must set the key to the cipher after this function has returned
187    by calling the ciphers set_key function. */
188
189 SilcBool silc_cipher_alloc(const unsigned char *name, SilcCipher *new_cipher)
190 {
191   SilcCipherObject *entry = NULL;
192
193   SILC_LOG_DEBUG(("Allocating new cipher object"));
194
195 #ifndef SILC_SYMBIAN
196   if (silc_cipher_list) {
197     silc_dlist_start(silc_cipher_list);
198     while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
199       if (!strcmp(entry->name, name))
200         break;
201     }
202   }
203 #else
204   {
205     /* On EPOC which don't have globals we check our constant cipher list. */
206     int i;
207     for (i = 0; silc_default_ciphers[i].name; i++) {
208       if (!strcmp(silc_default_ciphers[i].name, name)) {
209         entry = (SilcCipherObject *)&(silc_default_ciphers[i]);
210         break;
211       }
212     }
213   }
214 #endif /* SILC_SYMBIAN */
215
216   if (entry) {
217     *new_cipher = silc_calloc(1, sizeof(**new_cipher));
218     if (!(*new_cipher))
219       return FALSE;
220     (*new_cipher)->cipher = entry;
221     (*new_cipher)->context = silc_calloc(1, entry->context_len());
222     if (!(*new_cipher)->context) {
223       silc_free(*new_cipher);
224       return FALSE;
225     }
226     return TRUE;
227   }
228
229   return FALSE;
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 SilcBool silc_cipher_is_supported(const unsigned char *name)
245 {
246 #ifndef SILC_SYMBIAN
247   SilcCipherObject *entry;
248
249   if (silc_cipher_list) {
250     silc_dlist_start(silc_cipher_list);
251     while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
252       if (!strcmp(entry->name, name))
253         return TRUE;
254     }
255   }
256 #else
257   {
258     int i;
259     for (i = 0; silc_default_ciphers[i].name; i++)
260       if (!strcmp(silc_default_ciphers[i].name, name))
261         return TRUE;
262   }
263 #endif /* SILC_SYMBIAN */
264   return FALSE;
265 }
266
267 /* Returns comma separated list of supported ciphers. */
268
269 char *silc_cipher_get_supported(void)
270 {
271   SilcCipherObject *entry;
272   char *list = NULL;
273   int len = 0;
274
275 #ifndef SILC_SYMBIAN
276   if (silc_cipher_list) {
277     silc_dlist_start(silc_cipher_list);
278     while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
279       len += strlen(entry->name);
280       list = silc_realloc(list, len + 1);
281
282       memcpy(list + (len - strlen(entry->name)),
283              entry->name, strlen(entry->name));
284       memcpy(list + len, ",", 1);
285       len++;
286     }
287   }
288 #else
289   {
290     int i;
291     for (i = 0; silc_default_ciphers[i].name; i++) {
292       entry = (SilcCipherObject *)&(silc_default_ciphers[i]);
293       len += strlen(entry->name);
294       list = silc_realloc(list, len + 1);
295
296       memcpy(list + (len - strlen(entry->name)),
297              entry->name, strlen(entry->name));
298       memcpy(list + len, ",", 1);
299       len++;
300     }
301   }
302 #endif /* SILC_SYMBIAN */
303
304   if (list)
305     list[len - 1] = 0;
306
307   return list;
308 }
309
310 /* Encrypts */
311
312 SilcBool silc_cipher_encrypt(SilcCipher cipher, const unsigned char *src,
313                              unsigned char *dst, SilcUInt32 len,
314                              unsigned char *iv)
315 {
316   return cipher->cipher->encrypt(cipher->context, src, dst, len,
317                                  iv ? iv : cipher->iv);
318 }
319
320 /* Decrypts */
321
322 SilcBool silc_cipher_decrypt(SilcCipher cipher, const unsigned char *src,
323                              unsigned char *dst, SilcUInt32 len,
324                              unsigned char *iv)
325 {
326   return cipher->cipher->decrypt(cipher->context, src, dst, len,
327                                  iv ? iv : cipher->iv);
328 }
329
330 /* Sets the key for the cipher */
331
332 SilcBool silc_cipher_set_key(SilcCipher cipher, const unsigned char *key,
333                              SilcUInt32 keylen, SilcBool encryption)
334 {
335   return cipher->cipher->set_key(cipher->context, key, keylen, encryption);
336 }
337
338 /* Sets the IV (initial vector) for the cipher. */
339
340 void silc_cipher_set_iv(SilcCipher cipher, const unsigned char *iv)
341 {
342   if (iv)
343     memmove(&cipher->iv, iv, cipher->cipher->iv_len);
344   cipher->cipher->set_iv(cipher->context, iv);
345 }
346
347 /* Returns the IV (initial vector) of the cipher. */
348
349 unsigned char *silc_cipher_get_iv(SilcCipher cipher)
350 {
351   return cipher->iv;
352 }
353
354 /* Returns the key length of the cipher. */
355
356 SilcUInt32 silc_cipher_get_key_len(SilcCipher cipher)
357 {
358   return cipher->cipher->key_len;
359 }
360
361 /* Returns the block size of the cipher. */
362
363 SilcUInt32 silc_cipher_get_block_len(SilcCipher cipher)
364 {
365   return cipher->cipher->block_len;
366 }
367
368 /* Returns the IV length of the cipher. */
369
370 SilcUInt32 silc_cipher_get_iv_len(SilcCipher cipher)
371 {
372   return cipher->cipher->iv_len;
373 }
374
375 /* Returns the name of the cipher */
376
377 const char *silc_cipher_get_name(SilcCipher cipher)
378 {
379   return (const char *)cipher->cipher->name;
380 }
381
382 /* Returns cipher mode */
383
384 SilcCipherMode silc_cipher_get_mode(SilcCipher cipher)
385 {
386   return cipher->cipher->mode;
387 }