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