Added assembler AES for x86 and x86_64.
[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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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, 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->encrypt = cipher->encrypt;
111   new->decrypt = cipher->decrypt;
112   new->context_len = cipher->context_len;
113
114   /* Add to list */
115   if (silc_cipher_list == NULL)
116     silc_cipher_list = silc_dlist_init();
117   silc_dlist_add(silc_cipher_list, new);
118
119 #endif /* SILC_EPOC */
120   return TRUE;
121 }
122
123 /* Unregister a cipher from the SILC. */
124
125 SilcBool silc_cipher_unregister(SilcCipherObject *cipher)
126 {
127 #ifndef SILC_EPOC
128   SilcCipherObject *entry;
129
130   SILC_LOG_DEBUG(("Unregistering cipher"));
131
132   if (!silc_cipher_list)
133     return FALSE;
134
135   silc_dlist_start(silc_cipher_list);
136   while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
137     if (cipher == SILC_ALL_CIPHERS || entry == cipher) {
138       silc_dlist_del(silc_cipher_list, entry);
139       silc_free(entry->name);
140       silc_free(entry);
141
142       if (silc_dlist_count(silc_cipher_list) == 0) {
143         silc_dlist_uninit(silc_cipher_list);
144         silc_cipher_list = NULL;
145       }
146
147       return TRUE;
148     }
149   }
150
151 #endif /* SILC_EPOC */
152   return FALSE;
153 }
154
155 /* Function that registers all the default ciphers (all builtin ciphers).
156    The application may use this to register the default ciphers if specific
157    ciphers in any specific order is not wanted. */
158
159 SilcBool silc_cipher_register_default(void)
160 {
161 #ifndef SILC_EPOC
162   int i;
163
164   for (i = 0; silc_default_ciphers[i].name; i++)
165     silc_cipher_register(&(silc_default_ciphers[i]));
166
167 #endif /* SILC_EPOC */
168   return TRUE;
169 }
170
171 SilcBool silc_cipher_unregister_all(void)
172 {
173 #ifndef SILC_EPOC
174   SilcCipherObject *entry;
175
176   if (!silc_cipher_list)
177     return FALSE;
178
179   silc_dlist_start(silc_cipher_list);
180   while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
181     silc_cipher_unregister(entry);
182     if (!silc_cipher_list)
183       break;
184   }
185 #endif /* SILC_EPOC */
186   return TRUE;
187 }
188
189 /* Allocates a new SILC cipher object. Function returns 1 on succes and 0
190    on error. The allocated cipher is returned in new_cipher argument. The
191    caller must set the key to the cipher after this function has returned
192    by calling the ciphers set_key function. */
193
194 SilcBool silc_cipher_alloc(const unsigned char *name, SilcCipher *new_cipher)
195 {
196   SilcCipherObject *entry = NULL;
197
198   SILC_LOG_DEBUG(("Allocating new cipher object"));
199
200 #ifndef SILC_EPOC
201   if (silc_cipher_list) {
202     silc_dlist_start(silc_cipher_list);
203     while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
204       if (!strcmp(entry->name, name))
205         break;
206     }
207   }
208 #else
209   {
210     /* On EPOC which don't have globals we check our constant cipher list. */
211     int i;
212     for (i = 0; silc_default_ciphers[i].name; i++) {
213       if (!strcmp(silc_default_ciphers[i].name, name)) {
214         entry = (SilcCipherObject *)&(silc_default_ciphers[i]);
215         break;
216       }
217     }
218   }
219 #endif /* SILC_EPOC */
220
221   if (entry) {
222     *new_cipher = silc_calloc(1, sizeof(**new_cipher));
223     (*new_cipher)->cipher = entry;
224     (*new_cipher)->context = silc_calloc(1, entry->context_len());
225     return TRUE;
226   }
227
228   return FALSE;
229 }
230
231 /* Free's the given cipher. */
232
233 void silc_cipher_free(SilcCipher cipher)
234 {
235   if (cipher) {
236     silc_free(cipher->context);
237     silc_free(cipher);
238   }
239 }
240
241 /* Returns TRUE if cipher `name' is supported. */
242
243 SilcBool silc_cipher_is_supported(const unsigned char *name)
244 {
245 #ifndef SILC_EPOC
246   SilcCipherObject *entry;
247
248   if (silc_cipher_list) {
249     silc_dlist_start(silc_cipher_list);
250     while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
251       if (!strcmp(entry->name, name))
252         return TRUE;
253     }
254   }
255 #else
256   {
257     int i;
258     for (i = 0; silc_default_ciphers[i].name; i++)
259       if (!strcmp(silc_default_ciphers[i].name, name))
260         return TRUE;
261   }
262 #endif /* SILC_EPOC */
263   return FALSE;
264 }
265
266 /* Returns comma separated list of supported ciphers. */
267
268 char *silc_cipher_get_supported(void)
269 {
270   SilcCipherObject *entry;
271   char *list = NULL;
272   int len = 0;
273
274 #ifndef SILC_EPOC
275   if (silc_cipher_list) {
276     silc_dlist_start(silc_cipher_list);
277     while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
278       len += strlen(entry->name);
279       list = silc_realloc(list, len + 1);
280
281       memcpy(list + (len - strlen(entry->name)),
282              entry->name, strlen(entry->name));
283       memcpy(list + len, ",", 1);
284       len++;
285     }
286   }
287 #else
288   {
289     int i;
290     for (i = 0; silc_default_ciphers[i].name; i++) {
291       entry = (SilcCipherObject *)&(silc_default_ciphers[i]);
292       len += strlen(entry->name);
293       list = silc_realloc(list, len + 1);
294
295       memcpy(list + (len - strlen(entry->name)),
296              entry->name, strlen(entry->name));
297       memcpy(list + len, ",", 1);
298       len++;
299     }
300   }
301 #endif /* SILC_EPOC */
302
303   list[len - 1] = 0;
304
305   return list;
306 }
307
308 /* Encrypts */
309
310 SilcBool silc_cipher_encrypt(SilcCipher cipher, const unsigned char *src,
311                              unsigned char *dst, SilcUInt32 len,
312                              unsigned char *iv)
313 {
314   SILC_ASSERT((len & (cipher->cipher->block_len - 1)) == 0);
315   if (silc_unlikely(len & (cipher->cipher->block_len - 1)))
316     return FALSE;
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   if (silc_unlikely(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 SilcBool 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   memcpy(&cipher->iv, iv, cipher->cipher->iv_len);
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 }