5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2006 Pekka Riikonen
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.
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.
22 #include "ciphers.h" /* Includes cipher definitions */
24 /* The SilcCipher context */
25 struct SilcCipherStruct {
26 SilcCipherObject *cipher;
28 unsigned char iv[SILC_CIPHER_MAX_IV_SIZE];
32 /* Dynamically registered list of ciphers. */
33 SilcDList silc_cipher_list = NULL;
34 #endif /* SILC_EPOC */
36 /* Static list of ciphers for silc_cipher_register_default(). */
37 const SilcCipherObject silc_default_ciphers[] =
39 { "aes-256-cbc", 16, 256, silc_aes_set_key,
40 silc_aes_set_key_with_string, silc_aes_encrypt_cbc,
41 silc_aes_decrypt_cbc, silc_aes_context_len },
42 { "aes-192-cbc", 16, 192, silc_aes_set_key,
43 silc_aes_set_key_with_string, silc_aes_encrypt_cbc,
44 silc_aes_decrypt_cbc, silc_aes_context_len },
45 { "aes-128-cbc", 16, 128, silc_aes_set_key,
46 silc_aes_set_key_with_string, silc_aes_encrypt_cbc,
47 silc_aes_decrypt_cbc, silc_aes_context_len },
48 { "twofish-256-cbc", 16, 256, silc_twofish_set_key,
49 silc_twofish_set_key_with_string,
50 silc_twofish_encrypt_cbc, silc_twofish_decrypt_cbc,
51 silc_twofish_context_len },
52 { "twofish-192-cbc", 16, 192, silc_twofish_set_key,
53 silc_twofish_set_key_with_string,
54 silc_twofish_encrypt_cbc, silc_twofish_decrypt_cbc,
55 silc_twofish_context_len },
56 { "twofish-128-cbc", 16, 128, silc_twofish_set_key,
57 silc_twofish_set_key_with_string,
58 silc_twofish_encrypt_cbc, silc_twofish_decrypt_cbc,
59 silc_twofish_context_len },
60 { "cast-256-cbc", 16, 256, 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 { "cast-192-cbc", 16, 192, silc_cast_set_key, silc_cast_set_key_with_string,
64 silc_cast_encrypt_cbc, silc_cast_decrypt_cbc,
65 silc_cast_context_len },
66 { "cast-128-cbc", 16, 128, silc_cast_set_key, silc_cast_set_key_with_string,
67 silc_cast_encrypt_cbc, silc_cast_decrypt_cbc,
68 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 #endif /* SILC_DEBUG */
75 { NULL, 0, 0, NULL, NULL, NULL, NULL, NULL }
78 /* Register a new cipher into SILC. This is used at the initialization of
79 the SILC. This function allocates a new object for the cipher to be
80 registered. Therefore, if memory has been allocated for the object sent
81 as argument it has to be free'd after this function returns succesfully. */
83 SilcBool silc_cipher_register(const SilcCipherObject *cipher)
86 SilcCipherObject *new;
88 SILC_LOG_DEBUG(("Registering new cipher `%s'", cipher->name));
90 /* Check if exists already */
91 if (silc_cipher_list) {
92 SilcCipherObject *entry;
93 silc_dlist_start(silc_cipher_list);
94 while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
95 if (!strcmp(entry->name, cipher->name))
100 new = silc_calloc(1, sizeof(*new));
101 new->name = strdup(cipher->name);
102 new->block_len = cipher->block_len;
103 new->key_len = cipher->key_len;
104 new->set_key = cipher->set_key;
105 new->set_key_with_string = cipher->set_key_with_string;
106 new->encrypt = cipher->encrypt;
107 new->decrypt = cipher->decrypt;
108 new->context_len = cipher->context_len;
111 if (silc_cipher_list == NULL)
112 silc_cipher_list = silc_dlist_init();
113 silc_dlist_add(silc_cipher_list, new);
115 #endif /* SILC_EPOC */
119 /* Unregister a cipher from the SILC. */
121 SilcBool silc_cipher_unregister(SilcCipherObject *cipher)
124 SilcCipherObject *entry;
126 SILC_LOG_DEBUG(("Unregistering cipher"));
128 if (!silc_cipher_list)
131 silc_dlist_start(silc_cipher_list);
132 while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
133 if (cipher == SILC_ALL_CIPHERS || entry == cipher) {
134 silc_dlist_del(silc_cipher_list, entry);
135 silc_free(entry->name);
138 if (silc_dlist_count(silc_cipher_list) == 0) {
139 silc_dlist_uninit(silc_cipher_list);
140 silc_cipher_list = NULL;
147 #endif /* SILC_EPOC */
151 /* Function that registers all the default ciphers (all builtin ciphers).
152 The application may use this to register the default ciphers if specific
153 ciphers in any specific order is not wanted. */
155 SilcBool silc_cipher_register_default(void)
160 for (i = 0; silc_default_ciphers[i].name; i++)
161 silc_cipher_register(&(silc_default_ciphers[i]));
163 #endif /* SILC_EPOC */
167 SilcBool silc_cipher_unregister_all(void)
170 SilcCipherObject *entry;
172 if (!silc_cipher_list)
175 silc_dlist_start(silc_cipher_list);
176 while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
177 silc_cipher_unregister(entry);
178 if (!silc_cipher_list)
181 #endif /* SILC_EPOC */
185 /* Allocates a new SILC cipher object. Function returns 1 on succes and 0
186 on error. The allocated cipher is returned in new_cipher argument. The
187 caller must set the key to the cipher after this function has returned
188 by calling the ciphers set_key function. */
190 SilcBool silc_cipher_alloc(const unsigned char *name, SilcCipher *new_cipher)
192 SilcCipherObject *entry = NULL;
194 SILC_LOG_DEBUG(("Allocating new cipher object"));
197 if (silc_cipher_list) {
198 silc_dlist_start(silc_cipher_list);
199 while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
200 if (!strcmp(entry->name, name))
206 /* On EPOC which don't have globals we check our constant cipher list. */
208 for (i = 0; silc_default_ciphers[i].name; i++) {
209 if (!strcmp(silc_default_ciphers[i].name, name)) {
210 entry = (SilcCipherObject *)&(silc_default_ciphers[i]);
215 #endif /* SILC_EPOC */
218 *new_cipher = silc_calloc(1, sizeof(**new_cipher));
219 (*new_cipher)->cipher = entry;
220 (*new_cipher)->context = silc_calloc(1, entry->context_len());
227 /* Free's the given cipher. */
229 void silc_cipher_free(SilcCipher cipher)
232 silc_free(cipher->context);
237 /* Returns TRUE if cipher `name' is supported. */
239 SilcBool silc_cipher_is_supported(const unsigned char *name)
242 SilcCipherObject *entry;
244 if (silc_cipher_list) {
245 silc_dlist_start(silc_cipher_list);
246 while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
247 if (!strcmp(entry->name, name))
254 for (i = 0; silc_default_ciphers[i].name; i++)
255 if (!strcmp(silc_default_ciphers[i].name, name))
258 #endif /* SILC_EPOC */
262 /* Returns comma separated list of supported ciphers. */
264 char *silc_cipher_get_supported(void)
266 SilcCipherObject *entry;
271 if (silc_cipher_list) {
272 silc_dlist_start(silc_cipher_list);
273 while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
274 len += strlen(entry->name);
275 list = silc_realloc(list, len + 1);
277 memcpy(list + (len - strlen(entry->name)),
278 entry->name, strlen(entry->name));
279 memcpy(list + len, ",", 1);
286 for (i = 0; silc_default_ciphers[i].name; i++) {
287 entry = (SilcCipherObject *)&(silc_default_ciphers[i]);
288 len += strlen(entry->name);
289 list = silc_realloc(list, len + 1);
291 memcpy(list + (len - strlen(entry->name)),
292 entry->name, strlen(entry->name));
293 memcpy(list + len, ",", 1);
297 #endif /* SILC_EPOC */
306 SilcBool silc_cipher_encrypt(SilcCipher cipher, const unsigned char *src,
307 unsigned char *dst, SilcUInt32 len,
311 assert((len & (cipher->cipher->block_len - 1)) == 0);
313 if (len & (cipher->cipher->block_len - 1))
315 return cipher->cipher->encrypt(cipher->context, src, dst, len,
316 iv ? iv : cipher->iv);
321 SilcBool silc_cipher_decrypt(SilcCipher cipher, const unsigned char *src,
322 unsigned char *dst, SilcUInt32 len,
326 /* assert((len & (cipher->cipher->block_len - 1)) == 0); */
328 if (len & (cipher->cipher->block_len - 1))
330 return cipher->cipher->decrypt(cipher->context, src, dst, len,
331 iv ? iv : cipher->iv);
334 /* Sets the key for the cipher */
336 SilcBool silc_cipher_set_key(SilcCipher cipher, const unsigned char *key,
339 return cipher->cipher->set_key(cipher->context, key, keylen);
342 /* Sets the IV (initial vector) for the cipher. */
344 void silc_cipher_set_iv(SilcCipher cipher, const unsigned char *iv)
346 memset(&cipher->iv, 0, sizeof(cipher->iv));
347 memcpy(&cipher->iv, iv, cipher->cipher->block_len);
350 /* Returns the IV (initial vector) of the cipher. */
352 unsigned char *silc_cipher_get_iv(SilcCipher cipher)
357 /* Returns the key length of the cipher. */
359 SilcUInt32 silc_cipher_get_key_len(SilcCipher cipher)
361 return cipher->cipher->key_len;
364 /* Returns the block size of the cipher. */
366 SilcUInt32 silc_cipher_get_block_len(SilcCipher cipher)
368 return cipher->cipher->block_len;
371 /* Returns the name of the cipher */
373 const char *silc_cipher_get_name(SilcCipher cipher)
375 return (const char *)cipher->cipher->name;