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