summaryrefslogtreecommitdiff
path: root/src/libstrongswan/plugins/chapoly
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstrongswan/plugins/chapoly')
-rw-r--r--src/libstrongswan/plugins/chapoly/Makefile.am29
-rw-r--r--src/libstrongswan/plugins/chapoly/Makefile.in810
-rw-r--r--src/libstrongswan/plugins/chapoly/chapoly_aead.c333
-rw-r--r--src/libstrongswan/plugins/chapoly/chapoly_aead.h52
-rw-r--r--src/libstrongswan/plugins/chapoly/chapoly_drv.c43
-rw-r--r--src/libstrongswan/plugins/chapoly/chapoly_drv.h113
-rw-r--r--src/libstrongswan/plugins/chapoly/chapoly_drv_portable.c454
-rw-r--r--src/libstrongswan/plugins/chapoly/chapoly_drv_portable.h31
-rw-r--r--src/libstrongswan/plugins/chapoly/chapoly_drv_ssse3.c867
-rw-r--r--src/libstrongswan/plugins/chapoly/chapoly_drv_ssse3.h31
-rw-r--r--src/libstrongswan/plugins/chapoly/chapoly_plugin.c75
-rw-r--r--src/libstrongswan/plugins/chapoly/chapoly_plugin.h42
12 files changed, 2880 insertions, 0 deletions
diff --git a/src/libstrongswan/plugins/chapoly/Makefile.am b/src/libstrongswan/plugins/chapoly/Makefile.am
new file mode 100644
index 000000000..1753de0c7
--- /dev/null
+++ b/src/libstrongswan/plugins/chapoly/Makefile.am
@@ -0,0 +1,29 @@
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/libstrongswan
+
+AM_CFLAGS = \
+ $(PLUGIN_CFLAGS)
+
+noinst_LTLIBRARIES =
+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_drv_portable.h chapoly_drv_portable.c \
+ chapoly_aead.h chapoly_aead.c
+
+noinst_LTLIBRARIES += libchapoly-drv-ssse3.la
+libchapoly_drv_ssse3_la_SOURCES = chapoly_drv_ssse3.h chapoly_drv_ssse3.c
+if USE_X86X64
+ libchapoly_drv_ssse3_la_CFLAGS = $(PLUGIN_CFLAGS) -mssse3
+endif
+
+libstrongswan_chapoly_la_LIBADD = \
+ libchapoly-drv-ssse3.la
+
+libstrongswan_chapoly_la_LDFLAGS = -module -avoid-version
diff --git a/src/libstrongswan/plugins/chapoly/Makefile.in b/src/libstrongswan/plugins/chapoly/Makefile.in
new file mode 100644
index 000000000..98e1f4d9e
--- /dev/null
+++ b/src/libstrongswan/plugins/chapoly/Makefile.in
@@ -0,0 +1,810 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@MONOLITHIC_TRUE@am__append_1 = libstrongswan-chapoly.la
+subdir = src/libstrongswan/plugins/chapoly
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/depcomp
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \
+ $(top_srcdir)/m4/config/ltoptions.m4 \
+ $(top_srcdir)/m4/config/ltsugar.m4 \
+ $(top_srcdir)/m4/config/ltversion.m4 \
+ $(top_srcdir)/m4/config/lt~obsolete.m4 \
+ $(top_srcdir)/m4/macros/split-package-version.m4 \
+ $(top_srcdir)/m4/macros/with.m4 \
+ $(top_srcdir)/m4/macros/enable-disable.m4 \
+ $(top_srcdir)/m4/macros/add-plugin.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(plugindir)"
+LTLIBRARIES = $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES)
+libchapoly_drv_ssse3_la_LIBADD =
+am_libchapoly_drv_ssse3_la_OBJECTS = \
+ libchapoly_drv_ssse3_la-chapoly_drv_ssse3.lo
+libchapoly_drv_ssse3_la_OBJECTS = \
+ $(am_libchapoly_drv_ssse3_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libchapoly_drv_ssse3_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(libchapoly_drv_ssse3_la_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+libstrongswan_chapoly_la_DEPENDENCIES = libchapoly-drv-ssse3.la
+am_libstrongswan_chapoly_la_OBJECTS = chapoly_plugin.lo chapoly_drv.lo \
+ chapoly_drv_portable.lo chapoly_aead.lo
+libstrongswan_chapoly_la_OBJECTS = \
+ $(am_libstrongswan_chapoly_la_OBJECTS)
+libstrongswan_chapoly_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(libstrongswan_chapoly_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@MONOLITHIC_FALSE@am_libstrongswan_chapoly_la_rpath = -rpath \
+@MONOLITHIC_FALSE@ $(plugindir)
+@MONOLITHIC_TRUE@am_libstrongswan_chapoly_la_rpath =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libchapoly_drv_ssse3_la_SOURCES) \
+ $(libstrongswan_chapoly_la_SOURCES)
+DIST_SOURCES = $(libchapoly_drv_ssse3_la_SOURCES) \
+ $(libstrongswan_chapoly_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BFDLIB = @BFDLIB@
+BTLIB = @BTLIB@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+COVERAGE_CFLAGS = @COVERAGE_CFLAGS@
+COVERAGE_LDFLAGS = @COVERAGE_LDFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLIB = @DLLIB@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+EASY_INSTALL = @EASY_INSTALL@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GEM = @GEM@
+GENHTML = @GENHTML@
+GPERF = @GPERF@
+GPRBUILD = @GPRBUILD@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LCOV = @LCOV@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MYSQLCFLAG = @MYSQLCFLAG@
+MYSQLCONFIG = @MYSQLCONFIG@
+MYSQLLIB = @MYSQLLIB@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_LIB = @OPENSSL_LIB@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_BUILD = @PACKAGE_VERSION_BUILD@
+PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@
+PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
+PACKAGE_VERSION_REVIEW = @PACKAGE_VERSION_REVIEW@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PLUGIN_CFLAGS = @PLUGIN_CFLAGS@
+PTHREADLIB = @PTHREADLIB@
+PYTHON = @PYTHON@
+PYTHONEGGINSTALLDIR = @PYTHONEGGINSTALLDIR@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+PY_TEST = @PY_TEST@
+RANLIB = @RANLIB@
+RTLIB = @RTLIB@
+RUBY = @RUBY@
+RUBYGEMDIR = @RUBYGEMDIR@
+RUBYINCLUDE = @RUBYINCLUDE@
+RUBYLIB = @RUBYLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOCKLIB = @SOCKLIB@
+STRIP = @STRIP@
+UNWINDLIB = @UNWINDLIB@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+aikgen_plugins = @aikgen_plugins@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+attest_plugins = @attest_plugins@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+c_plugins = @c_plugins@
+charon_natt_port = @charon_natt_port@
+charon_plugins = @charon_plugins@
+charon_udp_port = @charon_udp_port@
+clearsilver_LIBS = @clearsilver_LIBS@
+cmd_plugins = @cmd_plugins@
+datadir = @datadir@
+datarootdir = @datarootdir@
+dbusservicedir = @dbusservicedir@
+dev_headers = @dev_headers@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+fips_mode = @fips_mode@
+gtk_CFLAGS = @gtk_CFLAGS@
+gtk_LIBS = @gtk_LIBS@
+h_plugins = @h_plugins@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+imcvdir = @imcvdir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+ipsec_script = @ipsec_script@
+ipsec_script_upper = @ipsec_script_upper@
+ipsecdir = @ipsecdir@
+ipsecgroup = @ipsecgroup@
+ipseclibdir = @ipseclibdir@
+ipsecuser = @ipsecuser@
+json_CFLAGS = @json_CFLAGS@
+json_LIBS = @json_LIBS@
+libdir = @libdir@
+libexecdir = @libexecdir@
+libiptc_CFLAGS = @libiptc_CFLAGS@
+libiptc_LIBS = @libiptc_LIBS@
+linux_headers = @linux_headers@
+localedir = @localedir@
+localstatedir = @localstatedir@
+maemo_CFLAGS = @maemo_CFLAGS@
+maemo_LIBS = @maemo_LIBS@
+manager_plugins = @manager_plugins@
+mandir = @mandir@
+medsrv_plugins = @medsrv_plugins@
+mkdir_p = @mkdir_p@
+nm_CFLAGS = @nm_CFLAGS@
+nm_LIBS = @nm_LIBS@
+nm_ca_dir = @nm_ca_dir@
+nm_plugins = @nm_plugins@
+oldincludedir = @oldincludedir@
+pcsclite_CFLAGS = @pcsclite_CFLAGS@
+pcsclite_LIBS = @pcsclite_LIBS@
+pdfdir = @pdfdir@
+piddir = @piddir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+pki_plugins = @pki_plugins@
+plugindir = @plugindir@
+pool_plugins = @pool_plugins@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+random_device = @random_device@
+resolv_conf = @resolv_conf@
+routing_table = @routing_table@
+routing_table_prio = @routing_table_prio@
+s_plugins = @s_plugins@
+sbindir = @sbindir@
+scepclient_plugins = @scepclient_plugins@
+scripts_plugins = @scripts_plugins@
+sharedstatedir = @sharedstatedir@
+soup_CFLAGS = @soup_CFLAGS@
+soup_LIBS = @soup_LIBS@
+srcdir = @srcdir@
+starter_plugins = @starter_plugins@
+strongswan_conf = @strongswan_conf@
+strongswan_options = @strongswan_options@
+swanctldir = @swanctldir@
+sysconfdir = @sysconfdir@
+systemd_daemon_CFLAGS = @systemd_daemon_CFLAGS@
+systemd_daemon_LIBS = @systemd_daemon_LIBS@
+systemd_journal_CFLAGS = @systemd_journal_CFLAGS@
+systemd_journal_LIBS = @systemd_journal_LIBS@
+systemdsystemunitdir = @systemdsystemunitdir@
+t_plugins = @t_plugins@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+urandom_device = @urandom_device@
+xml_CFLAGS = @xml_CFLAGS@
+xml_LIBS = @xml_LIBS@
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/libstrongswan
+
+AM_CFLAGS = \
+ $(PLUGIN_CFLAGS)
+
+noinst_LTLIBRARIES = $(am__append_1) libchapoly-drv-ssse3.la
+@MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-chapoly.la
+libstrongswan_chapoly_la_SOURCES = \
+ chapoly_plugin.h chapoly_plugin.c \
+ chapoly_drv.h chapoly_drv.c \
+ chapoly_drv_portable.h chapoly_drv_portable.c \
+ chapoly_aead.h chapoly_aead.c
+
+libchapoly_drv_ssse3_la_SOURCES = chapoly_drv_ssse3.h chapoly_drv_ssse3.c
+@USE_X86X64_TRUE@libchapoly_drv_ssse3_la_CFLAGS = $(PLUGIN_CFLAGS) -mssse3
+libstrongswan_chapoly_la_LIBADD = \
+ libchapoly-drv-ssse3.la
+
+libstrongswan_chapoly_la_LDFLAGS = -module -avoid-version
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libstrongswan/plugins/chapoly/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/libstrongswan/plugins/chapoly/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(plugindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(plugindir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \
+ }
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libchapoly-drv-ssse3.la: $(libchapoly_drv_ssse3_la_OBJECTS) $(libchapoly_drv_ssse3_la_DEPENDENCIES) $(EXTRA_libchapoly_drv_ssse3_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libchapoly_drv_ssse3_la_LINK) $(libchapoly_drv_ssse3_la_OBJECTS) $(libchapoly_drv_ssse3_la_LIBADD) $(LIBS)
+
+libstrongswan-chapoly.la: $(libstrongswan_chapoly_la_OBJECTS) $(libstrongswan_chapoly_la_DEPENDENCIES) $(EXTRA_libstrongswan_chapoly_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libstrongswan_chapoly_la_LINK) $(am_libstrongswan_chapoly_la_rpath) $(libstrongswan_chapoly_la_OBJECTS) $(libstrongswan_chapoly_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chapoly_aead.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chapoly_drv.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chapoly_drv_portable.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chapoly_plugin.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libchapoly_drv_ssse3_la-chapoly_drv_ssse3.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libchapoly_drv_ssse3_la-chapoly_drv_ssse3.lo: chapoly_drv_ssse3.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libchapoly_drv_ssse3_la_CFLAGS) $(CFLAGS) -MT libchapoly_drv_ssse3_la-chapoly_drv_ssse3.lo -MD -MP -MF $(DEPDIR)/libchapoly_drv_ssse3_la-chapoly_drv_ssse3.Tpo -c -o libchapoly_drv_ssse3_la-chapoly_drv_ssse3.lo `test -f 'chapoly_drv_ssse3.c' || echo '$(srcdir)/'`chapoly_drv_ssse3.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libchapoly_drv_ssse3_la-chapoly_drv_ssse3.Tpo $(DEPDIR)/libchapoly_drv_ssse3_la-chapoly_drv_ssse3.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='chapoly_drv_ssse3.c' object='libchapoly_drv_ssse3_la-chapoly_drv_ssse3.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libchapoly_drv_ssse3_la_CFLAGS) $(CFLAGS) -c -o libchapoly_drv_ssse3_la-chapoly_drv_ssse3.lo `test -f 'chapoly_drv_ssse3.c' || echo '$(srcdir)/'`chapoly_drv_ssse3.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+ for dir in "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ clean-pluginLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLTLIBRARIES clean-pluginLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-pluginLTLIBRARIES install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am uninstall-pluginLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/libstrongswan/plugins/chapoly/chapoly_aead.c b/src/libstrongswan/plugins/chapoly/chapoly_aead.c
new file mode 100644
index 000000000..50ad84b21
--- /dev/null
+++ b/src/libstrongswan/plugins/chapoly/chapoly_aead.c
@@ -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
index 000000000..e090541dd
--- /dev/null
+++ b/src/libstrongswan/plugins/chapoly/chapoly_aead.h
@@ -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
index 000000000..ca5e2be08
--- /dev/null
+++ b/src/libstrongswan/plugins/chapoly/chapoly_drv.c
@@ -0,0 +1,43 @@
+/*
+ * 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"
+#include "chapoly_drv_portable.h"
+#include "chapoly_drv_ssse3.h"
+
+typedef chapoly_drv_t*(*chapoly_drv_create)();
+
+/**
+ * See header.
+ */
+chapoly_drv_t *chapoly_drv_probe()
+{
+ chapoly_drv_create drivers[] = {
+ chapoly_drv_ssse3_create,
+ chapoly_drv_portable_create,
+ };
+ 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
index 000000000..bffc43447
--- /dev/null
+++ b/src/libstrongswan/plugins/chapoly/chapoly_drv.h
@@ -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_drv_portable.c b/src/libstrongswan/plugins/chapoly/chapoly_drv_portable.c
new file mode 100644
index 000000000..54e934e6a
--- /dev/null
+++ b/src/libstrongswan/plugins/chapoly/chapoly_drv_portable.c
@@ -0,0 +1,454 @@
+/*
+ * Copyright (C) 2015 Martin Willi
+ * Copyright (C) 2015 revosec AG
+ *
+ * Based on public domain code by Andrew Moon and Daniel J. Bernstein.
+ *
+ * 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_portable.h"
+
+#define CHACHA_DOUBLEROUNDS 10
+/* index of some state fields */
+#define CHACHA_BLOCKCOUNT 12
+#define CHACHA_NONCE1 13
+#define CHACHA_NONCE2 14
+#define CHACHA_NONCE3 15
+
+typedef struct private_chapoly_drv_portable_t private_chapoly_drv_portable_t;
+
+/**
+ * Private data of an chapoly_drv_portable_t object.
+ */
+struct private_chapoly_drv_portable_t {
+
+ /**
+ * Public chapoly_drv_portable_t interface.
+ */
+ chapoly_drv_t public;
+
+ /**
+ * ChaCha20 state matrix
+ */
+ u_int32_t m[16];
+
+ /**
+ * Poly1305 update key
+ */
+ u_int32_t r[5];
+
+ /**
+ * Poly1305 state
+ */
+ u_int32_t h[5];
+
+ /**
+ * Poly1305 finalize key
+ */
+ u_int32_t s[4];
+};
+
+/**
+ * Convert unaligned little endian to host byte order
+ */
+static inline u_int32_t uletoh32(void *p)
+{
+ u_int32_t ret;
+
+ memcpy(&ret, p, sizeof(ret));
+ ret = le32toh(ret);
+ return ret;
+}
+
+/**
+ * Convert host byte order to unaligned little endian
+ */
+static inline void htoule32(void *p, u_int32_t v)
+{
+ v = htole32(v);
+ memcpy(p, &v, sizeof(v));
+}
+
+/**
+ * XOR a 32-bit integer into an unaligned destination
+ */
+static inline void xor32u(void *p, u_int32_t x)
+{
+ u_int32_t y;
+
+ memcpy(&y, p, sizeof(y));
+ y ^= x;
+ memcpy(p, &y, sizeof(y));
+}
+
+/**
+ * Multiply two 64-bit words
+ */
+static inline u_int64_t mlt(u_int64_t a, u_int64_t b)
+{
+ return a * b;
+}
+
+/**
+ * Shift a 64-bit unsigned integer v right by n bits, clamp to 32 bit
+*/
+static inline u_int32_t sr(u_int64_t v, u_char n)
+{
+ return v >> n;
+}
+
+/**
+ * Circular left shift by n bits
+ */
+static inline u_int32_t rotl32(u_int32_t v, u_char n)
+{
+ return (v << n) | (v >> (sizeof(v) * 8 - n));
+}
+
+/**
+ * AND two values, using a native integer size >= sizeof(u_int32_t)
+ */
+static inline u_long and(u_long v, u_long mask)
+{
+ return v & mask;
+}
+
+/**
+ * XOR a Chacha20 keystream block into data, increment counter
+ */
+static void chacha_block_xor(private_chapoly_drv_portable_t *this, void *data)
+{
+ u_int32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, xa, xb, xc, xd, xe, xf;
+ u_int32_t *out = data;
+ u_int i;
+
+ x0 = this->m[ 0];
+ x1 = this->m[ 1];
+ x2 = this->m[ 2];
+ x3 = this->m[ 3];
+ x4 = this->m[ 4];
+ x5 = this->m[ 5];
+ x6 = this->m[ 6];
+ x7 = this->m[ 7];
+ x8 = this->m[ 8];
+ x9 = this->m[ 9];
+ xa = this->m[10];
+ xb = this->m[11];
+ xc = this->m[12];
+ xd = this->m[13];
+ xe = this->m[14];
+ xf = this->m[15];
+
+ for (i = 0; i < CHACHA_DOUBLEROUNDS; i++)
+ {
+ x0 += x4; xc = rotl32(xc ^ x0, 16);
+ x1 += x5; xd = rotl32(xd ^ x1, 16);
+ x2 += x6; xe = rotl32(xe ^ x2, 16);
+ x3 += x7; xf = rotl32(xf ^ x3, 16);
+
+ x8 += xc; x4 = rotl32(x4 ^ x8, 12);
+ x9 += xd; x5 = rotl32(x5 ^ x9, 12);
+ xa += xe; x6 = rotl32(x6 ^ xa, 12);
+ xb += xf; x7 = rotl32(x7 ^ xb, 12);
+
+ x0 += x4; xc = rotl32(xc ^ x0, 8);
+ x1 += x5; xd = rotl32(xd ^ x1, 8);
+ x2 += x6; xe = rotl32(xe ^ x2, 8);
+ x3 += x7; xf = rotl32(xf ^ x3, 8);
+
+ x8 += xc; x4 = rotl32(x4 ^ x8, 7);
+ x9 += xd; x5 = rotl32(x5 ^ x9, 7);
+ xa += xe; x6 = rotl32(x6 ^ xa, 7);
+ xb += xf; x7 = rotl32(x7 ^ xb, 7);
+
+ x0 += x5; xf = rotl32(xf ^ x0, 16);
+ x1 += x6; xc = rotl32(xc ^ x1, 16);
+ x2 += x7; xd = rotl32(xd ^ x2, 16);
+ x3 += x4; xe = rotl32(xe ^ x3, 16);
+
+ xa += xf; x5 = rotl32(x5 ^ xa, 12);
+ xb += xc; x6 = rotl32(x6 ^ xb, 12);
+ x8 += xd; x7 = rotl32(x7 ^ x8, 12);
+ x9 += xe; x4 = rotl32(x4 ^ x9, 12);
+
+ x0 += x5; xf = rotl32(xf ^ x0, 8);
+ x1 += x6; xc = rotl32(xc ^ x1, 8);
+ x2 += x7; xd = rotl32(xd ^ x2, 8);
+ x3 += x4; xe = rotl32(xe ^ x3, 8);
+
+ xa += xf; x5 = rotl32(x5 ^ xa, 7);
+ xb += xc; x6 = rotl32(x6 ^ xb, 7);
+ x8 += xd; x7 = rotl32(x7 ^ x8, 7);
+ x9 += xe; x4 = rotl32(x4 ^ x9, 7);
+ }
+
+ xor32u(out + 0, le32toh(x0 + this->m[ 0]));
+ xor32u(out + 1, le32toh(x1 + this->m[ 1]));
+ xor32u(out + 2, le32toh(x2 + this->m[ 2]));
+ xor32u(out + 3, le32toh(x3 + this->m[ 3]));
+ xor32u(out + 4, le32toh(x4 + this->m[ 4]));
+ xor32u(out + 5, le32toh(x5 + this->m[ 5]));
+ xor32u(out + 6, le32toh(x6 + this->m[ 6]));
+ xor32u(out + 7, le32toh(x7 + this->m[ 7]));
+ xor32u(out + 8, le32toh(x8 + this->m[ 8]));
+ xor32u(out + 9, le32toh(x9 + this->m[ 9]));
+ xor32u(out + 10, le32toh(xa + this->m[10]));
+ xor32u(out + 11, le32toh(xb + this->m[11]));
+ xor32u(out + 12, le32toh(xc + this->m[12]));
+ xor32u(out + 13, le32toh(xd + this->m[13]));
+ xor32u(out + 14, le32toh(xe + this->m[14]));
+ xor32u(out + 15, le32toh(xf + this->m[15]));
+
+ this->m[CHACHA_BLOCKCOUNT]++;
+}
+
+METHOD(chapoly_drv_t, set_key, bool,
+ private_chapoly_drv_portable_t *this, u_char *constant, u_char *key,
+ u_char *salt)
+{
+ this->m[ 0] = uletoh32(constant + 0);
+ this->m[ 1] = uletoh32(constant + 4);
+ this->m[ 2] = uletoh32(constant + 8);
+ this->m[ 3] = uletoh32(constant + 12);
+
+ this->m[ 4] = uletoh32(key + 0);
+ this->m[ 5] = uletoh32(key + 4);
+ this->m[ 6] = uletoh32(key + 8);
+ this->m[ 7] = uletoh32(key + 12);
+ this->m[ 8] = uletoh32(key + 16);
+ this->m[ 9] = uletoh32(key + 20);
+ this->m[10] = uletoh32(key + 24);
+ this->m[11] = uletoh32(key + 28);
+
+ this->m[CHACHA_NONCE1] = uletoh32(salt);
+
+ return TRUE;
+}
+
+METHOD(chapoly_drv_t, init, bool,
+ private_chapoly_drv_portable_t *this, u_char *iv)
+{
+ u_char key[CHACHA_BLOCK_SIZE];
+
+ this->m[CHACHA_BLOCKCOUNT] = 0;
+ this->m[CHACHA_NONCE2] = uletoh32(iv + 0);
+ this->m[CHACHA_NONCE3] = uletoh32(iv + 4);
+
+ memset(key, 0, CHACHA_BLOCK_SIZE);
+ chacha_block_xor(this, key);
+
+ /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
+ this->r[0] = (uletoh32(key + 0) >> 0) & 0x3ffffff;
+ this->r[1] = (uletoh32(key + 3) >> 2) & 0x3ffff03;
+ this->r[2] = (uletoh32(key + 6) >> 4) & 0x3ffc0ff;
+ this->r[3] = (uletoh32(key + 9) >> 6) & 0x3f03fff;
+ this->r[4] = (uletoh32(key + 12) >> 8) & 0x00fffff;
+
+ /* h = 0 */
+ memwipe(this->h, sizeof(this->h));
+
+ this->s[0] = uletoh32(key + 16);
+ this->s[1] = uletoh32(key + 20);
+ this->s[2] = uletoh32(key + 24);
+ this->s[3] = uletoh32(key + 28);
+
+ return TRUE;
+}
+
+METHOD(chapoly_drv_t, poly, bool,
+ private_chapoly_drv_portable_t *this, u_char *data, u_int blocks)
+{
+ u_int32_t r0, r1, r2, r3, r4;
+ u_int32_t s1, s2, s3, s4;
+ u_int32_t h0, h1, h2, h3, h4;
+ u_int64_t d0, d1, d2, d3, d4;
+ u_int i;
+
+ r0 = this->r[0];
+ r1 = this->r[1];
+ r2 = this->r[2];
+ r3 = this->r[3];
+ r4 = this->r[4];
+
+ s1 = r1 * 5;
+ s2 = r2 * 5;
+ s3 = r3 * 5;
+ s4 = r4 * 5;
+
+ h0 = this->h[0];
+ h1 = this->h[1];
+ h2 = this->h[2];
+ h3 = this->h[3];
+ h4 = this->h[4];
+
+ for (i = 0; i < blocks; i++)
+ {
+ /* h += m[i] */
+ h0 += (uletoh32(data + 0) >> 0) & 0x3ffffff;
+ h1 += (uletoh32(data + 3) >> 2) & 0x3ffffff;
+ h2 += (uletoh32(data + 6) >> 4) & 0x3ffffff;
+ h3 += (uletoh32(data + 9) >> 6) & 0x3ffffff;
+ h4 += (uletoh32(data + 12) >> 8) | (1 << 24);
+
+ /* h *= r */
+ d0 = mlt(h0, r0) + mlt(h1, s4) + mlt(h2, s3) + mlt(h3, s2) + mlt(h4, s1);
+ d1 = mlt(h0, r1) + mlt(h1, r0) + mlt(h2, s4) + mlt(h3, s3) + mlt(h4, s2);
+ d2 = mlt(h0, r2) + mlt(h1, r1) + mlt(h2, r0) + mlt(h3, s4) + mlt(h4, s3);
+ d3 = mlt(h0, r3) + mlt(h1, r2) + mlt(h2, r1) + mlt(h3, r0) + mlt(h4, s4);
+ d4 = mlt(h0, r4) + mlt(h1, r3) + mlt(h2, r2) + mlt(h3, r1) + mlt(h4, r0);
+
+ /* (partial) h %= p */
+ d1 += sr(d0, 26); h0 = and(d0, 0x3ffffff);
+ d2 += sr(d1, 26); h1 = and(d1, 0x3ffffff);
+ d3 += sr(d2, 26); h2 = and(d2, 0x3ffffff);
+ d4 += sr(d3, 26); h3 = and(d3, 0x3ffffff);
+ h0 += sr(d4, 26) * 5; h4 = and(d4, 0x3ffffff);
+ h1 += h0 >> 26; h0 = h0 & 0x3ffffff;
+
+ data += POLY_BLOCK_SIZE;
+ }
+
+ this->h[0] = h0;
+ this->h[1] = h1;
+ this->h[2] = h2;
+ this->h[3] = h3;
+ this->h[4] = h4;
+
+ return TRUE;
+}
+
+METHOD(chapoly_drv_t, chacha, bool,
+ private_chapoly_drv_portable_t *this, u_char *stream)
+{
+ memset(stream, 0, CHACHA_BLOCK_SIZE);
+ chacha_block_xor(this, stream);
+
+ return TRUE;
+}
+
+METHOD(chapoly_drv_t, encrypt, bool,
+ private_chapoly_drv_portable_t *this, u_char *data, u_int blocks)
+{
+ u_int i;
+
+ for (i = 0; i < blocks; i++)
+ {
+ chacha_block_xor(this, data);
+ poly(this, data, 4);
+ data += CHACHA_BLOCK_SIZE;
+ }
+ return TRUE;
+}
+
+METHOD(chapoly_drv_t, decrypt, bool,
+ private_chapoly_drv_portable_t *this, u_char *data, u_int blocks)
+{
+ u_int i;
+
+ for (i = 0; i < blocks; i++)
+ {
+ poly(this, data, 4);
+ chacha_block_xor(this, data);
+ data += CHACHA_BLOCK_SIZE;
+ }
+ return TRUE;
+}
+
+METHOD(chapoly_drv_t, finish, bool,
+ private_chapoly_drv_portable_t *this, u_char *mac)
+{
+ u_int32_t h0, h1, h2, h3, h4;
+ u_int32_t g0, g1, g2, g3, g4;
+ u_int32_t mask;
+ u_int64_t f = 0;
+
+ /* fully carry h */
+ h0 = this->h[0];
+ h1 = this->h[1];
+ h2 = this->h[2];
+ h3 = this->h[3];
+ h4 = this->h[4];
+
+ h2 += (h1 >> 26); h1 = h1 & 0x3ffffff;
+ h3 += (h2 >> 26); h2 = h2 & 0x3ffffff;
+ h4 += (h3 >> 26); h3 = h3 & 0x3ffffff;
+ h0 += (h4 >> 26) * 5; h4 = h4 & 0x3ffffff;
+ h1 += (h0 >> 26); h0 = h0 & 0x3ffffff;
+
+ /* compute h + -p */
+ g0 = h0 + 5;
+ g1 = h1 + (g0 >> 26); g0 &= 0x3ffffff;
+ g2 = h2 + (g1 >> 26); g1 &= 0x3ffffff;
+ g3 = h3 + (g2 >> 26); g2 &= 0x3ffffff;
+ g4 = h4 + (g3 >> 26) - (1 << 26); g3 &= 0x3ffffff;
+
+ /* select h if h < p, or h + -p if h >= p */
+ mask = (g4 >> ((sizeof(u_int32_t) * 8) - 1)) - 1;
+ g0 &= mask;
+ g1 &= mask;
+ g2 &= mask;
+ g3 &= mask;
+ g4 &= mask;
+ mask = ~mask;
+ h0 = (h0 & mask) | g0;
+ h1 = (h1 & mask) | g1;
+ h2 = (h2 & mask) | g2;
+ h3 = (h3 & mask) | g3;
+ h4 = (h4 & mask) | g4;
+
+ /* h = h % (2^128) */
+ h0 = (h0 >> 0) | (h1 << 26);
+ h1 = (h1 >> 6) | (h2 << 20);
+ h2 = (h2 >> 12) | (h3 << 14);
+ h3 = (h3 >> 18) | (h4 << 8);
+
+ /* mac = (h + s) % (2^128) */
+ f = (f >> 32) + h0 + this->s[0]; htoule32(mac + 0, f);
+ f = (f >> 32) + h1 + this->s[1]; htoule32(mac + 4, f);
+ f = (f >> 32) + h2 + this->s[2]; htoule32(mac + 8, f);
+ f = (f >> 32) + h3 + this->s[3]; htoule32(mac + 12, f);
+
+ return TRUE;
+}
+
+METHOD(chapoly_drv_t, destroy, void,
+ private_chapoly_drv_portable_t *this)
+{
+ memwipe(this->m, sizeof(this->m));
+ memwipe(this->h, sizeof(this->h));
+ memwipe(this->r, sizeof(this->r));
+ memwipe(this->s, sizeof(this->s));
+ free(this);
+}
+
+/**
+ * See header
+ */
+chapoly_drv_t *chapoly_drv_portable_create()
+{
+ private_chapoly_drv_portable_t *this;
+
+ INIT(this,
+ .public = {
+ .set_key = _set_key,
+ .init = _init,
+ .poly = _poly,
+ .chacha = _chacha,
+ .encrypt = _encrypt,
+ .decrypt = _decrypt,
+ .finish = _finish,
+ .destroy = _destroy,
+ },
+ );
+
+ return &this->public;
+}
diff --git a/src/libstrongswan/plugins/chapoly/chapoly_drv_portable.h b/src/libstrongswan/plugins/chapoly/chapoly_drv_portable.h
new file mode 100644
index 000000000..a320b2d41
--- /dev/null
+++ b/src/libstrongswan/plugins/chapoly/chapoly_drv_portable.h
@@ -0,0 +1,31 @@
+/*
+ * 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_portable chapoly_drv_portable
+ * @{ @ingroup chapoly
+ */
+
+#include "chapoly_drv.h"
+
+#ifndef CHAPOLY_DRV_PORTABLE_H_
+#define CHAPOLY_DRV_PORTABLE_H_
+
+/**
+ * Create a chapoly_drv_portable instance.
+ */
+chapoly_drv_t *chapoly_drv_portable_create();
+
+#endif /** CHAPOLY_drv_PORTABLE_H_ @}*/
diff --git a/src/libstrongswan/plugins/chapoly/chapoly_drv_ssse3.c b/src/libstrongswan/plugins/chapoly/chapoly_drv_ssse3.c
new file mode 100644
index 000000000..df88e7d77
--- /dev/null
+++ b/src/libstrongswan/plugins/chapoly/chapoly_drv_ssse3.c
@@ -0,0 +1,867 @@
+/*
+ * Copyright (C) 2015 Martin Willi
+ * Copyright (C) 2015 revosec AG
+ *
+ * Based on public domain code by Andrew Moon and Daniel J. Bernstein.
+ *
+ * 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_ssse3.h"
+
+#ifdef __SSSE3__
+
+#include <utils/cpu_feature.h>
+
+#include <tmmintrin.h>
+
+#define CHACHA_DOUBLEROUNDS 10
+
+typedef struct private_chapoly_drv_ssse3_t private_chapoly_drv_ssse3_t;
+
+/**
+ * Private data of an chapoly_drv_ssse3_t object.
+ */
+struct private_chapoly_drv_ssse3_t {
+
+ /**
+ * Public chapoly_drv_ssse3_t interface.
+ */
+ chapoly_drv_t public;
+
+ /**
+ * ChaCha20 state matrix, as 128-bit vectors
+ */
+ __m128i m[4];
+
+ /**
+ * Poly1305 update key
+ */
+ u_int32_t r[5];
+
+ /**
+ * Poly1305 update key r^2
+ */
+ u_int32_t u[5];
+
+ /**
+ * Poly1305 state
+ */
+ u_int32_t h[5];
+
+ /**
+ * Poly1305 finalize key
+ */
+ u_int32_t s[4];
+};
+
+/**
+ * Read a 32-bit integer from an unaligned address
+ */
+static inline u_int32_t ru32(void *p)
+{
+ u_int32_t ret;
+
+ memcpy(&ret, p, sizeof(ret));
+ return ret;
+}
+
+/**
+ * Write a 32-bit word to an unaligned address
+ */
+static inline void wu32(void *p, u_int32_t v)
+{
+ memcpy(p, &v, sizeof(v));
+}
+
+/**
+ * Shift a 64-bit unsigned integer v right by n bits, clamp to 32 bit
+*/
+static inline u_int32_t sr(u_int64_t v, u_char n)
+{
+ return v >> n;
+}
+
+/**
+ * AND two values, using a native integer size >= sizeof(u_int32_t)
+ */
+static inline u_long and(u_long v, u_long mask)
+{
+ return v & mask;
+}
+
+/**
+ * r = shuffle(a ^ b, s)
+ */
+static inline __m128i sfflxor32(__m128i a, __m128i b, __m128i s)
+{
+ return _mm_shuffle_epi8(_mm_xor_si128(a, b), s);
+}
+
+/**
+ * r = rotl32(a ^ b, r)
+ */
+static inline __m128i rotlxor32(__m128i a, __m128i b, u_char r)
+{
+ a = _mm_xor_si128(a, b);
+ return _mm_or_si128(_mm_slli_epi32(a, r), _mm_srli_epi32(a, 32 - r));
+}
+
+/**
+ * XOR a Chacha20 keystream block into data, increment counter
+ */
+static void chacha_block_xor(private_chapoly_drv_ssse3_t *this, void *data)
+{
+ __m128i x0, x1, x2, x3, r8, r16, *out = data;
+ u_int i;
+
+ r8 = _mm_set_epi8(14, 13, 12, 15, 10, 9, 8, 11, 6, 5, 4, 7, 2, 1, 0, 3);
+ r16 = _mm_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2);
+
+ x0 = this->m[0];
+ x1 = this->m[1];
+ x2 = this->m[2];
+ x3 = this->m[3];
+
+ for (i = 0 ; i < CHACHA_DOUBLEROUNDS; i++)
+ {
+ x0 = _mm_add_epi32(x0, x1);
+ x3 = sfflxor32(x3, x0, r16);
+
+ x2 = _mm_add_epi32(x2, x3);
+ x1 = rotlxor32(x1, x2, 12);
+
+ x0 = _mm_add_epi32(x0, x1);
+ x3 = sfflxor32(x3, x0, r8);
+
+ x2 = _mm_add_epi32(x2, x3);
+ x1 = rotlxor32(x1, x2, 7);
+
+ x1 = _mm_shuffle_epi32(x1, _MM_SHUFFLE(0, 3, 2, 1));
+ x2 = _mm_shuffle_epi32(x2, _MM_SHUFFLE(1, 0, 3, 2));
+ x3 = _mm_shuffle_epi32(x3, _MM_SHUFFLE(2, 1, 0, 3));
+
+ x0 = _mm_add_epi32(x0, x1);
+ x3 = sfflxor32(x3, x0, r16);
+
+ x2 = _mm_add_epi32(x2, x3);
+ x1 = rotlxor32(x1, x2, 12);
+
+ x0 = _mm_add_epi32(x0, x1);
+ x3 = sfflxor32(x3, x0, r8);
+
+ x2 = _mm_add_epi32(x2, x3);
+ x1 = rotlxor32(x1, x2, 7);
+
+ x1 = _mm_shuffle_epi32(x1, _MM_SHUFFLE(2, 1, 0, 3));
+ x2 = _mm_shuffle_epi32(x2, _MM_SHUFFLE(1, 0, 3, 2));
+ x3 = _mm_shuffle_epi32(x3, _MM_SHUFFLE(0, 3, 2, 1));
+ }
+
+ x0 = _mm_add_epi32(x0, this->m[0]);
+ x1 = _mm_add_epi32(x1, this->m[1]);
+ x2 = _mm_add_epi32(x2, this->m[2]);
+ x3 = _mm_add_epi32(x3, this->m[3]);
+ x0 = _mm_xor_si128(x0, _mm_loadu_si128(out + 0));
+ x1 = _mm_xor_si128(x1, _mm_loadu_si128(out + 1));
+ x2 = _mm_xor_si128(x2, _mm_loadu_si128(out + 2));
+ x3 = _mm_xor_si128(x3, _mm_loadu_si128(out + 3));
+ _mm_storeu_si128(out + 0, x0);
+ _mm_storeu_si128(out + 1, x1);
+ _mm_storeu_si128(out + 2, x2);
+ _mm_storeu_si128(out + 3, x3);
+
+ this->m[3] = _mm_add_epi32(this->m[3], _mm_set_epi32(0, 0, 0, 1));
+}
+
+/**
+ * XOR four Chacha20 keystream blocks into data, increment counter
+ */
+static void chacha_4block_xor(private_chapoly_drv_ssse3_t *this, void *data)
+{
+ __m128i x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, xa, xb, xc, xd, xe, xf;
+ __m128i r8, r16, ctrinc, t, *out = data;
+ u_int32_t *m = (u_int32_t*)this->m;
+ u_int i;
+
+ r8 = _mm_set_epi8(14, 13, 12, 15, 10, 9, 8, 11, 6, 5, 4, 7, 2, 1, 0, 3);
+ r16 = _mm_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2);
+ ctrinc = _mm_set_epi32(3, 2, 1, 0);
+
+ x0 = _mm_set1_epi32(m[ 0]);
+ x1 = _mm_set1_epi32(m[ 1]);
+ x2 = _mm_set1_epi32(m[ 2]);
+ x3 = _mm_set1_epi32(m[ 3]);
+ x4 = _mm_set1_epi32(m[ 4]);
+ x5 = _mm_set1_epi32(m[ 5]);
+ x6 = _mm_set1_epi32(m[ 6]);
+ x7 = _mm_set1_epi32(m[ 7]);
+ x8 = _mm_set1_epi32(m[ 8]);
+ x9 = _mm_set1_epi32(m[ 9]);
+ xa = _mm_set1_epi32(m[10]);
+ xb = _mm_set1_epi32(m[11]);
+ xc = _mm_set1_epi32(m[12]);
+ xd = _mm_set1_epi32(m[13]);
+ xe = _mm_set1_epi32(m[14]);
+ xf = _mm_set1_epi32(m[15]);
+
+ xc = _mm_add_epi32(xc, ctrinc);
+
+ for (i = 0 ; i < CHACHA_DOUBLEROUNDS; i++)
+ {
+ x0 = _mm_add_epi32(x0, x4); xc = sfflxor32(xc, x0, r16);
+ x1 = _mm_add_epi32(x1, x5); xd = sfflxor32(xd, x1, r16);
+ x2 = _mm_add_epi32(x2, x6); xe = sfflxor32(xe, x2, r16);
+ x3 = _mm_add_epi32(x3, x7); xf = sfflxor32(xf, x3, r16);
+
+ x8 = _mm_add_epi32(x8, xc); x4 = rotlxor32(x4, x8, 12);
+ x9 = _mm_add_epi32(x9, xd); x5 = rotlxor32(x5, x9, 12);
+ xa = _mm_add_epi32(xa, xe); x6 = rotlxor32(x6, xa, 12);
+ xb = _mm_add_epi32(xb, xf); x7 = rotlxor32(x7, xb, 12);
+
+ x0 = _mm_add_epi32(x0, x4); xc = sfflxor32(xc, x0, r8);
+ x1 = _mm_add_epi32(x1, x5); xd = sfflxor32(xd, x1, r8);
+ x2 = _mm_add_epi32(x2, x6); xe = sfflxor32(xe, x2, r8);
+ x3 = _mm_add_epi32(x3, x7); xf = sfflxor32(xf, x3, r8);
+
+ x8 = _mm_add_epi32(x8, xc); x4 = rotlxor32(x4, x8, 7);
+ x9 = _mm_add_epi32(x9, xd); x5 = rotlxor32(x5, x9, 7);
+ xa = _mm_add_epi32(xa, xe); x6 = rotlxor32(x6, xa, 7);
+ xb = _mm_add_epi32(xb, xf); x7 = rotlxor32(x7, xb, 7);
+
+ x0 = _mm_add_epi32(x0, x5); xf = sfflxor32(xf, x0, r16);
+ x1 = _mm_add_epi32(x1, x6); xc = sfflxor32(xc, x1, r16);
+ x2 = _mm_add_epi32(x2, x7); xd = sfflxor32(xd, x2, r16);
+ x3 = _mm_add_epi32(x3, x4); xe = sfflxor32(xe, x3, r16);
+
+ xa = _mm_add_epi32(xa, xf); x5 = rotlxor32(x5, xa, 12);
+ xb = _mm_add_epi32(xb, xc); x6 = rotlxor32(x6, xb, 12);
+ x8 = _mm_add_epi32(x8, xd); x7 = rotlxor32(x7, x8, 12);
+ x9 = _mm_add_epi32(x9, xe); x4 = rotlxor32(x4, x9, 12);
+
+ x0 = _mm_add_epi32(x0, x5); xf = sfflxor32(xf, x0, r8);
+ x1 = _mm_add_epi32(x1, x6); xc = sfflxor32(xc, x1, r8);
+ x2 = _mm_add_epi32(x2, x7); xd = sfflxor32(xd, x2, r8);
+ x3 = _mm_add_epi32(x3, x4); xe = sfflxor32(xe, x3, r8);
+
+ xa = _mm_add_epi32(xa, xf); x5 = rotlxor32(x5, xa, 7);
+ xb = _mm_add_epi32(xb, xc); x6 = rotlxor32(x6, xb, 7);
+ x8 = _mm_add_epi32(x8, xd); x7 = rotlxor32(x7, x8, 7);
+ x9 = _mm_add_epi32(x9, xe); x4 = rotlxor32(x4, x9, 7);
+ }
+
+ x0 = _mm_add_epi32(x0, _mm_set1_epi32(m[ 0]));
+ x1 = _mm_add_epi32(x1, _mm_set1_epi32(m[ 1]));
+ x2 = _mm_add_epi32(x2, _mm_set1_epi32(m[ 2]));
+ x3 = _mm_add_epi32(x3, _mm_set1_epi32(m[ 3]));
+ x4 = _mm_add_epi32(x4, _mm_set1_epi32(m[ 4]));
+ x5 = _mm_add_epi32(x5, _mm_set1_epi32(m[ 5]));
+ x6 = _mm_add_epi32(x6, _mm_set1_epi32(m[ 6]));
+ x7 = _mm_add_epi32(x7, _mm_set1_epi32(m[ 7]));
+ x8 = _mm_add_epi32(x8, _mm_set1_epi32(m[ 8]));
+ x9 = _mm_add_epi32(x9, _mm_set1_epi32(m[ 9]));
+ xa = _mm_add_epi32(xa, _mm_set1_epi32(m[10]));
+ xb = _mm_add_epi32(xb, _mm_set1_epi32(m[11]));
+ xc = _mm_add_epi32(xc, _mm_set1_epi32(m[12]));
+ xd = _mm_add_epi32(xd, _mm_set1_epi32(m[13]));
+ xe = _mm_add_epi32(xe, _mm_set1_epi32(m[14]));
+ xf = _mm_add_epi32(xf, _mm_set1_epi32(m[15]));
+
+ xc = _mm_add_epi32(xc, ctrinc);
+
+ /* transpose state matrix by interleaving 32-, then 64-bit words */
+ t = x0; x0 = _mm_unpacklo_epi32(t, x1);
+ x1 = _mm_unpackhi_epi32(t, x1);
+ t = x2; x2 = _mm_unpacklo_epi32(t, x3);
+ x3 = _mm_unpackhi_epi32(t, x3);
+ t = x4; x4 = _mm_unpacklo_epi32(t, x5);
+ x5 = _mm_unpackhi_epi32(t, x5);
+ t = x6; x6 = _mm_unpacklo_epi32(t, x7);
+ x7 = _mm_unpackhi_epi32(t, x7);
+ t = x8; x8 = _mm_unpacklo_epi32(t, x9);
+ x9 = _mm_unpackhi_epi32(t, x9);
+ t = xa; xa = _mm_unpacklo_epi32(t, xb);
+ xb = _mm_unpackhi_epi32(t, xb);
+ t = xc; xc = _mm_unpacklo_epi32(t, xd);
+ xd = _mm_unpackhi_epi32(t, xd);
+ t = xe; xe = _mm_unpacklo_epi32(t, xf);
+ xf = _mm_unpackhi_epi32(t, xf);
+
+ t = x0; x0 = _mm_unpacklo_epi64(t, x2);
+ x2 = _mm_unpackhi_epi64(t, x2);
+ t = x1; x1 = _mm_unpacklo_epi64(t, x3);
+ x3 = _mm_unpackhi_epi64(t, x3);
+ t = x4; x4 = _mm_unpacklo_epi64(t, x6);
+ x6 = _mm_unpackhi_epi64(t, x6);
+ t = x5; x5 = _mm_unpacklo_epi64(t, x7);
+ x7 = _mm_unpackhi_epi64(t, x7);
+ t = x8; x8 = _mm_unpacklo_epi64(t, xa);
+ xa = _mm_unpackhi_epi64(t, xa);
+ t = x9; x9 = _mm_unpacklo_epi64(t, xb);
+ xb = _mm_unpackhi_epi64(t, xb);
+ t = xc; xc = _mm_unpacklo_epi64(t, xe);
+ xe = _mm_unpackhi_epi64(t, xe);
+ t = xd; xd = _mm_unpacklo_epi64(t, xf);
+ xf = _mm_unpackhi_epi64(t, xf);
+
+ x0 = _mm_xor_si128(_mm_loadu_si128(out + 0), x0);
+ x1 = _mm_xor_si128(_mm_loadu_si128(out + 8), x1);
+ x2 = _mm_xor_si128(_mm_loadu_si128(out + 4), x2);
+ x3 = _mm_xor_si128(_mm_loadu_si128(out + 12), x3);
+ x4 = _mm_xor_si128(_mm_loadu_si128(out + 1), x4);
+ x5 = _mm_xor_si128(_mm_loadu_si128(out + 9), x5);
+ x6 = _mm_xor_si128(_mm_loadu_si128(out + 5), x6);
+ x7 = _mm_xor_si128(_mm_loadu_si128(out + 13), x7);
+ x8 = _mm_xor_si128(_mm_loadu_si128(out + 2), x8);
+ x9 = _mm_xor_si128(_mm_loadu_si128(out + 10), x9);
+ xa = _mm_xor_si128(_mm_loadu_si128(out + 6), xa);
+ xb = _mm_xor_si128(_mm_loadu_si128(out + 14), xb);
+ xc = _mm_xor_si128(_mm_loadu_si128(out + 3), xc);
+ xd = _mm_xor_si128(_mm_loadu_si128(out + 11), xd);
+ xe = _mm_xor_si128(_mm_loadu_si128(out + 7), xe);
+ xf = _mm_xor_si128(_mm_loadu_si128(out + 15), xf);
+
+ _mm_storeu_si128(out + 0, x0);
+ _mm_storeu_si128(out + 8, x1);
+ _mm_storeu_si128(out + 4, x2);
+ _mm_storeu_si128(out + 12, x3);
+ _mm_storeu_si128(out + 1, x4);
+ _mm_storeu_si128(out + 9, x5);
+ _mm_storeu_si128(out + 5, x6);
+ _mm_storeu_si128(out + 13, x7);
+ _mm_storeu_si128(out + 2, x8);
+ _mm_storeu_si128(out + 10, x9);
+ _mm_storeu_si128(out + 6, xa);
+ _mm_storeu_si128(out + 14, xb);
+ _mm_storeu_si128(out + 3, xc);
+ _mm_storeu_si128(out + 11, xd);
+ _mm_storeu_si128(out + 7, xe);
+ _mm_storeu_si128(out + 15, xf);
+
+ this->m[3] = _mm_add_epi32(this->m[3], _mm_set_epi32(0, 0, 0, 4));
+}
+
+METHOD(chapoly_drv_t, set_key, bool,
+ private_chapoly_drv_ssse3_t *this, u_char *constant, u_char *key,
+ u_char *salt)
+{
+ this->m[0] = _mm_loadu_si128((__m128i*)constant);
+ this->m[1] = _mm_loadu_si128((__m128i*)key + 0);
+ this->m[2] = _mm_loadu_si128((__m128i*)key + 1);
+ this->m[3] = _mm_set_epi32(0, 0, ru32(salt), 0);
+
+ return TRUE;
+}
+
+/**
+ * r[127:64] = h[95:64] * a, r[63:0] = h[31:0] * b
+ */
+static inline __m128i mul2(__m128i h, u_int32_t a, u_int32_t b)
+{
+ return _mm_mul_epu32(h, _mm_set_epi32(0, a, 0, b));
+}
+
+/**
+ * c = a[127:64] + a[63:0] + b[127:64] + b[63:0]
+ * z = x[127:64] + x[63:0] + y[127:64] + y[63:0]
+ */
+static inline void sum2(__m128i a, __m128i b, __m128i x, __m128i y,
+ u_int64_t *c, u_int64_t *z)
+{
+ __m128i r, s;
+
+ a = _mm_add_epi64(a, b);
+ x = _mm_add_epi64(x, y);
+ r = _mm_unpacklo_epi64(x, a);
+ s = _mm_unpackhi_epi64(x, a);
+ r = _mm_add_epi64(r, s);
+
+ _mm_storel_epi64((__m128i*)z, r);
+ _mm_storel_epi64((__m128i*)c, _mm_srli_si128(r, 8));
+}
+
+/**
+ * r = a[127:64] + b[127:64] + c[127:64] + d[127:64] + e[127:64]
+ * + a[63:0] + b[63:0] + c[63:0] + d[63:0] + e[63:0]
+ */
+static inline u_int64_t sum5(__m128i a, __m128i b, __m128i c,
+ __m128i d, __m128i e)
+{
+ u_int64_t r;
+
+ a = _mm_add_epi64(a, b);
+ c = _mm_add_epi64(c, d);
+ a = _mm_add_epi64(a, e);
+ a = _mm_add_epi64(a, c);
+
+ a = _mm_add_epi64(a, _mm_srli_si128(a, 8));
+ _mm_storel_epi64((__m128i*)&r, a);
+
+ return r;
+}
+
+/**
+ * Make second Poly1305 key u = r^2
+ */
+static void make_u(private_chapoly_drv_ssse3_t *this)
+{
+ __m128i r01, r23, r44, x0, x1, y0, y1, z0;
+ u_int32_t r0, r1, r2, r3, r4;
+ u_int32_t u0, u1, u2, u3, u4;
+ u_int32_t s1, s2, s3, s4;
+ u_int64_t d0, d1, d2, d3, d4;
+
+ r0 = this->r[0];
+ r1 = this->r[1];
+ r2 = this->r[2];
+ r3 = this->r[3];
+ r4 = this->r[4];
+
+ s1 = r1 * 5;
+ s2 = r2 * 5;
+ s3 = r3 * 5;
+ s4 = r4 * 5;
+
+ r01 = _mm_set_epi32(0, r0, 0, r1);
+ r23 = _mm_set_epi32(0, r2, 0, r3);
+ r44 = _mm_set_epi32(0, r4, 0, r4);
+
+ /* u = r^2 */
+ x0 = mul2(r01, r0, s4);
+ x1 = mul2(r01, r1, r0);
+ y0 = mul2(r23, s3, s2);
+ y1 = mul2(r23, s4, s3);
+ z0 = mul2(r44, s1, s2);
+ y0 = _mm_add_epi64(y0, _mm_srli_si128(z0, 8));
+ y1 = _mm_add_epi64(y1, _mm_slli_si128(z0, 8));
+ sum2(x0, y0, x1, y1, &d0, &d1);
+
+ x0 = mul2(r01, r2, r1);
+ x1 = mul2(r01, r3, r2);
+ y0 = mul2(r23, r0, s4);
+ y1 = mul2(r23, r1, r0);
+ z0 = mul2(r44, s3, s4);
+ y0 = _mm_add_epi64(y0, _mm_srli_si128(z0, 8));
+ y1 = _mm_add_epi64(y1, _mm_slli_si128(z0, 8));
+ sum2(x0, y0, x1, y1, &d2, &d3);
+
+ x0 = mul2(r01, r4, r3);
+ y0 = mul2(r23, r2, r1);
+ z0 = mul2(r44, r0, 0);
+ y0 = _mm_add_epi64(y0, z0);
+ x0 = _mm_add_epi64(x0, y0);
+ x0 = _mm_add_epi64(x0, _mm_srli_si128(x0, 8));
+ _mm_storel_epi64((__m128i*)&d4, x0);
+
+ /* (partial) r %= p */
+ d1 += sr(d0, 26); u0 = and(d0, 0x3ffffff);
+ d2 += sr(d1, 26); u1 = and(d1, 0x3ffffff);
+ d3 += sr(d2, 26); u2 = and(d2, 0x3ffffff);
+ d4 += sr(d3, 26); u3 = and(d3, 0x3ffffff);
+ u0 += sr(d4, 26) * 5; u4 = and(d4, 0x3ffffff);
+ u1 += u0 >> 26; u0 &= 0x3ffffff;
+
+ this->u[0] = u0;
+ this->u[1] = u1;
+ this->u[2] = u2;
+ this->u[3] = u3;
+ this->u[4] = u4;
+}
+
+METHOD(chapoly_drv_t, init, bool,
+ private_chapoly_drv_ssse3_t *this, u_char *iv)
+{
+ u_char key[CHACHA_BLOCK_SIZE];
+
+ this->m[3] = _mm_or_si128(
+ _mm_set_epi32(ru32(iv + 4), ru32(iv + 0), 0, 0),
+ _mm_and_si128(this->m[3], _mm_set_epi32(0, 0, ~0, 0)));
+
+ memset(key, 0, CHACHA_BLOCK_SIZE);
+ chacha_block_xor(this, key);
+
+ /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
+ this->r[0] = (ru32(key + 0) >> 0) & 0x3ffffff;
+ this->r[1] = (ru32(key + 3) >> 2) & 0x3ffff03;
+ this->r[2] = (ru32(key + 6) >> 4) & 0x3ffc0ff;
+ this->r[3] = (ru32(key + 9) >> 6) & 0x3f03fff;
+ this->r[4] = (ru32(key + 12) >> 8) & 0x00fffff;
+
+ make_u(this);
+
+ /* h = 0 */
+ memwipe(this->h, sizeof(this->h));
+
+ this->s[0] = ru32(key + 16);
+ this->s[1] = ru32(key + 20);
+ this->s[2] = ru32(key + 24);
+ this->s[3] = ru32(key + 28);
+
+ return TRUE;
+}
+
+/**
+ * Update Poly1305 for a multiple of two blocks
+ */
+static void poly2(private_chapoly_drv_ssse3_t *this, u_char *data, u_int dblks)
+{
+ u_int32_t r0, r1, r2, r3, r4, u0, u1, u2, u3, u4;
+ u_int32_t s1, s2, s3, s4, v1, v2, v3, v4;
+ __m128i hc0, hc1, hc2, hc3, hc4;
+ u_int32_t h0, h1, h2, h3, h4;
+ u_int32_t c0, c1, c2, c3, c4;
+ u_int64_t d0, d1, d2, d3, d4;
+ u_int i;
+
+ r0 = this->r[0];
+ r1 = this->r[1];
+ r2 = this->r[2];
+ r3 = this->r[3];
+ r4 = this->r[4];
+
+ s1 = r1 * 5;
+ s2 = r2 * 5;
+ s3 = r3 * 5;
+ s4 = r4 * 5;
+
+ u0 = this->u[0];
+ u1 = this->u[1];
+ u2 = this->u[2];
+ u3 = this->u[3];
+ u4 = this->u[4];
+
+ v1 = u1 * 5;
+ v2 = u2 * 5;
+ v3 = u3 * 5;
+ v4 = u4 * 5;
+
+ h0 = this->h[0];
+ h1 = this->h[1];
+ h2 = this->h[2];
+ h3 = this->h[3];
+ h4 = this->h[4];
+
+ /* h = (h + c1) * r^2 + c2 * r */
+ for (i = 0; i < dblks; i++)
+ {
+ /* h += m[i] */
+ h0 += (ru32(data + 0) >> 0) & 0x3ffffff;
+ h1 += (ru32(data + 3) >> 2) & 0x3ffffff;
+ h2 += (ru32(data + 6) >> 4) & 0x3ffffff;
+ h3 += (ru32(data + 9) >> 6) & 0x3ffffff;
+ h4 += (ru32(data + 12) >> 8) | (1 << 24);
+ data += POLY_BLOCK_SIZE;
+
+ /* c = m[i + 1] */
+ c0 = (ru32(data + 0) >> 0) & 0x3ffffff;
+ c1 = (ru32(data + 3) >> 2) & 0x3ffffff;
+ c2 = (ru32(data + 6) >> 4) & 0x3ffffff;
+ c3 = (ru32(data + 9) >> 6) & 0x3ffffff;
+ c4 = (ru32(data + 12) >> 8) | (1 << 24);
+ data += POLY_BLOCK_SIZE;
+
+ hc0 = _mm_set_epi32(0, h0, 0, c0);
+ hc1 = _mm_set_epi32(0, h1, 0, c1);
+ hc2 = _mm_set_epi32(0, h2, 0, c2);
+ hc3 = _mm_set_epi32(0, h3, 0, c3);
+ hc4 = _mm_set_epi32(0, h4, 0, c4);
+
+ /* h = h * r^2 + c * r */
+ d0 = sum5(mul2(hc0, u0, r0),
+ mul2(hc1, v4, s4),
+ mul2(hc2, v3, s3),
+ mul2(hc3, v2, s2),
+ mul2(hc4, v1, s1));
+ d1 = sum5(mul2(hc0, u1, r1),
+ mul2(hc1, u0, r0),
+ mul2(hc2, v4, s4),
+ mul2(hc3, v3, s3),
+ mul2(hc4, v2, s2));
+ d2 = sum5(mul2(hc0, u2, r2),
+ mul2(hc1, u1, r1),
+ mul2(hc2, u0, r0),
+ mul2(hc3, v4, s4),
+ mul2(hc4, v3, s3));
+ d3 = sum5(mul2(hc0, u3, r3),
+ mul2(hc1, u2, r2),
+ mul2(hc2, u1, r1),
+ mul2(hc3, u0, r0),
+ mul2(hc4, v4, s4));
+ d4 = sum5(mul2(hc0, u4, r4),
+ mul2(hc1, u3, r3),
+ mul2(hc2, u2, r2),
+ mul2(hc3, u1, r1),
+ mul2(hc4, u0, r0));
+
+ /* (partial) h %= p */
+ d1 += sr(d0, 26); h0 = and(d0, 0x3ffffff);
+ d2 += sr(d1, 26); h1 = and(d1, 0x3ffffff);
+ d3 += sr(d2, 26); h2 = and(d2, 0x3ffffff);
+ d4 += sr(d3, 26); h3 = and(d3, 0x3ffffff);
+ h0 += sr(d4, 26) * 5; h4 = and(d4, 0x3ffffff);
+ h1 += h0 >> 26; h0 = h0 & 0x3ffffff;
+ }
+
+ this->h[0] = h0;
+ this->h[1] = h1;
+ this->h[2] = h2;
+ this->h[3] = h3;
+ this->h[4] = h4;
+}
+
+/**
+ * Update Poly1305 for a single block
+ */
+static void poly1(private_chapoly_drv_ssse3_t *this, u_char *data)
+{
+ u_int32_t r0, r1, r2, r3, r4;
+ u_int32_t s1, s2, s3, s4;
+ u_int32_t h0, h1, h2, h3, h4;
+ u_int64_t d0, d1, d2, d3, d4;
+ __m128i h01, h23, h44;
+ __m128i x0, x1, y0, y1, z0;
+ u_int32_t t0, t1;
+
+ r0 = this->r[0];
+ r1 = this->r[1];
+ r2 = this->r[2];
+ r3 = this->r[3];
+ r4 = this->r[4];
+
+ s1 = r1 * 5;
+ s2 = r2 * 5;
+ s3 = r3 * 5;
+ s4 = r4 * 5;
+
+ h0 = this->h[0];
+ h1 = this->h[1];
+ h2 = this->h[2];
+ h3 = this->h[3];
+ h4 = this->h[4];
+
+ h01 = _mm_set_epi32(0, h0, 0, h1);
+ h23 = _mm_set_epi32(0, h2, 0, h3);
+ h44 = _mm_set_epi32(0, h4, 0, h4);
+
+ /* h += m[i] */
+ t0 = (ru32(data + 0) >> 0) & 0x3ffffff;
+ t1 = (ru32(data + 3) >> 2) & 0x3ffffff;
+ h01 = _mm_add_epi32(h01, _mm_set_epi32(0, t0, 0, t1));
+ t0 = (ru32(data + 6) >> 4) & 0x3ffffff;
+ t1 = (ru32(data + 9) >> 6) & 0x3ffffff;
+ h23 = _mm_add_epi32(h23, _mm_set_epi32(0, t0, 0, t1));
+ t0 = (ru32(data + 12) >> 8) | (1 << 24);
+ h44 = _mm_add_epi32(h44, _mm_set_epi32(0, t0, 0, t0));
+
+ /* h *= r */
+ x0 = mul2(h01, r0, s4);
+ x1 = mul2(h01, r1, r0);
+ y0 = mul2(h23, s3, s2);
+ y1 = mul2(h23, s4, s3);
+ z0 = mul2(h44, s1, s2);
+ y0 = _mm_add_epi64(y0, _mm_srli_si128(z0, 8));
+ y1 = _mm_add_epi64(y1, _mm_slli_si128(z0, 8));
+ sum2(x0, y0, x1, y1, &d0, &d1);
+
+ x0 = mul2(h01, r2, r1);
+ x1 = mul2(h01, r3, r2);
+ y0 = mul2(h23, r0, s4);
+ y1 = mul2(h23, r1, r0);
+ z0 = mul2(h44, s3, s4);
+ y0 = _mm_add_epi64(y0, _mm_srli_si128(z0, 8));
+ y1 = _mm_add_epi64(y1, _mm_slli_si128(z0, 8));
+ sum2(x0, y0, x1, y1, &d2, &d3);
+
+ x0 = mul2(h01, r4, r3);
+ y0 = mul2(h23, r2, r1);
+ z0 = mul2(h44, r0, 0);
+ y0 = _mm_add_epi64(y0, z0);
+ x0 = _mm_add_epi64(x0, y0);
+ x0 = _mm_add_epi64(x0, _mm_srli_si128(x0, 8));
+ _mm_storel_epi64((__m128i*)&d4, x0);
+
+ /* (partial) h %= p */
+ d1 += sr(d0, 26); h0 = and(d0, 0x3ffffff);
+ d2 += sr(d1, 26); h1 = and(d1, 0x3ffffff);
+ d3 += sr(d2, 26); h2 = and(d2, 0x3ffffff);
+ d4 += sr(d3, 26); h3 = and(d3, 0x3ffffff);
+ h0 += sr(d4, 26) * 5; h4 = and(d4, 0x3ffffff);
+ h1 += h0 >> 26; h0 = h0 & 0x3ffffff;
+
+ this->h[0] = h0;
+ this->h[1] = h1;
+ this->h[2] = h2;
+ this->h[3] = h3;
+ this->h[4] = h4;
+}
+
+METHOD(chapoly_drv_t, poly, bool,
+ private_chapoly_drv_ssse3_t *this, u_char *data, u_int blocks)
+{
+ poly2(this, data, blocks / 2);
+ if (blocks-- % 2)
+ {
+ poly1(this, data + POLY_BLOCK_SIZE * blocks);
+ }
+ return TRUE;
+}
+
+METHOD(chapoly_drv_t, chacha, bool,
+ private_chapoly_drv_ssse3_t *this, u_char *stream)
+{
+ memset(stream, 0, CHACHA_BLOCK_SIZE);
+ chacha_block_xor(this, stream);
+
+ return TRUE;
+}
+
+METHOD(chapoly_drv_t, encrypt, bool,
+ private_chapoly_drv_ssse3_t *this, u_char *data, u_int blocks)
+{
+ while (blocks >= 4)
+ {
+ chacha_4block_xor(this, data);
+ poly2(this, data, 8);
+ data += CHACHA_BLOCK_SIZE * 4;
+ blocks -= 4;
+ }
+ while (blocks--)
+ {
+ chacha_block_xor(this, data);
+ poly2(this, data, 2);
+ data += CHACHA_BLOCK_SIZE;
+ }
+ return TRUE;
+}
+
+METHOD(chapoly_drv_t, decrypt, bool,
+ private_chapoly_drv_ssse3_t *this, u_char *data, u_int blocks)
+{
+ while (blocks >= 4)
+ {
+ poly2(this, data, 8);
+ chacha_4block_xor(this, data);
+ data += CHACHA_BLOCK_SIZE * 4;
+ blocks -= 4;
+ }
+ while (blocks--)
+ {
+ poly2(this, data, 2);
+ chacha_block_xor(this, data);
+ data += CHACHA_BLOCK_SIZE;
+ }
+ return TRUE;
+}
+
+METHOD(chapoly_drv_t, finish, bool,
+ private_chapoly_drv_ssse3_t *this, u_char *mac)
+{
+ u_int32_t h0, h1, h2, h3, h4;
+ u_int32_t g0, g1, g2, g3, g4;
+ u_int32_t mask;
+ u_int64_t f = 0;
+
+ /* fully carry h */
+ h0 = this->h[0];
+ h1 = this->h[1];
+ h2 = this->h[2];
+ h3 = this->h[3];
+ h4 = this->h[4];
+
+ h2 += (h1 >> 26); h1 = h1 & 0x3ffffff;
+ h3 += (h2 >> 26); h2 = h2 & 0x3ffffff;
+ h4 += (h3 >> 26); h3 = h3 & 0x3ffffff;
+ h0 += (h4 >> 26) * 5; h4 = h4 & 0x3ffffff;
+ h1 += (h0 >> 26); h0 = h0 & 0x3ffffff;
+
+ /* compute h + -p */
+ g0 = h0 + 5;
+ g1 = h1 + (g0 >> 26); g0 &= 0x3ffffff;
+ g2 = h2 + (g1 >> 26); g1 &= 0x3ffffff;
+ g3 = h3 + (g2 >> 26); g2 &= 0x3ffffff;
+ g4 = h4 + (g3 >> 26) - (1 << 26); g3 &= 0x3ffffff;
+
+ /* select h if h < p, or h + -p if h >= p */
+ mask = (g4 >> ((sizeof(u_int32_t) * 8) - 1)) - 1;
+ g0 &= mask;
+ g1 &= mask;
+ g2 &= mask;
+ g3 &= mask;
+ g4 &= mask;
+ mask = ~mask;
+ h0 = (h0 & mask) | g0;
+ h1 = (h1 & mask) | g1;
+ h2 = (h2 & mask) | g2;
+ h3 = (h3 & mask) | g3;
+ h4 = (h4 & mask) | g4;
+
+ /* h = h % (2^128) */
+ h0 = (h0 >> 0) | (h1 << 26);
+ h1 = (h1 >> 6) | (h2 << 20);
+ h2 = (h2 >> 12) | (h3 << 14);
+ h3 = (h3 >> 18) | (h4 << 8);
+
+ /* mac = (h + s) % (2^128) */
+ f = (f >> 32) + h0 + this->s[0]; wu32(mac + 0, f);
+ f = (f >> 32) + h1 + this->s[1]; wu32(mac + 4, f);
+ f = (f >> 32) + h2 + this->s[2]; wu32(mac + 8, f);
+ f = (f >> 32) + h3 + this->s[3]; wu32(mac + 12, f);
+
+ return TRUE;
+}
+
+METHOD(chapoly_drv_t, destroy, void,
+ private_chapoly_drv_ssse3_t *this)
+{
+ memwipe(this->m, sizeof(this->m));
+ memwipe(this->h, sizeof(this->h));
+ memwipe(this->r, sizeof(this->r));
+ memwipe(this->u, sizeof(this->u));
+ memwipe(this->s, sizeof(this->s));
+ free_align(this);
+}
+
+/**
+ * See header
+ */
+chapoly_drv_t *chapoly_drv_ssse3_create()
+{
+ private_chapoly_drv_ssse3_t *this;
+
+ if (!cpu_feature_available(CPU_FEATURE_SSSE3))
+ {
+ return FALSE;
+ }
+
+ INIT_ALIGN(this, sizeof(__m128i),
+ .public = {
+ .set_key = _set_key,
+ .init = _init,
+ .poly = _poly,
+ .chacha = _chacha,
+ .encrypt = _encrypt,
+ .decrypt = _decrypt,
+ .finish = _finish,
+ .destroy = _destroy,
+ },
+ );
+
+ return &this->public;
+}
+
+#else /* !__SSSE3__ */
+
+chapoly_drv_t *chapoly_drv_ssse3_create()
+{
+ return NULL;
+}
+
+#endif /* !__SSSE3__ */
diff --git a/src/libstrongswan/plugins/chapoly/chapoly_drv_ssse3.h b/src/libstrongswan/plugins/chapoly/chapoly_drv_ssse3.h
new file mode 100644
index 000000000..7e0e8084c
--- /dev/null
+++ b/src/libstrongswan/plugins/chapoly/chapoly_drv_ssse3.h
@@ -0,0 +1,31 @@
+/*
+ * 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_ssse3 chapoly_drv_ssse3
+ * @{ @ingroup chapoly
+ */
+
+#include "chapoly_drv.h"
+
+#ifndef CHAPOLY_DRV_SSSE3_H_
+#define CHAPOLY_DRV_SSSE3_H_
+
+/**
+ * Create a chapoly_drv_ssse3 instance.
+ */
+chapoly_drv_t *chapoly_drv_ssse3_create();
+
+#endif /** CHAPOLY_DRV_SSSE3_H_ @}*/
diff --git a/src/libstrongswan/plugins/chapoly/chapoly_plugin.c b/src/libstrongswan/plugins/chapoly/chapoly_plugin.c
new file mode 100644
index 000000000..02e7121d6
--- /dev/null
+++ b/src/libstrongswan/plugins/chapoly/chapoly_plugin.c
@@ -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
index 000000000..f2b62e73c
--- /dev/null
+++ b/src/libstrongswan/plugins/chapoly/chapoly_plugin.h
@@ -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_ @}*/