ddaeee010e43539c0a16eb9bf3021bce4b5141ee
[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   { "cast-256-cbc", 16, 256, silc_cast_set_key, silc_cast_set_key_with_string,
62     silc_cast_encrypt_cbc, silc_cast_decrypt_cbc, 
63     silc_cast_context_len },
64   { "cast-192-cbc", 16, 192, silc_cast_set_key, silc_cast_set_key_with_string,
65     silc_cast_encrypt_cbc, silc_cast_decrypt_cbc, 
66     silc_cast_context_len },
67   { "cast-128-cbc", 16, 128, silc_cast_set_key, silc_cast_set_key_with_string,
68     silc_cast_encrypt_cbc, silc_cast_decrypt_cbc, 
69     silc_cast_context_len },
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
74   { NULL, 0, 0, NULL, NULL, NULL, NULL, NULL }
75 };
76
77 /* Register a new cipher into SILC. This is used at the initialization of
78    the SILC. This function allocates a new object for the cipher to be
79    registered. Therefore, if memory has been allocated for the object sent
80    as argument it has to be free'd after this function returns succesfully. */
81
82 bool silc_cipher_register(const SilcCipherObject *cipher)
83 {
84 #ifndef SILC_EPOC
85   SilcCipherObject *new;
86
87   SILC_LOG_DEBUG(("Registering new cipher `%s'", cipher->name));
88
89   /* Check if exists already */
90   if (silc_cipher_list) {
91     SilcCipherObject *entry;
92     silc_dlist_start(silc_cipher_list);
93     while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
94       if (!strcmp(entry->name, cipher->name))
95         return FALSE;
96     }
97   }
98
99   new = silc_calloc(1, sizeof(*new));
100   new->name = strdup(cipher->name);
101   new->block_len = cipher->block_len;
102   new->key_len = cipher->key_len;
103   new->set_key = cipher->set_key;
104   new->set_key_with_string = cipher->set_key_with_string;
105   new->encrypt = cipher->encrypt;
106   new->decrypt = cipher->decrypt;
107   new->context_len = cipher->context_len;
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_EPOC */
115   return TRUE;
116 }
117
118 /* Unregister a cipher from the SILC. */
119
120 bool silc_cipher_unregister(SilcCipherObject *cipher)
121 {
122 #ifndef SILC_EPOC
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_EPOC */
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 bool silc_cipher_register_default(void)
155 {
156 #ifndef SILC_EPOC
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_EPOC */
163   return TRUE;
164 }
165
166 bool silc_cipher_unregister_all(void)
167 {
168 #ifndef SILC_EPOC
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_EPOC */
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 bool 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_EPOC
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_EPOC */
215
216   if (entry) {
217     *new_cipher = silc_calloc(1, sizeof(**new_cipher));
218     (*new_cipher)->cipher = entry; 
219     (*new_cipher)->context = silc_calloc(1, entry->context_len());
220     return TRUE;
221   }
222
223   return FALSE;
224 }
225
226 /* Free's the given cipher. */
227
228 void silc_cipher_free(SilcCipher cipher)
229 {
230   if (cipher) {
231     silc_free(cipher->context);
232     silc_free(cipher);
233   }
234 }
235
236 /* Returns TRUE if cipher `name' is supported. */
237
238 bool silc_cipher_is_supported(const unsigned char *name)
239 {
240 #ifndef SILC_EPOC
241   SilcCipherObject *entry;
242
243   if (silc_cipher_list) {
244     silc_dlist_start(silc_cipher_list);
245     while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
246       if (!strcmp(entry->name, name))
247         return TRUE;
248     }
249   }
250 #else
251   {
252     int i;
253     for (i = 0; silc_default_ciphers[i].name; i++)
254       if (!strcmp(silc_default_ciphers[i].name, name))
255         return TRUE;
256   }
257 #endif /* SILC_EPOC */
258   return FALSE;
259 }
260
261 /* Returns comma separated list of supported ciphers. */
262
263 char *silc_cipher_get_supported(void)
264 {
265   SilcCipherObject *entry;
266   char *list = NULL;
267   int len = 0;
268
269 #ifndef SILC_EPOC
270   if (silc_cipher_list) {
271     silc_dlist_start(silc_cipher_list);
272     while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
273       len += strlen(entry->name);
274       list = silc_realloc(list, len + 1);
275       
276       memcpy(list + (len - strlen(entry->name)), 
277              entry->name, strlen(entry->name));
278       memcpy(list + len, ",", 1);
279       len++;
280     }
281   }
282 #else
283   {
284     int i;
285     for (i = 0; silc_default_ciphers[i].name; i++) {
286       entry = (SilcCipherObject *)&(silc_default_ciphers[i]);
287       len += strlen(entry->name);
288       list = silc_realloc(list, len + 1);
289       
290       memcpy(list + (len - strlen(entry->name)), 
291              entry->name, strlen(entry->name));
292       memcpy(list + len, ",", 1);
293       len++;
294     }
295   }
296 #endif /* SILC_EPOC */
297
298   list[len - 1] = 0;
299
300   return list;
301 }
302
303 /* Encrypts */
304
305 bool silc_cipher_encrypt(SilcCipher cipher, const unsigned char *src,
306                          unsigned char *dst, SilcUInt32 len, 
307                          unsigned char *iv)
308 {
309 #ifdef SILC_DEBUG
310   assert((len & (cipher->cipher->block_len - 1)) == 0);
311 #endif
312   if (len & (cipher->cipher->block_len - 1))
313     return FALSE;
314   return cipher->cipher->encrypt(cipher->context, src, dst, len,
315                                  iv ? iv : cipher->iv);
316 }
317
318 /* Decrypts */
319
320 bool silc_cipher_decrypt(SilcCipher cipher, const unsigned char *src,
321                          unsigned char *dst, SilcUInt32 len, 
322                          unsigned char *iv)
323 {
324 #ifdef SILC_DEBUG
325   assert((len & (cipher->cipher->block_len - 1)) == 0);
326 #endif
327   if (len & (cipher->cipher->block_len - 1))
328     return FALSE;
329   return cipher->cipher->decrypt(cipher->context, src, dst, len,
330                                  iv ? iv : cipher->iv);
331 }
332
333 /* Sets the key for the cipher */
334
335 bool silc_cipher_set_key(SilcCipher cipher, const unsigned char *key,
336                          SilcUInt32 keylen)
337 {
338   return cipher->cipher->set_key(cipher->context, key, keylen);
339 }
340
341 /* Sets the IV (initial vector) for the cipher. */
342
343 void silc_cipher_set_iv(SilcCipher cipher, const unsigned char *iv)
344 {
345   memset(&cipher->iv, 0, sizeof(cipher->iv));
346   memcpy(&cipher->iv, iv, cipher->cipher->block_len);
347 }
348
349 /* Returns the IV (initial vector) of the cipher. */
350
351 unsigned char *silc_cipher_get_iv(SilcCipher cipher)
352 {
353   return cipher->iv;
354 }
355
356 /* Returns the key length of the cipher. */
357
358 SilcUInt32 silc_cipher_get_key_len(SilcCipher cipher)
359 {
360   return cipher->cipher->key_len;
361 }
362
363 /* Returns the block size of the cipher. */
364
365 SilcUInt32 silc_cipher_get_block_len(SilcCipher cipher)
366 {
367   return cipher->cipher->block_len;
368 }
369
370 /* Returns the name of the cipher */
371
372 const char *silc_cipher_get_name(SilcCipher cipher)
373 {
374   return (const char *)cipher->cipher->name;
375 }