updates
[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
24 #include "ciphers.h"            /* Includes cipher definitions */
25
26 /* Dynamically registered list of ciphers. */
27 SilcDList silc_cipher_list = NULL;
28
29 /* Static list of ciphers for silc_cipher_register_default(). */
30 SilcCipherObject silc_default_ciphers[] =
31 {
32   { "aes-256-cbc", 16, 256, silc_aes_set_key, 
33     silc_aes_set_key_with_string, silc_aes_encrypt_cbc,
34     silc_aes_decrypt_cbc, silc_aes_context_len },
35   { "aes-192-cbc", 16, 192, silc_aes_set_key, 
36     silc_aes_set_key_with_string, silc_aes_encrypt_cbc,
37     silc_aes_decrypt_cbc, silc_aes_context_len },
38   { "aes-128-cbc", 16, 128, silc_aes_set_key, 
39     silc_aes_set_key_with_string, silc_aes_encrypt_cbc,
40     silc_aes_decrypt_cbc, silc_aes_context_len },
41   { "twofish-256-cbc", 16, 256, silc_twofish_set_key, 
42     silc_twofish_set_key_with_string,
43     silc_twofish_encrypt_cbc, silc_twofish_decrypt_cbc, 
44     silc_twofish_context_len },
45   { "twofish-192-cbc", 16, 192, silc_twofish_set_key, 
46     silc_twofish_set_key_with_string,
47     silc_twofish_encrypt_cbc, silc_twofish_decrypt_cbc, 
48     silc_twofish_context_len },
49   { "twofish-128-cbc", 16, 128, 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   { "rc6-256-cbc", 16, 256, silc_rc6_set_key, silc_rc6_set_key_with_string,
54     silc_rc6_encrypt_cbc, silc_rc6_decrypt_cbc, 
55     silc_rc6_context_len },
56   { "rc6-192-cbc", 16, 192, silc_rc6_set_key, silc_rc6_set_key_with_string,
57     silc_rc6_encrypt_cbc, silc_rc6_decrypt_cbc, 
58     silc_rc6_context_len },
59   { "rc6-128-cbc", 16, 128, silc_rc6_set_key, silc_rc6_set_key_with_string,
60     silc_rc6_encrypt_cbc, silc_rc6_decrypt_cbc, 
61     silc_rc6_context_len },
62   { "mars-256-cbc", 16, 256, silc_mars_set_key, silc_mars_set_key_with_string,
63     silc_mars_encrypt_cbc, silc_mars_decrypt_cbc, 
64     silc_mars_context_len },
65   { "mars-192-cbc", 16, 192, silc_mars_set_key, silc_mars_set_key_with_string,
66     silc_mars_encrypt_cbc, silc_mars_decrypt_cbc, 
67     silc_mars_context_len },
68   { "mars-128-cbc", 16, 128, silc_mars_set_key, silc_mars_set_key_with_string,
69     silc_mars_encrypt_cbc, silc_mars_decrypt_cbc, 
70     silc_mars_context_len },
71   { "cast-256-cbc", 16, 256, silc_cast_set_key, silc_cast_set_key_with_string,
72     silc_cast_encrypt_cbc, silc_cast_decrypt_cbc, 
73     silc_cast_context_len },
74   { "cast-192-cbc", 16, 192, silc_cast_set_key, silc_cast_set_key_with_string,
75     silc_cast_encrypt_cbc, silc_cast_decrypt_cbc, 
76     silc_cast_context_len },
77   { "cast-128-cbc", 16, 128, silc_cast_set_key, silc_cast_set_key_with_string,
78     silc_cast_encrypt_cbc, silc_cast_decrypt_cbc, 
79     silc_cast_context_len },
80   { "none", 0, 0, silc_none_set_key, silc_none_set_key_with_string,
81     silc_none_encrypt_cbc, silc_none_decrypt_cbc, 
82     silc_none_context_len },
83
84   { NULL, 0, 0, NULL, NULL, NULL, NULL, NULL }
85 };
86
87 /* Register a new cipher into SILC. This is used at the initialization of
88    the SILC. This function allocates a new object for the cipher to be
89    registered. Therefore, if memory has been allocated for the object sent
90    as argument it has to be free'd after this function returns succesfully. */
91
92 bool silc_cipher_register(SilcCipherObject *cipher)
93 {
94   SilcCipherObject *new;
95
96   SILC_LOG_DEBUG(("Registering new cipher `%s'", cipher->name));
97
98   new = silc_calloc(1, sizeof(*new));
99   new->name = strdup(cipher->name);
100   new->block_len = cipher->block_len;
101   new->key_len = cipher->key_len;
102   new->set_key = cipher->set_key;
103   new->set_key_with_string = cipher->set_key_with_string;
104   new->encrypt = cipher->encrypt;
105   new->decrypt = cipher->decrypt;
106   new->context_len = cipher->context_len;
107
108   /* Add to list */
109   if (silc_cipher_list == NULL)
110     silc_cipher_list = silc_dlist_init();
111   silc_dlist_add(silc_cipher_list, new);
112
113   return TRUE;
114 }
115
116 /* Unregister a cipher from the SILC. */
117
118 bool silc_cipher_unregister(SilcCipherObject *cipher)
119 {
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)) != SILC_LIST_END) {
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   return FALSE;
144 }
145
146 /* Function that registers all the default ciphers (all builtin ciphers). 
147    The application may use this to register the default ciphers if specific
148    ciphers in any specific order is not wanted. */
149
150 bool silc_cipher_register_default(void)
151 {
152   int i;
153
154   for (i = 0; silc_default_ciphers[i].name; i++)
155     silc_cipher_register(&(silc_default_ciphers[i]));
156
157   return TRUE;
158 }
159
160 /* Allocates a new SILC cipher object. Function returns 1 on succes and 0 
161    on error. The allocated cipher is returned in new_cipher argument. The
162    caller must set the key to the cipher after this function has returned
163    by calling the ciphers set_key function. */
164
165 bool silc_cipher_alloc(const unsigned char *name, SilcCipher *new_cipher)
166 {
167   SilcCipherObject *entry;
168
169   SILC_LOG_DEBUG(("Allocating new cipher object"));
170   
171   if (silc_cipher_list) {
172     silc_dlist_start(silc_cipher_list);
173     while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
174       if (!strcmp(entry->name, name)) {
175         *new_cipher = silc_calloc(1, sizeof(**new_cipher));
176         (*new_cipher)->cipher = entry; 
177         (*new_cipher)->context = silc_calloc(1, entry->context_len());
178         (*new_cipher)->set_iv = silc_cipher_set_iv;
179         (*new_cipher)->get_iv = silc_cipher_get_iv;
180         (*new_cipher)->get_key_len = silc_cipher_get_key_len;
181         (*new_cipher)->get_block_len = silc_cipher_get_block_len;
182         return TRUE;
183       }
184     }
185   }
186
187   return FALSE;
188 }
189
190 /* Free's the given cipher. */
191
192 void silc_cipher_free(SilcCipher cipher)
193 {
194   if (cipher) {
195     silc_free(cipher->context);
196     silc_free(cipher);
197   }
198 }
199
200 /* Returns TRUE if cipher `name' is supported. */
201
202 bool silc_cipher_is_supported(const unsigned char *name)
203 {
204   SilcCipherObject *entry;
205
206   if (silc_cipher_list) {
207     silc_dlist_start(silc_cipher_list);
208     while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
209       if (!strcmp(entry->name, name))
210         return TRUE;
211     }
212   }
213
214   return FALSE;
215 }
216
217 /* Returns comma separated list of supported ciphers. */
218
219 char *silc_cipher_get_supported(void)
220 {
221   SilcCipherObject *entry;
222   char *list = NULL;
223   int len;
224
225   len = 0;
226   if (silc_cipher_list) {
227     silc_dlist_start(silc_cipher_list);
228     while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
229       len += strlen(entry->name);
230       list = silc_realloc(list, len + 1);
231       
232       memcpy(list + (len - strlen(entry->name)), 
233              entry->name, strlen(entry->name));
234       memcpy(list + len, ",", 1);
235       len++;
236     }
237     list[len - 1] = 0;
238   }
239
240   return list;
241 }
242
243 /* Encrypts */
244
245 bool silc_cipher_encrypt(SilcCipher cipher, const unsigned char *src,
246                          unsigned char *dst, uint32 len, 
247                          unsigned char *iv)
248 {
249   return cipher->cipher->encrypt(cipher->context, src, dst, len, iv);
250 }
251
252 /* Decrypts */
253
254 bool silc_cipher_decrypt(SilcCipher cipher, const unsigned char *src,
255                          unsigned char *dst, uint32 len, 
256                          unsigned char *iv)
257 {
258   return cipher->cipher->decrypt(cipher->context, src, dst, len, iv);
259 }
260
261 /* Sets the key for the cipher */
262
263 bool silc_cipher_set_key(SilcCipher cipher, const unsigned char *key,
264                          uint32 keylen)
265 {
266   return cipher->cipher->set_key(cipher->context, key, keylen);
267 }
268
269 /* Sets the IV (initial vector) for the cipher. */
270
271 void silc_cipher_set_iv(SilcCipher cipher, const unsigned char *iv)
272 {
273   memset(&cipher->iv, 0, sizeof(cipher->iv));
274   memcpy(&cipher->iv, iv, cipher->cipher->block_len);
275 }
276
277 /* Returns the IV (initial vector) of the cipher. The IV is returned 
278    to 'iv' argument. */
279
280 void silc_cipher_get_iv(SilcCipher cipher, unsigned char *iv)
281 {
282   memcpy(iv, &cipher->iv, cipher->cipher->block_len);
283 }
284
285 /* Returns the key length of the cipher. */
286
287 uint32 silc_cipher_get_key_len(SilcCipher cipher)
288 {
289   return cipher->cipher->key_len;
290 }
291
292 /* Returns the block size of the cipher. */
293
294 uint32 silc_cipher_get_block_len(SilcCipher cipher)
295 {
296   return cipher->cipher->block_len;
297 }