X-Git-Url: http://git.silcnet.org/gitweb/?p=crypto.git;a=blobdiff_plain;f=lib%2Fsilcacc%2Fsilcacc_cipher.c;fp=lib%2Fsilcacc%2Fsilcacc_cipher.c;h=e87091bdcb576797b8dec6213d0f0634b10c7224;hp=0000000000000000000000000000000000000000;hb=80dc2a39c614ea1376a2e19ebe2460af11c9afee;hpb=9f20f0382b6229eca740925a73f96294f6dcedc6 diff --git a/lib/silcacc/silcacc_cipher.c b/lib/silcacc/silcacc_cipher.c new file mode 100644 index 00000000..e87091bd --- /dev/null +++ b/lib/silcacc/silcacc_cipher.c @@ -0,0 +1,253 @@ +/* + + silcacc_cipher.c + + Author: Pekka Riikonen + + Copyright (C) 2008 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; 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. + +*/ + +#include "silccrypto.h" + +/************************** Types and definitions ***************************/ + +SILC_CIPHER_API_SET_KEY(acc_cipher); +SILC_CIPHER_API_SET_IV(acc_cipher); +SILC_CIPHER_API_ENCRYPT(acc_cipher); +SILC_CIPHER_API_DECRYPT(acc_cipher); +SILC_CIPHER_API_INIT(acc_cipher); +SILC_CIPHER_API_UNINIT(acc_cipher); + +/* Accelerated cipher */ +typedef struct SilcAcceleratorCipherStruct { + SilcCipher cipher; /* Associated cipher */ + SilcCipher acc_cipher; /* Accelerator cipher */ +} *SilcAcceleratorCipher; + +/************************** Accelerator Cipher API **************************/ + +/* The Cipher API for the accelerated cipher is simply a wrapper. It + calls the SILC Cipher API for the accelerator cipher. */ + +const SilcCipherObject silc_acc_ciph = +{ + "silc_acc_cipher", + "silc_acc_cipher", + + silc_acc_cipher_set_key, + silc_acc_cipher_set_iv, + silc_acc_cipher_encrypt, + silc_acc_cipher_decrypt, + silc_acc_cipher_init, + silc_acc_cipher_uninit, + + 0, 0, 0, 0 +}; + +SILC_CIPHER_API_SET_KEY(acc_cipher) +{ + SilcAcceleratorCipher c = context; + + /* Set key for the associated cipher too */ + silc_cipher_set_key(c->cipher, key, keylen, encryption); + + /* Set key for accelerator */ + return silc_cipher_set_key(c->acc_cipher, key, keylen, encryption); +} + +SILC_CIPHER_API_SET_IV(acc_cipher) +{ + SilcAcceleratorCipher c = context; + + /* Set IV for the associated cipher too */ + silc_cipher_set_iv(c->cipher, iv); + + /* Set IV for accelerator */ + silc_cipher_set_iv(c->acc_cipher, iv); +} + +SILC_CIPHER_API_ENCRYPT(acc_cipher) +{ + SilcAcceleratorCipher c = context; + return silc_cipher_encrypt(c->acc_cipher, src, dst, len, iv); +} + +SILC_CIPHER_API_DECRYPT(acc_cipher) +{ + SilcAcceleratorCipher c = context; + return silc_cipher_decrypt(c->acc_cipher, src, dst, len, iv); +} + +SILC_CIPHER_API_INIT(acc_cipher) +{ + /* This operation is never called */ + return NULL; +} + +SILC_CIPHER_API_UNINIT(acc_cipher) +{ + SilcAcceleratorCipher c = context; + SilcCipherObject *acc_ops = c->acc_cipher->cipher; + + /* Free the accelerator cipher and its operations we allocated earlier. */ + silc_cipher_free(c->acc_cipher); + silc_free(acc_ops); + + /* Free our operations too */ + silc_free(ops); +} + +/*************************** SILC Accelerator API ***************************/ + +/* Accelerate cipher */ + +SilcCipher silc_acc_cipher(SilcAccelerator acc, SilcCipher cipher) +{ + SilcCipher c; + SilcAcceleratorCipher acc_cipher; + const SilcCipherObject *alg; + int i; + + if (!acc || !cipher) + return NULL; + + SILC_LOG_DEBUG(("Accelerate cipher %p with accelerator %s", + cipher, acc->name)); + + if (!acc->cipher) { + SILC_LOG_ERROR(("Accelerator '%s' does not support cipher acceleration ", + acc->name)); + return NULL; + } + + if (silc_acc_get_cipher(NULL, cipher)) { + SILC_LOG_DEBUG(("Cipher %p is already accelerated", cipher)); + return NULL; + } + + /* Check that accelerator supports this cipher algorithm */ + alg = cipher->cipher; + for (i = 0; acc->cipher[i].alg_name; i++) { + if ((!strcmp(acc->cipher[i].alg_name, alg->alg_name) || + !strcmp(acc->cipher[i].alg_name, "any")) && + (acc->cipher[i].mode == alg->mode || + acc->cipher[i].mode == 0) && + (acc->cipher[i].key_len == alg->key_len || + acc->cipher[i].key_len == 0)) { + alg = NULL; + break; + } + } + if (alg) { + SILC_LOG_DEBUG(("Accelerator %s does not support %s (mode %d) " + "acceleration", acc->name, alg->name, alg->mode)); + return NULL; + } + + /* Allocate cipher context for the SILC Cipher API */ + c = silc_calloc(1, sizeof(*c)); + if (!c) + return NULL; + + /* Allocate cipher operations */ + c->cipher = silc_calloc(1, sizeof(SilcCipherObject)); + if (!c->cipher) { + silc_free(c); + return NULL; + } + *c->cipher = silc_acc_ciph; + + /* Allocate cipher context */ + c->context = acc_cipher = silc_calloc(1, sizeof(*acc_cipher)); + if (!acc_cipher) { + silc_free(c->cipher); + silc_free(c); + return NULL; + } + acc_cipher->cipher = cipher; + + /* Allocate the actual algorithm accelerator. */ + acc_cipher->acc_cipher = silc_calloc(1, sizeof(*acc_cipher->acc_cipher)); + if (!acc_cipher->acc_cipher) { + silc_free(c->cipher); + silc_free(c); + silc_free(acc_cipher); + } + + /* Initialize the algorithm accelerator */ + acc_cipher->acc_cipher->context = + acc->cipher[i].init((struct SilcCipherObjectStruct *)&acc->cipher[i]); + if (!acc_cipher->acc_cipher->context) { + silc_free(c->cipher); + silc_free(c); + silc_free(acc_cipher->acc_cipher); + silc_free(acc_cipher); + return NULL; + } + + /* Allocate algorithm accelerator operations */ + acc_cipher->acc_cipher->cipher = silc_calloc(1, sizeof(SilcCipherObject)); + if (!acc_cipher->acc_cipher->cipher) { + silc_free(c->cipher); + silc_free(c); + silc_free(acc_cipher->acc_cipher->context); + silc_free(acc_cipher->acc_cipher); + silc_free(acc_cipher); + return NULL; + } + + /* Set algorithm accelerator operations. They are copied from the + accelerator, but algorithm specific things come from associated + cipher. This way accelerators get the associated cipher details. */ + *acc_cipher->acc_cipher->cipher = acc->cipher[i]; + acc_cipher->acc_cipher->cipher->alg_name = + (char *)silc_cipher_get_alg_name(cipher); + acc_cipher->acc_cipher->cipher->key_len = silc_cipher_get_key_len(cipher); + acc_cipher->acc_cipher->cipher->block_len = + silc_cipher_get_block_len(cipher); + acc_cipher->acc_cipher->cipher->iv_len = silc_cipher_get_iv_len(cipher); + + /* Set for the accelerator cipher too */ + c->cipher->key_len = silc_cipher_get_key_len(cipher); + c->cipher->block_len = silc_cipher_get_block_len(cipher); + c->cipher->iv_len = silc_cipher_get_iv_len(cipher); + + /* Start the accelerator. The accelerator is started by setting key + with NULL key. */ + if (!silc_cipher_set_key(acc_cipher->acc_cipher, NULL, 0, FALSE)) { + SilcCipherObject *ops = acc_cipher->acc_cipher->cipher; + silc_cipher_free(acc_cipher->acc_cipher); + silc_free(ops); + silc_free(c->cipher); + silc_free(c); + return NULL; + } + + SILC_LOG_DEBUG(("New accelerated cipher %p", c)); + + return c; +} + +/* Return underlaying cipher from accelerated cipher. */ + +SilcCipher silc_acc_get_cipher(SilcAccelerator acc, SilcCipher cipher) +{ + SilcAcceleratorCipher acc_cipher; + + if (!cipher || cipher->cipher != &silc_acc_ciph) + return NULL; + + acc_cipher = cipher->context; + + return acc_cipher->cipher; +}