Added cipher acceleration to SILC Accelerator. Added cipher softacc.
[crypto.git] / lib / silcacc / softacc_pkcs.c
1 /*
2
3   softacc_pkcs.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2007 - 2008 Pekka Riikonen
8
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.
12
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.
17
18 */
19
20 #include "silccrypto.h"
21 #include "softacc.h"
22 #include "softacc_i.h"
23
24 /* The public and private key accelerator.  We perform the public key and
25    private key operations in threads.  Threads are run in the thread pool. */
26
27 /************************** Types and definitions ***************************/
28
29 /* Software accelerator PKCS algorithm operations */
30 const SilcPKCSAlgorithm softacc_pkcs[] =
31 {
32   {
33     "any", "any", NULL, NULL,
34     silc_softacc_acc_public_key,
35     NULL, NULL, NULL, NULL,
36     silc_softacc_free_public_key,
37     silc_softacc_acc_private_key,
38     NULL, NULL,
39     silc_softacc_free_private_key,
40     silc_softacc_encrypt,
41     silc_softacc_decrypt,
42     silc_softacc_sign,
43     silc_softacc_verify,
44   },
45
46   {
47     NULL, NULL, NULL, NULL,
48     NULL, NULL, NULL, NULL,
49     NULL, NULL, NULL, NULL,
50     NULL, NULL
51   }
52 };
53
54 /* Software accelerator public key */
55 typedef struct {
56   SilcPublicKey key;                     /* Accelerated public key */
57 } *SilcSoftaccPublicKey;
58
59 /* Software accelerator private key */
60 typedef struct {
61   SilcPrivateKey key;                    /* Accelerated private key */
62 } *SilcSoftaccPrivateKey;
63
64 /* Execution types */
65 typedef enum {
66   SILC_SOFTACC_ENCRYPT,
67   SILC_SOFTACC_DECRYPT,
68   SILC_SOFTACC_SIGN,
69   SILC_SOFTACC_VERIFY,
70 } SilcSoftaccType;
71
72 /* Executor context */
73 typedef struct {
74   SilcStack stack;                       /* Executor stack */
75   void *context;                         /* Callback context */
76   SilcSoftaccType type;                  /* Execution type */
77   SilcAsyncOperationStruct op;           /* Operation for aborting */
78
79   unsigned char *src;                    /* Source data */
80   unsigned char *data;                   /* More source data */
81   SilcUInt32 src_len;
82   SilcUInt32 data_len;
83   SilcHash hash;                         /* Hash function to use */
84   SilcRng rng;                           /* RNG, may be NULL */
85
86   union {
87     SilcPublicKey public_key;
88     SilcPrivateKey private_key;
89   } key;
90
91   union {
92     SilcPKCSEncryptCb encrypt_cb;
93     SilcPKCSDecryptCb decrypt_cb;
94     SilcPKCSSignCb sign_cb;
95     SilcPKCSVerifyCb verify_cb;
96   } cb;
97
98   unsigned char *result_data;
99   SilcUInt32 result_len;
100
101   unsigned int result       : 1;
102   unsigned int compute_hash : 1;
103   unsigned int aborted      : 1;
104 } *SilcSoftaccExec;
105
106 /****************************** PKCS ALG API ********************************/
107
108 /* Abort operation */
109
110 void silc_softacc_pkcs_abort(SilcAsyncOperation op, void *context)
111 {
112   SilcSoftaccExec e = context;
113   e->aborted = TRUE;
114 }
115
116 /* Accelerator completion, executed in main thread. */
117
118 SILC_TASK_CALLBACK(silc_softacc_pkcs_completion)
119 {
120   SilcSoftaccExec e = context;
121   SilcStack stack = e->stack;
122
123   /* At the latest, abort is catched here in the main thread.  Don't
124      deliver callback if we were aborted */
125   if (e->aborted)
126     goto out;
127
128   SILC_LOG_DEBUG(("Call completion, result=%s", e->result ? "Ok" : "failed"));
129
130   /* Call completion callback */
131   switch (e->type) {
132   case SILC_SOFTACC_ENCRYPT:
133     e->cb.encrypt_cb(e->result, e->result_data, e->result_len, e->context);
134     break;
135
136   case SILC_SOFTACC_DECRYPT:
137     e->cb.decrypt_cb(e->result, e->result_data, e->result_len, e->context);
138     break;
139
140   case SILC_SOFTACC_SIGN:
141     e->cb.sign_cb(e->result, e->result_data, e->result_len, e->context);
142     break;
143
144   case SILC_SOFTACC_VERIFY:
145     e->cb.verify_cb(e->result, e->context);
146     break;
147   }
148
149  out:
150   silc_sfree(stack, e->src);
151   silc_sfree(stack, e->data);
152   silc_sfree(stack, e->result_data);
153   silc_sfree(stack, e);
154   silc_stack_free(stack);
155 }
156
157 /* Callback for encrypt, decrypt and signature */
158
159 void silc_softacc_pkcs_data_cb(SilcBool success, const unsigned char *data,
160                                SilcUInt32 data_len, void *context)
161 {
162   SilcSoftaccExec e = context;
163   SilcStack stack = e->stack;
164
165   /* Pop e->src */
166   silc_stack_pop(stack);
167
168   if (success)
169     e->result_data = silc_smemdup(stack, data, data_len);
170   e->result_len = data_len;
171   e->result = success;
172 }
173
174 /* Verification callback */
175
176 void silc_softacc_pkcs_verify_cb(SilcBool success, void *context)
177 {
178   SilcSoftaccExec e = context;
179   SilcStack stack = e->stack;
180
181   /* Pop e->src and e->data from memory */
182   silc_stack_pop(stack);
183
184   e->result = success;
185 }
186
187 /* Accelerator thread */
188
189 void silc_softacc_pkcs_thread(SilcSchedule schedule, void *context)
190 {
191   SilcSoftaccExec e = context;
192
193   if (e->aborted)
194     return;
195
196   SILC_LOG_DEBUG(("Execute type %d", e->type));
197
198   /* Call the operation */
199   switch (e->type) {
200   case SILC_SOFTACC_ENCRYPT:
201     silc_pkcs_encrypt(e->key.public_key, e->src, e->src_len, e->rng,
202                       silc_softacc_pkcs_data_cb, e);
203     break;
204
205   case SILC_SOFTACC_DECRYPT:
206     silc_pkcs_decrypt(e->key.private_key, e->src, e->src_len,
207                       silc_softacc_pkcs_data_cb, e);
208     break;
209
210   case SILC_SOFTACC_SIGN:
211     silc_pkcs_sign(e->key.private_key, e->src, e->src_len, e->compute_hash,
212                    e->hash, e->rng, silc_softacc_pkcs_data_cb, e);
213     break;
214
215   case SILC_SOFTACC_VERIFY:
216     silc_pkcs_verify(e->key.public_key, e->src, e->src_len, e->data,
217                      e->data_len, e->hash, silc_softacc_pkcs_verify_cb, e);
218     break;
219   }
220 }
221
222 /* Accelerate public key */
223
224 SILC_PKCS_ALG_IMPORT_PUBLIC_KEY(silc_softacc_acc_public_key)
225 {
226   SilcSoftaccPublicKey pubkey;
227   SilcSoftacc sa;
228
229   sa = silc_global_get_var("softacc", FALSE);
230   if (!sa || !sa->schedule) {
231     SILC_LOG_ERROR(("Software accelerator not initialized"));
232     return FALSE;
233   }
234
235   pubkey = silc_calloc(1, sizeof(*pubkey));
236   if (!pubkey)
237     return FALSE;
238   pubkey->key = key;
239
240   *ret_public_key = pubkey;
241
242   return TRUE;
243 }
244
245 /* Accelerate private key */
246
247 SILC_PKCS_ALG_IMPORT_PRIVATE_KEY(silc_softacc_acc_private_key)
248 {
249   SilcSoftaccPrivateKey privkey;
250   SilcSoftacc sa;
251
252   sa = silc_global_get_var("softacc", FALSE);
253   if (!sa || !sa->schedule) {
254     SILC_LOG_ERROR(("Software accelerator not initialized"));
255     return FALSE;
256   }
257
258   privkey = silc_calloc(1, sizeof(*privkey));
259   if (!privkey)
260     return FALSE;
261   privkey->key = key;
262
263   *ret_private_key = privkey;
264
265   return TRUE;
266 }
267
268 /* Free public key */
269
270 SILC_PKCS_ALG_PUBLIC_KEY_FREE(silc_softacc_free_public_key)
271 {
272   silc_free(public_key);
273 }
274
275 /* Free private key */
276
277 SILC_PKCS_ALG_PRIVATE_KEY_FREE(silc_softacc_free_private_key)
278 {
279   silc_free(private_key);
280 }
281
282 /* Accelerated encrypt */
283
284 SILC_PKCS_ALG_ENCRYPT(silc_softacc_encrypt)
285 {
286   SilcSoftaccPublicKey pubkey = public_key;
287   SilcStack stack;
288   SilcSoftaccExec e;
289   SilcSoftacc sa;
290
291   SILC_LOG_DEBUG(("Encrypt"));
292
293   sa = silc_global_get_var("softacc", FALSE);
294   if (!sa || !sa->schedule) {
295     SILC_LOG_ERROR(("Software accelerator not initialized"));
296     encrypt_cb(FALSE, NULL, 0, context);
297     return NULL;
298   }
299
300   stack = silc_stack_alloc(2048, silc_crypto_stack());
301
302   e = silc_scalloc(stack, 1, sizeof(*e));
303   if (!e) {
304     silc_stack_free(stack);
305     encrypt_cb(FALSE, NULL, 0, context);
306     return NULL;
307   }
308
309   silc_stack_push(stack, NULL);
310
311   e->stack = stack;
312   e->type = SILC_SOFTACC_ENCRYPT;
313   e->src = silc_smemdup(stack, src, src_len);
314   e->src_len = src_len;
315   e->rng = rng;
316   e->key.public_key = pubkey->key;
317   e->cb.encrypt_cb = encrypt_cb;
318   e->context = context;
319   silc_async_init(&e->op, silc_softacc_pkcs_abort, NULL, e);
320
321   /* Run */
322   silc_thread_pool_run(sa->tp, TRUE, sa->schedule, silc_softacc_pkcs_thread, e,
323                        silc_softacc_pkcs_completion, e);
324
325   return &e->op;
326 }
327
328 /* Acceleted decrypt */
329
330 SILC_PKCS_ALG_DECRYPT(silc_softacc_decrypt)
331 {
332   SilcSoftaccPrivateKey privkey = private_key;
333   SilcStack stack;
334   SilcSoftaccExec e;
335   SilcSoftacc sa;
336
337   SILC_LOG_DEBUG(("Decrypt"));
338
339   sa = silc_global_get_var("softacc", FALSE);
340   if (!sa || !sa->schedule) {
341     SILC_LOG_ERROR(("Software accelerator not initialized"));
342     decrypt_cb(FALSE, NULL, 0, context);
343     return NULL;
344   }
345
346   stack = silc_stack_alloc(2048, silc_crypto_stack());
347
348   e = silc_scalloc(stack, 1, sizeof(*e));
349   if (!e) {
350     silc_stack_free(stack);
351     decrypt_cb(FALSE, NULL, 0, context);
352     return NULL;
353   }
354
355   silc_stack_push(stack, NULL);
356
357   e->stack = stack;
358   e->type = SILC_SOFTACC_DECRYPT;
359   e->src = silc_smemdup(stack, src, src_len);
360   e->src_len = src_len;
361   e->key.private_key = privkey->key;
362   e->cb.decrypt_cb = decrypt_cb;
363   e->context = context;
364   silc_async_init(&e->op, silc_softacc_pkcs_abort, NULL, e);
365
366   /* Run */
367   silc_thread_pool_run(sa->tp, TRUE, sa->schedule, silc_softacc_pkcs_thread, e,
368                        silc_softacc_pkcs_completion, e);
369
370   return &e->op;
371 }
372
373 /* Accelerated signature */
374
375 SILC_PKCS_ALG_SIGN(silc_softacc_sign)
376 {
377   SilcSoftaccPrivateKey privkey = private_key;
378   SilcStack stack;
379   SilcSoftaccExec e;
380   SilcSoftacc sa;
381
382   SILC_LOG_DEBUG(("Sign"));
383
384   sa = silc_global_get_var("softacc", FALSE);
385   if (!sa || !sa->schedule) {
386     SILC_LOG_ERROR(("Software accelerator not initialized"));
387     sign_cb(FALSE, NULL, 0, context);
388     return NULL;
389   }
390
391   stack = silc_stack_alloc(2048, silc_crypto_stack());
392
393   e = silc_scalloc(stack, 1, sizeof(*e));
394   if (!e) {
395     silc_stack_free(stack);
396     sign_cb(FALSE, NULL, 0, context);
397     return NULL;
398   }
399
400   silc_stack_push(stack, NULL);
401
402   e->stack = stack;
403   e->type = SILC_SOFTACC_SIGN;
404   e->rng = rng;
405   e->src = silc_smemdup(stack, src, src_len);
406   e->src_len = src_len;
407   e->compute_hash = compute_hash;
408   e->hash = hash;
409   e->key.private_key = privkey->key;
410   e->cb.sign_cb = sign_cb;
411   e->context = context;
412   silc_async_init(&e->op, silc_softacc_pkcs_abort, NULL, e);
413
414   /* Run */
415   silc_thread_pool_run(sa->tp, TRUE, sa->schedule, silc_softacc_pkcs_thread, e,
416                        silc_softacc_pkcs_completion, e);
417
418   return &e->op;
419 }
420
421 /* Accelerated verification */
422
423 SILC_PKCS_ALG_VERIFY(silc_softacc_verify)
424 {
425   SilcSoftaccPublicKey pubkey = public_key;
426   SilcStack stack;
427   SilcSoftaccExec e;
428   SilcSoftacc sa;
429
430   SILC_LOG_DEBUG(("Verify"));
431
432   sa = silc_global_get_var("softacc", FALSE);
433   if (!sa || !sa->schedule) {
434     SILC_LOG_ERROR(("Software accelerator not initialized"));
435     verify_cb(FALSE, context);
436     return NULL;
437   }
438
439   stack = silc_stack_alloc(2048, silc_crypto_stack());
440
441   e = silc_scalloc(stack, 1, sizeof(*e));
442   if (!e) {
443     silc_stack_free(stack);
444     verify_cb(FALSE, context);
445     return NULL;
446   }
447
448   silc_stack_push(stack, NULL);
449
450   e->stack = stack;
451   e->type = SILC_SOFTACC_VERIFY;
452   e->src = silc_smemdup(stack, signature, signature_len);
453   e->src_len = signature_len;
454   e->data = silc_smemdup(stack, data, data_len);
455   e->data_len = data_len;
456   e->hash = hash;
457   e->key.public_key = pubkey->key;
458   e->cb.verify_cb = verify_cb;
459   e->context = context;
460   silc_async_init(&e->op, silc_softacc_pkcs_abort, NULL, e);
461
462   /* Run */
463   silc_thread_pool_run(sa->tp, TRUE, sa->schedule, silc_softacc_pkcs_thread, e,
464                        silc_softacc_pkcs_completion, e);
465
466   return &e->op;
467 }