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);
176 SilcBool silc_softacc_uninit(void)
181 SILC_LOG_DEBUG(("Uninitialize software accelerator"));
183 silc_thread_pool_free(sa->tp, TRUE);
190 /****************************** PKCS ALG API ********************************/
192 /* Abort operation */
194 void silc_softacc_abort(SilcAsyncOperation op, void *context)
196 SilcSoftaccExec e = context;
200 /* Accelerator completion, executed in main thread. */
202 SILC_TASK_CALLBACK(silc_softacc_completion)
204 SilcSoftaccExec e = context;
205 SilcStack stack = e->stack;
207 /* At the latest, abort is catched here in the main thread. Don't
208 deliver callback if we were aborted */
212 SILC_LOG_DEBUG(("Call completion, result=%s", e->result ? "Ok" : "failed"));
214 /* Call completion callback */
216 case SILC_SOFTACC_ENCRYPT:
217 e->cb.encrypt_cb(e->result, e->result_data, e->result_len, e->context);
220 case SILC_SOFTACC_DECRYPT:
221 e->cb.decrypt_cb(e->result, e->result_data, e->result_len, e->context);
224 case SILC_SOFTACC_SIGN:
225 e->cb.sign_cb(e->result, e->result_data, e->result_len, e->context);
228 case SILC_SOFTACC_VERIFY:
229 e->cb.verify_cb(e->result, e->context);
234 silc_sfree(stack, e->src);
235 silc_sfree(stack, e->data);
236 silc_sfree(stack, e);
237 silc_stack_free(stack);
240 /* Callback for encrypt, decrypt and signature */
242 void silc_softacc_data_cb(SilcBool success, const unsigned char *data,
243 SilcUInt32 data_len, void *context)
245 SilcSoftaccExec e = context;
246 SilcStack stack = e->stack;
248 /* Pop e->src and e->data from memory */
249 silc_stack_pop(stack);
252 e->result_data = silc_smemdup(stack, data, data_len);
253 e->result_len = data_len;
257 /* Verification callback */
259 void silc_softacc_verify_cb(SilcBool success, void *context)
261 SilcSoftaccExec e = context;
262 SilcStack stack = e->stack;
264 silc_stack_pop(stack);
268 /* Accelerator thread */
270 void silc_softacc_thread(SilcSchedule schedule, void *context)
272 SilcSoftaccExec e = context;
277 SILC_LOG_DEBUG(("Execute type %d", e->type));
279 /* Call the operation */
281 case SILC_SOFTACC_ENCRYPT:
282 silc_pkcs_encrypt(e->key.public_key, e->src, e->src_len, e->rng,
283 silc_softacc_data_cb, e);
286 case SILC_SOFTACC_DECRYPT:
287 silc_pkcs_decrypt(e->key.private_key, e->src, e->src_len,
288 silc_softacc_data_cb, e);
291 case SILC_SOFTACC_SIGN:
292 silc_pkcs_sign(e->key.private_key, e->src, e->src_len, e->compute_hash,
293 e->hash, silc_softacc_data_cb, e);
296 case SILC_SOFTACC_VERIFY:
297 silc_pkcs_verify(e->key.public_key, e->src, e->src_len, e->data,
298 e->data_len, e->hash, silc_softacc_verify_cb, e);
303 /* Accelerate public key */
305 SILC_PKCS_ALG_IMPORT_PUBLIC_KEY(silc_softacc_acc_public_key)
307 SilcSoftaccPublicKey pubkey;
310 SILC_LOG_ERROR(("Software accelerator not initialized"));
314 pubkey = silc_calloc(1, sizeof(*pubkey));
319 *ret_public_key = pubkey;
324 /* Accelerate private key */
326 SILC_PKCS_ALG_IMPORT_PRIVATE_KEY(silc_softacc_acc_private_key)
328 SilcSoftaccPrivateKey privkey;
331 SILC_LOG_ERROR(("Software accelerator not initialized"));
335 privkey = silc_calloc(1, sizeof(*privkey));
340 *ret_private_key = privkey;
345 /* Free public key */
347 SILC_PKCS_ALG_PUBLIC_KEY_FREE(silc_softacc_free_public_key)
349 silc_free(public_key);
352 /* Free private key */
354 SILC_PKCS_ALG_PRIVATE_KEY_FREE(silc_softacc_free_private_key)
356 silc_free(private_key);
359 /* Accelerated encrypt */
361 SILC_PKCS_ALG_ENCRYPT(silc_softacc_encrypt)
363 SilcSoftaccPublicKey pubkey = public_key;
367 SILC_LOG_DEBUG(("Encrypt"));
370 SILC_LOG_ERROR(("Software accelerator not initialized"));
371 encrypt_cb(FALSE, NULL, 0, context);
375 stack = silc_stack_alloc(2048, silc_crypto_stack());
377 e = silc_scalloc(stack, 1, sizeof(*e));
379 silc_stack_free(stack);
380 encrypt_cb(FALSE, NULL, 0, context);
384 silc_stack_push(stack, NULL);
387 e->type = SILC_SOFTACC_ENCRYPT;
388 e->src = silc_smemdup(stack, src, src_len);
389 e->src_len = src_len;
391 e->key.public_key = pubkey->key;
392 e->cb.encrypt_cb = encrypt_cb;
393 e->context = context;
394 silc_async_init(&e->op, silc_softacc_abort, NULL, e);
397 silc_thread_pool_run(sa->tp, TRUE, sa->schedule, silc_softacc_thread, e,
398 silc_softacc_completion, e);
403 /* Acceleted decrypt */
405 SILC_PKCS_ALG_DECRYPT(silc_softacc_decrypt)
407 SilcSoftaccPrivateKey privkey = private_key;
411 SILC_LOG_DEBUG(("Decrypt"));
414 SILC_LOG_ERROR(("Software accelerator not initialized"));
415 decrypt_cb(FALSE, NULL, 0, context);
419 stack = silc_stack_alloc(2048, silc_crypto_stack());
421 e = silc_scalloc(stack, 1, sizeof(*e));
423 silc_stack_free(stack);
424 decrypt_cb(FALSE, NULL, 0, context);
428 silc_stack_push(stack, NULL);
431 e->type = SILC_SOFTACC_DECRYPT;
432 e->src = silc_smemdup(stack, src, src_len);
433 e->src_len = src_len;
434 e->key.private_key = privkey->key;
435 e->cb.decrypt_cb = decrypt_cb;
436 e->context = context;
437 silc_async_init(&e->op, silc_softacc_abort, NULL, e);
440 silc_thread_pool_run(sa->tp, TRUE, sa->schedule, silc_softacc_thread, e,
441 silc_softacc_completion, e);
446 /* Accelerated signature */
448 SILC_PKCS_ALG_SIGN(silc_softacc_sign)
450 SilcSoftaccPrivateKey privkey = private_key;
454 SILC_LOG_DEBUG(("Sign"));
457 SILC_LOG_ERROR(("Software accelerator not initialized"));
458 sign_cb(FALSE, NULL, 0, context);
462 stack = silc_stack_alloc(2048, silc_crypto_stack());
464 e = silc_scalloc(stack, 1, sizeof(*e));
466 silc_stack_free(stack);
467 sign_cb(FALSE, NULL, 0, context);
471 silc_stack_push(stack, NULL);
474 e->type = SILC_SOFTACC_SIGN;
475 e->src = silc_smemdup(stack, src, src_len);
476 e->src_len = src_len;
477 e->compute_hash = compute_hash;
479 e->key.private_key = privkey->key;
480 e->cb.sign_cb = sign_cb;
481 e->context = context;
482 silc_async_init(&e->op, silc_softacc_abort, NULL, e);
485 silc_thread_pool_run(sa->tp, TRUE, sa->schedule, silc_softacc_thread, e,
486 silc_softacc_completion, e);
491 /* Accelerated verification */
493 SILC_PKCS_ALG_VERIFY(silc_softacc_verify)
495 SilcSoftaccPublicKey pubkey = public_key;
499 SILC_LOG_DEBUG(("Verify"));
502 SILC_LOG_ERROR(("Software accelerator not initialized"));
503 verify_cb(FALSE, context);
507 stack = silc_stack_alloc(2048, silc_crypto_stack());
509 e = silc_scalloc(stack, 1, sizeof(*e));
511 silc_stack_free(stack);
512 verify_cb(FALSE, context);
516 silc_stack_push(stack, NULL);
519 e->type = SILC_SOFTACC_VERIFY;
520 e->src = silc_smemdup(stack, signature, signature_len);
521 e->src_len = signature_len;
522 e->data = silc_smemdup(stack, data, data_len);
523 e->data_len = data_len;
525 e->key.public_key = pubkey->key;
526 e->cb.verify_cb = verify_cb;
527 e->context = context;
528 silc_async_init(&e->op, silc_softacc_abort, NULL, e);
531 silc_thread_pool_run(sa->tp, TRUE, sa->schedule, silc_softacc_thread, e,
532 silc_softacc_completion, e);