diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2011-04-10 08:55:41 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2011-04-10 09:55:27 +0200 |
commit | 57555c75a8faf71bc7d664d73a2b9914ddb809d0 (patch) | |
tree | 69ef7906240427ee77d9a3f0d0cec7fc04098982 | |
parent | 6ceb3b0e0836f08ede425fd58ff93f322b881636 (diff) | |
download | gnutls-57555c75a8faf71bc7d664d73a2b9914ddb809d0.tar.gz |
Added support for x86 intel AES instruction acceleration if detected.
-rw-r--r-- | configure.ac | 180 | ||||
-rw-r--r-- | lib/Makefile.am | 3 | ||||
-rw-r--r-- | lib/accelerated/Makefile.am | 40 | ||||
-rw-r--r-- | lib/accelerated/accelerated.c | 14 | ||||
-rw-r--r-- | lib/accelerated/accelerated.h | 1 | ||||
-rw-r--r-- | lib/accelerated/aes-x86.c | 221 | ||||
-rw-r--r-- | lib/accelerated/aes-x86.h | 1 | ||||
-rw-r--r-- | lib/accelerated/x86.h | 3 | ||||
-rw-r--r-- | lib/gnutls_global.c | 3 | ||||
-rw-r--r-- | m4/gcc.m4 | 28 |
10 files changed, 416 insertions, 78 deletions
diff --git a/configure.ac b/configure.ac index f451464d72..941fa9f686 100644 --- a/configure.ac +++ b/configure.ac @@ -91,85 +91,27 @@ AC_CHECK_TYPES(uint,,, [ # include <sys/types.h> ]) -# For Guile bindings. -opt_guile_bindings=yes -AC_MSG_CHECKING([whether building Guile bindings]) -AC_ARG_ENABLE(guile, - AS_HELP_STRING([--enable-guile], [build GNU Guile bindings]), -opt_guile_bindings=$enableval) -AC_MSG_RESULT($opt_guile_bindings) - -AC_ARG_WITH([--with-guile-site-dir], - [AS_HELP_STRING([--with-guile-site-dir], - [use the given directory as the Guile site (use with care)])]) - -if test "$opt_guile_bindings" = "yes"; then - AC_MSG_RESULT([*** -*** Detecting GNU Guile... -]) - - AC_PATH_PROG([guile_snarf], [guile-snarf]) - if test "x$guile_snarf" = "x"; then - AC_MSG_WARN([`guile-snarf' from Guile 1.8 not found. Guile bindings not built.]) - opt_guile_bindings=no - else - GUILE_PROGS - GUILE_FLAGS - - save_CFLAGS="$CFLAGS" - save_LIBS="$LIBS" - CFLAGS="$CFLAGS $GUILE_CFLAGS" - LIBS="$LIBS $GUILE_LDFLAGS" - AC_MSG_CHECKING([whether GNU Guile is recent enough]) - AC_LINK_IFELSE(AC_LANG_CALL([], [scm_from_locale_string]), - [], [opt_guile_bindings=no]) - CFLAGS="$save_CFLAGS" - LIBS="$save_LIBS" - - if test "$opt_guile_bindings" = "yes"; then - AC_MSG_RESULT([yes]) - case "x$with_guile_site_dir" in - xno) - # Use the default $(GUILE_SITE). - GUILE_SITE_DIR - ;; - x|xyes) - # Automatically derive $(GUILE_SITE) from $(pkgdatadir). This - # hack is used to allow `distcheck' to work (see - # `DISTCHECK_CONFIGURE_FLAGS' in the top-level `Makefile.am'). - GUILE_SITE="\$(datadir)/guile/site" - AC_SUBST(GUILE_SITE) - ;; - *) - # Use the user-specified directory as $(GUILE_SITE). - GUILE_SITE="$with_guile_site_dir" - AC_SUBST(GUILE_SITE) - ;; - esac - AC_MSG_CHECKING([whether gcc supports -fgnu89-inline]) - _gcc_cflags_save="$CFLAGS" - CFLAGS="${CFLAGS} -fgnu89-inline" - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])], - gnu89_inline=yes, gnu89_inline=no) - AC_MSG_RESULT($gnu89_inline) - CFLAGS="$_gcc_cflags_save" +AC_ARG_ENABLE(hardware-acceleration, + AS_HELP_STRING([--disable-hardware-acceleration], [unconditionally disable hardware acceleration]), + use_accel=$enableval, use_accel=yes) +hw_accel=none + +if test "$use_accel" != "no"; then +case $host_cpu in + i?86 | x86_64 | amd64) + GCC_FLAG_ADD([-maes -mpclmul],[X86]) + + if test "x$X86" = "xyes";then + hw_accel="x86" + fi + ;; + *) + ;; +esac - # Optional Guile functions. - save_CFLAGS="$CFLAGS" - save_LIBS="$LIBS" - CFLAGS="$CFLAGS $GUILE_CFLAGS" - LIBS="$LIBS $GUILE_LDFLAGS" - AC_CHECK_FUNCS([scm_gc_malloc_pointerless]) - CFLAGS="$save_CFLAGS" - LIBS="$save_LIBS" - else - AC_MSG_RESULT([no]) - AC_MSG_WARN([A sufficiently recent GNU Guile not found. Guile bindings not built.]) - opt_guile_bindings=no - fi - fi fi -AM_CONDITIONAL(HAVE_GUILE, test "$opt_guile_bindings" = "yes") + +AM_CONDITIONAL(TRY_X86_OPTIMIZATIONS, test "$X86" = "yes") AM_CONDITIONAL(HAVE_GCC_GNU89_INLINE_OPTION, test "$gnu89_inline" = "yes"]) AM_CONDITIONAL(HAVE_GCC, test "$GCC" = "yes") @@ -310,6 +252,87 @@ AC_SUBST([WSTACK_CFLAGS]) AC_SUBST([WARN_CFLAGS]) AM_CONDITIONAL(ENABLE_CXX, test "$use_cxx" != "no") +# For Guile bindings. +opt_guile_bindings=yes +AC_MSG_CHECKING([whether building Guile bindings]) +AC_ARG_ENABLE(guile, + AS_HELP_STRING([--enable-guile], [build GNU Guile bindings]), +opt_guile_bindings=$enableval) +AC_MSG_RESULT($opt_guile_bindings) + +AC_ARG_WITH([--with-guile-site-dir], + [AS_HELP_STRING([--with-guile-site-dir], + [use the given directory as the Guile site (use with care)])]) + +if test "$opt_guile_bindings" = "yes"; then + AC_MSG_RESULT([*** +*** Detecting GNU Guile... +]) + + AC_PATH_PROG([guile_snarf], [guile-snarf]) + if test "x$guile_snarf" = "x"; then + AC_MSG_WARN([`guile-snarf' from Guile 1.8 not found. Guile bindings not built.]) + opt_guile_bindings=no + else + GUILE_PROGS + GUILE_FLAGS + + save_CFLAGS="$CFLAGS" + save_LIBS="$LIBS" + CFLAGS="$CFLAGS $GUILE_CFLAGS" + LIBS="$LIBS $GUILE_LDFLAGS" + AC_MSG_CHECKING([whether GNU Guile is recent enough]) + AC_LINK_IFELSE(AC_LANG_CALL([], [scm_from_locale_string]), + [], [opt_guile_bindings=no]) + CFLAGS="$save_CFLAGS" + LIBS="$save_LIBS" + + if test "$opt_guile_bindings" = "yes"; then + AC_MSG_RESULT([yes]) + case "x$with_guile_site_dir" in + xno) + # Use the default $(GUILE_SITE). + GUILE_SITE_DIR + ;; + x|xyes) + # Automatically derive $(GUILE_SITE) from $(pkgdatadir). This + # hack is used to allow `distcheck' to work (see + # `DISTCHECK_CONFIGURE_FLAGS' in the top-level `Makefile.am'). + GUILE_SITE="\$(datadir)/guile/site" + AC_SUBST(GUILE_SITE) + ;; + *) + # Use the user-specified directory as $(GUILE_SITE). + GUILE_SITE="$with_guile_site_dir" + AC_SUBST(GUILE_SITE) + ;; + esac + AC_MSG_CHECKING([whether gcc supports -fgnu89-inline]) + _gcc_cflags_save="$CFLAGS" + CFLAGS="${CFLAGS} -fgnu89-inline" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])], + gnu89_inline=yes, gnu89_inline=no) + AC_MSG_RESULT($gnu89_inline) + CFLAGS="$_gcc_cflags_save" + + # Optional Guile functions. + save_CFLAGS="$CFLAGS" + save_LIBS="$LIBS" + CFLAGS="$CFLAGS $GUILE_CFLAGS" + LIBS="$LIBS $GUILE_LDFLAGS" + AC_CHECK_FUNCS([scm_gc_malloc_pointerless]) + CFLAGS="$save_CFLAGS" + LIBS="$save_LIBS" + else + AC_MSG_RESULT([no]) + AC_MSG_WARN([A sufficiently recent GNU Guile not found. Guile bindings not built.]) + opt_guile_bindings=no + fi + fi +fi +AM_CONDITIONAL(HAVE_GUILE, test "$opt_guile_bindings" = "yes") + + LIBGNUTLS_EXTRA_LIBS="-L${libdir} -lgnutls-extra $LZO_LIBS $LIBGNUTLS_LIBS" LIBGNUTLS_EXTRA_CFLAGS="-I${includedir}" AC_SUBST(LIBGNUTLS_EXTRA_LIBS) @@ -376,6 +399,7 @@ AC_CONFIG_FILES([ lib/gcrypt/Makefile lib/nettle/Makefile tests/suite/Makefile + lib/accelerated/Makefile ]) AC_OUTPUT @@ -386,6 +410,7 @@ AC_MSG_NOTICE([summary of build options: Host type: ${host} Install prefix: ${prefix} Compiler: ${CC} + CFlags: ${CFLAGS} Warning flags: errors: ${WERROR_CFLAGS} warnings: ${WARN_CFLAGS} Library types: Shared=${enable_shared}, Static=${enable_static} Valgrind: $opt_valgrind_tests ${VALGRIND} @@ -393,5 +418,6 @@ AC_MSG_NOTICE([summary of build options: C++ library: $use_cxx OpenSSL library: $enable_openssl /dev/crypto: $enable_cryptodev + Hardware accel: $hw_accel Crypto library: $cryptolib ]) diff --git a/lib/Makefile.am b/lib/Makefile.am index f8dac6716a..982ae6ea48 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -23,7 +23,7 @@ ACLOCAL_AMFLAGS = -I ../m4 -I ../gl/m4 -SUBDIRS = includes x509 +SUBDIRS = includes x509 accelerated if ENABLE_MINITASN1 SUBDIRS += minitasn1 endif @@ -121,6 +121,7 @@ libgnutls_la_LDFLAGS = -no-undefined \ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) libgnutls_la_LIBADD = ../gl/libgnu.la x509/libgnutls_x509.la \ + accelerated/libaccelerated.la \ $(LTLIBZ) $(LTLIBINTL) $(LIBSOCKET) if ENABLE_OPENPGP diff --git a/lib/accelerated/Makefile.am b/lib/accelerated/Makefile.am new file mode 100644 index 0000000000..bfe9a168c1 --- /dev/null +++ b/lib/accelerated/Makefile.am @@ -0,0 +1,40 @@ +## Process this file with automake to produce Makefile.in +# Copyright (C) 2011 Free Software +# Foundation, Inc. +# +# Author: Nikos Mavrogiannopoulos +# +# This file is part of GNUTLS. +# +# The GNUTLS library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 of +# the License, or (at your option) any later version. +# +# The GNUTLS library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with the GNUTLS library; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA + +AM_CFLAGS = $(WERROR_CFLAGS) $(WSTACK_CFLAGS) $(WARN_CFLAGS) +AM_CPPFLAGS = \ + -I$(srcdir)/../../gl \ + -I$(srcdir)/../includes \ + -I$(builddir)/../includes \ + -I$(srcdir)/.. + +noinst_LTLIBRARIES = libaccelerated.la + +EXTRA_DIST = x86.h aes-x86.h accelerated.h +libaccelerated_la_SOURCES = accelerated.c + +if TRY_X86_OPTIMIZATIONS +AM_CFLAGS += -DTRY_X86_OPTIMIZATIONS +libaccelerated_la_SOURCES += aes-x86.c +endif + diff --git a/lib/accelerated/accelerated.c b/lib/accelerated/accelerated.c new file mode 100644 index 0000000000..91e7040fb0 --- /dev/null +++ b/lib/accelerated/accelerated.c @@ -0,0 +1,14 @@ +#include <accelerated.h> +#ifdef TRY_X86_OPTIMIZATIONS +# include <aes-x86.h> +#endif + +void _gnutls_register_accel_crypto(void) +{ + +#ifdef TRY_X86_OPTIMIZATIONS + register_x86_crypto (); +#endif + + return; +} diff --git a/lib/accelerated/accelerated.h b/lib/accelerated/accelerated.h new file mode 100644 index 0000000000..1fccccbb3c --- /dev/null +++ b/lib/accelerated/accelerated.h @@ -0,0 +1 @@ +void _gnutls_register_accel_crypto(void); diff --git a/lib/accelerated/aes-x86.c b/lib/accelerated/aes-x86.c new file mode 100644 index 0000000000..1b705edf5d --- /dev/null +++ b/lib/accelerated/aes-x86.c @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2011, Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * The GnuTLS is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + * The following code is an implementation of the AES-128-CBC cipher + * using intel's AES instruction set. It is based on Intel reference + * code. + */ + +#include <gnutls_errors.h> +#include <gnutls_int.h> +#include <gnutls/crypto.h> +#include <gnutls_errors.h> +#include <wmmintrin.h> +#include <aes-x86.h> +#include <x86.h> + +struct aes_ctx { + uint8_t iv[16]; + uint8_t key[16*10]; + size_t keysize; +}; + +static int +aes_cipher_init (gnutls_cipher_algorithm_t algorithm, void **_ctx) +{ + struct aes_ctx *ctx; + + if (algorithm != GNUTLS_CIPHER_AES_128_CBC) + return GNUTLS_E_INVALID_REQUEST; + + *_ctx = gnutls_calloc (1, sizeof (struct aes_ctx)); + if (*_ctx == NULL) + { + gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + ctx = *_ctx; + + return 0; +} + +inline static __m128i aes128_assist (__m128i temp1, __m128i temp2) +{ +__m128i temp3; + temp2 = _mm_shuffle_epi32 (temp2 ,0xff); + temp3 = _mm_slli_si128 (temp1, 0x4); + temp1 = _mm_xor_si128 (temp1, temp3); + temp3 = _mm_slli_si128 (temp3, 0x4); + temp1 = _mm_xor_si128 (temp1, temp3); + temp3 = _mm_slli_si128 (temp3, 0x4); + temp1 = _mm_xor_si128 (temp1, temp3); + temp1 = _mm_xor_si128 (temp1, temp2); + + return temp1; +} + +static int +aes_cipher_setkey (void *_ctx, const void *userkey, size_t keysize) +{ +struct aes_ctx *ctx = _ctx; +__m128i temp1, temp2; +__m128i *Key_Schedule = (__m128i*)ctx->key; + + temp1 = _mm_loadu_si128((__m128i*)userkey); + Key_Schedule[0] = temp1; + temp2 = _mm_aeskeygenassist_si128 (temp1 ,0x1); + temp1 = aes128_assist(temp1, temp2); + Key_Schedule[1] = temp1; + temp2 = _mm_aeskeygenassist_si128 (temp1,0x2); + temp1 = aes128_assist(temp1, temp2); + Key_Schedule[2] = temp1; + temp2 = _mm_aeskeygenassist_si128 (temp1,0x4); + temp1 = aes128_assist(temp1, temp2); + Key_Schedule[3] = temp1; + temp2 = _mm_aeskeygenassist_si128 (temp1,0x8); + temp1 = aes128_assist(temp1, temp2); + Key_Schedule[4] = temp1; + temp2 = _mm_aeskeygenassist_si128 (temp1,0x10); + temp1 = aes128_assist(temp1, temp2); + Key_Schedule[5] = temp1; + temp2 = _mm_aeskeygenassist_si128 (temp1,0x20); + temp1 = aes128_assist(temp1, temp2); + Key_Schedule[6] = temp1; + temp2 = _mm_aeskeygenassist_si128 (temp1,0x40); + temp1 = aes128_assist(temp1, temp2); + Key_Schedule[7] = temp1; + temp2 = _mm_aeskeygenassist_si128 (temp1,0x80); + temp1 = aes128_assist(temp1, temp2); + Key_Schedule[8] = temp1; + temp2 = _mm_aeskeygenassist_si128 (temp1,0x1b); + temp1 = aes128_assist(temp1, temp2); + Key_Schedule[9] = temp1; + temp2 = _mm_aeskeygenassist_si128 (temp1,0x36); + temp1 = aes128_assist(temp1, temp2); + Key_Schedule[10] = temp1; + + ctx->keysize = keysize; + + return 0; +} + +static int +aes_setiv (void *_ctx, const void *iv, size_t iv_size) +{ + struct aes_ctx *ctx = _ctx; + + memcpy (ctx->iv, iv, 16); + + return 0; +} + +#define AES_128_ROUNDS 10 + +static int +aes_encrypt (void *_ctx, const void *plain, size_t plainsize, + void *encr, size_t length) +{ +struct aes_ctx *ctx = _ctx; +__m128i feedback,data; +int i,j; + + feedback=_mm_loadu_si128 ((__m128i*)ctx->iv); + for(i=0; i < length; i++) { + data = _mm_loadu_si128 (&((__m128i*)plain)[i]); + feedback = _mm_xor_si128 (data,feedback); + feedback = _mm_xor_si128 (feedback,((__m128i*)ctx->key)[0]); + + for(j=1; j <AES_128_ROUNDS; j++) + feedback = _mm_aesenc_si128 (feedback,((__m128i*)ctx->key)[j]); + + feedback = _mm_aesenclast_si128 (feedback,((__m128i*)ctx->key)[j]); + _mm_storeu_si128 (&((__m128i*)encr)[i],feedback); + } + + return 0; +} + +static int +aes_decrypt (void *_ctx, const void *encr, size_t encrsize, + void *plain, size_t length) +{ +struct aes_ctx *ctx = _ctx; +__m128i data,feedback,last_in; +int i,j; + + feedback=_mm_loadu_si128 ((__m128i*)ctx->iv); + + for(i=0; i < length; i++) { + last_in=_mm_loadu_si128 (&((__m128i*)encr)[i]); + data = _mm_xor_si128 (last_in,((__m128i*)ctx->key)[0]); + + for(j=1; j <AES_128_ROUNDS; j++) + data = _mm_aesdec_si128 (data,((__m128i*)ctx->key)[j]); + + data = _mm_aesdeclast_si128 (data,((__m128i*)ctx->key)[j]); + data = _mm_xor_si128 (data,feedback); + _mm_storeu_si128 (&((__m128i*)plain)[i],data); + feedback=last_in; + } + + return 0; +} + +static void +aes_deinit (void *_ctx) +{ + gnutls_free (_ctx); +} + +static const gnutls_crypto_cipher_st cipher_struct = { + .init = aes_cipher_init, + .setkey = aes_cipher_setkey, + .setiv = aes_setiv, + .encrypt = aes_encrypt, + .decrypt = aes_decrypt, + .deinit = aes_deinit, +}; + +static unsigned check_optimized_aes(void) +{ +unsigned int a,b,c,d; + cpuid(1, a,b,c,d); + + return (c & 0x2000000); +} + +void +register_x86_crypto (void) +{ +int ret; + if (check_optimized_aes()) { + fprintf(stderr, "Intel AES accelerator was detected\n"); + ret = gnutls_crypto_single_cipher_register (GNUTLS_CIPHER_AES_128_CBC, 90, &cipher_struct); + if (ret < 0) + { + gnutls_assert (); + } + } + + return; +} diff --git a/lib/accelerated/aes-x86.h b/lib/accelerated/aes-x86.h new file mode 100644 index 0000000000..40d6a0c2b2 --- /dev/null +++ b/lib/accelerated/aes-x86.h @@ -0,0 +1 @@ +void register_x86_crypto (void); diff --git a/lib/accelerated/x86.h b/lib/accelerated/x86.h new file mode 100644 index 0000000000..c344283e36 --- /dev/null +++ b/lib/accelerated/x86.h @@ -0,0 +1,3 @@ +#define cpuid(func,ax,bx,cx,dx)\ + __asm__ __volatile__ ("cpuid":\ + "=a" (ax), "=b" (bx), "=c" (cx), "=d" (dx) : "a" (func)); diff --git a/lib/gnutls_global.c b/lib/gnutls_global.c index 1a59bdfc19..3c7f263968 100644 --- a/lib/gnutls_global.c +++ b/lib/gnutls_global.c @@ -33,6 +33,7 @@ #include <gnutls_extensions.h> /* for _gnutls_ext_init */ #include <gnutls_cryptodev.h> #include <locks.h> +#include <accelerated/accelerated.h> #include "sockets.h" #include "gettext.h" @@ -187,6 +188,8 @@ gnutls_global_init (void) return GNUTLS_E_CRYPTO_INIT_FAILED; } + _gnutls_register_accel_crypto(); + /* initialize ASN.1 parser * This should not deal with files in the final * version. diff --git a/m4/gcc.m4 b/m4/gcc.m4 new file mode 100644 index 0000000000..ad40adac7e --- /dev/null +++ b/m4/gcc.m4 @@ -0,0 +1,28 @@ +# gcc.m4 serial 2 +dnl Copyright (C) 2008-2011 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl Based on code by Simon Josefsson + +# GCC_FLAG_ADD(PARAMETER, [ACTION]) +# ------------------------------------------------ +# Adds parameter to CFLAGS if the compiler supports it. For example, +# GCC_FLAG_ADD([-maes], [VAR]). +AC_DEFUN([GCC_FLAG_ADD], +[AS_VAR_PUSHDEF([GCC_FLAG], [gl_cv_GCC_FLAG_$1])dnl +AC_CACHE_CHECK([whether compiler handles $1], [GCC_FLAG], [ + save_CFLAGS="$CFLAGS" + CFLAGS="${CFLAGS} $1" + AC_PREPROC_IFELSE([AC_LANG_PROGRAM([])], + [AS_VAR_SET([GCC_FLAG], [yes])], + [AS_VAR_SET([GCC_FLAG], [no])]) + CFLAGS="$save_CFLAGS" +]) +AS_VAR_IF([GCC_FLAG], [yes], [ +m4_ifval([$2], [AC_SUBST([$2],[yes])]) +CFLAGS="${CFLAGS} $1" +])dnl +AS_VAR_POPDEF([GCC_FLAG]) +]) |