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