silccipher.c
- Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+ Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2000 Pekka Riikonen
+ Copyright (C) 1997 - 2007 Pekka Riikonen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
+ the Free Software Foundation; version 2 of the License.
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
-/*
- * $Id$
- * $Log$
- * Revision 1.1.1.1 2000/06/27 11:36:54 priikone
- * Importet from internal CVS/Added Log headers.
- *
- *
- */
-
-#include "silcincludes.h"
+/* $Id$ */
+#include "silc.h"
#include "ciphers.h" /* Includes cipher definitions */
-/* List of all ciphers in SILC. You can dynamically add new ciphers
- into the list. At the initialization of SILC this list is filled with
- the configured ciphers. */
-struct SilcCipherListStruct {
+/* The SilcCipher context */
+struct SilcCipherStruct {
SilcCipherObject *cipher;
- struct SilcCipherListStruct *next;
+ void *context;
+ unsigned char iv[SILC_CIPHER_MAX_IV_SIZE];
};
+#ifndef SILC_SYMBIAN
/* Dynamically registered list of ciphers. */
-struct SilcCipherListStruct *silc_cipher_list = NULL;
+SilcDList silc_cipher_list = NULL;
+#endif /* SILC_SYMBIAN */
-/* XXX: add the other good ciphers here as well */
+/* Macro to define cipher to cipher list */
+#define SILC_CIPHER_API_DEF(name, cipher, keylen, blocklen, ivlen, mode) \
+{ name, silc_##cipher##_set_key, silc_##cipher##_set_iv, \
+ silc_##cipher##_encrypt, silc_##cipher##_decrypt, \
+ silc_##cipher##_context_len, keylen, blocklen, ivlen, mode }
-/* Staticly declared list of ciphers. This is used if system doesn't
- support SIM's. */
-SilcCipherObject silc_cipher_builtin_list[] =
+/* Static list of ciphers for silc_cipher_register_default(). */
+const SilcCipherObject silc_default_ciphers[] =
{
- { "none", 0, 0, silc_none_set_key, silc_none_set_key_with_string,
- silc_none_encrypt_cbc, silc_none_decrypt_cbc,
- silc_none_context_len },
- { "twofish", 16, 16, silc_twofish_set_key, silc_twofish_set_key_with_string,
- silc_twofish_encrypt_cbc, silc_twofish_decrypt_cbc,
- silc_twofish_context_len },
- { "rc6", 16, 16, silc_rc6_set_key, silc_rc6_set_key_with_string,
- silc_rc6_encrypt_cbc, silc_rc6_decrypt_cbc,
- silc_rc6_context_len },
- { "mars", 16, 16, silc_mars_set_key, silc_mars_set_key_with_string,
- silc_mars_encrypt_cbc, silc_mars_decrypt_cbc,
- silc_mars_context_len },
-
- { NULL, 0, 0, NULL, NULL, NULL, NULL, NULL }
+ SILC_CIPHER_API_DEF("aes-256-ctr", aes_ctr, 256, 16, 16,
+ SILC_CIPHER_MODE_CTR),
+ SILC_CIPHER_API_DEF("aes-192-ctr", aes_ctr, 192, 16, 16,
+ SILC_CIPHER_MODE_CTR),
+ SILC_CIPHER_API_DEF("aes-128-ctr", aes_ctr, 128, 16, 16,
+ SILC_CIPHER_MODE_CTR),
+ SILC_CIPHER_API_DEF("aes-256-cbc", aes_cbc, 256, 16, 16,
+ SILC_CIPHER_MODE_CBC),
+ SILC_CIPHER_API_DEF("aes-192-cbc", aes_cbc, 192, 16, 16,
+ SILC_CIPHER_MODE_CBC),
+ SILC_CIPHER_API_DEF("aes-128-cbc", aes_cbc, 128, 16, 16,
+ SILC_CIPHER_MODE_CBC),
+ SILC_CIPHER_API_DEF("twofish-256-cbc", twofish_cbc, 256, 16, 16,
+ SILC_CIPHER_MODE_CBC),
+ SILC_CIPHER_API_DEF("twofish-192-cbc", twofish_cbc, 192, 16, 16,
+ SILC_CIPHER_MODE_CBC),
+ SILC_CIPHER_API_DEF("twofish-128-cbc", twofish_cbc, 128, 16, 16,
+ SILC_CIPHER_MODE_CBC),
+#ifdef SILC_DEBUG
+ SILC_CIPHER_API_DEF("none", none, 0, 0, 0, 0),
+#endif /* SILC_DEBUG */
+ { NULL, NULL, 0, 0, 0, 0 }
};
/* Register a new cipher into SILC. This is used at the initialization of
registered. Therefore, if memory has been allocated for the object sent
as argument it has to be free'd after this function returns succesfully. */
-int silc_cipher_register(SilcCipherObject *cipher)
+SilcBool silc_cipher_register(const SilcCipherObject *cipher)
{
- struct SilcCipherListStruct *new, *c;
+#ifndef SILC_SYMBIAN
+ SilcCipherObject *new;
- SILC_LOG_DEBUG(("Registering new cipher"));
+ SILC_LOG_DEBUG(("Registering new cipher `%s'", cipher->name));
- new = silc_calloc(1, sizeof(*new));
- if (!new) {
- SILC_LOG_ERROR(("Could not allocate new cipher list object: %s",
- strerror(errno)));
- return FALSE;
+ /* Check if exists already */
+ if (silc_cipher_list) {
+ SilcCipherObject *entry;
+ silc_dlist_start(silc_cipher_list);
+ while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
+ if (!strcmp(entry->name, cipher->name))
+ return FALSE;
+ }
}
- new->cipher = silc_calloc(1, sizeof(*new->cipher));
- if (!new->cipher) {
- SILC_LOG_ERROR(("Could not allocate new cipher object: %s",
- strerror(errno)));
+ new = silc_calloc(1, sizeof(*new));
+ if (!new)
+ return FALSE;
+ new->name = strdup(cipher->name);
+ if (!new->name) {
+ silc_free(new);
return FALSE;
}
-
- /* Set the pointers */
- new->cipher->name = strdup(cipher->name);
- new->cipher->block_len = cipher->block_len;
- new->cipher->key_len = cipher->key_len;
- new->cipher->set_key = cipher->set_key;
- new->cipher->set_key_with_string = cipher->set_key_with_string;
- new->cipher->encrypt = cipher->encrypt;
- new->cipher->decrypt = cipher->decrypt;
- new->cipher->context_len = cipher->context_len;
- new->next = NULL;
-
- /* Add the new cipher to the list */
- if (!silc_cipher_list) {
- silc_cipher_list = new;
- return TRUE;
- }
-
- c = silc_cipher_list;
- while (c) {
- if (!c->next) {
- c->next = new;
- break;
- }
- c = c->next;
- }
-
+ new->key_len = cipher->key_len;
+ new->block_len = cipher->block_len;
+ new->iv_len = cipher->iv_len;
+ new->set_key = cipher->set_key;
+ new->set_iv = cipher->set_iv;
+ new->encrypt = cipher->encrypt;
+ new->decrypt = cipher->decrypt;
+ new->context_len = cipher->context_len;
+ new->mode = cipher->mode;
+
+ /* Add to list */
+ if (silc_cipher_list == NULL)
+ silc_cipher_list = silc_dlist_init();
+ silc_dlist_add(silc_cipher_list, new);
+
+#endif /* SILC_SYMBIAN */
return TRUE;
}
/* Unregister a cipher from the SILC. */
-int silc_cipher_unregister(SilcCipherObject *cipher)
+SilcBool silc_cipher_unregister(SilcCipherObject *cipher)
{
- struct SilcCipherListStruct *c, *tmp;
+#ifndef SILC_SYMBIAN
+ SilcCipherObject *entry;
SILC_LOG_DEBUG(("Unregistering cipher"));
- c = silc_cipher_list;
-
- if (cipher == SILC_ALL_CIPHERS) {
- /* Unregister all ciphers */
- while (c) {
- tmp = c->next;
- silc_free(c->cipher->name);
- silc_free(c);
- c = tmp;
- }
-
- return TRUE;
- }
-
- /* Unregister the cipher */
- if (c->cipher == cipher) {
- tmp = c->next;
- silc_free(c->cipher->name);
- silc_free(c);
- silc_cipher_list = tmp;
-
- return TRUE;
- }
+ if (!silc_cipher_list)
+ return FALSE;
- while (c) {
- if (c->next->cipher == cipher) {
+ silc_dlist_start(silc_cipher_list);
+ while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
+ if (cipher == SILC_ALL_CIPHERS || entry == cipher) {
+ silc_dlist_del(silc_cipher_list, entry);
+ silc_free(entry->name);
+ silc_free(entry);
- tmp = c->next->next;
- silc_free(c->cipher->name);
- silc_free(c);
- c->next = tmp;
+ if (silc_dlist_count(silc_cipher_list) == 0) {
+ silc_dlist_uninit(silc_cipher_list);
+ silc_cipher_list = NULL;
+ }
return TRUE;
}
-
- c = c->next;
}
+#endif /* SILC_SYMBIAN */
return FALSE;
}
-/* Allocates a new SILC cipher object. Function returns 1 on succes and 0
+/* Function that registers all the default ciphers (all builtin ciphers).
+ The application may use this to register the default ciphers if specific
+ ciphers in any specific order is not wanted. */
+
+SilcBool silc_cipher_register_default(void)
+{
+#ifndef SILC_SYMBIAN
+ int i;
+
+ for (i = 0; silc_default_ciphers[i].name; i++)
+ silc_cipher_register(&(silc_default_ciphers[i]));
+
+#endif /* SILC_SYMBIAN */
+ return TRUE;
+}
+
+SilcBool silc_cipher_unregister_all(void)
+{
+#ifndef SILC_SYMBIAN
+ SilcCipherObject *entry;
+
+ if (!silc_cipher_list)
+ return FALSE;
+
+ silc_dlist_start(silc_cipher_list);
+ while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
+ silc_cipher_unregister(entry);
+ if (!silc_cipher_list)
+ break;
+ }
+#endif /* SILC_SYMBIAN */
+ return TRUE;
+}
+
+/* Allocates a new SILC cipher object. Function returns 1 on succes and 0
on error. The allocated cipher is returned in new_cipher argument. The
caller must set the key to the cipher after this function has returned
by calling the ciphers set_key function. */
-int silc_cipher_alloc(const unsigned char *name, SilcCipher *new_cipher)
+SilcBool silc_cipher_alloc(const unsigned char *name, SilcCipher *new_cipher)
{
- struct SilcCipherListStruct *c;
- int i;
+ SilcCipherObject *entry = NULL;
SILC_LOG_DEBUG(("Allocating new cipher object"));
- /* Allocate the new object */
- *new_cipher = silc_calloc(1, sizeof(**new_cipher));
- if (*new_cipher == NULL) {
- SILC_LOG_ERROR(("Could not allocate new cipher object"));
- return FALSE;
- }
-
+#ifndef SILC_SYMBIAN
if (silc_cipher_list) {
-
- c = silc_cipher_list;
- while (c) {
- if (!strcmp(c->cipher->name, name))
+ silc_dlist_start(silc_cipher_list);
+ while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
+ if (!strcmp(entry->name, name))
break;
- c = c->next;
}
-
- if (!c)
- goto check_builtin;
-
- /* Set the pointers */
- (*new_cipher)->cipher = c->cipher;
- (*new_cipher)->context = silc_calloc(1, c->cipher->context_len());
- (*new_cipher)->set_iv = silc_cipher_set_iv;
- (*new_cipher)->get_iv = silc_cipher_get_iv;
- (*new_cipher)->get_key_len = silc_cipher_get_key_len;
- (*new_cipher)->get_block_len = silc_cipher_get_block_len;
-
- return TRUE;
}
-
- check_builtin:
-
- for (i = 0; silc_cipher_builtin_list[i].name; i++)
- if (!strcmp(silc_cipher_builtin_list[i].name, name))
- break;
-
- if (silc_cipher_builtin_list[i].name == NULL) {
- silc_free(*new_cipher);
- return FALSE;
+#else
+ {
+ /* On EPOC which don't have globals we check our constant cipher list. */
+ int i;
+ for (i = 0; silc_default_ciphers[i].name; i++) {
+ if (!strcmp(silc_default_ciphers[i].name, name)) {
+ entry = (SilcCipherObject *)&(silc_default_ciphers[i]);
+ break;
+ }
+ }
+ }
+#endif /* SILC_SYMBIAN */
+
+ if (entry) {
+ *new_cipher = silc_calloc(1, sizeof(**new_cipher));
+ if (!(*new_cipher))
+ return FALSE;
+ (*new_cipher)->cipher = entry;
+ (*new_cipher)->context = silc_calloc(1, entry->context_len());
+ if (!(*new_cipher)->context) {
+ silc_free(*new_cipher);
+ return FALSE;
+ }
+ return TRUE;
}
- /* Set the pointers */
- (*new_cipher)->cipher = &silc_cipher_builtin_list[i];
- (*new_cipher)->context =
- silc_calloc(1, (*new_cipher)->cipher->context_len());
- (*new_cipher)->set_iv = silc_cipher_set_iv;
- (*new_cipher)->get_iv = silc_cipher_get_iv;
- (*new_cipher)->get_key_len = silc_cipher_get_key_len;
- (*new_cipher)->get_block_len = silc_cipher_get_block_len;
- memset(&(*new_cipher)->iv, 0, sizeof((*new_cipher)->iv));
-
- return TRUE;
+ return FALSE;
}
/* Free's the given cipher. */
/* Returns TRUE if cipher `name' is supported. */
-int silc_cipher_is_supported(const unsigned char *name)
+SilcBool silc_cipher_is_supported(const unsigned char *name)
{
- struct SilcCipherListStruct *c;
- int i;
+#ifndef SILC_SYMBIAN
+ SilcCipherObject *entry;
if (silc_cipher_list) {
- c = silc_cipher_list;
-
- while (c) {
- if (!strcmp(c->cipher->name, name))
+ silc_dlist_start(silc_cipher_list);
+ while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
+ if (!strcmp(entry->name, name))
return TRUE;
- c = c->next;
}
}
-
- for (i = 0; silc_cipher_builtin_list[i].name; i++)
- if (!strcmp(silc_cipher_builtin_list[i].name, name))
- return TRUE;
-
+#else
+ {
+ int i;
+ for (i = 0; silc_default_ciphers[i].name; i++)
+ if (!strcmp(silc_default_ciphers[i].name, name))
+ return TRUE;
+ }
+#endif /* SILC_SYMBIAN */
return FALSE;
}
/* Returns comma separated list of supported ciphers. */
-char *silc_cipher_get_supported()
+char *silc_cipher_get_supported(void)
{
+ SilcCipherObject *entry;
char *list = NULL;
- int i, len;
- struct SilcCipherListStruct *c;
+ int len = 0;
- len = 0;
+#ifndef SILC_SYMBIAN
if (silc_cipher_list) {
- c = silc_cipher_list;
-
- while (c) {
- len += strlen(c->cipher->name);
+ silc_dlist_start(silc_cipher_list);
+ while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
+ len += strlen(entry->name);
list = silc_realloc(list, len + 1);
-
- memcpy(list + (len - strlen(c->cipher->name)),
- c->cipher->name, strlen(c->cipher->name));
+
+ memcpy(list + (len - strlen(entry->name)),
+ entry->name, strlen(entry->name));
memcpy(list + len, ",", 1);
len++;
-
- c = c->next;
}
}
+#else
+ {
+ int i;
+ for (i = 0; silc_default_ciphers[i].name; i++) {
+ entry = (SilcCipherObject *)&(silc_default_ciphers[i]);
+ len += strlen(entry->name);
+ list = silc_realloc(list, len + 1);
- for (i = 0; silc_cipher_builtin_list[i].name; i++) {
- len += strlen(silc_cipher_builtin_list[i].name);
- list = silc_realloc(list, len + 1);
-
- memcpy(list + (len - strlen(silc_cipher_builtin_list[i].name)),
- silc_cipher_builtin_list[i].name,
- strlen(silc_cipher_builtin_list[i].name));
- memcpy(list + len, ",", 1);
- len++;
+ memcpy(list + (len - strlen(entry->name)),
+ entry->name, strlen(entry->name));
+ memcpy(list + len, ",", 1);
+ len++;
+ }
}
+#endif /* SILC_SYMBIAN */
list[len - 1] = 0;
return list;
}
+/* Encrypts */
+
+SilcBool silc_cipher_encrypt(SilcCipher cipher, const unsigned char *src,
+ unsigned char *dst, SilcUInt32 len,
+ unsigned char *iv)
+{
+ return cipher->cipher->encrypt(cipher->context, src, dst, len,
+ iv ? iv : cipher->iv);
+}
+
+/* Decrypts */
+
+SilcBool silc_cipher_decrypt(SilcCipher cipher, const unsigned char *src,
+ unsigned char *dst, SilcUInt32 len,
+ unsigned char *iv)
+{
+ return cipher->cipher->decrypt(cipher->context, src, dst, len,
+ iv ? iv : cipher->iv);
+}
+
+/* Sets the key for the cipher */
+
+SilcBool silc_cipher_set_key(SilcCipher cipher, const unsigned char *key,
+ SilcUInt32 keylen, SilcBool encryption)
+{
+ return cipher->cipher->set_key(cipher->context, key, keylen, encryption);
+}
+
/* Sets the IV (initial vector) for the cipher. */
-void silc_cipher_set_iv(SilcCipher itself, const unsigned char *iv)
+void silc_cipher_set_iv(SilcCipher cipher, const unsigned char *iv)
{
- memset(&itself->iv, 0, sizeof(itself->iv));
- memcpy(&itself->iv, iv, itself->cipher->block_len);
+ if (iv)
+ memmove(&cipher->iv, iv, cipher->cipher->iv_len);
+ cipher->cipher->set_iv(cipher->context, iv);
}
-/* Returns the IV (initial vector) of the cipher. The IV is returned
- to 'iv' argument. */
+/* Returns the IV (initial vector) of the cipher. */
-void silc_cipher_get_iv(SilcCipher itself, unsigned char *iv)
+unsigned char *silc_cipher_get_iv(SilcCipher cipher)
{
- memcpy(iv, &itself->iv, itself->cipher->block_len);
+ return cipher->iv;
}
/* Returns the key length of the cipher. */
-/* XXX */
-unsigned int silc_cipher_get_key_len(SilcCipher itself,
- const unsigned char *name)
+SilcUInt32 silc_cipher_get_key_len(SilcCipher cipher)
{
-
- return TRUE;
+ return cipher->cipher->key_len;
}
/* Returns the block size of the cipher. */
-/* XXX */
-unsigned int silc_cipher_get_block_len(SilcCipher itself)
+SilcUInt32 silc_cipher_get_block_len(SilcCipher cipher)
{
+ return cipher->cipher->block_len;
+}
- return TRUE;
+/* Returns the IV length of the cipher. */
+
+SilcUInt32 silc_cipher_get_iv_len(SilcCipher cipher)
+{
+ return cipher->cipher->iv_len;
+}
+
+/* Returns the name of the cipher */
+
+const char *silc_cipher_get_name(SilcCipher cipher)
+{
+ return (const char *)cipher->cipher->name;
+}
+
+/* Returns cipher mode */
+
+SilcCipherMode silc_cipher_get_mode(SilcCipher cipher)
+{
+ return cipher->cipher->mode;
}