Merged silc_1_1_branch to trunk.
[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   list[len - 1] = 0;
305
306   return list;
307 }
308
309 /* Encrypts */
310
311 SilcBool silc_cipher_encrypt(SilcCipher cipher, const unsigned char *src,
312                              unsigned char *dst, SilcUInt32 len,
313                              unsigned char *iv)
314 {
315   return cipher->cipher->encrypt(cipher->context, src, dst, len,
316                                  iv ? iv : cipher->iv);
317 }
318
319 /* Decrypts */
320
321 SilcBool silc_cipher_decrypt(SilcCipher cipher, const unsigned char *src,
322                              unsigned char *dst, SilcUInt32 len,
323                              unsigned char *iv)
324 {
325   return cipher->cipher->decrypt(cipher->context, src, dst, len,
326                                  iv ? iv : cipher->iv);
327 }
328
329 /* Sets the key for the cipher */
330
331 SilcBool silc_cipher_set_key(SilcCipher cipher, const unsigned char *key,
332                              SilcUInt32 keylen, SilcBool encryption)
333 {
334   return cipher->cipher->set_key(cipher->context, key, keylen, encryption);
335 }
336
337 /* Sets the IV (initial vector) for the cipher. */
338
339 void silc_cipher_set_iv(SilcCipher cipher, const unsigned char *iv)
340 {
341   if (iv)
342     memmove(&cipher->iv, iv, cipher->cipher->iv_len);
343   cipher->cipher->set_iv(cipher->context, iv);
344 }
345
346 /* Returns the IV (initial vector) of the cipher. */
347
348 unsigned char *silc_cipher_get_iv(SilcCipher cipher)
349 {
350   return cipher->iv;
351 }
352
353 /* Returns the key length of the cipher. */
354
355 SilcUInt32 silc_cipher_get_key_len(SilcCipher cipher)
356 {
357   return cipher->cipher->key_len;
358 }
359
360 /* Returns the block size of the cipher. */
361
362 SilcUInt32 silc_cipher_get_block_len(SilcCipher cipher)
363 {
364   return cipher->cipher->block_len;
365 }
366
367 /* Returns the IV length of the cipher. */
368
369 SilcUInt32 silc_cipher_get_iv_len(SilcCipher cipher)
370 {
371   return cipher->cipher->iv_len;
372 }
373
374 /* Returns the name of the cipher */
375
376 const char *silc_cipher_get_name(SilcCipher cipher)
377 {
378   return (const char *)cipher->cipher->name;
379 }
380
381 /* Returns cipher mode */
382
383 SilcCipherMode silc_cipher_get_mode(SilcCipher cipher)
384 {
385   return cipher->cipher->mode;
386 }