Rewrote crypto library init/uninit. Added silc_crypto_init
[crypto.git] / lib / silccrypt / silccipher.c
1 /*
2
3   silccipher.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2007 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_SYMBIAN
32 /* Dynamically registered list of ciphers. */
33 SilcDList silc_cipher_list = NULL;
34 #endif /* SILC_SYMBIAN */
35
36 /* Macro to define cipher to cipher list */
37 #define SILC_CIPHER_API_DEF(name, cipher, keylen, blocklen, ivlen, mode) \
38 { name, silc_##cipher##_set_key, silc_##cipher##_set_iv,                \
39   silc_##cipher##_encrypt, silc_##cipher##_decrypt,                     \
40   silc_##cipher##_context_len, keylen, blocklen, ivlen, mode }
41
42 /* Static list of ciphers for silc_cipher_register_default(). */
43 const SilcCipherObject silc_default_ciphers[] =
44 {
45   SILC_CIPHER_API_DEF("aes-256-ctr", aes_ctr, 256, 16, 16,
46                       SILC_CIPHER_MODE_CTR),
47   SILC_CIPHER_API_DEF("aes-192-ctr", aes_ctr, 192, 16, 16,
48                       SILC_CIPHER_MODE_CTR),
49   SILC_CIPHER_API_DEF("aes-128-ctr", aes_ctr, 128, 16, 16,
50                       SILC_CIPHER_MODE_CTR),
51   SILC_CIPHER_API_DEF("aes-256-cbc", aes_cbc, 256, 16, 16,
52                       SILC_CIPHER_MODE_CBC),
53   SILC_CIPHER_API_DEF("aes-192-cbc", aes_cbc, 192, 16, 16,
54                       SILC_CIPHER_MODE_CBC),
55   SILC_CIPHER_API_DEF("aes-128-cbc", aes_cbc, 128, 16, 16,
56                       SILC_CIPHER_MODE_CBC),
57   SILC_CIPHER_API_DEF("twofish-256-cbc", twofish_cbc, 256, 16, 16,
58                       SILC_CIPHER_MODE_CBC),
59   SILC_CIPHER_API_DEF("twofish-192-cbc", twofish_cbc, 192, 16, 16,
60                       SILC_CIPHER_MODE_CBC),
61   SILC_CIPHER_API_DEF("twofish-128-cbc", twofish_cbc, 128, 16, 16,
62                       SILC_CIPHER_MODE_CBC),
63 #ifdef SILC_DEBUG
64   SILC_CIPHER_API_DEF("none", none, 0, 0, 0, 0),
65 #endif /* SILC_DEBUG */
66   { NULL, NULL, 0, 0, 0, 0 }
67 };
68
69 /* Register new cipher */
70
71 SilcBool silc_cipher_register(const SilcCipherObject *cipher)
72 {
73 #ifndef SILC_SYMBIAN
74   SilcCipherObject *new;
75
76   SILC_LOG_DEBUG(("Registering new cipher `%s'", cipher->name));
77
78   /* Check if exists already */
79   if (silc_cipher_list) {
80     SilcCipherObject *entry;
81     silc_dlist_start(silc_cipher_list);
82     while ((entry = silc_dlist_get(silc_cipher_list))) {
83       if (!strcmp(entry->name, cipher->name))
84         return FALSE;
85     }
86   }
87
88   new = silc_calloc(1, sizeof(*new));
89   if (!new)
90     return FALSE;
91   new->name = strdup(cipher->name);
92   if (!new->name) {
93     silc_free(new);
94     return FALSE;
95   }
96   new->key_len = cipher->key_len;
97   new->block_len = cipher->block_len;
98   new->iv_len = cipher->iv_len;
99   new->set_key = cipher->set_key;
100   new->set_iv = cipher->set_iv;
101   new->encrypt = cipher->encrypt;
102   new->decrypt = cipher->decrypt;
103   new->context_len = cipher->context_len;
104   new->mode = cipher->mode;
105
106   /* Add to list */
107   if (silc_cipher_list == NULL)
108     silc_cipher_list = silc_dlist_init();
109   silc_dlist_add(silc_cipher_list, new);
110
111 #endif /* SILC_SYMBIAN */
112   return TRUE;
113 }
114
115 /* Unregister a cipher */
116
117 SilcBool silc_cipher_unregister(SilcCipherObject *cipher)
118 {
119 #ifndef SILC_SYMBIAN
120   SilcCipherObject *entry;
121
122   SILC_LOG_DEBUG(("Unregistering cipher"));
123
124   if (!silc_cipher_list)
125     return FALSE;
126
127   silc_dlist_start(silc_cipher_list);
128   while ((entry = silc_dlist_get(silc_cipher_list))) {
129     if (cipher == SILC_ALL_CIPHERS || entry == cipher) {
130       silc_dlist_del(silc_cipher_list, entry);
131       silc_free(entry->name);
132       silc_free(entry);
133
134       if (silc_dlist_count(silc_cipher_list) == 0) {
135         silc_dlist_uninit(silc_cipher_list);
136         silc_cipher_list = NULL;
137       }
138
139       return TRUE;
140     }
141   }
142
143 #endif /* SILC_SYMBIAN */
144   return FALSE;
145 }
146
147 /* Register default ciphers */
148
149 SilcBool silc_cipher_register_default(void)
150 {
151   /* We use builtin ciphers */
152   return TRUE;
153 }
154
155 /* Unregister all ciphers */
156
157 SilcBool silc_cipher_unregister_all(void)
158 {
159 #ifndef SILC_SYMBIAN
160   SilcCipherObject *entry;
161
162   if (!silc_cipher_list)
163     return FALSE;
164
165   silc_dlist_start(silc_cipher_list);
166   while ((entry = silc_dlist_get(silc_cipher_list))) {
167     silc_cipher_unregister(entry);
168     if (!silc_cipher_list)
169       break;
170   }
171 #endif /* SILC_SYMBIAN */
172   return TRUE;
173 }
174
175 /* Allocates a new SILC cipher object. Function returns 1 on succes and 0
176    on error. The allocated cipher is returned in new_cipher argument. The
177    caller must set the key to the cipher after this function has returned
178    by calling the ciphers set_key function. */
179
180 SilcBool silc_cipher_alloc(const unsigned char *name, SilcCipher *new_cipher)
181 {
182   SilcCipherObject *entry = NULL;
183   int i;
184
185   SILC_LOG_DEBUG(("Allocating new cipher object"));
186
187 #ifndef SILC_SYMBIAN
188   /* First check registered list of ciphers */
189   if (silc_cipher_list) {
190     silc_dlist_start(silc_cipher_list);
191     while ((entry = silc_dlist_get(silc_cipher_list))) {
192       if (!strcmp(entry->name, name))
193         break;
194     }
195   }
196 #endif /* SILC_SYMBIAN */
197
198   if (!entry) {
199     /* Check builtin list of ciphers */
200     for (i = 0; silc_default_ciphers[i].name; i++) {
201       if (!strcmp(silc_default_ciphers[i].name, name)) {
202         entry = (SilcCipherObject *)&(silc_default_ciphers[i]);
203         break;
204       }
205     }
206   }
207
208   if (entry) {
209     *new_cipher = silc_calloc(1, sizeof(**new_cipher));
210     if (!(*new_cipher))
211       return FALSE;
212     (*new_cipher)->cipher = entry;
213     (*new_cipher)->context = silc_calloc(1, entry->context_len());
214     if (!(*new_cipher)->context) {
215       silc_free(*new_cipher);
216       return FALSE;
217     }
218
219     return TRUE;
220   }
221
222   return FALSE;
223 }
224
225 /* Free's the given cipher. */
226
227 void silc_cipher_free(SilcCipher cipher)
228 {
229   if (cipher) {
230     silc_free(cipher->context);
231     silc_free(cipher);
232   }
233 }
234
235 /* Returns TRUE if cipher `name' is supported. */
236
237 SilcBool silc_cipher_is_supported(const unsigned char *name)
238 {
239   SilcCipherObject *entry;
240   int i;
241
242 #ifndef SILC_SYMBIAN
243   /* First check registered list of ciphers */
244   if (silc_cipher_list) {
245     silc_dlist_start(silc_cipher_list);
246     while ((entry = silc_dlist_get(silc_cipher_list))) {
247       if (!strcmp(entry->name, name))
248         return TRUE;
249     }
250   }
251 #endif /* SILC_SYMBIAN */
252
253   /* Check builtin list of ciphers */
254   for (i = 0; silc_default_ciphers[i].name; i++)
255     if (!strcmp(silc_default_ciphers[i].name, name))
256       return TRUE;
257
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, *entry2;
266   char *list = NULL;
267   int i, len = 0;
268
269 #ifndef SILC_SYMBIAN
270   if (silc_cipher_list) {
271     silc_dlist_start(silc_cipher_list);
272     while ((entry = silc_dlist_get(silc_cipher_list))) {
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 #endif /* SILC_SYMBIAN */
283
284   for (i = 0; silc_default_ciphers[i].name; i++) {
285     entry = (SilcCipherObject *)&(silc_default_ciphers[i]);
286
287     if (silc_cipher_list) {
288       silc_dlist_start(silc_cipher_list);
289       while ((entry2 = silc_dlist_get(silc_cipher_list))) {
290         if (!strcmp(entry2->name, entry->name))
291           break;
292       }
293       if (entry2)
294         continue;
295     }
296
297     len += strlen(entry->name);
298     list = silc_realloc(list, len + 1);
299
300     memcpy(list + (len - strlen(entry->name)),
301            entry->name, strlen(entry->name));
302     memcpy(list + len, ",", 1);
303     len++;
304   }
305
306   list[len - 1] = 0;
307
308   return list;
309 }
310
311 /* Encrypts */
312
313 SilcBool silc_cipher_encrypt(SilcCipher cipher, const unsigned char *src,
314                              unsigned char *dst, SilcUInt32 len,
315                              unsigned char *iv)
316 {
317   return cipher->cipher->encrypt(cipher->context, src, dst, len,
318                                  iv ? iv : cipher->iv);
319 }
320
321 /* Decrypts */
322
323 SilcBool silc_cipher_decrypt(SilcCipher cipher, const unsigned char *src,
324                              unsigned char *dst, SilcUInt32 len,
325                              unsigned char *iv)
326 {
327   return cipher->cipher->decrypt(cipher->context, src, dst, len,
328                                  iv ? iv : cipher->iv);
329 }
330
331 /* Sets the key for the cipher */
332
333 SilcBool silc_cipher_set_key(SilcCipher cipher, const unsigned char *key,
334                              SilcUInt32 keylen, SilcBool encryption)
335 {
336   return cipher->cipher->set_key(cipher->context, key, keylen, encryption);
337 }
338
339 /* Sets the IV (initial vector) for the cipher. */
340
341 void silc_cipher_set_iv(SilcCipher cipher, const unsigned char *iv)
342 {
343   if (iv)
344     memmove(&cipher->iv, iv, cipher->cipher->iv_len);
345   cipher->cipher->set_iv(cipher->context, iv);
346 }
347
348 /* Returns the IV (initial vector) of the cipher. */
349
350 unsigned char *silc_cipher_get_iv(SilcCipher cipher)
351 {
352   return cipher->iv;
353 }
354
355 /* Returns the key length of the cipher. */
356
357 SilcUInt32 silc_cipher_get_key_len(SilcCipher cipher)
358 {
359   return cipher->cipher->key_len;
360 }
361
362 /* Returns the block size of the cipher. */
363
364 SilcUInt32 silc_cipher_get_block_len(SilcCipher cipher)
365 {
366   return cipher->cipher->block_len;
367 }
368
369 /* Returns the IV length of the cipher. */
370
371 SilcUInt32 silc_cipher_get_iv_len(SilcCipher cipher)
372 {
373   return cipher->cipher->iv_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 }
382
383 /* Returns cipher mode */
384
385 SilcCipherMode silc_cipher_get_mode(SilcCipher cipher)
386 {
387   return cipher->cipher->mode;
388 }