Added SILC Accelerator Library.
authorPekka Riikonen <priikone@silcnet.org>
Mon, 9 Jul 2007 17:33:41 +0000 (17:33 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Mon, 9 Jul 2007 17:33:41 +0000 (17:33 +0000)
Added software accelerator.

lib/silcacc/Makefile.ad [new file with mode: 0644]
lib/silcacc/silcacc.c [new file with mode: 0644]
lib/silcacc/silcacc.h [new file with mode: 0644]
lib/silcacc/silcacc_pkcs.c [new file with mode: 0644]
lib/silcacc/softacc.c [new file with mode: 0644]
lib/silcacc/softacc.h [new file with mode: 0644]
lib/silcacc/tests/Makefile.am [new file with mode: 0644]
lib/silcacc/tests/test_softacc.c [new file with mode: 0644]

diff --git a/lib/silcacc/Makefile.ad b/lib/silcacc/Makefile.ad
new file mode 100644 (file)
index 0000000..3bb430a
--- /dev/null
@@ -0,0 +1,30 @@
+#
+#  Makefile.ad
+#
+#  Author: Pekka Riikonen <priikone@silcnet.org>
+#
+#  Copyright (C) 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; 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.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+noinst_LTLIBRARIES = libsilcacc.la
+
+libsilcacc_la_SOURCES = silcacc.c silcacc_pkcs.c softacc.c
+
+#ifdef SILC_DIST_TOOLKIT
+include_HEADERS = silcacc.h
+#endif SILC_DIST_TOOLKIT
+
+EXTRA_DIST = *.h $(SILC_EXTRA_DIST)
+
+include $(top_srcdir)/Makefile.defines.in
diff --git a/lib/silcacc/silcacc.c b/lib/silcacc/silcacc.c
new file mode 100644 (file)
index 0000000..e50a0ea
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+
+  silcacc.c
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 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; 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 "silc.h"
+#include "softacc.h"
+
+/************************** Types and definitions ***************************/
+
+#ifndef SILC_SYMBIAN
+/* Dynamically registered list of accelerators. */
+SilcDList silc_acc_list = NULL;
+#endif /* SILC_SYMBIAN */
+
+/* Static list of accelerators */
+const SilcAcceleratorStruct *silc_default_accs[] =
+{
+#ifndef SILC_SYMBIAN
+  /* Software accelerator */
+  &softacc,
+#endif /* SILC_SYMBIAN */
+  NULL
+};
+
+/*************************** SILC Accelerator API ***************************/
+
+/* Register accelerator */
+
+SilcBool silc_acc_register(const SilcAccelerator acc)
+{
+  if (!acc)
+    return FALSE;
+
+  if (!silc_acc_list) {
+    silc_acc_list = silc_dlist_init();
+    if (!silc_acc_list)
+      return FALSE;
+  }
+
+  SILC_LOG_DEBUG(("Register accelerator %p, name %s", acc, acc->name));
+  silc_dlist_add(silc_acc_list, acc);
+
+  return TRUE;
+}
+
+/* Unregister accelerator */
+
+void silc_acc_unregister(SilcAccelerator acc)
+{
+  if (!acc)
+    return;
+
+  if (!silc_acc_list)
+    return;
+
+  SILC_LOG_DEBUG(("Unregister accelerator %p, name %s", acc, acc->name));
+  silc_dlist_del(silc_acc_list, acc);
+
+  if (!silc_dlist_count(silc_acc_list)) {
+    silc_dlist_uninit(silc_acc_list);
+    silc_acc_list = NULL;
+  }
+}
+
+/* Initialize accelerator */
+
+SilcBool silc_acc_init(SilcAccelerator acc, SilcSchedule schedule, ...)
+{
+  va_list va;
+  SilcBool ret;
+
+  if (!acc || !schedule)
+    return FALSE;
+
+  SILC_LOG_DEBUG(("Initialize accelerator %p, name %s", acc, acc->name));
+
+  va_start(va, schedule);
+  ret = acc->init(schedule, va);
+  va_end(va);
+
+  return ret;
+}
+
+/* Uninitialize accelerator */
+
+SilcBool silc_acc_uninit(SilcAccelerator acc)
+{
+  if (!acc)
+    return FALSE;
+
+  SILC_LOG_DEBUG(("Uninitialize accelerator %p, name %s", acc, acc->name));
+  return acc->uninit();
+}
+
+/* Get list of registered accelerator */
+
+SilcDList silc_acc_get_supported(void)
+{
+  SilcDList list;
+  SilcAccelerator acc;
+  int i;
+
+  list = silc_dlist_init();
+  if (!list)
+    return NULL;
+
+  if (silc_acc_list) {
+    silc_dlist_start(silc_acc_list);
+    while ((acc = silc_dlist_get(silc_acc_list)))
+      silc_dlist_add(list, acc);
+  }
+
+  for (i = 0; silc_default_accs[i]->name; i++)
+    silc_dlist_add(list, (void *)silc_default_accs[i]);
+
+  return list;
+}
+
+/* Get accelerator */
+
+SilcAccelerator silc_acc_find(const char *name)
+{
+  SilcAccelerator acc;
+  int i;
+
+  if (!name)
+    return NULL;
+
+  SILC_LOG_DEBUG(("Find accelerator %s", name));
+
+  if (silc_acc_list) {
+    silc_dlist_start(silc_acc_list);
+    while ((acc = silc_dlist_get(silc_acc_list))) {
+      if (!strcmp(acc->name, name)) {
+       SILC_LOG_DEBUG(("Found accelerator %p", acc));
+       return acc;
+      }
+    }
+  }
+
+  for (i = 0; silc_default_accs[i]->name; i++) {
+    if (!strcmp(silc_default_accs[i]->name, name)) {
+      SILC_LOG_DEBUG(("Found accelerator %p", silc_default_accs[i]));
+      return (SilcAccelerator)silc_default_accs[i];
+    }
+  }
+
+  SILC_LOG_DEBUG(("Accelerator %s does not exist", name));
+  return NULL;
+}
+
+/* Get accelerator name */
+
+const char *silc_acc_get_name(SilcAccelerator acc)
+{
+  if (!acc)
+    return NULL;
+  return acc->name;
+}
diff --git a/lib/silcacc/silcacc.h b/lib/silcacc/silcacc.h
new file mode 100644 (file)
index 0000000..e438bc8
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+
+  silcacc.h
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 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; 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.
+
+*/
+
+/****h* silcskr/SILC Accelerator Interface
+ *
+ * DESCRIPTION
+ *
+ ***/
+
+#ifndef SILCACC_H
+#define SILCACC_H
+
+/****s* silcacc/SilcAccAPI/SilcAccelerator
+ *
+ * NAME
+ *
+ *    typedef struct SilcAcceleratorObject { ... }
+ *                            *SilcAccelerator, SilcAcceleratorStruct;
+ *
+ * DESCRIPTION
+ *
+ *    The accelerator context.  This is given as argument to silc_acc_register
+ *    when registering new accelerator, and it is given as argument to all
+ *    other silc_acc_* functions.  Registered accelerator context can be
+ *    retrieved by calling silc_acc_find.
+ *
+ ***/
+typedef struct SilcAcceleratorObject {
+  const char *name;                         /* Accelerator's name */
+  SilcBool (*init)(SilcSchedule schedule,
+                  va_list va);             /* Initialize accelerator */
+  SilcBool (*uninit)(void);                /* Uninitialize accelerator */
+  const SilcPKCSAlgorithm *pkcs;            /* Accelerated PKCS algorithms */
+#if 0
+  const SilcDHObject *dh;                   /* Accelerated Diffie-Hellmans */
+  const SilcCipherObject *cipher;          /* Accelerated ciphers */
+  const SilcHashObject *hash;              /* Accelerated hashes */
+  const SilcHmacObject *hmac;              /* Accelerated HMACs */
+  const SilcRngObject *rng;                /* Accelerated RNG's */
+#endif /* 0 */
+} *SilcAccelerator, SilcAcceleratorStruct;
+
+/****f* silcacc/SilcAccAPI/silc_acc_register
+ *
+ * SYNOPSIS
+ *
+ *    SilcBool silc_acc_register(const SilcAccelerator acc);
+ *
+ * DESCRIPTION
+ *
+ *    Register new accelerator to the accelerator library.  The `acc'
+ *    is the accelerator context to be registered.
+ *
+ * NOTES
+ *
+ *    This needs to be called only when adding new accelerator to the
+ *    library.  The accelerator library has some pre-registered accelerators
+ *    that need not be registered with this call.
+ *
+ ***/
+SilcBool silc_acc_register(const SilcAccelerator acc);
+
+/****f* silcacc/SilcAccAPI/silc_acc_unregister
+ *
+ * SYNOPSIS
+ *
+ *    void silc_acc_unregister(SilcAccelerator acc);
+ *
+ * DESCRIPTION
+ *
+ *    Unregister the accelerator `acc' from the accelerator library.  The
+ *    accelerator cannot be used anymore after this call has returned.
+ *
+ ***/
+void silc_acc_unregister(SilcAccelerator acc);
+
+/****f* silcacc/SilcAccAPI/silc_acc_init
+ *
+ * SYNOPSIS
+ *
+ *    SilcBool silc_acc_init(SilcAccelerator acc, SilcSchedule schedule, ...);
+ *
+ * DESCRIPTION
+ *
+ *    Initialize accelerator `acc'.  Usually accelerator may be initialized
+ *    only once and should be done after registering it.  The `schedule'
+ *    must be given as argument, in case the accelerator needs to do operations
+ *    through the scheduler.  The variable argument list is optional
+ *    accelerator specific initialization arguments.  The argument list must
+ *    be ended with NULL.  Returns FALSE if initialization failed.
+ *
+ * EXAMPLE
+ *
+ *    silc_acc_init(softacc, "min_threads", 2, "max_threads", 16, NULL);
+ *
+ ***/
+SilcBool silc_acc_init(SilcAccelerator acc, SilcSchedule schedule, ...);
+
+/****f* silcacc/SilcAccAPI/silc_acc_uninit
+ *
+ * SYNOPSIS
+ *
+ *    SilcBool silc_acc_uninit(SilcAccelerator acc);
+ *
+ * DESCRIPTION
+ *
+ *    Uninitialize the accelerator `acc'.  The accelerator may not be used
+ *    after this call has returned.  Some accelerators may be re-initialized
+ *    by calling silc_acc_init again.  Returns FALSE if error occurred
+ *    during uninitializing.
+ *
+ ***/
+SilcBool silc_acc_uninit(SilcAccelerator acc);
+
+/****f* silcacc/SilcAccAPI/silc_acc_get_supported
+ *
+ * SYNOPSIS
+ *
+ *    SilcDList silc_acc_get_supported(void);
+ *
+ * DESCRIPTION
+ *
+ *    Returns list of registered accelerators.  The caller must free the
+ *    returned list by calling silc_dlist_uninit.
+ *
+ ***/
+SilcDList silc_acc_get_supported(void);
+
+/****f* silcacc/SilcAccAPI/silc_acc_find
+ *
+ * SYNOPSIS
+ *
+ *    SilcAccelerator silc_acc_find(const char *name);
+ *
+ * DESCRIPTION
+ *
+ *    Find accelerator by its name indicated by `name'.  Returns the
+ *    accelerator context or NULL if such accelerator is not registered.
+ *
+ ***/
+SilcAccelerator silc_acc_find(const char *name);
+
+/****f* silcacc/SilcAccAPI/silc_acc_get_name
+ *
+ * SYNOPSIS
+ *
+ *    const char *silc_acc_get_name(SilcAccelerator acc);
+ *
+ * DESCRIPTION
+ *
+ *    Returns the name of the accelerator `acc'.
+ *
+ ***/
+const char *silc_acc_get_name(SilcAccelerator acc);
+
+/****f* silcacc/SilcAccAPI/silc_acc_public_key
+ *
+ * SYNOPSIS
+ *
+ *    SilcPublicKey silc_acc_public_key(SilcAccelerator acc,
+ *                                      SilcPublicKey public_key);
+ *
+ * DESCRIPTION
+ *
+ *    Accelerate the public key indicated by `public_key'.  Returns new
+ *    accelerated SilcPublicKey context.  It can be used just as normal
+ *    public key and must be freed by calling silc_pkcs_public_key_free.
+ *    The associated `public_key' is not freed when the accelerated public
+ *    key is freed.  The `public_key' must not be freed as long as it is
+ *    accelerated.
+ *
+ *    The associated `public_key' can be retrieved from the returned
+ *    public key by calling silc_acc_get_public_key.
+ *
+ ***/
+SilcPublicKey silc_acc_public_key(SilcAccelerator acc,
+                                 SilcPublicKey public_key);
+
+/****f* silcacc/SilcAccAPI/silc_acc_private_key
+ *
+ * SYNOPSIS
+ *
+ *    SilcPrivateKey silc_acc_private_key(SilcAccelerator acc,
+ *                                        SilcPrivateKey private_key);
+ *
+ * DESCRIPTION
+ *
+ *    Accelerate the private key indicated by `private_key'.  Returns new
+ *    accelerated SilcPrivateKey context.  It can be used just as normal
+ *    private key and must be freed by calling silc_pkcs_private_key_free.
+ *    The associated `private_key' is not freed when the accelerated private
+ *    key is freed.  The `private_key' must not be freed as long as it is
+ *    accelerated.
+ *
+ *    The associated `private_key' can be retrieved from the returned
+ *    private key by calling silc_acc_get_private_key.
+ *
+ ***/
+SilcPrivateKey silc_acc_private_key(SilcAccelerator acc,
+                                   SilcPrivateKey private_key);
+
+/****f* silcacc/SilcAccAPI/silc_acc_get_public_key
+ *
+ * SYNOPSIS
+ *
+ *    SilcPublicKey silc_acc_get_public_key(SilcAccelerator acc,
+ *                                          SilcPublicKey public_key);
+ *
+ * DESCRIPTION
+ *
+ *    Returns the underlaying public key from the accelerated public key
+ *    indicated by `public_key'.  Returns NULL if `public_key' is not
+ *    accelerated public key.
+ *
+ ***/
+SilcPublicKey silc_acc_get_public_key(SilcAccelerator acc,
+                                     SilcPublicKey public_key);
+
+/****f* silcacc/SilcAccAPI/silc_acc_get_private_key
+ *
+ * SYNOPSIS
+ *
+ *    SilcPrivateKey silc_acc_get_private_key(SilcAccelerator acc,
+ *                                            SilcPrivateKey private_key);
+ *
+ * DESCRIPTION
+ *
+ *    Returns the underlaying private key from the accelerated private key
+ *    indicated by `private_key'.  Returns NULL if `private_key' is not
+ *    accelerated private key.
+ *
+ ***/
+SilcPrivateKey silc_acc_get_private_key(SilcAccelerator acc,
+                                       SilcPrivateKey private_key);
+
+#endif /* SILCACC_H */
diff --git a/lib/silcacc/silcacc_pkcs.c b/lib/silcacc/silcacc_pkcs.c
new file mode 100644 (file)
index 0000000..ee2c5a2
--- /dev/null
@@ -0,0 +1,426 @@
+/*
+
+  silcacc_pkcs.c
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 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; 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 "silc.h"
+
+/************************** Types and definitions ***************************/
+
+SILC_PKCS_GET_ALGORITHM(silc_acc_pkcs_get_algorithm);
+SILC_PKCS_IMPORT_PUBLIC_KEY_FILE(silc_acc_pkcs_import_public_key_file);
+SILC_PKCS_IMPORT_PUBLIC_KEY(silc_acc_pkcs_import_public_key);
+SILC_PKCS_EXPORT_PUBLIC_KEY_FILE(silc_acc_pkcs_export_public_key_file);
+SILC_PKCS_EXPORT_PUBLIC_KEY(silc_acc_pkcs_export_public_key);
+SILC_PKCS_PUBLIC_KEY_BITLEN(silc_acc_pkcs_public_key_bitlen);
+SILC_PKCS_PUBLIC_KEY_COPY(silc_acc_pkcs_public_key_copy);
+SILC_PKCS_PUBLIC_KEY_COMPARE(silc_acc_pkcs_public_key_compare);
+SILC_PKCS_PUBLIC_KEY_FREE(silc_acc_pkcs_public_key_free);
+SILC_PKCS_IMPORT_PRIVATE_KEY_FILE(silc_acc_pkcs_import_private_key_file);
+SILC_PKCS_IMPORT_PRIVATE_KEY(silc_acc_pkcs_import_private_key);
+SILC_PKCS_EXPORT_PRIVATE_KEY_FILE(silc_acc_pkcs_export_private_key_file);
+SILC_PKCS_EXPORT_PRIVATE_KEY(silc_acc_pkcs_export_private_key);
+SILC_PKCS_PRIVATE_KEY_BITLEN(silc_acc_pkcs_private_key_bitlen);
+SILC_PKCS_PRIVATE_KEY_FREE(silc_acc_pkcs_private_key_free);
+SILC_PKCS_ENCRYPT(silc_acc_pkcs_encrypt);
+SILC_PKCS_DECRYPT(silc_acc_pkcs_decrypt);
+SILC_PKCS_SIGN(silc_acc_pkcs_sign);
+SILC_PKCS_VERIFY(silc_acc_pkcs_verify);
+
+/* Accelerator public key */
+typedef struct {
+  int pkcs_index;              /* Accelerator PKCS index */
+  SilcAccelerator acc;         /* The accelerator */
+  void *context;               /* Accelerator context */
+  SilcPublicKey accelerated;   /* Associated public key */
+} *SilcAcceleratorPublicKey;
+
+/* Accelerator private key */
+typedef struct {
+  int pkcs_index;              /* Accelerator PKCS index */
+  SilcAccelerator acc;         /* The accelerator */
+  void *context;               /* Accelerator context */
+  SilcPrivateKey accelerated;  /* Associated private key */
+} *SilcAcceleratorPrivateKey;
+
+/*************************** Accelerator PKCS API ***************************/
+
+/* The PKCS API for the accelerated public key and private key is simply
+   a wrapper for the underlaying key.  Encrypt, decrypt, sign and verify
+   operations are accelerated by calling the accelerator operations. */
+
+const SilcPKCSObject silc_acc_pkcs =
+{
+  SILC_PKCS_SILC,
+
+  /* Wrappers */
+  silc_acc_pkcs_get_algorithm,
+  silc_acc_pkcs_import_public_key_file,
+  silc_acc_pkcs_import_public_key,
+  silc_acc_pkcs_export_public_key_file,
+  silc_acc_pkcs_export_public_key,
+  silc_acc_pkcs_public_key_bitlen,
+  silc_acc_pkcs_public_key_copy,
+  silc_acc_pkcs_public_key_compare,
+  silc_acc_pkcs_public_key_free,
+  silc_acc_pkcs_import_private_key_file,
+  silc_acc_pkcs_import_private_key,
+  silc_acc_pkcs_export_private_key_file,
+  silc_acc_pkcs_export_private_key,
+  silc_acc_pkcs_private_key_bitlen,
+  silc_acc_pkcs_private_key_free,
+
+  /* Accelerated */
+  silc_acc_pkcs_encrypt,
+  silc_acc_pkcs_decrypt,
+  silc_acc_pkcs_sign,
+  silc_acc_pkcs_verify
+};
+
+SILC_PKCS_GET_ALGORITHM(silc_acc_pkcs_get_algorithm)
+{
+  SilcAcceleratorPublicKey pub = public_key;
+  return pub->accelerated->pkcs->get_algorithm(pub->accelerated->pkcs,
+                                              pub->accelerated->public_key);
+}
+
+SILC_PKCS_IMPORT_PUBLIC_KEY_FILE(silc_acc_pkcs_import_public_key_file)
+{
+  /* Not implemented */
+  return FALSE;
+}
+
+SILC_PKCS_IMPORT_PUBLIC_KEY(silc_acc_pkcs_import_public_key)
+{
+  /* Not implemented */
+  return FALSE;
+}
+
+SILC_PKCS_EXPORT_PUBLIC_KEY_FILE(silc_acc_pkcs_export_public_key_file)
+{
+  SilcAcceleratorPublicKey pub = public_key;
+  return pub->accelerated->pkcs->
+    export_public_key_file(pub->accelerated->pkcs, NULL,
+                          pub->accelerated->public_key,
+                          encoding, ret_len);
+}
+
+SILC_PKCS_EXPORT_PUBLIC_KEY(silc_acc_pkcs_export_public_key)
+{
+  SilcAcceleratorPublicKey pub = public_key;
+  return pub->accelerated->pkcs->export_public_key(pub->accelerated->pkcs,
+                                                  NULL,
+                                                  pub->accelerated->public_key,
+                                                  ret_len);
+}
+
+SILC_PKCS_PUBLIC_KEY_BITLEN(silc_acc_pkcs_public_key_bitlen)
+{
+  SilcAcceleratorPublicKey pub = public_key;
+  return pub->accelerated->pkcs->
+    public_key_bitlen(pub->accelerated->pkcs,
+                     pub->accelerated->public_key);
+}
+
+SILC_PKCS_PUBLIC_KEY_COPY(silc_acc_pkcs_public_key_copy)
+{
+  SilcAcceleratorPublicKey pub = public_key;
+  return pub->accelerated->pkcs->public_key_copy(pub->accelerated->pkcs,
+                                                pub->accelerated->public_key);
+}
+
+SILC_PKCS_PUBLIC_KEY_COMPARE(silc_acc_pkcs_public_key_compare)
+{
+  /* XXX */
+  return FALSE;
+}
+
+SILC_PKCS_IMPORT_PRIVATE_KEY_FILE(silc_acc_pkcs_import_private_key_file)
+{
+  return 0;
+}
+
+SILC_PKCS_IMPORT_PRIVATE_KEY(silc_acc_pkcs_import_private_key)
+{
+  return 0;
+}
+
+SILC_PKCS_EXPORT_PRIVATE_KEY_FILE(silc_acc_pkcs_export_private_key_file)
+{
+  return 0;
+}
+
+SILC_PKCS_EXPORT_PRIVATE_KEY(silc_acc_pkcs_export_private_key)
+{
+  return 0;
+}
+
+SILC_PKCS_PRIVATE_KEY_BITLEN(silc_acc_pkcs_private_key_bitlen)
+{
+  return 0;
+}
+
+SILC_PKCS_PUBLIC_KEY_FREE(silc_acc_pkcs_public_key_free)
+{
+
+}
+
+SILC_PKCS_PRIVATE_KEY_FREE(silc_acc_pkcs_private_key_free)
+{
+
+}
+
+SILC_PKCS_ENCRYPT(silc_acc_pkcs_encrypt)
+{
+  SilcAcceleratorPublicKey pub = public_key;
+
+  /* Accelerate */
+  return pub->acc->pkcs[pub->pkcs_index].encrypt(
+                      &pub->acc->pkcs[pub->pkcs_index], pub->context, src,
+                      src_len, rng, encrypt_cb, context);
+}
+
+SILC_PKCS_DECRYPT(silc_acc_pkcs_decrypt)
+{
+  SilcAcceleratorPrivateKey prv = private_key;
+
+  /* Accelerate */
+  return prv->acc->pkcs[prv->pkcs_index].decrypt(
+                      &prv->acc->pkcs[prv->pkcs_index], prv->context, src,
+                      src_len, decrypt_cb, context);
+}
+
+SILC_PKCS_SIGN(silc_acc_pkcs_sign)
+{
+  SilcAcceleratorPrivateKey prv = private_key;
+
+  /* Accelerate */
+  return prv->acc->pkcs[prv->pkcs_index].sign(
+                      &prv->acc->pkcs[prv->pkcs_index], prv->context, src,
+                      src_len, compute_hash, hash, sign_cb, context);
+}
+
+SILC_PKCS_VERIFY(silc_acc_pkcs_verify)
+{
+  SilcAcceleratorPublicKey pub = public_key;
+
+  /* Accelerate */
+  return pub->acc->pkcs[pub->pkcs_index].verify(
+                      &pub->acc->pkcs[pub->pkcs_index], pub->context,
+                      signature, signature_len, data, data_len, hash,
+                      verify_cb, context);
+}
+
+/*************************** SILC Accelerator API ***************************/
+
+/* Accelerate public key */
+
+SilcPublicKey silc_acc_public_key(SilcAccelerator acc,
+                                 SilcPublicKey public_key)
+{
+  SilcPublicKey pubkey;
+  SilcAcceleratorPublicKey acc_pubkey;
+  const SilcPKCSAlgorithm *alg;
+  int i;
+
+  if (!acc || !public_key)
+    return NULL;
+
+  SILC_LOG_DEBUG(("Accelerate public key %p with accelerator %s",
+                 public_key, acc->name));
+
+  if (!acc->pkcs) {
+    SILC_LOG_ERROR(("Accelerator '%s' does not support public key "
+                   "acceleration", acc->name));
+    return NULL;
+  }
+
+  /* Check that accelerator supports this public key algorithm */
+  alg = silc_pkcs_get_algorithm(public_key);
+  if (!alg)
+    return NULL;
+  for (i = 0; acc->pkcs[i].name; i++) {
+    if ((!strcmp(acc->pkcs[i].name, alg->name) &&
+        !strcmp(acc->pkcs[i].scheme, alg->scheme)) ||
+       !strcmp(acc->pkcs[i].name, "any")) {
+      alg = NULL;
+      break;
+    }
+  }
+  if (alg) {
+    SILC_LOG_DEBUG(("Accelerator %s does not support %s/%s acceleration",
+                   alg->name, alg->scheme));
+    return NULL;
+  }
+
+  pubkey = silc_calloc(1, sizeof(*pubkey));
+  if (!pubkey)
+    return NULL;
+
+  /* Allocate PKCS operations */
+  pubkey->pkcs = silc_calloc(1, sizeof(*pubkey->pkcs));
+  if (!pubkey->pkcs) {
+    silc_free(pubkey);
+    return NULL;
+  }
+  *pubkey->pkcs = silc_acc_pkcs;
+  pubkey->pkcs->type = silc_pkcs_get_type(public_key);
+
+  /* Allocate accelerator public key */
+  acc_pubkey = silc_calloc(1, sizeof(*acc_pubkey));
+  if (!acc_pubkey) {
+    silc_free(pubkey->pkcs);
+    silc_free(pubkey);
+    return NULL;
+  }
+  acc_pubkey->accelerated = public_key;
+  acc_pubkey->acc = acc;
+  acc_pubkey->pkcs_index = i;
+
+  /* Accelerate the public key.  Returns accelerator context. */
+  if (!acc->pkcs->import_public_key(&acc->pkcs[i], public_key, 0,
+                                   &acc_pubkey->context)) {
+    SILC_LOG_ERROR(("Error accelerating public key with accelerator '%s'",
+                   acc->name));
+    silc_free(acc_pubkey);
+    silc_free(pubkey->pkcs);
+    silc_free(pubkey);
+    return NULL;
+  }
+  pubkey->public_key = acc_pubkey;
+
+  SILC_LOG_DEBUG(("New accelerated public key %p", pubkey));
+
+  return pubkey;
+}
+
+/* Accelerate private key */
+
+SilcPrivateKey silc_acc_private_key(SilcAccelerator acc,
+                                   SilcPrivateKey private_key)
+{
+  SilcPrivateKey privkey;
+  SilcAcceleratorPrivateKey acc_privkey;
+  const SilcPKCSAlgorithm *alg;
+  int i;
+
+  if (!acc || !private_key)
+    return NULL;
+
+  SILC_LOG_DEBUG(("Accelerate private key %p with accelerator %s",
+                 private_key, acc->name));
+
+  if (!acc->pkcs) {
+    SILC_LOG_ERROR(("Accelerator '%s' does not support private key "
+                   "acceleration", acc->name));
+    return NULL;
+  }
+
+  /* Check that accelerator supports this private key algorithm */
+  alg = silc_pkcs_get_algorithm(private_key);
+  if (!alg)
+    return NULL;
+  for (i = 0; acc->pkcs[i].name; i++) {
+    if ((!strcmp(acc->pkcs[i].name, alg->name) &&
+        !strcmp(acc->pkcs[i].scheme, alg->scheme)) ||
+       !strcmp(acc->pkcs[i].name, "any")) {
+      alg = NULL;
+      break;
+    }
+  }
+  if (alg) {
+    SILC_LOG_DEBUG(("Accelerator %s does not support %s/%s acceleration",
+                   alg->name, alg->scheme));
+    return NULL;
+  }
+
+  privkey = silc_calloc(1, sizeof(*privkey));
+  if (!privkey)
+    return NULL;
+
+  /* Allocate PKCS operations */
+  privkey->pkcs = silc_calloc(1, sizeof(*privkey->pkcs));
+  if (!privkey->pkcs) {
+    silc_free(privkey);
+    return NULL;
+  }
+  *privkey->pkcs = silc_acc_pkcs;
+  privkey->pkcs->type = silc_pkcs_get_type(private_key);
+
+  /* Allocate accelerator public key */
+  acc_privkey = silc_calloc(1, sizeof(*acc_privkey));
+  if (!acc_privkey) {
+    silc_free(privkey->pkcs);
+    silc_free(privkey);
+    return NULL;
+  }
+  acc_privkey->accelerated = private_key;
+  acc_privkey->acc = acc;
+  acc_privkey->pkcs_index = i;
+
+  /* Accelerate the public key.  Returns accelerator context. */
+  if (!acc->pkcs->import_private_key(&acc->pkcs[i], private_key, 0,
+                                    &acc_privkey->context)) {
+    SILC_LOG_ERROR(("Error accelerating private key with accelerator '%s'",
+                   acc->name));
+    silc_free(acc_privkey);
+    silc_free(privkey->pkcs);
+    silc_free(privkey);
+    return NULL;
+  }
+  privkey->private_key = acc_privkey;
+
+  SILC_LOG_DEBUG(("New accelerated private key %p", privkey));
+
+  return privkey;
+}
+
+/* Get associated public key */
+
+SilcPublicKey silc_acc_get_public_key(SilcAccelerator acc,
+                                     SilcPublicKey public_key)
+{
+  SilcAcceleratorPublicKey pubkey;
+
+  if (!public_key)
+    return NULL;
+
+  if (public_key->pkcs->get_algorithm != silc_acc_pkcs_get_algorithm)
+    return NULL;
+
+  pubkey = public_key->public_key;
+
+  return pubkey->accelerated;
+}
+
+/* Get associated private key */
+
+SilcPrivateKey silc_acc_get_private_key(SilcAccelerator acc,
+                                       SilcPrivateKey private_key)
+{
+  SilcAcceleratorPrivateKey privkey;
+
+  if (!private_key)
+    return NULL;
+
+  if (private_key->pkcs->get_algorithm != silc_acc_pkcs_get_algorithm)
+    return NULL;
+
+  privkey = private_key->private_key;
+
+  return privkey->accelerated;
+}
diff --git a/lib/silcacc/softacc.c b/lib/silcacc/softacc.c
new file mode 100644 (file)
index 0000000..89c1ada
--- /dev/null
@@ -0,0 +1,535 @@
+/*
+
+  softacc.c
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 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; 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 "silc.h"
+#include "softacc.h"
+
+/* Software accelerator is a thread-pool system where public key and private
+   key operations are executed in threads for the purpose of off-loading and
+   balancing the computations across multiple processors. */
+
+#define SILC_SOFTACC_MIN_THREADS 0
+#define SILC_SOFTACC_MAX_THREADS 4
+
+/************************** Types and definitions ***************************/
+
+/* Software accelerator PKCS algorithm operations */
+const SilcPKCSAlgorithm softacc_pkcs[] =
+{
+  {
+    "any", "any", NULL, NULL,
+    silc_softacc_acc_public_key,
+    NULL, NULL, NULL, NULL,
+    silc_softacc_free_public_key,
+    silc_softacc_acc_private_key,
+    NULL, NULL,
+    silc_softacc_free_private_key,
+    silc_softacc_encrypt,
+    silc_softacc_decrypt,
+    silc_softacc_sign,
+    silc_softacc_verify,
+  },
+
+  {
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+    NULL, NULL
+  }
+};
+
+/* Software accelerator operations */
+const SilcAcceleratorStruct softacc =
+{
+  "softacc", silc_softacc_init, silc_softacc_uninit, softacc_pkcs
+};
+
+/* Software accelerator public key */
+typedef struct {
+  SilcPublicKey key;                    /* Accelerated public key */
+} *SilcSoftaccPublicKey;
+
+/* Software accelerator private key */
+typedef struct {
+  SilcPrivateKey key;                   /* Accelerated private key */
+} *SilcSoftaccPrivateKey;
+
+/* Execution types */
+typedef enum {
+  SILC_SOFTACC_ENCRYPT,
+  SILC_SOFTACC_DECRYPT,
+  SILC_SOFTACC_SIGN,
+  SILC_SOFTACC_VERIFY,
+} SilcSoftaccType;
+
+/* Executor context */
+typedef struct {
+  SilcStack stack;                      /* Executor stack */
+  void *context;                        /* Callback context */
+  SilcSoftaccType type;                         /* Execution type */
+  SilcAsyncOperationStruct op;          /* Operation for aborting */
+
+  unsigned char *src;                   /* Source data */
+  unsigned char *data;                  /* More source data */
+  SilcUInt32 src_len;
+  SilcUInt32 data_len;
+  SilcHash hash;                        /* Hash function to use */
+  SilcRng rng;                          /* RNG, may be NULL */
+
+  union {
+    SilcPublicKey public_key;
+    SilcPrivateKey private_key;
+  } key;
+
+  union {
+    SilcPKCSEncryptCb encrypt_cb;
+    SilcPKCSDecryptCb decrypt_cb;
+    SilcPKCSSignCb sign_cb;
+    SilcPKCSVerifyCb verify_cb;
+  } cb;
+
+  unsigned char *result_data;
+  SilcUInt32 result_len;
+
+  unsigned int result       : 1;
+  unsigned int compute_hash : 1;
+  unsigned int aborted      : 1;
+} *SilcSoftaccExec;
+
+/* Software accelerator context */
+typedef struct {
+  SilcSchedule schedule;                /* Scheduler */
+  SilcThreadPool tp;                    /* The thread pool */
+} *SilcSoftacc;
+
+SilcSoftacc sa = NULL;                  /* The accelerator */
+
+/***************************** Accelerator API ******************************/
+
+/* Initialize software accelerator.  Optional initialization parameters:
+
+   min_threads     number        Minimum number of threads (default 0)
+   max_thread      number        Maximum number of threads (default 4)
+
+   Eg. silc_acc_init(softacc, "min_threads", 2, "max_threads", 8, NULL);
+
+*/
+
+SilcBool silc_softacc_init(SilcSchedule schedule, va_list va)
+{
+  SilcUInt32 min_threads = SILC_SOFTACC_MIN_THREADS;
+  SilcUInt32 max_threads = SILC_SOFTACC_MAX_THREADS;
+  char *opt;
+
+  if (!schedule)
+    return FALSE;
+
+  /* If already initialized, uninitialize first. */
+  if (sa)
+    silc_softacc_uninit();
+
+  /* Get options */
+  while ((opt = va_arg(va, char *))) {
+    if (!strcmp(opt, "min_threads"))
+      min_threads = va_arg(va, SilcUInt32);
+    else if (!strcmp(opt, "max_threads"))
+      max_threads = va_arg(va, SilcUInt32);
+  }
+
+  SILC_LOG_DEBUG(("Initialize software accelerator, min_threads %d, "
+                 "max_threads %d", min_threads, max_threads));
+
+  sa = silc_calloc(1, sizeof(*sa));
+  if (!sa)
+    return FALSE;
+
+  sa->schedule = schedule;
+
+  /* Start the thread pool */
+  sa->tp = silc_thread_pool_alloc(NULL, min_threads, max_threads, TRUE);
+  if (!sa->tp) {
+    silc_free(sa);
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/* Uninitialize */
+
+SilcBool silc_softacc_uninit(void)
+{
+  if (!sa)
+    return FALSE;
+
+  SILC_LOG_DEBUG(("Uninitialize software accelerator"));
+
+  silc_thread_pool_free(sa->tp, TRUE);
+  silc_free(sa);
+  sa = NULL;
+
+  return TRUE;
+}
+
+/****************************** PKCS ALG API ********************************/
+
+/* Abort operation */
+
+void silc_softacc_abort(SilcAsyncOperation op, void *context)
+{
+  SilcSoftaccExec e = context;
+  e->aborted = TRUE;
+}
+
+/* Accelerator completion, executed in main thread. */
+
+SILC_TASK_CALLBACK(silc_softacc_completion)
+{
+  SilcSoftaccExec e = context;
+  SilcStack stack = e->stack;
+
+  /* At the latest, abort is catched here in the main thread.  Don't
+     deliver callback if we were aborted */
+  if (e->aborted)
+    goto out;
+
+  SILC_LOG_DEBUG(("Call completion, result=%s", e->result ? "Ok" : "failed"));
+
+  /* Call completion callback */
+  switch (e->type) {
+  case SILC_SOFTACC_ENCRYPT:
+    e->cb.encrypt_cb(e->result, e->result_data, e->result_len, e->context);
+    break;
+
+  case SILC_SOFTACC_DECRYPT:
+    e->cb.decrypt_cb(e->result, e->result_data, e->result_len, e->context);
+    break;
+
+  case SILC_SOFTACC_SIGN:
+    e->cb.sign_cb(e->result, e->result_data, e->result_len, e->context);
+    break;
+
+  case SILC_SOFTACC_VERIFY:
+    e->cb.verify_cb(e->result, e->context);
+    break;
+  }
+
+ out:
+  silc_sfree(stack, e->src);
+  silc_sfree(stack, e->data);
+  silc_sfree(stack, e);
+  silc_stack_free(stack);
+}
+
+/* Callback for encrypt, decrypt and signature */
+
+void silc_softacc_data_cb(SilcBool success, const unsigned char *data,
+                         SilcUInt32 data_len, void *context)
+{
+  SilcSoftaccExec e = context;
+  SilcStack stack = e->stack;
+
+  /* Pop e->src and e->data from memory */
+  silc_stack_pop(stack);
+
+  if (success)
+    e->result_data = silc_smemdup(stack, data, data_len);
+  e->result_len = data_len;
+  e->result = success;
+}
+
+/* Verification callback */
+
+void silc_softacc_verify_cb(SilcBool success, void *context)
+{
+  SilcSoftaccExec e = context;
+  SilcStack stack = e->stack;
+
+  silc_stack_pop(stack);
+  e->result = success;
+}
+
+/* Accelerator thread */
+
+void silc_softacc_thread(SilcSchedule schedule, void *context)
+{
+  SilcSoftaccExec e = context;
+
+  if (e->aborted)
+    return;
+
+  SILC_LOG_DEBUG(("Execute type %d", e->type));
+
+  /* Call the operation */
+  switch (e->type) {
+  case SILC_SOFTACC_ENCRYPT:
+    silc_pkcs_encrypt(e->key.public_key, e->src, e->src_len, e->rng,
+                     silc_softacc_data_cb, e);
+    break;
+
+  case SILC_SOFTACC_DECRYPT:
+    silc_pkcs_decrypt(e->key.private_key, e->src, e->src_len,
+                     silc_softacc_data_cb, e);
+    break;
+
+  case SILC_SOFTACC_SIGN:
+    silc_pkcs_sign(e->key.private_key, e->src, e->src_len, e->compute_hash,
+                  e->hash, silc_softacc_data_cb, e);
+    break;
+
+  case SILC_SOFTACC_VERIFY:
+    silc_pkcs_verify(e->key.public_key, e->src, e->src_len, e->data,
+                    e->data_len, e->hash, silc_softacc_verify_cb, e);
+    break;
+  }
+}
+
+/* Accelerate public key */
+
+SILC_PKCS_ALG_IMPORT_PUBLIC_KEY(silc_softacc_acc_public_key)
+{
+  SilcSoftaccPublicKey pubkey;
+
+  if (!sa) {
+    SILC_LOG_ERROR(("Software accelerator not initialized"));
+    return FALSE;
+  }
+
+  pubkey = silc_calloc(1, sizeof(*pubkey));
+  if (!pubkey)
+    return FALSE;
+  pubkey->key = key;
+
+  *ret_public_key = pubkey;
+
+  return TRUE;
+}
+
+/* Accelerate private key */
+
+SILC_PKCS_ALG_IMPORT_PRIVATE_KEY(silc_softacc_acc_private_key)
+{
+  SilcSoftaccPrivateKey privkey;
+
+  if (!sa) {
+    SILC_LOG_ERROR(("Software accelerator not initialized"));
+    return FALSE;
+  }
+
+  privkey = silc_calloc(1, sizeof(*privkey));
+  if (!privkey)
+    return FALSE;
+  privkey->key = key;
+
+  *ret_private_key = privkey;
+
+  return TRUE;
+}
+
+/* Free public key */
+
+SILC_PKCS_ALG_PUBLIC_KEY_FREE(silc_softacc_free_public_key)
+{
+  silc_free(public_key);
+}
+
+/* Free private key */
+
+SILC_PKCS_ALG_PRIVATE_KEY_FREE(silc_softacc_free_private_key)
+{
+  silc_free(private_key);
+}
+
+/* Accelerated encrypt */
+
+SILC_PKCS_ALG_ENCRYPT(silc_softacc_encrypt)
+{
+  SilcSoftaccPublicKey pubkey = public_key;
+  SilcStack stack;
+  SilcSoftaccExec e;
+
+  SILC_LOG_DEBUG(("Encrypt"));
+
+  if (!sa) {
+    SILC_LOG_ERROR(("Software accelerator not initialized"));
+    encrypt_cb(FALSE, NULL, 0, context);
+    return NULL;
+  }
+
+  stack = silc_stack_alloc(2048, silc_crypto_stack());
+
+  e = silc_scalloc(stack, 1, sizeof(*e));
+  if (!e) {
+    silc_stack_free(stack);
+    encrypt_cb(FALSE, NULL, 0, context);
+    return NULL;
+  }
+
+  silc_stack_push(stack, NULL);
+
+  e->stack = stack;
+  e->type = SILC_SOFTACC_ENCRYPT;
+  e->src = silc_smemdup(stack, src, src_len);
+  e->src_len = src_len;
+  e->rng = rng;
+  e->key.public_key = pubkey->key;
+  e->cb.encrypt_cb = encrypt_cb;
+  e->context = context;
+  silc_async_init(&e->op, silc_softacc_abort, NULL, e);
+
+  /* Run */
+  silc_thread_pool_run(sa->tp, TRUE, sa->schedule, silc_softacc_thread, e,
+                      silc_softacc_completion, e);
+
+  return &e->op;
+}
+
+/* Acceleted decrypt */
+
+SILC_PKCS_ALG_DECRYPT(silc_softacc_decrypt)
+{
+  SilcSoftaccPrivateKey privkey = private_key;
+  SilcStack stack;
+  SilcSoftaccExec e;
+
+  SILC_LOG_DEBUG(("Decrypt"));
+
+  if (!sa) {
+    SILC_LOG_ERROR(("Software accelerator not initialized"));
+    decrypt_cb(FALSE, NULL, 0, context);
+    return NULL;
+  }
+
+  stack = silc_stack_alloc(2048, silc_crypto_stack());
+
+  e = silc_scalloc(stack, 1, sizeof(*e));
+  if (!e) {
+    silc_stack_free(stack);
+    decrypt_cb(FALSE, NULL, 0, context);
+    return NULL;
+  }
+
+  silc_stack_push(stack, NULL);
+
+  e->stack = stack;
+  e->type = SILC_SOFTACC_DECRYPT;
+  e->src = silc_smemdup(stack, src, src_len);
+  e->src_len = src_len;
+  e->key.private_key = privkey->key;
+  e->cb.decrypt_cb = decrypt_cb;
+  e->context = context;
+  silc_async_init(&e->op, silc_softacc_abort, NULL, e);
+
+  /* Run */
+  silc_thread_pool_run(sa->tp, TRUE, sa->schedule, silc_softacc_thread, e,
+                      silc_softacc_completion, e);
+
+  return &e->op;
+}
+
+/* Accelerated signature */
+
+SILC_PKCS_ALG_SIGN(silc_softacc_sign)
+{
+  SilcSoftaccPrivateKey privkey = private_key;
+  SilcStack stack;
+  SilcSoftaccExec e;
+
+  SILC_LOG_DEBUG(("Sign"));
+
+  if (!sa) {
+    SILC_LOG_ERROR(("Software accelerator not initialized"));
+    sign_cb(FALSE, NULL, 0, context);
+    return NULL;
+  }
+
+  stack = silc_stack_alloc(2048, silc_crypto_stack());
+
+  e = silc_scalloc(stack, 1, sizeof(*e));
+  if (!e) {
+    silc_stack_free(stack);
+    sign_cb(FALSE, NULL, 0, context);
+    return NULL;
+  }
+
+  silc_stack_push(stack, NULL);
+
+  e->stack = stack;
+  e->type = SILC_SOFTACC_SIGN;
+  e->src = silc_smemdup(stack, src, src_len);
+  e->src_len = src_len;
+  e->compute_hash = compute_hash;
+  e->hash = hash;
+  e->key.private_key = privkey->key;
+  e->cb.sign_cb = sign_cb;
+  e->context = context;
+  silc_async_init(&e->op, silc_softacc_abort, NULL, e);
+
+  /* Run */
+  silc_thread_pool_run(sa->tp, TRUE, sa->schedule, silc_softacc_thread, e,
+                      silc_softacc_completion, e);
+
+  return &e->op;
+}
+
+/* Accelerated verification */
+
+SILC_PKCS_ALG_VERIFY(silc_softacc_verify)
+{
+  SilcSoftaccPublicKey pubkey = public_key;
+  SilcStack stack;
+  SilcSoftaccExec e;
+
+  SILC_LOG_DEBUG(("Verify"));
+
+  if (!sa) {
+    SILC_LOG_ERROR(("Software accelerator not initialized"));
+    verify_cb(FALSE, context);
+    return NULL;
+  }
+
+  stack = silc_stack_alloc(2048, silc_crypto_stack());
+
+  e = silc_scalloc(stack, 1, sizeof(*e));
+  if (!e) {
+    silc_stack_free(stack);
+    verify_cb(FALSE, context);
+    return NULL;
+  }
+
+  silc_stack_push(stack, NULL);
+
+  e->stack = stack;
+  e->type = SILC_SOFTACC_VERIFY;
+  e->src = silc_smemdup(stack, signature, signature_len);
+  e->src_len = signature_len;
+  e->data = silc_smemdup(stack, data, data_len);
+  e->data_len = data_len;
+  e->hash = hash;
+  e->key.public_key = pubkey->key;
+  e->cb.verify_cb = verify_cb;
+  e->context = context;
+  silc_async_init(&e->op, silc_softacc_abort, NULL, e);
+
+  /* Run */
+  silc_thread_pool_run(sa->tp, TRUE, sa->schedule, silc_softacc_thread, e,
+                      silc_softacc_completion, e);
+
+  return &e->op;
+}
diff --git a/lib/silcacc/softacc.h b/lib/silcacc/softacc.h
new file mode 100644 (file)
index 0000000..a359736
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+
+  softacc.h
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 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; 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.
+
+*/
+
+#ifndef SOFTACC_H
+#define SOFTACC_H
+
+/* The software accelerator */
+extern DLLAPI const SilcAcceleratorStruct softacc;
+
+SilcBool silc_softacc_init(SilcSchedule schedule, va_list va);
+SilcBool silc_softacc_uninit(void);
+SILC_PKCS_ALG_IMPORT_PUBLIC_KEY(silc_softacc_acc_public_key);
+SILC_PKCS_ALG_PUBLIC_KEY_FREE(silc_softacc_free_public_key);
+SILC_PKCS_ALG_IMPORT_PRIVATE_KEY(silc_softacc_acc_private_key);
+SILC_PKCS_ALG_PRIVATE_KEY_FREE(silc_softacc_free_private_key);
+SILC_PKCS_ALG_ENCRYPT(silc_softacc_encrypt);
+SILC_PKCS_ALG_DECRYPT(silc_softacc_decrypt);
+SILC_PKCS_ALG_SIGN(silc_softacc_sign);
+SILC_PKCS_ALG_VERIFY(silc_softacc_verify);
+
+#endif /* SOFTACC_H */
diff --git a/lib/silcacc/tests/Makefile.am b/lib/silcacc/tests/Makefile.am
new file mode 100644 (file)
index 0000000..b431654
--- /dev/null
@@ -0,0 +1,27 @@
+#
+#  Makefile.am
+#
+#  Author: Pekka Riikonen <priikone@silcnet.org>
+#
+#  Copyright (C) 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; 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.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+bin_PROGRAMS = test_softacc
+
+test_softacc_SOURCES = test_softacc.c
+
+LIBS = $(SILC_COMMON_LIBS)
+LDADD = -L.. -L../.. -lsilc -lsilcacc
+
+include $(top_srcdir)/Makefile.defines.in
diff --git a/lib/silcacc/tests/test_softacc.c b/lib/silcacc/tests/test_softacc.c
new file mode 100644 (file)
index 0000000..066fd2a
--- /dev/null
@@ -0,0 +1,88 @@
+/* Software accelerator tests */
+
+#include "silc.h"
+
+SilcSchedule schedule;
+SilcPublicKey public_key, accpub;
+SilcPrivateKey private_key, accprv;
+SilcHash hash;
+unsigned char data[] = "Single block msg";
+int data_len = 16;
+int s = 100;
+
+void sign_compl(SilcBool success, const unsigned char *signature,
+               SilcUInt32 signature_len, void *context)
+{
+  SILC_LOG_DEBUG(("Sign compl %s", success ? "Ok" : "failed"));
+}
+
+SILC_TASK_CALLBACK(quit)
+{
+  silc_schedule_stop(schedule);
+}
+
+SILC_TASK_CALLBACK(sign)
+{
+  silc_pkcs_sign(accprv, data, data_len, TRUE, hash, sign_compl, NULL);
+  if (--s > 0)
+    silc_schedule_task_add_timeout(schedule, sign, NULL, 0, 70000);
+}
+
+int main(int argc, char **argv)
+{
+  SilcBool success = FALSE;
+  SilcAccelerator softacc;
+
+  if (argc > 1 && !strcmp(argv[1], "-d")) {
+    silc_log_debug(TRUE);
+    silc_log_quick(TRUE);
+    silc_log_debug_hexdump(TRUE);
+    silc_log_set_debug_string("*acc*");
+  }
+
+  silc_crypto_init(NULL);
+  if (!silc_hash_alloc("sha1", &hash))
+    goto err;
+
+  if (!silc_create_key_pair("rsa", 2048, "pubkey.pub", "privkey.prv", NULL,
+                           "", &public_key, &private_key, FALSE))
+    goto err;
+
+  schedule = silc_schedule_init(0, NULL, NULL);
+
+  softacc = silc_acc_find("softacc");
+  if (!softacc)
+    goto err;
+
+  if (!silc_acc_init(softacc, schedule, "min_threads", 2, "max_threads", 
+                    8, NULL))
+    goto err;
+
+  accpub = silc_acc_public_key(softacc, public_key);
+  if (!accpub)
+    goto err;
+  accprv = silc_acc_private_key(softacc, private_key);
+  if (!accprv)
+    goto err;
+
+  if (silc_acc_get_public_key(softacc, accpub) != public_key)
+    goto err;
+  if (silc_acc_get_private_key(softacc, accprv) != private_key)
+    goto err;
+
+  silc_schedule_task_add_timeout(schedule, sign, NULL, 0, 1);
+  silc_schedule_task_add_timeout(schedule, quit, NULL, 15, 0);
+  silc_schedule(schedule);
+
+  silc_acc_uninit(softacc);
+  silc_schedule_uninit(schedule);
+  silc_crypto_uninit();
+
+  success = TRUE;
+
+ err:
+  SILC_LOG_DEBUG(("Testing was %s", success ? "SUCCESS" : "FAILURE"));
+  fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE");
+
+  return success;
+}