]> git.ipfire.org Git - people/ms/strongswan.git/commitdiff
chapoly: Provide a generic ChaCha20/Poly1305 AEAD supporting driver backends
authorMartin Willi <martin@revosec.ch>
Wed, 1 Apr 2015 17:17:25 +0000 (19:17 +0200)
committerMartin Willi <martin@revosec.ch>
Mon, 29 Jun 2015 15:32:14 +0000 (17:32 +0200)
configure.ac
src/libstrongswan/Makefile.am
src/libstrongswan/plugins/chapoly/Makefile.am [new file with mode: 0644]
src/libstrongswan/plugins/chapoly/chapoly_aead.c [new file with mode: 0644]
src/libstrongswan/plugins/chapoly/chapoly_aead.h [new file with mode: 0644]
src/libstrongswan/plugins/chapoly/chapoly_drv.c [new file with mode: 0644]
src/libstrongswan/plugins/chapoly/chapoly_drv.h [new file with mode: 0644]
src/libstrongswan/plugins/chapoly/chapoly_plugin.c [new file with mode: 0644]
src/libstrongswan/plugins/chapoly/chapoly_plugin.h [new file with mode: 0644]

index 65098d7eede732d2120eda99b114deeea4dd88e5..95018f47ed73802ac2dbf6f1b283cb9dbdf18799 100644 (file)
@@ -127,6 +127,7 @@ ARG_ENABL_SET([af-alg],         [enable AF_ALG crypto interface to Linux Crypto
 ARG_ENABL_SET([bliss],          [enable BLISS software implementation plugin.])
 ARG_ENABL_SET([blowfish],       [enable Blowfish software implementation plugin.])
 ARG_ENABL_SET([ccm],            [enables the CCM AEAD wrapper crypto plugin.])
+ARG_ENABL_SET([chapoly],        [enables the ChaCha20/Poly1305 AEAD plugin.])
 ARG_DISBL_SET([cmac],           [disable CMAC crypto implementation plugin.])
 ARG_ENABL_SET([ctr],            [enables the Counter Mode wrapper crypto plugin.])
 ARG_DISBL_SET([des],            [disable DES/3DES software implementation plugin.])
@@ -1293,6 +1294,7 @@ ADD_PLUGIN([fips-prf],             [s charon nm cmd])
 ADD_PLUGIN([gmp],                  [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen])
 ADD_PLUGIN([agent],                [s charon nm cmd])
 ADD_PLUGIN([keychain],             [s charon cmd])
+ADD_PLUGIN([chapoly],              [s charon scripts nm cmd])
 ADD_PLUGIN([xcbc],                 [s charon nm cmd])
 ADD_PLUGIN([cmac],                 [s charon nm cmd])
 ADD_PLUGIN([hmac],                 [s charon pki scripts nm cmd])
@@ -1449,6 +1451,7 @@ AM_CONDITIONAL(USE_GCRYPT, test x$gcrypt = xtrue)
 AM_CONDITIONAL(USE_AGENT, test x$agent = xtrue)
 AM_CONDITIONAL(USE_KEYCHAIN, test x$keychain = xtrue)
 AM_CONDITIONAL(USE_PKCS11, test x$pkcs11 = xtrue)
+AM_CONDITIONAL(USE_CHAPOLY, test x$chapoly = xtrue)
 AM_CONDITIONAL(USE_CTR, test x$ctr = xtrue)
 AM_CONDITIONAL(USE_CCM, test x$ccm = xtrue)
 AM_CONDITIONAL(USE_GCM, test x$gcm = xtrue)
@@ -1698,6 +1701,7 @@ AC_CONFIG_FILES([
        src/libstrongswan/plugins/agent/Makefile
        src/libstrongswan/plugins/keychain/Makefile
        src/libstrongswan/plugins/pkcs11/Makefile
+       src/libstrongswan/plugins/chapoly/Makefile
        src/libstrongswan/plugins/ctr/Makefile
        src/libstrongswan/plugins/ccm/Makefile
        src/libstrongswan/plugins/gcm/Makefile
index 6b629ade868849f1341552ece8f194e8af7cdaea..adf3687aecd3d9adf89a4f1b7d70ca5c2106d4b2 100644 (file)
@@ -540,6 +540,13 @@ if MONOLITHIC
 endif
 endif
 
+if USE_CHAPOLY
+  SUBDIRS += plugins/chapoly
+if MONOLITHIC
+  libstrongswan_la_LIBADD += plugins/chapoly/libstrongswan-chapoly.la
+endif
+endif
+
 if USE_CTR
   SUBDIRS += plugins/ctr
 if MONOLITHIC
diff --git a/src/libstrongswan/plugins/chapoly/Makefile.am b/src/libstrongswan/plugins/chapoly/Makefile.am
new file mode 100644 (file)
index 0000000..0a6fbf4
--- /dev/null
@@ -0,0 +1,18 @@
+AM_CPPFLAGS = \
+       -I$(top_srcdir)/src/libstrongswan
+
+AM_CFLAGS = \
+       $(PLUGIN_CFLAGS)
+
+if MONOLITHIC
+noinst_LTLIBRARIES = libstrongswan-chapoly.la
+else
+plugin_LTLIBRARIES = libstrongswan-chapoly.la
+endif
+
+libstrongswan_chapoly_la_SOURCES = \
+       chapoly_plugin.h chapoly_plugin.c \
+       chapoly_drv.h chapoly_drv.c \
+       chapoly_aead.h chapoly_aead.c
+
+libstrongswan_chapoly_la_LDFLAGS = -module -avoid-version
diff --git a/src/libstrongswan/plugins/chapoly/chapoly_aead.c b/src/libstrongswan/plugins/chapoly/chapoly_aead.c
new file mode 100644 (file)
index 0000000..50ad84b
--- /dev/null
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2015 Martin Willi
+ * Copyright (C) 2015 revosec AG
+ *
+ * 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; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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 "chapoly_aead.h"
+#include "chapoly_drv.h"
+
+#include <crypto/iv/iv_gen_seq.h>
+
+/* maximum plain message size */
+#define P_MAX 247877906880
+
+typedef struct private_chapoly_aead_t private_chapoly_aead_t;
+
+/**
+ * Private data of an chapoly_aead_t object.
+ */
+struct private_chapoly_aead_t {
+
+       /**
+        * Public chapoly_aead_t interface.
+        */
+       chapoly_aead_t public;
+
+       /**
+        * IV generator.
+        */
+       iv_gen_t *iv_gen;
+
+       /**
+        * Driver backend
+        */
+       chapoly_drv_t *drv;
+};
+
+/**
+ * Include a partial block to ICV by padding it with zero bytes
+ */
+static bool poly_update_padded(private_chapoly_aead_t *this,
+                                                          u_char *in, size_t len)
+{
+       u_char b[POLY_BLOCK_SIZE];
+
+       memset(b, 0, sizeof(b));
+       memcpy(b, in, len);
+
+       return this->drv->poly(this->drv, b, 1);
+}
+
+/**
+ * Include associated data with padding to ICV
+ */
+static bool poly_head(private_chapoly_aead_t *this, u_char *assoc, size_t len)
+{
+       u_int blocks, rem;
+
+       blocks = len / POLY_BLOCK_SIZE;
+       rem = len % POLY_BLOCK_SIZE;
+       if (!this->drv->poly(this->drv, assoc, blocks))
+       {
+               return FALSE;
+       }
+       if (rem)
+       {
+               return poly_update_padded(this, assoc + blocks * POLY_BLOCK_SIZE, rem);
+       }
+       return TRUE;
+}
+
+/**
+ * Include length fields to ICV
+ */
+static bool poly_tail(private_chapoly_aead_t *this, size_t alen, size_t clen)
+{
+       struct {
+               u_int64_t alen;
+               u_int64_t clen;
+       } b;
+
+       b.alen = htole64(alen);
+       b.clen = htole64(clen);
+
+       return this->drv->poly(this->drv, (u_char*)&b, 1);
+}
+
+/**
+ * Perform ChaCha20 encryption inline and generate an ICV tag
+ */
+static bool do_encrypt(private_chapoly_aead_t *this, size_t len, u_char *data,
+                                          u_char *iv, size_t alen, u_char *assoc, u_char *icv)
+{
+       u_int blocks, rem, prem;
+
+       if (!this->drv->init(this->drv, iv) ||
+               !poly_head(this, assoc, alen))
+       {
+               return FALSE;
+       }
+       blocks = len / CHACHA_BLOCK_SIZE;
+       if (!this->drv->encrypt(this->drv, data, blocks))
+       {
+               return FALSE;
+       }
+       rem = len % CHACHA_BLOCK_SIZE;
+       if (rem)
+       {
+               u_char stream[CHACHA_BLOCK_SIZE];
+
+               data += blocks * CHACHA_BLOCK_SIZE;
+               if (!this->drv->chacha(this->drv, stream))
+               {
+                       return FALSE;
+               }
+               memxor(data, stream, rem);
+
+               blocks = rem / POLY_BLOCK_SIZE;
+               if (!this->drv->poly(this->drv, data, blocks))
+               {
+                       return FALSE;
+               }
+               prem = rem % POLY_BLOCK_SIZE;
+               if (prem)
+               {
+                       poly_update_padded(this, data + blocks * POLY_BLOCK_SIZE, prem);
+               }
+       }
+       return poly_tail(this, alen, len) &&
+                  this->drv->finish(this->drv, icv);
+}
+
+/**
+ * Perform ChaCha20 decryption inline and generate an ICV tag
+ */
+static bool do_decrypt(private_chapoly_aead_t *this, size_t len, u_char *data,
+                                          u_char *iv, size_t alen, u_char *assoc, u_char *icv)
+{
+       u_int blocks, rem, prem;
+
+       if (!this->drv->init(this->drv, iv) ||
+               !poly_head(this, assoc, alen))
+       {
+               return FALSE;
+       }
+       blocks = len / CHACHA_BLOCK_SIZE;
+       if (!this->drv->decrypt(this->drv, data, blocks))
+       {
+               return FALSE;
+       }
+       rem = len % CHACHA_BLOCK_SIZE;
+       if (rem)
+       {
+               u_char stream[CHACHA_BLOCK_SIZE];
+
+               data += blocks * CHACHA_BLOCK_SIZE;
+
+               blocks = rem / POLY_BLOCK_SIZE;
+               if (!this->drv->poly(this->drv, data, blocks))
+               {
+                       return FALSE;
+               }
+               prem = rem % POLY_BLOCK_SIZE;
+               if (prem)
+               {
+                       poly_update_padded(this, data + blocks * POLY_BLOCK_SIZE, prem);
+               }
+               if (!this->drv->chacha(this->drv, stream))
+               {
+                       return FALSE;
+               }
+               memxor(data, stream, rem);
+       }
+       return poly_tail(this, alen, len) &&
+                  this->drv->finish(this->drv, icv);
+}
+
+METHOD(aead_t, encrypt, bool,
+       private_chapoly_aead_t *this, chunk_t plain, chunk_t assoc, chunk_t iv,
+       chunk_t *encr)
+{
+       u_char *out;
+
+       if (sizeof(plain.len) > sizeof(u_int32_t) && plain.len > P_MAX)
+       {
+               return FALSE;
+       }
+       if (iv.len != CHACHA_IV_SIZE)
+       {
+               return FALSE;
+       }
+       out = plain.ptr;
+       if (encr)
+       {
+               *encr = chunk_alloc(plain.len + POLY_ICV_SIZE);
+               out = encr->ptr;
+               memcpy(out, plain.ptr, plain.len);
+       }
+       do_encrypt(this, plain.len, out, iv.ptr, assoc.len, assoc.ptr,
+                          out + plain.len);
+       return TRUE;
+}
+
+METHOD(aead_t, decrypt, bool,
+       private_chapoly_aead_t *this, chunk_t encr, chunk_t assoc, chunk_t iv,
+       chunk_t *plain)
+{
+       u_char *out, icv[POLY_ICV_SIZE];
+       if (iv.len != CHACHA_IV_SIZE || encr.len < POLY_ICV_SIZE)
+       {
+               return FALSE;
+       }
+       encr.len -= POLY_ICV_SIZE;
+       if (sizeof(encr.len) > sizeof(u_int32_t) && encr.len > P_MAX)
+       {
+               return FALSE;
+       }
+       out = encr.ptr;
+       if (plain)
+       {
+               *plain = chunk_alloc(encr.len);
+               out = plain->ptr;
+               memcpy(out, encr.ptr, encr.len);
+       }
+       do_decrypt(this, encr.len, out, iv.ptr, assoc.len, assoc.ptr, icv);
+       return memeq_const(icv, encr.ptr + encr.len, POLY_ICV_SIZE);
+}
+
+METHOD(aead_t, get_block_size, size_t,
+       private_chapoly_aead_t *this)
+{
+       return 1;
+}
+
+METHOD(aead_t, get_icv_size, size_t,
+       private_chapoly_aead_t *this)
+{
+       return POLY_ICV_SIZE;
+}
+
+METHOD(aead_t, get_iv_size, size_t,
+       private_chapoly_aead_t *this)
+{
+       return CHACHA_IV_SIZE;
+}
+
+METHOD(aead_t, get_iv_gen, iv_gen_t*,
+       private_chapoly_aead_t *this)
+{
+       return this->iv_gen;
+}
+
+METHOD(aead_t, get_key_size, size_t,
+       private_chapoly_aead_t *this)
+{
+       return CHACHA_KEY_SIZE + CHACHA_SALT_SIZE;
+}
+
+METHOD(aead_t, set_key, bool,
+       private_chapoly_aead_t *this, chunk_t key)
+{
+       if (key.len != CHACHA_KEY_SIZE + CHACHA_SALT_SIZE)
+       {
+               return FALSE;
+       }
+       return this->drv->set_key(this->drv, "expand 32-byte k",
+                                                         key.ptr, key.ptr + CHACHA_KEY_SIZE);
+}
+
+METHOD(aead_t, destroy, void,
+       private_chapoly_aead_t *this)
+{
+       this->drv->destroy(this->drv);
+       this->iv_gen->destroy(this->iv_gen);
+       free(this);
+}
+
+/**
+ * See header
+ */
+chapoly_aead_t *chapoly_aead_create(encryption_algorithm_t algo,
+                                                                       size_t key_size, size_t salt_size)
+{
+       private_chapoly_aead_t *this;
+       chapoly_drv_t *drv;
+
+       if (algo != ENCR_CHACHA20_POLY1305)
+       {
+               return NULL;
+       }
+       if (key_size && key_size != CHACHA_KEY_SIZE)
+       {
+               return NULL;
+       }
+       if (salt_size && salt_size != CHACHA_SALT_SIZE)
+       {
+               return NULL;
+       }
+       drv = chapoly_drv_probe();
+       if (!drv)
+       {
+               return NULL;
+       }
+
+       INIT(this,
+               .public = {
+                       .aead = {
+                               .encrypt = _encrypt,
+                               .decrypt = _decrypt,
+                               .get_block_size = _get_block_size,
+                               .get_icv_size = _get_icv_size,
+                               .get_iv_size = _get_iv_size,
+                               .get_iv_gen = _get_iv_gen,
+                               .get_key_size = _get_key_size,
+                               .set_key = _set_key,
+                               .destroy = _destroy,
+                       },
+               },
+               .iv_gen = iv_gen_seq_create(),
+               .drv = drv,
+       );
+
+       return &this->public;
+}
diff --git a/src/libstrongswan/plugins/chapoly/chapoly_aead.h b/src/libstrongswan/plugins/chapoly/chapoly_aead.h
new file mode 100644 (file)
index 0000000..e090541
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2015 Martin Willi
+ * Copyright (C) 2015 revosec AG
+ *
+ * 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; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup chapoly_aead chapoly_aead
+ * @{ @ingroup chapoly
+ */
+
+#ifndef CHAPOLY_AEAD_H_
+#define CHAPOLY_AEAD_H_
+
+#include <crypto/aead.h>
+
+typedef struct chapoly_aead_t chapoly_aead_t;
+
+/**
+ * ChaCha20/Poly1305 AEAD implementation.
+ *
+ * TODO-Chapoly: draft-ietf-ipsecme-chacha20-poly1305-05
+ */
+struct chapoly_aead_t {
+
+       /**
+        * Implements aead_t interface.
+        */
+       aead_t aead;
+};
+
+/**
+ * Create a chapoly_aead instance.
+ *
+ * @param algo                 algorithm to implement, ENCR_CHACHA20_POLY1305
+ * @param key_size             key size in bytes, 32
+ * @param salt_size            size of implicit salt length, 0
+ * @return                             AEAD, NULL if not supported
+ */
+chapoly_aead_t *chapoly_aead_create(encryption_algorithm_t algo,
+                                                                       size_t key_size, size_t salt_size);
+
+#endif /** CHAPOLY_AEAD_H_ @}*/
diff --git a/src/libstrongswan/plugins/chapoly/chapoly_drv.c b/src/libstrongswan/plugins/chapoly/chapoly_drv.c
new file mode 100644 (file)
index 0000000..78ea0f0
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 Martin Willi
+ * Copyright (C) 2015 revosec AG
+ *
+ * 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; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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 "chapoly_drv.h"
+
+typedef chapoly_drv_t*(*chapoly_drv_create)();
+
+/**
+ * See header.
+ */
+chapoly_drv_t *chapoly_drv_probe()
+{
+       chapoly_drv_create drivers[] = {
+       };
+       chapoly_drv_t *driver;
+       int i;
+
+       for (i = 0; i < countof(drivers); i++)
+       {
+               driver = drivers[i]();
+               if (driver)
+               {
+                       return driver;
+               }
+       }
+       return NULL;
+}
diff --git a/src/libstrongswan/plugins/chapoly/chapoly_drv.h b/src/libstrongswan/plugins/chapoly/chapoly_drv.h
new file mode 100644 (file)
index 0000000..bffc434
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2015 Martin Willi
+ * Copyright (C) 2015 revosec AG
+ *
+ * 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; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup chapoly_drv chapoly_drv
+ * @{ @ingroup chapoly
+ */
+
+#ifndef CHAPOLY_DRV_H_
+#define CHAPOLY_DRV_H_
+
+#include <library.h>
+
+#define CHACHA_BLOCK_SIZE 64
+#define CHACHA_IV_SIZE 8
+#define CHACHA_SALT_SIZE 4
+#define CHACHA_KEY_SIZE 32
+#define POLY_BLOCK_SIZE 16
+#define POLY_ICV_SIZE 16
+
+typedef struct chapoly_drv_t chapoly_drv_t;
+
+/**
+ * ChaCha20/Poly1305 backend implementation.
+ */
+struct chapoly_drv_t {
+
+       /**
+        * Set the ChaCha20 encryption key.
+        *
+        * @param constant              16 byte key constant to use
+        * @param key                   32 byte encryption key
+        * @param salt                  4 byte nonce salt
+        * @return                              TRUE if key set
+        */
+       bool (*set_key)(chapoly_drv_t *this, u_char *constant, u_char *key,
+                                       u_char *salt);
+
+       /**
+        * Start an AEAD en/decryption session, reset state.
+        *
+        * @param iv                    8 byte initialization vector for nonce
+        * @return                              TRUE if initialized
+        */
+       bool (*init)(chapoly_drv_t *this, u_char *iv);
+
+       /**
+        * Poly1305 update multiple blocks.
+        *
+        * @param data                  data to update Poly1305 for
+        * @param blocks                number of 16-byte blocks to process
+        * @return                              TRUE if updated
+        */
+       bool (*poly)(chapoly_drv_t *this, u_char *data, u_int blocks);
+
+       /**
+        * Create a single ChaCha20 keystream block.
+        *
+        * @param stream                64-byte block to write key stream data to
+        * @return                              TRUE if keystream returned
+        */
+       bool (*chacha)(chapoly_drv_t *this, u_char *stream);
+
+       /**
+        * Encrypt multiple blocks of data inline, update Poly1305.
+        *
+        * @param data                  data to process
+        * @param blocks                number of 64-byte blocks to process
+        * @return                              TRUE if encrypted
+        */
+       bool (*encrypt)(chapoly_drv_t *this, u_char *data, u_int blocks);
+
+       /**
+        * Decrypt multiple blocks of data inline, update Poly1305.
+        *
+        * @param data                  data to process
+        * @param blocks                number of 64-byte blocks to process
+        * @return                              TRUE if decrypted
+        */
+       bool (*decrypt)(chapoly_drv_t *this, u_char *data, u_int blocks);
+
+       /**
+        * End a AEAD encryption session, return MAC.
+        *
+        * @param mac                   16-byte block to write MAC to
+        * @return                              TRUE if MAC returned
+        */
+       bool (*finish)(chapoly_drv_t *this, u_char *mac);
+
+       /**
+        * Destroy a chapoly_drv_t.
+        */
+       void (*destroy)(chapoly_drv_t *this);
+};
+
+/**
+ * Create a chapoly_drv instance.
+ */
+chapoly_drv_t *chapoly_drv_probe();
+
+#endif /** CHAPOLY_DRV_H_ @}*/
diff --git a/src/libstrongswan/plugins/chapoly/chapoly_plugin.c b/src/libstrongswan/plugins/chapoly/chapoly_plugin.c
new file mode 100644 (file)
index 0000000..02e7121
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2015 Martin Willi
+ * Copyright (C) 2015 revosec AG
+ *
+ * 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; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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 "chapoly_plugin.h"
+#include "chapoly_aead.h"
+
+#include <library.h>
+
+typedef struct private_chapoly_plugin_t private_chapoly_plugin_t;
+
+/**
+ * Private data of chapoly_plugin
+ */
+struct private_chapoly_plugin_t {
+
+       /**
+        * Public functions
+        */
+       chapoly_plugin_t public;
+};
+
+METHOD(plugin_t, get_name, char*,
+       private_chapoly_plugin_t *this)
+{
+       return "chapoly";
+}
+
+METHOD(plugin_t, get_features, int,
+       private_chapoly_plugin_t *this, plugin_feature_t *features[])
+{
+       static plugin_feature_t f[] = {
+               PLUGIN_REGISTER(AEAD, chapoly_aead_create),
+                       PLUGIN_PROVIDE(AEAD, ENCR_CHACHA20_POLY1305, 32),
+       };
+       *features = f;
+       return countof(f);
+}
+
+METHOD(plugin_t, destroy, void,
+       private_chapoly_plugin_t *this)
+{
+       free(this);
+}
+
+/*
+ * see header file
+ */
+plugin_t *chapoly_plugin_create()
+{
+       private_chapoly_plugin_t *this;
+
+       INIT(this,
+               .public = {
+                       .plugin = {
+                               .get_name = _get_name,
+                               .get_features = _get_features,
+                               .destroy = _destroy,
+                       },
+               },
+       );
+
+       return &this->public.plugin;
+}
diff --git a/src/libstrongswan/plugins/chapoly/chapoly_plugin.h b/src/libstrongswan/plugins/chapoly/chapoly_plugin.h
new file mode 100644 (file)
index 0000000..f2b62e7
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2015 Martin Willi
+ * Copyright (C) 2015 revosec AG
+ *
+ * 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; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup chapoly chapoly
+ * @ingroup plugins
+ *
+ * @defgroup chapoly_plugin chapoly_plugin
+ * @{ @ingroup chapoly
+ */
+
+#ifndef CHAPOLY_PLUGIN_H_
+#define CHAPOLY_PLUGIN_H_
+
+#include <plugins/plugin.h>
+
+typedef struct chapoly_plugin_t chapoly_plugin_t;
+
+/**
+ * Plugin providing a ChaCha20/Poly1305 AEAD.
+ */
+struct chapoly_plugin_t {
+
+       /**
+        * Implements plugin interface.
+        */
+       plugin_t plugin;
+};
+
+#endif /** CHAPOLY_PLUGIN_H_ @}*/