5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2007 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.
23 /* Software accelerator is a thread-pool system where public key and private
24 key operations are executed in threads for the purpose of off-loading and
25 balancing the computations across multiple processors. */
27 #define SILC_SOFTACC_MIN_THREADS 0
28 #define SILC_SOFTACC_MAX_THREADS 4
30 /************************** Types and definitions ***************************/
32 /* Software accelerator PKCS algorithm operations */
33 const SilcPKCSAlgorithm softacc_pkcs[] =
36 "any", "any", NULL, NULL,
37 silc_softacc_acc_public_key,
38 NULL, NULL, NULL, NULL,
39 silc_softacc_free_public_key,
40 silc_softacc_acc_private_key,
42 silc_softacc_free_private_key,
50 NULL, NULL, NULL, NULL,
51 NULL, NULL, NULL, NULL,
52 NULL, NULL, NULL, NULL,
57 /* Software accelerator operations */
58 const SilcAcceleratorStruct softacc =
60 "softacc", silc_softacc_init, silc_softacc_uninit, softacc_pkcs
63 /* Software accelerator public key */
65 SilcPublicKey key; /* Accelerated public key */
66 } *SilcSoftaccPublicKey;
68 /* Software accelerator private key */
70 SilcPrivateKey key; /* Accelerated private key */
71 } *SilcSoftaccPrivateKey;
81 /* Executor context */
83 SilcStack stack; /* Executor stack */
84 void *context; /* Callback context */
85 SilcSoftaccType type; /* Execution type */
86 SilcAsyncOperationStruct op; /* Operation for aborting */
88 unsigned char *src; /* Source data */
89 unsigned char *data; /* More source data */
92 SilcHash hash; /* Hash function to use */
93 SilcRng rng; /* RNG, may be NULL */
96 SilcPublicKey public_key;
97 SilcPrivateKey private_key;
101 SilcPKCSEncryptCb encrypt_cb;
102 SilcPKCSDecryptCb decrypt_cb;
103 SilcPKCSSignCb sign_cb;
104 SilcPKCSVerifyCb verify_cb;
107 unsigned char *result_data;
108 SilcUInt32 result_len;
110 unsigned int result : 1;
111 unsigned int compute_hash : 1;
112 unsigned int aborted : 1;
115 /* Software accelerator context */
117 SilcSchedule schedule; /* Scheduler */
118 SilcThreadPool tp; /* The thread pool */
121 SilcSoftacc sa = NULL; /* The accelerator */
123 /***************************** Accelerator API ******************************/
125 /* Initialize software accelerator. Optional initialization parameters:
127 min_threads number Minimum number of threads (default 0)
128 max_thread number Maximum number of threads (default 4)
130 Eg. silc_acc_init(softacc, "min_threads", 2, "max_threads", 8, NULL);
134 SilcBool silc_softacc_init(SilcSchedule schedule, va_list va)
136 SilcUInt32 min_threads = SILC_SOFTACC_MIN_THREADS;
137 SilcUInt32 max_threads = SILC_SOFTACC_MAX_THREADS;
143 /* If already initialized, uninitialize first. */
145 silc_softacc_uninit();
148 while ((opt = va_arg(va, char *))) {
149 if (!strcmp(opt, "min_threads"))
150 min_threads = va_arg(va, SilcUInt32);
151 else if (!strcmp(opt, "max_threads"))
152 max_threads = va_arg(va, SilcUInt32);
155 SILC_LOG_DEBUG(("Initialize software accelerator, min_threads %d, "
156 "max_threads %d", min_threads, max_threads));
158 sa = silc_calloc(1, sizeof(*sa));
162 sa->schedule = schedule;
164 /* Start the thread pool */
165 sa->tp = silc_thread_pool_alloc(NULL, min_threads, max_threads, TRUE);
177 SilcBool silc_softacc_uninit(void)
182 SILC_LOG_DEBUG(("Uninitialize software accelerator"));
184 silc_thread_pool_free(sa->tp, TRUE);
191 /****************************** PKCS ALG API ********************************/
193 /* Abort operation */
195 void silc_softacc_abort(SilcAsyncOperation op, void *context)
197 SilcSoftaccExec e = context;
201 /* Accelerator completion, executed in main thread. */
203 SILC_TASK_CALLBACK(silc_softacc_completion)
205 SilcSoftaccExec e = context;
206 SilcStack stack = e->stack;
208 /* At the latest, abort is catched here in the main thread. Don't
209 deliver callback if we were aborted */
213 SILC_LOG_DEBUG(("Call completion, result=%s", e->result ? "Ok" : "failed"));
215 /* Call completion callback */
217 case SILC_SOFTACC_ENCRYPT:
218 e->cb.encrypt_cb(e->result, e->result_data, e->result_len, e->context);
221 case SILC_SOFTACC_DECRYPT:
222 e->cb.decrypt_cb(e->result, e->result_data, e->result_len, e->context);
225 case SILC_SOFTACC_SIGN:
226 e->cb.sign_cb(e->result, e->result_data, e->result_len, e->context);
229 case SILC_SOFTACC_VERIFY:
230 e->cb.verify_cb(e->result, e->context);
235 silc_sfree(stack, e->src);
236 silc_sfree(stack, e->data);
237 silc_sfree(stack, e->result_data);
238 silc_sfree(stack, e);
239 silc_stack_free(stack);
242 /* Callback for encrypt, decrypt and signature */
244 void silc_softacc_data_cb(SilcBool success, const unsigned char *data,
245 SilcUInt32 data_len, void *context)
247 SilcSoftaccExec e = context;
248 SilcStack stack = e->stack;
251 silc_stack_pop(stack);
254 e->result_data = silc_smemdup(stack, data, data_len);
255 e->result_len = data_len;
259 /* Verification callback */
261 void silc_softacc_verify_cb(SilcBool success, void *context)
263 SilcSoftaccExec e = context;
264 SilcStack stack = e->stack;
266 /* Pop e->src and e->data from memory */
267 silc_stack_pop(stack);
272 /* Accelerator thread */
274 void silc_softacc_thread(SilcSchedule schedule, void *context)
276 SilcSoftaccExec e = context;
281 SILC_LOG_DEBUG(("Execute type %d", e->type));
283 /* Call the operation */
285 case SILC_SOFTACC_ENCRYPT:
286 silc_pkcs_encrypt(e->key.public_key, e->src, e->src_len, e->rng,
287 silc_softacc_data_cb, e);
290 case SILC_SOFTACC_DECRYPT:
291 silc_pkcs_decrypt(e->key.private_key, e->src, e->src_len,
292 silc_softacc_data_cb, e);
295 case SILC_SOFTACC_SIGN:
296 silc_pkcs_sign(e->key.private_key, e->src, e->src_len, e->compute_hash,
297 e->hash, e->rng, silc_softacc_data_cb, e);
300 case SILC_SOFTACC_VERIFY:
301 silc_pkcs_verify(e->key.public_key, e->src, e->src_len, e->data,
302 e->data_len, e->hash, e->rng, silc_softacc_verify_cb, e);
307 /* Accelerate public key */
309 SILC_PKCS_ALG_IMPORT_PUBLIC_KEY(silc_softacc_acc_public_key)
311 SilcSoftaccPublicKey pubkey;
314 SILC_LOG_ERROR(("Software accelerator not initialized"));
318 pubkey = silc_calloc(1, sizeof(*pubkey));
323 *ret_public_key = pubkey;
328 /* Accelerate private key */
330 SILC_PKCS_ALG_IMPORT_PRIVATE_KEY(silc_softacc_acc_private_key)
332 SilcSoftaccPrivateKey privkey;
335 SILC_LOG_ERROR(("Software accelerator not initialized"));
339 privkey = silc_calloc(1, sizeof(*privkey));
344 *ret_private_key = privkey;
349 /* Free public key */
351 SILC_PKCS_ALG_PUBLIC_KEY_FREE(silc_softacc_free_public_key)
353 silc_free(public_key);
356 /* Free private key */
358 SILC_PKCS_ALG_PRIVATE_KEY_FREE(silc_softacc_free_private_key)
360 silc_free(private_key);
363 /* Accelerated encrypt */
365 SILC_PKCS_ALG_ENCRYPT(silc_softacc_encrypt)
367 SilcSoftaccPublicKey pubkey = public_key;
371 SILC_LOG_DEBUG(("Encrypt"));
374 SILC_LOG_ERROR(("Software accelerator not initialized"));
375 encrypt_cb(FALSE, NULL, 0, context);
379 stack = silc_stack_alloc(2048, silc_crypto_stack());
381 e = silc_scalloc(stack, 1, sizeof(*e));
383 silc_stack_free(stack);
384 encrypt_cb(FALSE, NULL, 0, context);
388 silc_stack_push(stack, NULL);
391 e->type = SILC_SOFTACC_ENCRYPT;
392 e->src = silc_smemdup(stack, src, src_len);
393 e->src_len = src_len;
395 e->key.public_key = pubkey->key;
396 e->cb.encrypt_cb = encrypt_cb;
397 e->context = context;
398 silc_async_init(&e->op, silc_softacc_abort, NULL, e);
401 silc_thread_pool_run(sa->tp, TRUE, sa->schedule, silc_softacc_thread, e,
402 silc_softacc_completion, e);
407 /* Acceleted decrypt */
409 SILC_PKCS_ALG_DECRYPT(silc_softacc_decrypt)
411 SilcSoftaccPrivateKey privkey = private_key;
415 SILC_LOG_DEBUG(("Decrypt"));
418 SILC_LOG_ERROR(("Software accelerator not initialized"));
419 decrypt_cb(FALSE, NULL, 0, context);
423 stack = silc_stack_alloc(2048, silc_crypto_stack());
425 e = silc_scalloc(stack, 1, sizeof(*e));
427 silc_stack_free(stack);
428 decrypt_cb(FALSE, NULL, 0, context);
432 silc_stack_push(stack, NULL);
435 e->type = SILC_SOFTACC_DECRYPT;
436 e->src = silc_smemdup(stack, src, src_len);
437 e->src_len = src_len;
438 e->key.private_key = privkey->key;
439 e->cb.decrypt_cb = decrypt_cb;
440 e->context = context;
441 silc_async_init(&e->op, silc_softacc_abort, NULL, e);
444 silc_thread_pool_run(sa->tp, TRUE, sa->schedule, silc_softacc_thread, e,
445 silc_softacc_completion, e);
450 /* Accelerated signature */
452 SILC_PKCS_ALG_SIGN(silc_softacc_sign)
454 SilcSoftaccPrivateKey privkey = private_key;
458 SILC_LOG_DEBUG(("Sign"));
461 SILC_LOG_ERROR(("Software accelerator not initialized"));
462 sign_cb(FALSE, NULL, 0, context);
466 stack = silc_stack_alloc(2048, silc_crypto_stack());
468 e = silc_scalloc(stack, 1, sizeof(*e));
470 silc_stack_free(stack);
471 sign_cb(FALSE, NULL, 0, context);
475 silc_stack_push(stack, NULL);
478 e->type = SILC_SOFTACC_SIGN;
479 e->src = silc_smemdup(stack, src, src_len);
480 e->src_len = src_len;
481 e->compute_hash = compute_hash;
483 e->key.private_key = privkey->key;
484 e->cb.sign_cb = sign_cb;
485 e->context = context;
486 silc_async_init(&e->op, silc_softacc_abort, NULL, e);
489 silc_thread_pool_run(sa->tp, TRUE, sa->schedule, silc_softacc_thread, e,
490 silc_softacc_completion, e);
495 /* Accelerated verification */
497 SILC_PKCS_ALG_VERIFY(silc_softacc_verify)
499 SilcSoftaccPublicKey pubkey = public_key;
503 SILC_LOG_DEBUG(("Verify"));
506 SILC_LOG_ERROR(("Software accelerator not initialized"));
507 verify_cb(FALSE, context);
511 stack = silc_stack_alloc(2048, silc_crypto_stack());
513 e = silc_scalloc(stack, 1, sizeof(*e));
515 silc_stack_free(stack);
516 verify_cb(FALSE, context);
520 silc_stack_push(stack, NULL);
523 e->type = SILC_SOFTACC_VERIFY;
524 e->src = silc_smemdup(stack, signature, signature_len);
525 e->src_len = signature_len;
526 e->data = silc_smemdup(stack, data, data_len);
527 e->data_len = data_len;
529 e->key.public_key = pubkey->key;
530 e->cb.verify_cb = verify_cb;
531 e->context = context;
532 silc_async_init(&e->op, silc_softacc_abort, NULL, e);
535 silc_thread_pool_run(sa->tp, TRUE, sa->schedule, silc_softacc_thread, e,
536 silc_softacc_completion, e);