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