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