Douglas Held | 23 Apr 23:09 2014
Picon

libgcrypt compile error on OS X: mpih-mul1-asm.S:43:9: error: invalid alignment value

Hello all,

I had trouble building 1.6.1 on OS X.  So I tried building 1.6.0 and I get the same error. I am happy to make an OS X 10.9 server available if a developer would like to take a look.

$ make
/Applications/Xcode.app/Contents/Developer/usr/bin/make  all-recursive
Making all in compat
make[2]: Nothing to be done for `all'.
Making all in mpi
/bin/sh ../libtool   --mode=compile gcc -DHAVE_CONFIG_H -I. -I..  -I../src -I../src   -g -O2 -MT mpih-mul1-asm.lo -MD -MP -MF .deps/mpih-mul1-asm.Tpo -c -o mpih-mul1-asm.lo mpih-mul1-asm.S
libtool: compile:  gcc -DHAVE_CONFIG_H -I. -I.. -I../src -I../src -g -O2 -MT mpih-mul1-asm.lo -MD -MP -MF .deps/mpih-mul1-asm.Tpo -c mpih-mul1-asm.S  -fno-common -DPIC -o .libs/mpih-mul1-asm.o
mpih-mul1-asm.S:43:9: error: invalid alignment value
 .align 1<<(5)
        ^
make[2]: *** [mpih-mul1-asm.lo] Error 1
make[1]: *** [all-recursive] Error 1
make: *** [all] Error 2

$ uname -a
Darwin dougair 13.1.0 Darwin Kernel Version 13.1.0: Wed Apr  2 23:52:02 PDT 2014; root:xnu-2422.92.1~2/RELEASE_X86_64 x86_64

$ make --version
GNU Make 3.81
Copyright (C) 2006  Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.

This program built for i386-apple-darwin11.3.0
$





--
Douglas Held
doug <at> douglasheld.net
+447775733093
_______________________________________________
Gcrypt-devel mailing list
Gcrypt-devel <at> gnupg.org
http://lists.gnupg.org/mailman/listinfo/gcrypt-devel
NIIBE Yutaka | 23 Apr 13:06 2014

[PATCH] Curve25519 support

Hello,

Here is a patch to support Curve25519.  It's not mature, to be
revised, but it works for me with GnuPG (with patch).

I'm posting this now, to share what's going on my side.

In this code, we don't put any information in Y (it's 0), and
it is assumed that only X coordinate will be used by ECDH.

TODO:

It breaks "make check".  It fails now.

We need to consider number of bits in Elliptic curve domain parameter.
We have the field, but it's not precise, and it's a kind of UI.  We
need precise number of bits so that we can use the information for key
generation.

We need to consider to have cofactor field in Elliptic curve domain
parameter.

We need to consider about cofactor and key handling.

We need to consider ephemeral key generation in libgcrypt
(currently, GnuPG does its own ephemeral key generation).

We need to introduce selective copy routine to avoid branches based on
scalar (which is secret) in _gcry_mpi_ec_add_points.

We need to implement Jivsov's compact representation.

We need to implement _gcry_mpi_ec_curve_point for Montgomery curve.
Also, dup_point_montgomery and add_points_montgomery.

diff --git a/cipher/ecc-curves.c b/cipher/ecc-curves.c
index 0f622f7..e7dbc17 100644
--- a/cipher/ecc-curves.c
+++ b/cipher/ecc-curves.c
 <at>  <at>  -40,7 +40,7  <at>  <at>  static const struct
   const char *other; /* Other name. */
 } curve_aliases[] =
   {
-  /*{ "Curve25519", "1.3.6.1.4.1.3029.1.5.1" },*/
+    { "Curve25519", "1.3.6.1.4.1.3029.1.5.1" },
     { "Ed25519",    "1.3.6.1.4.1.11591.15.1" },

     { "NIST P-192", "1.2.840.10045.3.1.1" }, /* X9.62 OID  */
 <at>  <at>  -127,6 +127,17  <at>  <at>  static const ecc_domain_parms_t domain_parms[] =
       "0x216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A",
       "0x6666666666666666666666666666666666666666666666666666666666666658"
     },
+    {
+      /* (y^2 = x^3 + 486662*x^2 + x) */
+      "Curve25519", 256, 0,
+      MPI_EC_MONTGOMERY, ECC_DIALECT_STANDARD,
+      "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED",
+      "0x01DB41", /* (A-2)/4 */
+      "0x01",
+      "0x1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED",
+      "0x0000000000000000000000000000000000000000000000000000000000000009",
+      "0x20AE19A1B8A086B4E01EDD2C7748D14C923D4D7E6D7C61B229E9C5A27ECED3D9"
+    },
 #if 0 /* No real specs yet found.  */
     {
       /* x^2 + y^2 = 1 + 3617x^2y^2 mod 2^414 - 17 */
 <at>  <at>  -507,9 +518,8  <at>  <at>  _gcry_ecc_fill_in_curve (unsigned int nbits, const char *name,
     {
     case MPI_EC_WEIERSTRASS:
     case MPI_EC_EDWARDS:
-      break;
     case MPI_EC_MONTGOMERY:
-      return GPG_ERR_NOT_SUPPORTED;
+      break;
     default:
       return GPG_ERR_BUG;
     }
diff --git a/cipher/ecc-misc.c b/cipher/ecc-misc.c
index 3f284fe..595aa0c 100644
--- a/cipher/ecc-misc.c
+++ b/cipher/ecc-misc.c
 <at>  <at>  -202,8 +202,13  <at>  <at>  _gcry_ecc_os2ec (mpi_point_t result, gcry_mpi_t value)
     }
   if (*buf != 4)
     {
+      /* x-coordinate only */
+      mpi_set (result->x, value);
+      mpi_clear (result->y);
+      mpi_set_ui (result->z, 1);
+
       xfree (buf_memory);
-      return GPG_ERR_NOT_IMPLEMENTED; /* No support for point compression.  */
+      return 0;
     }
   if ( ((n-1)%2) )
     {
diff --git a/cipher/ecc.c b/cipher/ecc.c
index e0be2d4..679aa39 100644
--- a/cipher/ecc.c
+++ b/cipher/ecc.c
 <at>  <at>  -117,7 +117,25  <at>  <at>  nist_generate_key (ECC_secret_key *sk, elliptic_curve_t *E, mpi_ec_t ctx,
   point_init (&Q);

   /* Generate a secret.  */
-  if (ctx->dialect == ECC_DIALECT_ED25519)
+  /*
+   * FIXME.  It should be something like this:
+   *
+   *   When the co-factor of the curve is not 1, we guarantee that
+   *   scalar value k is multiple of its co-factor to avoid sub-group
+   *   attack.  Also, we make sure that the most significant bit of k
+   *   is 1.
+   *
+   * It works for now as we only have two curves which have co-factor!=1;
+   * Ed25519 and Curve25519.
+   * Note that we need some a way to get number of bits of the curve to
+   * set MSB of k.  Currently, E.nbits is not precise for this purpuse.
+   * We also need a way to get co-factor of a curve.
+   *
+   * Currently, we distinguish the two curves by ECC_DIALECT_ED25519
+   * and MPI_EC_MONTGOMERY, which works, but is not that correct.
+   */
+  if (ctx->dialect == ECC_DIALECT_ED25519
+      || E->model == MPI_EC_MONTGOMERY)
     {
       char *rndbuf;

 <at>  <at>  -156,7 +174,7  <at>  <at>  nist_generate_key (ECC_secret_key *sk, elliptic_curve_t *E, mpi_ec_t ctx,
    * possibilities without any loss of security.  Note that we don't
    * do that for Ed25519 so that we do not violate the special
    * construction of the secret key.  */
-  if (E->dialect == ECC_DIALECT_ED25519)
+  if (E->dialect == ECC_DIALECT_ED25519 || E->model == MPI_EC_MONTGOMERY)
     point_set (&sk->Q, &Q);
   else
     {
 <at>  <at>  -227,12 +245,8  <at>  <at>  static void
 test_keys (ECC_secret_key *sk, unsigned int nbits)
 {
   ECC_public_key pk;
-  gcry_mpi_t test = mpi_new (nbits);
+  gcry_mpi_t test;
   mpi_point_struct R_;
-  gcry_mpi_t c = mpi_new (nbits);
-  gcry_mpi_t out = mpi_new (nbits);
-  gcry_mpi_t r = mpi_new (nbits);
-  gcry_mpi_t s = mpi_new (nbits);

   if (DBG_CIPHER)
     log_debug ("Testing key.\n");
 <at>  <at>  -243,27 +257,84  <at>  <at>  test_keys (ECC_secret_key *sk, unsigned int nbits)
   point_init (&pk.Q);
   point_set (&pk.Q, &sk->Q);

-  _gcry_mpi_randomize (test, nbits, GCRY_WEAK_RANDOM);
+  if (sk->E.model == MPI_EC_MONTGOMERY)
+    /* It's ECDH only. */
+    /* FIXME: see the FIXME comment of nist_generate_key.
+     * Here, we generate ephemeral key, same handling is needed for secret.
+     */
+    {
+      char *rndbuf;
+      gcry_mpi_t x0, x1;
+      mpi_ec_t ec;
+
+      test = mpi_new (256);
+      rndbuf = _gcry_random_bytes (32, GCRY_WEAK_RANDOM);
+      rndbuf[0] &= 0x7f;  /* Clear bit 255. */
+      rndbuf[0] |= 0x40;  /* Set bit 254.   */
+      rndbuf[31] &= 0xf8; /* Clear bits 2..0 so that d mod 8 == 0  */
+      _gcry_mpi_set_buffer (test, rndbuf, 32, 0);
+      xfree (rndbuf);
+
+      ec = _gcry_mpi_ec_p_internal_new (pk.E.model, pk.E.dialect, 0,
+					pk.E.p, pk.E.a, pk.E.b);
+      x0 = mpi_new (0);
+      x1 = mpi_new (0);

-  if (_gcry_ecc_ecdsa_sign (test, sk, r, s, 0, 0) )
-    log_fatal ("ECDSA operation: sign failed\n");
+      /* R_ = kQ  <=>  R_ = kdG  */
+      _gcry_mpi_ec_mul_point (&R_, test, &pk.Q, ec);
+      if (_gcry_mpi_ec_get_affine (x0, NULL, &R_, ec))
+	  log_fatal ("ecdh: Failed to get affine coordinates for kQ\n");

-  if (_gcry_ecc_ecdsa_verify (test, &pk, r, s))
-    {
-      log_fatal ("ECDSA operation: sign, verify failed\n");
+      /* R_ = kG */
+      _gcry_mpi_ec_mul_point (&R_, test, &pk.E.G, ec);
+      /* R_ = dkG */
+      _gcry_mpi_ec_mul_point (&R_, sk->d, &R_, ec);
+
+      if (_gcry_mpi_ec_get_affine (x1, NULL, &R_, ec))
+	log_fatal ("ecdh: Failed to get affine coordinates for dkG\n");
+
+      if (mpi_cmp (x0, x1))
+	{
+	  log_printmpi ("x0 ", x0);
+	  log_printmpi ("x1 ", x1);
+	  log_fatal ("ECDH test failed.\n");
+	}
+
+      mpi_free (x0);
+      mpi_free (x1);
+      _gcry_mpi_ec_free (ec);
     }
+  else
+    {
+      gcry_mpi_t c = mpi_new (nbits);
+      gcry_mpi_t out = mpi_new (nbits);
+      gcry_mpi_t r = mpi_new (nbits);
+      gcry_mpi_t s = mpi_new (nbits);

-  if (DBG_CIPHER)
-    log_debug ("ECDSA operation: sign, verify ok.\n");
+      test = mpi_new (nbits);
+      _gcry_mpi_randomize (test, nbits, GCRY_WEAK_RANDOM);
+
+      if (_gcry_ecc_ecdsa_sign (test, sk, r, s, 0, 0) )
+	log_fatal ("ECDSA operation: sign failed\n");
+
+      if (_gcry_ecc_ecdsa_verify (test, &pk, r, s))
+	{
+	  log_fatal ("ECDSA operation: sign, verify failed\n");
+	}
+
+      if (DBG_CIPHER)
+	log_debug ("ECDSA operation: sign, verify ok.\n");
+
+      mpi_free (s);
+      mpi_free (r);
+      mpi_free (out);
+      mpi_free (c);
+    }

   point_free (&pk.Q);
   _gcry_ecc_curve_free (&pk.E);

   point_free (&R_);
-  mpi_free (s);
-  mpi_free (r);
-  mpi_free (out);
-  mpi_free (c);
   mpi_free (test);
 }

diff --git a/mpi/ec.c b/mpi/ec.c
index 4f35de0..4fd9e53 100644
--- a/mpi/ec.c
+++ b/mpi/ec.c
 <at>  <at>  -600,10 +600,13  <at>  <at>  _gcry_mpi_ec_get_affine (gcry_mpi_t x, gcry_mpi_t y, mpi_point_t point,

     case MPI_EC_MONTGOMERY:
       {
-        log_fatal ("%s: %s not yet supported\n",
-                   "_gcry_mpi_ec_get_affine", "Montgomery");
+        if (x)
+          mpi_set (x, point->x);
+
+        if (y)
+          mpi_set (y, point->y);
       }
-      return -1;
+      return 0;

     case MPI_EC_EDWARDS:
       {
 <at>  <at>  -1073,6 +1076,35  <at>  <at>  add_points_edwards (mpi_point_t result,
 }

+/* PRD = 2 * P1.
+   SUM = P1 + P2.
+   P1 - P2 = DIF  */
+static void
+dup_and_add_montgomery (mpi_point_t prd, mpi_point_t sum,
+                        mpi_point_t p1, mpi_point_t p2, gcry_mpi_t dif_x,
+                        mpi_ec_t ctx)
+{
+  ec_addm (sum->x, p2->x, p2->z, ctx);
+  ec_subm (p2->z, p2->x, p2->z, ctx);
+  ec_addm (prd->x, p1->x, p1->z, ctx);
+  ec_subm (p1->z, p1->x, p1->z, ctx);
+  ec_mulm (p2->x, p1->z, sum->x, ctx);
+  ec_mulm (p2->z, prd->x, p2->z, ctx);
+  ec_pow2 (p1->x, prd->x, ctx);
+  ec_pow2 (p1->z, p1->z, ctx);
+  ec_addm (sum->x, p2->x, p2->z, ctx);
+  ec_subm (p2->z, p2->x, p2->z, ctx);
+  ec_mulm (prd->x, p1->x, p1->z, ctx);
+  ec_subm (p1->z, p1->x, p1->z, ctx);
+  ec_pow2 (sum->x, sum->x, ctx);
+  ec_pow2 (sum->z, p2->z, ctx);
+  ec_mulm (prd->z, p1->z, ctx->a, ctx); /* ctx->a: (A-2)/4 */
+  ec_mulm (sum->z, sum->z, dif_x, ctx);
+  ec_addm (prd->z, p1->x, prd->z, ctx);
+  ec_mulm (prd->z, prd->z, p1->z, ctx);
+}
+
+
 /* RESULT = P1 + P2 */
 void
 _gcry_mpi_ec_add_points (mpi_point_t result,
 <at>  <at>  -1144,6 +1176,86  <at>  <at>  _gcry_mpi_ec_mul_point (mpi_point_t result,
         }
       return;
     }
+  else if (ctx->model == MPI_EC_MONTGOMERY)
+    {
+      unsigned int nbits;
+      int j;
+      mpi_point_struct p1_, p2_;
+
+      nbits = mpi_get_nbits (scalar);
+      point_init (&p1);
+      point_init (&p2);
+      point_init (&p1_);
+      point_init (&p2_);
+      mpi_set_ui (p1.x, 1);
+      mpi_free (p2.x);
+      p2.x  = mpi_copy (point->x);
+      mpi_set_ui (p2.z, 1);
+
+      for (j=nbits-1; j >= 0; j--)
+        {
+          mpi_point_t q1, q2;
+          mpi_point_t sum_n, prd_n;
+
+          if (mpi_test_bit (scalar, j))
+            {
+              q1 = &p2;
+              q2 = &p1;
+              sum_n = &p1_;
+              prd_n = &p2_;
+            }
+          else
+            {
+              q1 = &p1;
+              q2 = &p2;
+              sum_n = &p2_;
+              prd_n = &p1_;
+            }
+          dup_and_add_montgomery (prd_n, sum_n, q1, q2, point->x, ctx);
+
+          if (--j < 0)
+            break;
+
+          if (mpi_test_bit (scalar, j))
+            {
+              q1 = &p2_;
+              q2 = &p1_;
+              sum_n = &p1;
+              prd_n = &p2;
+            }
+          else
+            {
+              q1 = &p1_;
+              q2 = &p2_;
+              sum_n = &p2;
+              prd_n = &p1;
+            }
+
+          dup_and_add_montgomery (prd_n, sum_n, q1, q2, point->x, ctx);
+        }
+
+      z1 = mpi_new (0);
+      mpi_clear (result->y);
+      mpi_set_ui (result->z, 1);
+      if ((nbits & 1))
+        {
+	  ec_invm (z1, p1_.z, ctx);
+	  ec_mulm (result->x, p1_.x, z1, ctx);
+          mpi_clear (result->y);
+        }
+      else
+        {
+	  ec_invm (z1, p1.z, ctx);
+	  ec_mulm (result->x, p1.x, z1, ctx);
+        }
+
+      mpi_free (z1);
+      point_free (&p1);
+      point_free (&p2);
+      point_free (&p1_);
+      point_free (&p2_);
+      return;
+    }

   x1 = mpi_alloc_like (ctx->p);
   y1 = mpi_alloc_like (ctx->p);
diff --git a/tests/curves.c b/tests/curves.c
index 0581452..977001e 100644
--- a/tests/curves.c
+++ b/tests/curves.c
 <at>  <at>  -29,7 +29,7  <at>  <at> 
 #include "../src/gcrypt-int.h"

 /* Number of curves defined in ../cipger/ecc.c */
-#define N_CURVES 21
+#define N_CURVES 22

 /* A real world sample public key.  */
 static char const sample_key_1[] =
diff --git a/tests/keygen.c b/tests/keygen.c
index 4aff9c9..c53246c 100644
--- a/tests/keygen.c
+++ b/tests/keygen.c
 <at>  <at>  -365,7 +365,7  <at>  <at>  static void
 check_ecc_keys (void)
 {
   const char *curves[] = { "NIST P-521", "NIST P-384", "NIST P-256",
-                           "Ed25519", NULL };
+                           "Ed25519", "Curve25519", NULL };
   int testno;
   gcry_sexp_t keyparm, key;
   int rc;
--

-- 
by Werner Koch | 22 Apr 10:34 2014
Picon

[git] GCRYPT - branch, master, updated. libgcrypt-1.6.0-64-ga79c4ad

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU crypto library".

The branch, master has been updated
       via  a79c4ad7c56ee4410f17beb73eeb58b0dd36bfc6 (commit)
      from  773e23698218755e9172d2507031a8263c47cc0b (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit a79c4ad7c56ee4410f17beb73eeb58b0dd36bfc6
Author: Werner Koch <wk <at> gnupg.org>
Date:   Tue Apr 15 16:40:48 2014 +0200

    random: Small patch for consistency and really burn the stack.

    * random/rndlinux.c (_gcry_rndlinux_gather_random): s/int/size_t/.
    (_gcry_rndlinux_gather_random): Replace memset by wipememory.
    --

    size_t was suggested by Marcus Meissner <meissner <at> suse.de>.  While
    looking at the code I identified the useless (i.e. likely optimized
    away) memset.

diff --git a/random/rndlinux.c b/random/rndlinux.c
index 89ac203..9eeec57 100644
--- a/random/rndlinux.c
+++ b/random/rndlinux.c
 <at>  <at>  -226,21 +226,23  <at>  <at>  _gcry_rndlinux_gather_random (void (*add)(const void*, size_t,

       do
         {
-          int nbytes = length < sizeof(buffer)? length : sizeof(buffer);
-          n = read(fd, buffer, nbytes );
-          if( n >= 0 && n > nbytes )
+          size_t nbytes;
+
+          nbytes = length < sizeof(buffer)? length : sizeof(buffer);
+          n = read (fd, buffer, nbytes);
+          if (n >= 0 && n > nbytes)
             {
               log_error("bogus read from random device (n=%d)\n", n );
               n = nbytes;
             }
         }
-      while( n == -1 && errno == EINTR );
-      if ( n == -1 )
+      while (n == -1 && errno == EINTR);
+      if  (n == -1)
         log_fatal("read error on random device: %s\n", strerror(errno));
-      (*add)( buffer, n, origin );
+      (*add)(buffer, n, origin);
       length -= n;
     }
-  memset(buffer, 0, sizeof(buffer) );
+  wipememory (buffer, sizeof buffer);

   if (any_need_entropy)
     _gcry_random_progress ("need_entropy", 'X', (int)want, (int)want);

-----------------------------------------------------------------------

Summary of changes:
 random/rndlinux.c |   16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

hooks/post-receive
--

-- 
The GNU crypto library
http://git.gnupg.org

_______________________________________________
Gnupg-commits mailing list
Gnupg-commits <at> gnupg.org
http://lists.gnupg.org/mailman/listinfo/gnupg-commits
by Werner Koch | 16 Apr 15:03 2014
Picon

[git] GCRYPT - branch, master, updated. libgcrypt-1.6.0-63-g773e236

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU crypto library".

The branch, master has been updated
       via  773e23698218755e9172d2507031a8263c47cc0b (commit)
      from  ae1fbce6dacf14747af0126e640bd4e54cb8c680 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 773e23698218755e9172d2507031a8263c47cc0b
Author: Werner Koch <wk <at> gnupg.org>
Date:   Tue Apr 15 16:40:48 2014 +0200

    pubkey: Re-map all depreccated RSA algo numbers.

    * cipher/pubkey.c (map_algo): Mape RSA_E and RSA_S.

diff --git a/cipher/pubkey.c b/cipher/pubkey.c
index 9aeaced..e3842c0 100644
--- a/cipher/pubkey.c
+++ b/cipher/pubkey.c
 <at>  <at>  -57,18 +57,16  <at>  <at>  map_algo (int algo)
 {
  switch (algo)
    {
-   case GCRY_PK_ECDSA:
-   case GCRY_PK_ECDH:
-     return GCRY_PK_ECC;
-   case GCRY_PK_ELG_E:
-     return GCRY_PK_ELG;
-   default:
-     return algo;
+   case GCRY_PK_RSA_E: return GCRY_PK_RSA;
+   case GCRY_PK_RSA_S: return GCRY_PK_RSA;
+   case GCRY_PK_ELG_E: return GCRY_PK_ELG;
+   case GCRY_PK_ECDSA: return GCRY_PK_ECC;
+   case GCRY_PK_ECDH:  return GCRY_PK_ECC;
+   default:            return algo;
    }
 }

 
-
 /* Return the spec structure for the public key algorithm ALGO.  For
    an unknown algorithm NULL is returned.  */
 static gcry_pk_spec_t *

-----------------------------------------------------------------------

Summary of changes:
 cipher/pubkey.c |   14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

hooks/post-receive
--

-- 
The GNU crypto library
http://git.gnupg.org

_______________________________________________
Gnupg-commits mailing list
Gnupg-commits <at> gnupg.org
http://lists.gnupg.org/mailman/listinfo/gnupg-commits
NIIBE Yutaka | 16 Apr 06:22 2014

25519 is 255-bit?

I don't know if we should "fix" this or not, but I think that
it's 255-bit.

GnuPG uses this information when it tries to send private key to
smartcard.  In development version of Gnuk, the key attribute says
it's 255-bit.  And I encounter the mismatch.

Here is a patch to show the issue.  It is no problem for me to modify
Gnuk side.

diff --git a/cipher/ecc-curves.c b/cipher/ecc-curves.c
index 0f622f7..13e043e 100644
--- a/cipher/ecc-curves.c
+++ b/cipher/ecc-curves.c
 <at>  <at>  -118,7 +118,7  <at>  <at>  static const ecc_domain_parms_t domain_parms[] =
   {
     {
       /* (-x^2 + y^2 = 1 + dx^2y^2) */
-      "Ed25519", 256, 0,
+      "Ed25519", 255, 0,
       MPI_EC_EDWARDS, ECC_DIALECT_ED25519,
       "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED",
       "-0x01",
--

-- 
by Werner Koch | 15 Apr 22:21 2014
Picon

[git] GCRYPT - branch, master, updated. libgcrypt-1.6.0-62-gae1fbce

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU crypto library".

The branch, master has been updated
       via  ae1fbce6dacf14747af0126e640bd4e54cb8c680 (commit)
      from  b76b632a453b8d100d024e2439b4358454dc286e (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit ae1fbce6dacf14747af0126e640bd4e54cb8c680
Author: Werner Koch <wk <at> gnupg.org>
Date:   Tue Apr 15 16:40:48 2014 +0200

    cipher: Fix possible NULL dereference.

    * cipher/md.c (_gcry_md_selftest): Check for spec being NULL.
    --

    Also removed left-over code in unused file cipher/test-getrusage.c.

    Found by Hans-Christoph Steiner with cppcheck.

diff --git a/cipher/md.c b/cipher/md.c
index 461ad64..5ab89cb 100644
--- a/cipher/md.c
+++ b/cipher/md.c
 <at>  <at>  -1250,7 +1250,8  <at>  <at>  _gcry_md_selftest (int algo, int extended, selftest_report_func_t report)
     ec = spec->selftest (algo, extended, report);
   else
     {
-      ec = spec->selftest? GPG_ERR_DIGEST_ALGO : GPG_ERR_NOT_IMPLEMENTED;
+      ec = (spec && spec->selftest) ? GPG_ERR_DIGEST_ALGO
+        /* */                       : GPG_ERR_NOT_IMPLEMENTED;
       if (report)
         report ("digest", algo, "module",
                 (spec && !spec->flags.disabled)?
diff --git a/cipher/test-getrusage.c b/cipher/test-getrusage.c
index 6fc8372..7f586dd 100644
--- a/cipher/test-getrusage.c
+++ b/cipher/test-getrusage.c
 <at>  <at>  -45,10 +45,6  <at>  <at>  main (int argc, char **argv)
   printf ("ru_nvcsw   = %ld\n", buf.ru_nvcsw    );
   printf ("ru_nivcsw  = %ld\n", buf.ru_nivcsw   );

-  fprintf (stderr, "ru_utime   ru_stime   ru_minflt  ru_nccsw  ru_nivcsw\n");
-  fprintf (stderr, "%ld.%06ld  %ld.%06ld  %5ld       %5ld      %5ld\n");
-
-
   return 0;
 }

-----------------------------------------------------------------------

Summary of changes:
 cipher/md.c             |    3 ++-
 cipher/test-getrusage.c |    4 ----
 2 files changed, 2 insertions(+), 5 deletions(-)

hooks/post-receive
--

-- 
The GNU crypto library
http://git.gnupg.org

_______________________________________________
Gnupg-commits mailing list
Gnupg-commits <at> gnupg.org
http://lists.gnupg.org/mailman/listinfo/gnupg-commits
by Jussi Kivilinna | 4 Apr 17:07 2014
Picon

[git] GCRYPT - branch, master, updated. libgcrypt-1.6.0-61-gb76b632

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU crypto library".

The branch, master has been updated
       via  b76b632a453b8d100d024e2439b4358454dc286e (commit)
      from  50aeee51a0b1a09dd9fff2bb71749a816fe7a791 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit b76b632a453b8d100d024e2439b4358454dc286e
Author: Jussi Kivilinna <jussi.kivilinna <at> iki.fi>
Date:   Sun Mar 30 18:11:09 2014 +0300

    3des: add amd64 assembly implementation for 3DES
    
    * cipher/Makefile.am: Add 'des-amd64.S'.
    * cipher/cipher-selftests.c (_gcry_selftest_helper_cbc)
    (_gcry_selftest_helper_cfb, _gcry_selftest_helper_ctr): Handle failures
    from 'setkey' function.
    * cipher/cipher.c (_gcry_cipher_open_internal) [USE_DES]: Setup bulk
    functions for 3DES.
    * cipher/des-amd64.S: New file.
    * cipher/des.c (USE_AMD64_ASM, ATTR_ALIGNED_16): New macros.
    [USE_AMD64_ASM] (_gcry_3des_amd64_crypt_block)
    (_gcry_3des_amd64_ctr_enc), _gcry_3des_amd64_cbc_dec)
    (_gcry_3des_amd64_cfb_dec): New prototypes.
    [USE_AMD64_ASM] (tripledes_ecb_crypt): New function.
    (TRIPLEDES_ECB_BURN_STACK): New macro.
    (_gcry_3des_ctr_enc, _gcry_3des_cbc_dec, _gcry_3des_cfb_dec)
    (bulk_selftest_setkey, selftest_ctr, selftest_cbc, selftest_cfb): New
    functions.
    (selftest): Add call to CTR, CBC and CFB selftest functions.
    (do_tripledes_encrypt, do_tripledes_decrypt): Use
    TRIPLEDES_ECB_BURN_STACK.
    * configure.ac [host=x86-64]: Add 'des-amd64.lo'.
    * src/cipher.h (_gcry_3des_ctr_enc, _gcry_3des_cbc_dec)
    (_gcry_3des_cfb_dec): New prototypes.
    --
    
    Add non-parallel functions for small speed-up and 3-way parallel functions for
    modes of operation that support parallel processing.
    
    Old vs new (Intel Core i5-4570):
    ================================
            enc    dec
     ECB    1.17x  1.17x
     CBC    1.17x  2.51x
     CFB    1.16x  2.49x
     OFB    1.17x  1.17x
     CTR    2.56x  2.56x
    
    Old vs new (Intel Core i5-2450M):
    =================================
            enc    dec
     ECB    1.28x  1.28x
     CBC    1.27x  2.33x
     CFB    1.27x  2.34x
     OFB    1.27x  1.27x
     CTR    2.36x  2.35x
    
    New (Intel Core i5-4570):
    =========================
     3DES           |  nanosecs/byte   mebibytes/sec   cycles/byte
            ECB enc |     28.39 ns/B     33.60 MiB/s     90.84 c/B
            ECB dec |     28.27 ns/B     33.74 MiB/s     90.45 c/B
            CBC enc |     29.50 ns/B     32.33 MiB/s     94.40 c/B
            CBC dec |     13.35 ns/B     71.45 MiB/s     42.71 c/B
            CFB enc |     29.59 ns/B     32.23 MiB/s     94.68 c/B
            CFB dec |     13.41 ns/B     71.12 MiB/s     42.91 c/B
            OFB enc |     28.90 ns/B     33.00 MiB/s     92.47 c/B
            OFB dec |     28.90 ns/B     33.00 MiB/s     92.48 c/B
            CTR enc |     13.39 ns/B     71.20 MiB/s     42.86 c/B
            CTR dec |     13.39 ns/B     71.21 MiB/s     42.86 c/B
    
    Old (Intel Core i5-4570):
    =========================
     3DES           |  nanosecs/byte   mebibytes/sec   cycles/byte
            ECB enc |     33.24 ns/B     28.69 MiB/s     106.4 c/B
            ECB dec |     33.26 ns/B     28.67 MiB/s     106.4 c/B
            CBC enc |     34.45 ns/B     27.69 MiB/s     110.2 c/B
            CBC dec |     33.45 ns/B     28.51 MiB/s     107.1 c/B
            CFB enc |     34.43 ns/B     27.70 MiB/s     110.2 c/B
            CFB dec |     33.41 ns/B     28.55 MiB/s     106.9 c/B
            OFB enc |     33.79 ns/B     28.22 MiB/s     108.1 c/B
            OFB dec |     33.79 ns/B     28.22 MiB/s     108.1 c/B
            CTR enc |     34.27 ns/B     27.83 MiB/s     109.7 c/B
            CTR dec |     34.27 ns/B     27.83 MiB/s     109.7 c/B
    
    New (Intel Core i5-2450M):
    ==========================
     3DES           |  nanosecs/byte   mebibytes/sec   cycles/byte
            ECB enc |     42.21 ns/B     22.59 MiB/s     105.5 c/B
            ECB dec |     42.23 ns/B     22.58 MiB/s     105.6 c/B
            CBC enc |     43.70 ns/B     21.82 MiB/s     109.2 c/B
            CBC dec |     23.25 ns/B     41.02 MiB/s     58.12 c/B
            CFB enc |     43.71 ns/B     21.82 MiB/s     109.3 c/B
            CFB dec |     23.23 ns/B     41.05 MiB/s     58.08 c/B
            OFB enc |     42.73 ns/B     22.32 MiB/s     106.8 c/B
            OFB dec |     42.73 ns/B     22.32 MiB/s     106.8 c/B
            CTR enc |     23.31 ns/B     40.92 MiB/s     58.27 c/B
            CTR dec |     23.35 ns/B     40.84 MiB/s     58.38 c/B
    
    Old (Intel Core i5-2450M):
    ==========================
     3DES           |  nanosecs/byte   mebibytes/sec   cycles/byte
            ECB enc |     53.98 ns/B     17.67 MiB/s     134.9 c/B
            ECB dec |     54.00 ns/B     17.66 MiB/s     135.0 c/B
            CBC enc |     55.43 ns/B     17.20 MiB/s     138.6 c/B
            CBC dec |     54.27 ns/B     17.57 MiB/s     135.7 c/B
            CFB enc |     55.42 ns/B     17.21 MiB/s     138.6 c/B
            CFB dec |     54.35 ns/B     17.55 MiB/s     135.9 c/B
            OFB enc |     54.49 ns/B     17.50 MiB/s     136.2 c/B
            OFB dec |     54.49 ns/B     17.50 MiB/s     136.2 c/B
            CTR enc |     55.02 ns/B     17.33 MiB/s     137.5 c/B
            CTR dec |     55.01 ns/B     17.34 MiB/s     137.5 c/B
    
    Signed-off-by: Jussi Kivilinna <jussi.kivilinna <at> iki.fi>

diff --git a/cipher/Makefile.am b/cipher/Makefile.am
index 462e6db..3c20d3c 100644
--- a/cipher/Makefile.am
+++ b/cipher/Makefile.am
 <at>  <at>  -60,7 +60,7  <at>  <at>  arcfour.c arcfour-amd64.S \
 blowfish.c blowfish-amd64.S blowfish-arm.S \
 cast5.c cast5-amd64.S cast5-arm.S \
 crc.c \
-des.c \
+des.c des-amd64.S \
 dsa.c \
 elgamal.c \
 ecc.c ecc-curves.c ecc-misc.c ecc-common.h \
diff --git a/cipher/cipher-selftest.c b/cipher/cipher-selftest.c
index 5e95814..852368a 100644
--- a/cipher/cipher-selftest.c
+++ b/cipher/cipher-selftest.c
 <at>  <at>  -82,7 +82,11  <at>  <at>  _gcry_selftest_helper_cbc (const char *cipher, gcry_cipher_setkey_t setkey_func,
   ciphertext = plaintext2 + nblocks * blocksize;
 
   /* Initialize ctx */
-  setkey_func (ctx, key, sizeof(key));
+  if (setkey_func (ctx, key, sizeof(key)) != GPG_ERR_NO_ERROR)
+   {
+     xfree(mem);
+     return "setkey failed";
+   }
 
   /* Test single block code path */
   memset (iv, 0x4e, blocksize);
 <at>  <at>  -199,7 +203,11  <at>  <at>  _gcry_selftest_helper_cfb (const char *cipher, gcry_cipher_setkey_t setkey_func,
   ciphertext = plaintext2 + nblocks * blocksize;
 
   /* Initialize ctx */
-  setkey_func (ctx, key, sizeof(key));
+  if (setkey_func (ctx, key, sizeof(key)) != GPG_ERR_NO_ERROR)
+   {
+     xfree(mem);
+     return "setkey failed";
+   }
 
   /* Test single block code path */
   memset(iv, 0xd3, blocksize);
 <at>  <at>  -316,7 +324,11  <at>  <at>  _gcry_selftest_helper_ctr (const char *cipher, gcry_cipher_setkey_t setkey_func,
   ciphertext2 = ciphertext + nblocks * blocksize;
 
   /* Initialize ctx */
-  setkey_func (ctx, key, sizeof(key));
+  if (setkey_func (ctx, key, sizeof(key)) != GPG_ERR_NO_ERROR)
+   {
+     xfree(mem);
+     return "setkey failed";
+   }
 
   /* Test single block code path */
   memset (iv, 0xff, blocksize);
diff --git a/cipher/cipher.c b/cipher/cipher.c
index baa4720..6552ed3 100644
--- a/cipher/cipher.c
+++ b/cipher/cipher.c
 <at>  <at>  -513,6 +513,13  <at>  <at>  _gcry_cipher_open_internal (gcry_cipher_hd_t *handle,
               h->bulk.ctr_enc = _gcry_camellia_ctr_enc;
               break;
 #endif /*USE_CAMELLIA*/
+#ifdef USE_DES
+            case GCRY_CIPHER_3DES:
+              h->bulk.cbc_dec =  _gcry_3des_cbc_dec;
+              h->bulk.cfb_dec =  _gcry_3des_cfb_dec;
+              h->bulk.ctr_enc =  _gcry_3des_ctr_enc;
+              break;
+#endif /*USE_DES*/
 #ifdef USE_SERPENT
 	    case GCRY_CIPHER_SERPENT128:
 	    case GCRY_CIPHER_SERPENT192:
diff --git a/cipher/des-amd64.S b/cipher/des-amd64.S
new file mode 100644
index 0000000..e8b2c56
--- /dev/null
+++ b/cipher/des-amd64.S
 <at>  <at>  -0,0 +1,1030  <at>  <at> 
+/* des-amd64.S  -  AMD64 assembly implementation of 3DES cipher
+ *
+ * Copyright (C) 2014 Jussi Kivilinna <jussi.kivilinna <at> iki.fi>
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt 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.
+ *
+ * Libgcrypt 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 program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef __x86_64
+#include <config.h>
+#if defined(USE_DES) && defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS)
+
+#ifdef __PIC__
+#  define RIP (%rip)
+#else
+#  define RIP
+#endif
+
+.text
+
+#define s1 0
+#define s2 ((s1) + (64*8))
+#define s3 ((s2) + (64*8))
+#define s4 ((s3) + (64*8))
+#define s5 ((s4) + (64*8))
+#define s6 ((s5) + (64*8))
+#define s7 ((s6) + (64*8))
+#define s8 ((s7) + (64*8))
+
+/* register macros */
+#define CTX %rdi
+#define SBOXES %rbp
+
+#define RL0 %r8
+#define RL1 %r9
+#define RL2 %r10
+
+#define RL0d %r8d
+#define RL1d %r9d
+#define RL2d %r10d
+
+#define RR0 %r11
+#define RR1 %r12
+#define RR2 %r13
+
+#define RR0d %r11d
+#define RR1d %r12d
+#define RR2d %r13d
+
+#define RW0 %rax
+#define RW1 %rbx
+#define RW2 %rcx
+
+#define RW0d %eax
+#define RW1d %ebx
+#define RW2d %ecx
+
+#define RW0bl %al
+#define RW1bl %bl
+#define RW2bl %cl
+
+#define RW0bh %ah
+#define RW1bh %bh
+#define RW2bh %ch
+
+#define RT0 %r15
+#define RT1 %rsi
+#define RT2 %r14
+#define RT3 %rdx
+
+#define RT0d %r15d
+#define RT1d %esi
+#define RT2d %r14d
+#define RT3d %edx
+
+/***********************************************************************
+ * 1-way 3DES
+ ***********************************************************************/
+#define do_permutation(a, b, offset, mask) \
+	movl a, RT0d; \
+	shrl $(offset), RT0d; \
+	xorl b, RT0d; \
+	andl $(mask), RT0d; \
+	xorl RT0d, b; \
+	shll $(offset), RT0d; \
+	xorl RT0d, a;
+
+#define expand_to_64bits(val, mask) \
+	movl val##d, RT0d; \
+	rorl $4, RT0d; \
+	shlq $32, RT0; \
+	orq RT0, val; \
+	andq mask, val;
+
+#define compress_to_64bits(val) \
+	movq val, RT0; \
+	shrq $32, RT0; \
+	roll $4, RT0d; \
+	orl RT0d, val##d;
+
+#define initial_permutation(left, right) \
+	do_permutation(left##d, right##d,  4, 0x0f0f0f0f); \
+	do_permutation(left##d, right##d, 16, 0x0000ffff); \
+	do_permutation(right##d, left##d,  2, 0x33333333); \
+	do_permutation(right##d, left##d,  8, 0x00ff00ff); \
+	movabs $0x3f3f3f3f3f3f3f3f, RT3; \
+	movl left##d, RW0d; \
+	roll $1, right##d; \
+	xorl right##d, RW0d; \
+	andl $0xaaaaaaaa, RW0d; \
+	xorl RW0d, left##d; \
+	xorl RW0d, right##d; \
+	roll $1, left##d; \
+	expand_to_64bits(right, RT3); \
+	expand_to_64bits(left, RT3);
+
+#define final_permutation(left, right) \
+	compress_to_64bits(right); \
+	compress_to_64bits(left); \
+	movl right##d, RW0d; \
+	rorl $1, left##d; \
+	xorl left##d, RW0d; \
+	andl $0xaaaaaaaa, RW0d; \
+	xorl RW0d, right##d; \
+	xorl RW0d, left##d; \
+	rorl $1, right##d; \
+	do_permutation(right##d, left##d,  8, 0x00ff00ff); \
+	do_permutation(right##d, left##d,  2, 0x33333333); \
+	do_permutation(left##d, right##d, 16, 0x0000ffff); \
+	do_permutation(left##d, right##d,  4, 0x0f0f0f0f);
+
+#define round1(n, from, to, load_next_key) \
+	xorq from, RW0; \
+	\
+	movzbl RW0bl, RT0d; \
+	movzbl RW0bh, RT1d; \
+	shrq $16, RW0; \
+	movzbl RW0bl, RT2d; \
+	movzbl RW0bh, RT3d; \
+	shrq $16, RW0; \
+	movq s8(SBOXES, RT0, 8), RT0; \
+	xorq s6(SBOXES, RT1, 8), to; \
+	movzbl RW0bl, RL1d; \
+	movzbl RW0bh, RT1d; \
+	shrl $16, RW0d; \
+	xorq s4(SBOXES, RT2, 8), RT0; \
+	xorq s2(SBOXES, RT3, 8), to; \
+	movzbl RW0bl, RT2d; \
+	movzbl RW0bh, RT3d; \
+	xorq s7(SBOXES, RL1, 8), RT0; \
+	xorq s5(SBOXES, RT1, 8), to; \
+	xorq s3(SBOXES, RT2, 8), RT0; \
+	load_next_key(n, RW0); \
+	xorq RT0, to; \
+	xorq s1(SBOXES, RT3, 8), to; \
+
+#define load_next_key(n, RWx) \
+	movq (((n) + 1) * 8)(CTX), RWx;
+
+#define dummy2(a, b) /*_*/
+
+#define read_block(io, left, right) \
+	movl    (io), left##d; \
+	movl   4(io), right##d; \
+	bswapl left##d; \
+	bswapl right##d;
+
+#define write_block(io, left, right) \
+	bswapl left##d; \
+	bswapl right##d; \
+	movl   left##d,   (io); \
+	movl   right##d, 4(io);
+
+.align 8
+.globl _gcry_3des_amd64_crypt_block
+.type  _gcry_3des_amd64_crypt_block, <at> function;
+
+_gcry_3des_amd64_crypt_block:
+	/* input:
+	 *	%rdi: round keys, CTX
+	 *	%rsi: dst
+	 *	%rdx: src
+	 */
+	pushq %rbp;
+	pushq %rbx;
+	pushq %r12;
+	pushq %r13;
+	pushq %r14;
+	pushq %r15;
+	pushq %rsi; /*dst*/
+
+	leaq .L_s1 RIP, SBOXES;
+
+	read_block(%rdx, RL0, RR0);
+	initial_permutation(RL0, RR0);
+
+	movq (CTX), RW0;
+
+	round1(0, RR0, RL0, load_next_key);
+	round1(1, RL0, RR0, load_next_key);
+	round1(2, RR0, RL0, load_next_key);
+	round1(3, RL0, RR0, load_next_key);
+	round1(4, RR0, RL0, load_next_key);
+	round1(5, RL0, RR0, load_next_key);
+	round1(6, RR0, RL0, load_next_key);
+	round1(7, RL0, RR0, load_next_key);
+	round1(8, RR0, RL0, load_next_key);
+	round1(9, RL0, RR0, load_next_key);
+	round1(10, RR0, RL0, load_next_key);
+	round1(11, RL0, RR0, load_next_key);
+	round1(12, RR0, RL0, load_next_key);
+	round1(13, RL0, RR0, load_next_key);
+	round1(14, RR0, RL0, load_next_key);
+	round1(15, RL0, RR0, load_next_key);
+
+	round1(16+0, RL0, RR0, load_next_key);
+	round1(16+1, RR0, RL0, load_next_key);
+	round1(16+2, RL0, RR0, load_next_key);
+	round1(16+3, RR0, RL0, load_next_key);
+	round1(16+4, RL0, RR0, load_next_key);
+	round1(16+5, RR0, RL0, load_next_key);
+	round1(16+6, RL0, RR0, load_next_key);
+	round1(16+7, RR0, RL0, load_next_key);
+	round1(16+8, RL0, RR0, load_next_key);
+	round1(16+9, RR0, RL0, load_next_key);
+	round1(16+10, RL0, RR0, load_next_key);
+	round1(16+11, RR0, RL0, load_next_key);
+	round1(16+12, RL0, RR0, load_next_key);
+	round1(16+13, RR0, RL0, load_next_key);
+	round1(16+14, RL0, RR0, load_next_key);
+	round1(16+15, RR0, RL0, load_next_key);
+
+	round1(32+0, RR0, RL0, load_next_key);
+	round1(32+1, RL0, RR0, load_next_key);
+	round1(32+2, RR0, RL0, load_next_key);
+	round1(32+3, RL0, RR0, load_next_key);
+	round1(32+4, RR0, RL0, load_next_key);
+	round1(32+5, RL0, RR0, load_next_key);
+	round1(32+6, RR0, RL0, load_next_key);
+	round1(32+7, RL0, RR0, load_next_key);
+	round1(32+8, RR0, RL0, load_next_key);
+	round1(32+9, RL0, RR0, load_next_key);
+	round1(32+10, RR0, RL0, load_next_key);
+	round1(32+11, RL0, RR0, load_next_key);
+	round1(32+12, RR0, RL0, load_next_key);
+	round1(32+13, RL0, RR0, load_next_key);
+	round1(32+14, RR0, RL0, load_next_key);
+	round1(32+15, RL0, RR0, dummy2);
+
+	popq RW2; /*dst*/
+	final_permutation(RR0, RL0);
+	write_block(RW2, RR0, RL0);
+
+	popq %r15;
+	popq %r14;
+	popq %r13;
+	popq %r12;
+	popq %rbx;
+	popq %rbp;
+
+	ret;
+.size _gcry_3des_amd64_crypt_block,.-_gcry_3des_amd64_crypt_block;
+
+/***********************************************************************
+ * 3-way 3DES
+ ***********************************************************************/
+#define expand_to_64bits(val, mask) \
+	movl val##d, RT0d; \
+	rorl $4, RT0d; \
+	shlq $32, RT0; \
+	orq RT0, val; \
+	andq mask, val;
+
+#define compress_to_64bits(val) \
+	movq val, RT0; \
+	shrq $32, RT0; \
+	roll $4, RT0d; \
+	orl RT0d, val##d;
+
+#define initial_permutation3(left, right) \
+	do_permutation(left##0d, right##0d,  4, 0x0f0f0f0f); \
+	do_permutation(left##0d, right##0d, 16, 0x0000ffff); \
+	  do_permutation(left##1d, right##1d,  4, 0x0f0f0f0f); \
+	  do_permutation(left##1d, right##1d, 16, 0x0000ffff); \
+	    do_permutation(left##2d, right##2d,  4, 0x0f0f0f0f); \
+	    do_permutation(left##2d, right##2d, 16, 0x0000ffff); \
+	    \
+	do_permutation(right##0d, left##0d,  2, 0x33333333); \
+	do_permutation(right##0d, left##0d,  8, 0x00ff00ff); \
+	  do_permutation(right##1d, left##1d,  2, 0x33333333); \
+	  do_permutation(right##1d, left##1d,  8, 0x00ff00ff); \
+	    do_permutation(right##2d, left##2d,  2, 0x33333333); \
+	    do_permutation(right##2d, left##2d,  8, 0x00ff00ff); \
+	    \
+	movabs $0x3f3f3f3f3f3f3f3f, RT3; \
+	    \
+	movl left##0d, RW0d; \
+	roll $1, right##0d; \
+	xorl right##0d, RW0d; \
+	andl $0xaaaaaaaa, RW0d; \
+	xorl RW0d, left##0d; \
+	xorl RW0d, right##0d; \
+	roll $1, left##0d; \
+	expand_to_64bits(right##0, RT3); \
+	expand_to_64bits(left##0, RT3); \
+	  movl left##1d, RW1d; \
+	  roll $1, right##1d; \
+	  xorl right##1d, RW1d; \
+	  andl $0xaaaaaaaa, RW1d; \
+	  xorl RW1d, left##1d; \
+	  xorl RW1d, right##1d; \
+	  roll $1, left##1d; \
+	  expand_to_64bits(right##1, RT3); \
+	  expand_to_64bits(left##1, RT3); \
+	    movl left##2d, RW2d; \
+	    roll $1, right##2d; \
+	    xorl right##2d, RW2d; \
+	    andl $0xaaaaaaaa, RW2d; \
+	    xorl RW2d, left##2d; \
+	    xorl RW2d, right##2d; \
+	    roll $1, left##2d; \
+	    expand_to_64bits(right##2, RT3); \
+	    expand_to_64bits(left##2, RT3);
+
+#define final_permutation3(left, right) \
+	compress_to_64bits(right##0); \
+	compress_to_64bits(left##0); \
+	movl right##0d, RW0d; \
+	rorl $1, left##0d; \
+	xorl left##0d, RW0d; \
+	andl $0xaaaaaaaa, RW0d; \
+	xorl RW0d, right##0d; \
+	xorl RW0d, left##0d; \
+	rorl $1, right##0d; \
+	  compress_to_64bits(right##1); \
+	  compress_to_64bits(left##1); \
+	  movl right##1d, RW1d; \
+	  rorl $1, left##1d; \
+	  xorl left##1d, RW1d; \
+	  andl $0xaaaaaaaa, RW1d; \
+	  xorl RW1d, right##1d; \
+	  xorl RW1d, left##1d; \
+	  rorl $1, right##1d; \
+	    compress_to_64bits(right##2); \
+	    compress_to_64bits(left##2); \
+	    movl right##2d, RW2d; \
+	    rorl $1, left##2d; \
+	    xorl left##2d, RW2d; \
+	    andl $0xaaaaaaaa, RW2d; \
+	    xorl RW2d, right##2d; \
+	    xorl RW2d, left##2d; \
+	    rorl $1, right##2d; \
+	    \
+	do_permutation(right##0d, left##0d,  8, 0x00ff00ff); \
+	do_permutation(right##0d, left##0d,  2, 0x33333333); \
+	  do_permutation(right##1d, left##1d,  8, 0x00ff00ff); \
+	  do_permutation(right##1d, left##1d,  2, 0x33333333); \
+	    do_permutation(right##2d, left##2d,  8, 0x00ff00ff); \
+	    do_permutation(right##2d, left##2d,  2, 0x33333333); \
+	    \
+	do_permutation(left##0d, right##0d, 16, 0x0000ffff); \
+	do_permutation(left##0d, right##0d,  4, 0x0f0f0f0f); \
+	  do_permutation(left##1d, right##1d, 16, 0x0000ffff); \
+	  do_permutation(left##1d, right##1d,  4, 0x0f0f0f0f); \
+	    do_permutation(left##2d, right##2d, 16, 0x0000ffff); \
+	    do_permutation(left##2d, right##2d,  4, 0x0f0f0f0f);
+
+#define round3(n, from, to, load_next_key, do_movq) \
+	xorq from##0, RW0; \
+	movzbl RW0bl, RT3d; \
+	movzbl RW0bh, RT1d; \
+	shrq $16, RW0; \
+	xorq s8(SBOXES, RT3, 8), to##0; \
+	xorq s6(SBOXES, RT1, 8), to##0; \
+	movzbl RW0bl, RT3d; \
+	movzbl RW0bh, RT1d; \
+	shrq $16, RW0; \
+	xorq s4(SBOXES, RT3, 8), to##0; \
+	xorq s2(SBOXES, RT1, 8), to##0; \
+	movzbl RW0bl, RT3d; \
+	movzbl RW0bh, RT1d; \
+	shrl $16, RW0d; \
+	xorq s7(SBOXES, RT3, 8), to##0; \
+	xorq s5(SBOXES, RT1, 8), to##0; \
+	movzbl RW0bl, RT3d; \
+	movzbl RW0bh, RT1d; \
+	load_next_key(n, RW0); \
+	xorq s3(SBOXES, RT3, 8), to##0; \
+	xorq s1(SBOXES, RT1, 8), to##0; \
+		xorq from##1, RW1; \
+		movzbl RW1bl, RT3d; \
+		movzbl RW1bh, RT1d; \
+		shrq $16, RW1; \
+		xorq s8(SBOXES, RT3, 8), to##1; \
+		xorq s6(SBOXES, RT1, 8), to##1; \
+		movzbl RW1bl, RT3d; \
+		movzbl RW1bh, RT1d; \
+		shrq $16, RW1; \
+		xorq s4(SBOXES, RT3, 8), to##1; \
+		xorq s2(SBOXES, RT1, 8), to##1; \
+		movzbl RW1bl, RT3d; \
+		movzbl RW1bh, RT1d; \
+		shrl $16, RW1d; \
+		xorq s7(SBOXES, RT3, 8), to##1; \
+		xorq s5(SBOXES, RT1, 8), to##1; \
+		movzbl RW1bl, RT3d; \
+		movzbl RW1bh, RT1d; \
+		do_movq(RW0, RW1); \
+		xorq s3(SBOXES, RT3, 8), to##1; \
+		xorq s1(SBOXES, RT1, 8), to##1; \
+			xorq from##2, RW2; \
+			movzbl RW2bl, RT3d; \
+			movzbl RW2bh, RT1d; \
+			shrq $16, RW2; \
+			xorq s8(SBOXES, RT3, 8), to##2; \
+			xorq s6(SBOXES, RT1, 8), to##2; \
+			movzbl RW2bl, RT3d; \
+			movzbl RW2bh, RT1d; \
+			shrq $16, RW2; \
+			xorq s4(SBOXES, RT3, 8), to##2; \
+			xorq s2(SBOXES, RT1, 8), to##2; \
+			movzbl RW2bl, RT3d; \
+			movzbl RW2bh, RT1d; \
+			shrl $16, RW2d; \
+			xorq s7(SBOXES, RT3, 8), to##2; \
+			xorq s5(SBOXES, RT1, 8), to##2; \
+			movzbl RW2bl, RT3d; \
+			movzbl RW2bh, RT1d; \
+			do_movq(RW0, RW2); \
+			xorq s3(SBOXES, RT3, 8), to##2; \
+			xorq s1(SBOXES, RT1, 8), to##2;
+
+#define __movq(src, dst) \
+	movq src, dst;
+
+#define read_block(io, left, right) \
+	movl    (io), left##d; \
+	movl   4(io), right##d; \
+	bswapl left##d; \
+	bswapl right##d;
+
+#define write_block(io, left, right) \
+	bswapl left##d; \
+	bswapl right##d; \
+	movl   left##d,   (io); \
+	movl   right##d, 4(io);
+
+.align 8
+.type  _gcry_3des_amd64_crypt_blk3, <at> function;
+_gcry_3des_amd64_crypt_blk3:
+	/* input:
+	 *  %rdi: round keys, CTX
+	 *  RL0d, RR0d, RL1d, RR1d, RL2d, RR2d: 3 input blocks
+	 *  RR0d, RL0d, RR1d, RL1d, RR2d, RL2d: 3 output blocks
+	 */
+
+	leaq .L_s1 RIP, SBOXES;
+
+	initial_permutation3(RL, RR);
+
+	movq 0(CTX), RW0;
+	movq RW0, RW1;
+	movq RW0, RW2;
+
+	round3(0, RR, RL, load_next_key, __movq);
+	round3(1, RL, RR, load_next_key, __movq);
+	round3(2, RR, RL, load_next_key, __movq);
+	round3(3, RL, RR, load_next_key, __movq);
+	round3(4, RR, RL, load_next_key, __movq);
+	round3(5, RL, RR, load_next_key, __movq);
+	round3(6, RR, RL, load_next_key, __movq);
+	round3(7, RL, RR, load_next_key, __movq);
+	round3(8, RR, RL, load_next_key, __movq);
+	round3(9, RL, RR, load_next_key, __movq);
+	round3(10, RR, RL, load_next_key, __movq);
+	round3(11, RL, RR, load_next_key, __movq);
+	round3(12, RR, RL, load_next_key, __movq);
+	round3(13, RL, RR, load_next_key, __movq);
+	round3(14, RR, RL, load_next_key, __movq);
+	round3(15, RL, RR, load_next_key, __movq);
+
+	round3(16+0, RL, RR, load_next_key, __movq);
+	round3(16+1, RR, RL, load_next_key, __movq);
+	round3(16+2, RL, RR, load_next_key, __movq);
+	round3(16+3, RR, RL, load_next_key, __movq);
+	round3(16+4, RL, RR, load_next_key, __movq);
+	round3(16+5, RR, RL, load_next_key, __movq);
+	round3(16+6, RL, RR, load_next_key, __movq);
+	round3(16+7, RR, RL, load_next_key, __movq);
+	round3(16+8, RL, RR, load_next_key, __movq);
+	round3(16+9, RR, RL, load_next_key, __movq);
+	round3(16+10, RL, RR, load_next_key, __movq);
+	round3(16+11, RR, RL, load_next_key, __movq);
+	round3(16+12, RL, RR, load_next_key, __movq);
+	round3(16+13, RR, RL, load_next_key, __movq);
+	round3(16+14, RL, RR, load_next_key, __movq);
+	round3(16+15, RR, RL, load_next_key, __movq);
+
+	round3(32+0, RR, RL, load_next_key, __movq);
+	round3(32+1, RL, RR, load_next_key, __movq);
+	round3(32+2, RR, RL, load_next_key, __movq);
+	round3(32+3, RL, RR, load_next_key, __movq);
+	round3(32+4, RR, RL, load_next_key, __movq);
+	round3(32+5, RL, RR, load_next_key, __movq);
+	round3(32+6, RR, RL, load_next_key, __movq);
+	round3(32+7, RL, RR, load_next_key, __movq);
+	round3(32+8, RR, RL, load_next_key, __movq);
+	round3(32+9, RL, RR, load_next_key, __movq);
+	round3(32+10, RR, RL, load_next_key, __movq);
+	round3(32+11, RL, RR, load_next_key, __movq);
+	round3(32+12, RR, RL, load_next_key, __movq);
+	round3(32+13, RL, RR, load_next_key, __movq);
+	round3(32+14, RR, RL, load_next_key, __movq);
+	round3(32+15, RL, RR, dummy2, dummy2);
+
+	final_permutation3(RR, RL);
+
+	ret;
+.size _gcry_3des_amd64_crypt_blk3,.-_gcry_3des_amd64_crypt_blk3;
+
+.align 8
+.globl  _gcry_3des_amd64_cbc_dec
+.type   _gcry_3des_amd64_cbc_dec, <at> function;
+_gcry_3des_amd64_cbc_dec:
+	/* input:
+	 *	%rdi: ctx, CTX
+	 *	%rsi: dst (3 blocks)
+	 *	%rdx: src (3 blocks)
+	 *	%rcx: iv (64bit)
+	 */
+
+	pushq %rbp;
+	pushq %rbx;
+	pushq %r12;
+	pushq %r13;
+	pushq %r14;
+	pushq %r15;
+
+	pushq %rsi; /*dst*/
+	pushq %rdx; /*src*/
+	pushq %rcx; /*iv*/
+
+	/* load input */
+	movl 0 * 4(%rdx), RL0d;
+	movl 1 * 4(%rdx), RR0d;
+	movl 2 * 4(%rdx), RL1d;
+	movl 3 * 4(%rdx), RR1d;
+	movl 4 * 4(%rdx), RL2d;
+	movl 5 * 4(%rdx), RR2d;
+
+	bswapl RL0d;
+	bswapl RR0d;
+	bswapl RL1d;
+	bswapl RR1d;
+	bswapl RL2d;
+	bswapl RR2d;
+
+	call _gcry_3des_amd64_crypt_blk3;
+
+	popq %rcx; /*iv*/
+	popq %rdx; /*src*/
+	popq %rsi; /*dst*/
+
+	bswapl RR0d;
+	bswapl RL0d;
+	bswapl RR1d;
+	bswapl RL1d;
+	bswapl RR2d;
+	bswapl RL2d;
+
+	movq 2 * 8(%rdx), RT0;
+	xorl 0 * 4(%rcx), RR0d;
+	xorl 1 * 4(%rcx), RL0d;
+	xorl 0 * 4(%rdx), RR1d;
+	xorl 1 * 4(%rdx), RL1d;
+	xorl 2 * 4(%rdx), RR2d;
+	xorl 3 * 4(%rdx), RL2d;
+	movq RT0, (%rcx); /* store new IV */
+
+	movl RR0d, 0 * 4(%rsi);
+	movl RL0d, 1 * 4(%rsi);
+	movl RR1d, 2 * 4(%rsi);
+	movl RL1d, 3 * 4(%rsi);
+	movl RR2d, 4 * 4(%rsi);
+	movl RL2d, 5 * 4(%rsi);
+
+	popq %r15;
+	popq %r14;
+	popq %r13;
+	popq %r12;
+	popq %rbx;
+	popq %rbp;
+
+	ret;
+.size _gcry_3des_amd64_cbc_dec,.-_gcry_3des_amd64_cbc_dec;
+
+.align 8
+.globl  _gcry_3des_amd64_ctr_enc
+.type   _gcry_3des_amd64_ctr_enc, <at> function;
+_gcry_3des_amd64_ctr_enc:
+	/* input:
+	 *	%rdi: ctx, CTX
+	 *	%rsi: dst (3 blocks)
+	 *	%rdx: src (3 blocks)
+	 *	%rcx: iv (64bit)
+	 */
+
+	pushq %rbp;
+	pushq %rbx;
+	pushq %r12;
+	pushq %r13;
+	pushq %r14;
+	pushq %r15;
+
+	pushq %rsi; /*dst*/
+	pushq %rdx; /*src*/
+	movq %rcx, RW2;
+
+	/* load IV and byteswap */
+	movq (RW2), RT0;
+	bswapq RT0;
+	movq RT0, RR0;
+
+	/* construct IVs */
+	leaq 1(RT0), RR1;
+	leaq 2(RT0), RR2;
+	leaq 3(RT0), RT0;
+	movq RR0, RL0;
+	movq RR1, RL1;
+	movq RR2, RL2;
+	bswapq RT0;
+	shrq $32, RL0;
+	shrq $32, RL1;
+	shrq $32, RL2;
+
+	/* store new IV */
+	movq RT0, (RW2);
+
+	call _gcry_3des_amd64_crypt_blk3;
+
+	popq %rdx; /*src*/
+	popq %rsi; /*dst*/
+
+	bswapl RR0d;
+	bswapl RL0d;
+	bswapl RR1d;
+	bswapl RL1d;
+	bswapl RR2d;
+	bswapl RL2d;
+
+	xorl 0 * 4(%rdx), RR0d;
+	xorl 1 * 4(%rdx), RL0d;
+	xorl 2 * 4(%rdx), RR1d;
+	xorl 3 * 4(%rdx), RL1d;
+	xorl 4 * 4(%rdx), RR2d;
+	xorl 5 * 4(%rdx), RL2d;
+
+	movl RR0d, 0 * 4(%rsi);
+	movl RL0d, 1 * 4(%rsi);
+	movl RR1d, 2 * 4(%rsi);
+	movl RL1d, 3 * 4(%rsi);
+	movl RR2d, 4 * 4(%rsi);
+	movl RL2d, 5 * 4(%rsi);
+
+	popq %r15;
+	popq %r14;
+	popq %r13;
+	popq %r12;
+	popq %rbx;
+	popq %rbp;
+
+	ret;
+.size _gcry_3des_amd64_cbc_dec,.-_gcry_3des_amd64_cbc_dec;
+
+.align 8
+.globl  _gcry_3des_amd64_cfb_dec
+.type   _gcry_3des_amd64_cfb_dec, <at> function;
+_gcry_3des_amd64_cfb_dec:
+	/* input:
+	 *	%rdi: ctx, CTX
+	 *	%rsi: dst (3 blocks)
+	 *	%rdx: src (3 blocks)
+	 *	%rcx: iv (64bit)
+	 */
+	pushq %rbp;
+	pushq %rbx;
+	pushq %r12;
+	pushq %r13;
+	pushq %r14;
+	pushq %r15;
+
+	pushq %rsi; /*dst*/
+	pushq %rdx; /*src*/
+	movq %rcx, RW2;
+
+	/* Load input */
+	movl 0 * 4(RW2), RL0d;
+	movl 1 * 4(RW2), RR0d;
+	movl 0 * 4(%rdx), RL1d;
+	movl 1 * 4(%rdx), RR1d;
+	movl 2 * 4(%rdx), RL2d;
+	movl 3 * 4(%rdx), RR2d;
+
+	bswapl RL0d;
+	bswapl RR0d;
+	bswapl RL1d;
+	bswapl RR1d;
+	bswapl RL2d;
+	bswapl RR2d;
+
+	/* Update IV */
+	movq 4 * 4(%rdx), RW0;
+	movq RW0, (RW2);
+
+	call _gcry_3des_amd64_crypt_blk3;
+
+	popq %rdx; /*src*/
+	popq %rsi; /*dst*/
+
+	bswapl RR0d;
+	bswapl RL0d;
+	bswapl RR1d;
+	bswapl RL1d;
+	bswapl RR2d;
+	bswapl RL2d;
+
+	xorl 0 * 4(%rdx), RR0d;
+	xorl 1 * 4(%rdx), RL0d;
+	xorl 2 * 4(%rdx), RR1d;
+	xorl 3 * 4(%rdx), RL1d;
+	xorl 4 * 4(%rdx), RR2d;
+	xorl 5 * 4(%rdx), RL2d;
+
+	movl RR0d, 0 * 4(%rsi);
+	movl RL0d, 1 * 4(%rsi);
+	movl RR1d, 2 * 4(%rsi);
+	movl RL1d, 3 * 4(%rsi);
+	movl RR2d, 4 * 4(%rsi);
+	movl RL2d, 5 * 4(%rsi);
+
+	popq %r15;
+	popq %r14;
+	popq %r13;
+	popq %r12;
+	popq %rbx;
+	popq %rbp;
+	ret;
+.size _gcry_3des_amd64_cfb_dec,.-_gcry_3des_amd64_cfb_dec;
+
+.data
+.align 16
+.L_s1:
+	.quad 0x0010100001010400, 0x0000000000000000
+	.quad 0x0000100000010000, 0x0010100001010404
+	.quad 0x0010100001010004, 0x0000100000010404
+	.quad 0x0000000000000004, 0x0000100000010000
+	.quad 0x0000000000000400, 0x0010100001010400
+	.quad 0x0010100001010404, 0x0000000000000400
+	.quad 0x0010000001000404, 0x0010100001010004
+	.quad 0x0010000001000000, 0x0000000000000004
+	.quad 0x0000000000000404, 0x0010000001000400
+	.quad 0x0010000001000400, 0x0000100000010400
+	.quad 0x0000100000010400, 0x0010100001010000
+	.quad 0x0010100001010000, 0x0010000001000404
+	.quad 0x0000100000010004, 0x0010000001000004
+	.quad 0x0010000001000004, 0x0000100000010004
+	.quad 0x0000000000000000, 0x0000000000000404
+	.quad 0x0000100000010404, 0x0010000001000000
+	.quad 0x0000100000010000, 0x0010100001010404
+	.quad 0x0000000000000004, 0x0010100001010000
+	.quad 0x0010100001010400, 0x0010000001000000
+	.quad 0x0010000001000000, 0x0000000000000400
+	.quad 0x0010100001010004, 0x0000100000010000
+	.quad 0x0000100000010400, 0x0010000001000004
+	.quad 0x0000000000000400, 0x0000000000000004
+	.quad 0x0010000001000404, 0x0000100000010404
+	.quad 0x0010100001010404, 0x0000100000010004
+	.quad 0x0010100001010000, 0x0010000001000404
+	.quad 0x0010000001000004, 0x0000000000000404
+	.quad 0x0000100000010404, 0x0010100001010400
+	.quad 0x0000000000000404, 0x0010000001000400
+	.quad 0x0010000001000400, 0x0000000000000000
+	.quad 0x0000100000010004, 0x0000100000010400
+	.quad 0x0000000000000000, 0x0010100001010004
+.L_s2:
+	.quad 0x0801080200100020, 0x0800080000000000
+	.quad 0x0000080000000000, 0x0001080200100020
+	.quad 0x0001000000100000, 0x0000000200000020
+	.quad 0x0801000200100020, 0x0800080200000020
+	.quad 0x0800000200000020, 0x0801080200100020
+	.quad 0x0801080000100000, 0x0800000000000000
+	.quad 0x0800080000000000, 0x0001000000100000
+	.quad 0x0000000200000020, 0x0801000200100020
+	.quad 0x0001080000100000, 0x0001000200100020
+	.quad 0x0800080200000020, 0x0000000000000000
+	.quad 0x0800000000000000, 0x0000080000000000
+	.quad 0x0001080200100020, 0x0801000000100000
+	.quad 0x0001000200100020, 0x0800000200000020
+	.quad 0x0000000000000000, 0x0001080000100000
+	.quad 0x0000080200000020, 0x0801080000100000
+	.quad 0x0801000000100000, 0x0000080200000020
+	.quad 0x0000000000000000, 0x0001080200100020
+	.quad 0x0801000200100020, 0x0001000000100000
+	.quad 0x0800080200000020, 0x0801000000100000
+	.quad 0x0801080000100000, 0x0000080000000000
+	.quad 0x0801000000100000, 0x0800080000000000
+	.quad 0x0000000200000020, 0x0801080200100020
+	.quad 0x0001080200100020, 0x0000000200000020
+	.quad 0x0000080000000000, 0x0800000000000000
+	.quad 0x0000080200000020, 0x0801080000100000
+	.quad 0x0001000000100000, 0x0800000200000020
+	.quad 0x0001000200100020, 0x0800080200000020
+	.quad 0x0800000200000020, 0x0001000200100020
+	.quad 0x0001080000100000, 0x0000000000000000
+	.quad 0x0800080000000000, 0x0000080200000020
+	.quad 0x0800000000000000, 0x0801000200100020
+	.quad 0x0801080200100020, 0x0001080000100000
+.L_s3:
+	.quad 0x0000002000000208, 0x0000202008020200
+	.quad 0x0000000000000000, 0x0000200008020008
+	.quad 0x0000002008000200, 0x0000000000000000
+	.quad 0x0000202000020208, 0x0000002008000200
+	.quad 0x0000200000020008, 0x0000000008000008
+	.quad 0x0000000008000008, 0x0000200000020000
+	.quad 0x0000202008020208, 0x0000200000020008
+	.quad 0x0000200008020000, 0x0000002000000208
+	.quad 0x0000000008000000, 0x0000000000000008
+	.quad 0x0000202008020200, 0x0000002000000200
+	.quad 0x0000202000020200, 0x0000200008020000
+	.quad 0x0000200008020008, 0x0000202000020208
+	.quad 0x0000002008000208, 0x0000202000020200
+	.quad 0x0000200000020000, 0x0000002008000208
+	.quad 0x0000000000000008, 0x0000202008020208
+	.quad 0x0000002000000200, 0x0000000008000000
+	.quad 0x0000202008020200, 0x0000000008000000
+	.quad 0x0000200000020008, 0x0000002000000208
+	.quad 0x0000200000020000, 0x0000202008020200
+	.quad 0x0000002008000200, 0x0000000000000000
+	.quad 0x0000002000000200, 0x0000200000020008
+	.quad 0x0000202008020208, 0x0000002008000200
+	.quad 0x0000000008000008, 0x0000002000000200
+	.quad 0x0000000000000000, 0x0000200008020008
+	.quad 0x0000002008000208, 0x0000200000020000
+	.quad 0x0000000008000000, 0x0000202008020208
+	.quad 0x0000000000000008, 0x0000202000020208
+	.quad 0x0000202000020200, 0x0000000008000008
+	.quad 0x0000200008020000, 0x0000002008000208
+	.quad 0x0000002000000208, 0x0000200008020000
+	.quad 0x0000202000020208, 0x0000000000000008
+	.quad 0x0000200008020008, 0x0000202000020200
+.L_s4:
+	.quad 0x1008020000002001, 0x1000020800002001
+	.quad 0x1000020800002001, 0x0000000800000000
+	.quad 0x0008020800002000, 0x1008000800000001
+	.quad 0x1008000000000001, 0x1000020000002001
+	.quad 0x0000000000000000, 0x0008020000002000
+	.quad 0x0008020000002000, 0x1008020800002001
+	.quad 0x1000000800000001, 0x0000000000000000
+	.quad 0x0008000800000000, 0x1008000000000001
+	.quad 0x1000000000000001, 0x0000020000002000
+	.quad 0x0008000000000000, 0x1008020000002001
+	.quad 0x0000000800000000, 0x0008000000000000
+	.quad 0x1000020000002001, 0x0000020800002000
+	.quad 0x1008000800000001, 0x1000000000000001
+	.quad 0x0000020800002000, 0x0008000800000000
+	.quad 0x0000020000002000, 0x0008020800002000
+	.quad 0x1008020800002001, 0x1000000800000001
+	.quad 0x0008000800000000, 0x1008000000000001
+	.quad 0x0008020000002000, 0x1008020800002001
+	.quad 0x1000000800000001, 0x0000000000000000
+	.quad 0x0000000000000000, 0x0008020000002000
+	.quad 0x0000020800002000, 0x0008000800000000
+	.quad 0x1008000800000001, 0x1000000000000001
+	.quad 0x1008020000002001, 0x1000020800002001
+	.quad 0x1000020800002001, 0x0000000800000000
+	.quad 0x1008020800002001, 0x1000000800000001
+	.quad 0x1000000000000001, 0x0000020000002000
+	.quad 0x1008000000000001, 0x1000020000002001
+	.quad 0x0008020800002000, 0x1008000800000001
+	.quad 0x1000020000002001, 0x0000020800002000
+	.quad 0x0008000000000000, 0x1008020000002001
+	.quad 0x0000000800000000, 0x0008000000000000
+	.quad 0x0000020000002000, 0x0008020800002000
+.L_s5:
+	.quad 0x0000001000000100, 0x0020001002080100
+	.quad 0x0020000002080000, 0x0420001002000100
+	.quad 0x0000000000080000, 0x0000001000000100
+	.quad 0x0400000000000000, 0x0020000002080000
+	.quad 0x0400001000080100, 0x0000000000080000
+	.quad 0x0020001002000100, 0x0400001000080100
+	.quad 0x0420001002000100, 0x0420000002080000
+	.quad 0x0000001000080100, 0x0400000000000000
+	.quad 0x0020000002000000, 0x0400000000080000
+	.quad 0x0400000000080000, 0x0000000000000000
+	.quad 0x0400001000000100, 0x0420001002080100
+	.quad 0x0420001002080100, 0x0020001002000100
+	.quad 0x0420000002080000, 0x0400001000000100
+	.quad 0x0000000000000000, 0x0420000002000000
+	.quad 0x0020001002080100, 0x0020000002000000
+	.quad 0x0420000002000000, 0x0000001000080100
+	.quad 0x0000000000080000, 0x0420001002000100
+	.quad 0x0000001000000100, 0x0020000002000000
+	.quad 0x0400000000000000, 0x0020000002080000
+	.quad 0x0420001002000100, 0x0400001000080100
+	.quad 0x0020001002000100, 0x0400000000000000
+	.quad 0x0420000002080000, 0x0020001002080100
+	.quad 0x0400001000080100, 0x0000001000000100
+	.quad 0x0020000002000000, 0x0420000002080000
+	.quad 0x0420001002080100, 0x0000001000080100
+	.quad 0x0420000002000000, 0x0420001002080100
+	.quad 0x0020000002080000, 0x0000000000000000
+	.quad 0x0400000000080000, 0x0420000002000000
+	.quad 0x0000001000080100, 0x0020001002000100
+	.quad 0x0400001000000100, 0x0000000000080000
+	.quad 0x0000000000000000, 0x0400000000080000
+	.quad 0x0020001002080100, 0x0400001000000100
+.L_s6:
+	.quad 0x0200000120000010, 0x0204000020000000
+	.quad 0x0000040000000000, 0x0204040120000010
+	.quad 0x0204000020000000, 0x0000000100000010
+	.quad 0x0204040120000010, 0x0004000000000000
+	.quad 0x0200040020000000, 0x0004040100000010
+	.quad 0x0004000000000000, 0x0200000120000010
+	.quad 0x0004000100000010, 0x0200040020000000
+	.quad 0x0200000020000000, 0x0000040100000010
+	.quad 0x0000000000000000, 0x0004000100000010
+	.quad 0x0200040120000010, 0x0000040000000000
+	.quad 0x0004040000000000, 0x0200040120000010
+	.quad 0x0000000100000010, 0x0204000120000010
+	.quad 0x0204000120000010, 0x0000000000000000
+	.quad 0x0004040100000010, 0x0204040020000000
+	.quad 0x0000040100000010, 0x0004040000000000
+	.quad 0x0204040020000000, 0x0200000020000000
+	.quad 0x0200040020000000, 0x0000000100000010
+	.quad 0x0204000120000010, 0x0004040000000000
+	.quad 0x0204040120000010, 0x0004000000000000
+	.quad 0x0000040100000010, 0x0200000120000010
+	.quad 0x0004000000000000, 0x0200040020000000
+	.quad 0x0200000020000000, 0x0000040100000010
+	.quad 0x0200000120000010, 0x0204040120000010
+	.quad 0x0004040000000000, 0x0204000020000000
+	.quad 0x0004040100000010, 0x0204040020000000
+	.quad 0x0000000000000000, 0x0204000120000010
+	.quad 0x0000000100000010, 0x0000040000000000
+	.quad 0x0204000020000000, 0x0004040100000010
+	.quad 0x0000040000000000, 0x0004000100000010
+	.quad 0x0200040120000010, 0x0000000000000000
+	.quad 0x0204040020000000, 0x0200000020000000
+	.quad 0x0004000100000010, 0x0200040120000010
+.L_s7:
+	.quad 0x0002000000200000, 0x2002000004200002
+	.quad 0x2000000004000802, 0x0000000000000000
+	.quad 0x0000000000000800, 0x2000000004000802
+	.quad 0x2002000000200802, 0x0002000004200800
+	.quad 0x2002000004200802, 0x0002000000200000
+	.quad 0x0000000000000000, 0x2000000004000002
+	.quad 0x2000000000000002, 0x0000000004000000
+	.quad 0x2002000004200002, 0x2000000000000802
+	.quad 0x0000000004000800, 0x2002000000200802
+	.quad 0x2002000000200002, 0x0000000004000800
+	.quad 0x2000000004000002, 0x0002000004200000
+	.quad 0x0002000004200800, 0x2002000000200002
+	.quad 0x0002000004200000, 0x0000000000000800
+	.quad 0x2000000000000802, 0x2002000004200802
+	.quad 0x0002000000200800, 0x2000000000000002
+	.quad 0x0000000004000000, 0x0002000000200800
+	.quad 0x0000000004000000, 0x0002000000200800
+	.quad 0x0002000000200000, 0x2000000004000802
+	.quad 0x2000000004000802, 0x2002000004200002
+	.quad 0x2002000004200002, 0x2000000000000002
+	.quad 0x2002000000200002, 0x0000000004000000
+	.quad 0x0000000004000800, 0x0002000000200000
+	.quad 0x0002000004200800, 0x2000000000000802
+	.quad 0x2002000000200802, 0x0002000004200800
+	.quad 0x2000000000000802, 0x2000000004000002
+	.quad 0x2002000004200802, 0x0002000004200000
+	.quad 0x0002000000200800, 0x0000000000000000
+	.quad 0x2000000000000002, 0x2002000004200802
+	.quad 0x0000000000000000, 0x2002000000200802
+	.quad 0x0002000004200000, 0x0000000000000800
+	.quad 0x2000000004000002, 0x0000000004000800
+	.quad 0x0000000000000800, 0x2002000000200002
+.L_s8:
+	.quad 0x0100010410001000, 0x0000010000001000
+	.quad 0x0000000000040000, 0x0100010410041000
+	.quad 0x0100000010000000, 0x0100010410001000
+	.quad 0x0000000400000000, 0x0100000010000000
+	.quad 0x0000000400040000, 0x0100000010040000
+	.quad 0x0100010410041000, 0x0000010000041000
+	.quad 0x0100010010041000, 0x0000010400041000
+	.quad 0x0000010000001000, 0x0000000400000000
+	.quad 0x0100000010040000, 0x0100000410000000
+	.quad 0x0100010010001000, 0x0000010400001000
+	.quad 0x0000010000041000, 0x0000000400040000
+	.quad 0x0100000410040000, 0x0100010010041000
+	.quad 0x0000010400001000, 0x0000000000000000
+	.quad 0x0000000000000000, 0x0100000410040000
+	.quad 0x0100000410000000, 0x0100010010001000
+	.quad 0x0000010400041000, 0x0000000000040000
+	.quad 0x0000010400041000, 0x0000000000040000
+	.quad 0x0100010010041000, 0x0000010000001000
+	.quad 0x0000000400000000, 0x0100000410040000
+	.quad 0x0000010000001000, 0x0000010400041000
+	.quad 0x0100010010001000, 0x0000000400000000
+	.quad 0x0100000410000000, 0x0100000010040000
+	.quad 0x0100000410040000, 0x0100000010000000
+	.quad 0x0000000000040000, 0x0100010410001000
+	.quad 0x0000000000000000, 0x0100010410041000
+	.quad 0x0000000400040000, 0x0100000410000000
+	.quad 0x0100000010040000, 0x0100010010001000
+	.quad 0x0100010410001000, 0x0000000000000000
+	.quad 0x0100010410041000, 0x0000010000041000
+	.quad 0x0000010000041000, 0x0000010400001000
+	.quad 0x0000010400001000, 0x0000000400040000
+	.quad 0x0100000010000000, 0x0100010010041000
+
+#endif
+#endif
diff --git a/cipher/des.c b/cipher/des.c
index 6611fd3..bc2a474 100644
--- a/cipher/des.c
+++ b/cipher/des.c
 <at>  <at>  -119,9 +119,27  <at>  <at> 
 #include "g10lib.h"
 #include "cipher.h"
 #include "bufhelp.h"
+#include "cipher-selftest.h"
+
+
+#define DES_BLOCKSIZE 8
+
+
+/* USE_AMD64_ASM indicates whether to use AMD64 assembly code. */
+#undef USE_AMD64_ASM
+#if defined(__x86_64__) && defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS)
+# define USE_AMD64_ASM 1
+#endif
+
+/* Helper macro to force alignment to 16 bytes.  */
+#ifdef HAVE_GCC_ATTRIBUTE_ALIGNED
+# define ATTR_ALIGNED_16  __attribute__ ((aligned (16)))
+#else
+# define ATTR_ALIGNED_16
+#endif
 
 #if defined(__GNUC__) && defined(__GNU_LIBRARY__)
-#define working_memcmp memcmp
+# define working_memcmp memcmp
 #else
 /*
  * According to the SunOS man page, memcmp returns indeterminate sign
 <at>  <at>  -171,6 +189,12  <at>  <at>  static int tripledes_ecb_crypt (struct _tripledes_ctx *,
                                 const byte *, byte *, int);
 static int is_weak_key ( const byte *key );
 static const char *selftest (void);
+static unsigned int do_tripledes_encrypt(void *context, byte *outbuf,
+					 const byte *inbuf );
+static unsigned int do_tripledes_decrypt(void *context, byte *outbuf,
+					 const byte *inbuf );
+static gcry_err_code_t do_tripledes_setkey(void *context, const byte *key,
+                                           unsigned keylen);
 
 static int initialized;
 
 <at>  <at>  -727,6 +751,46  <at>  <at>  tripledes_set3keys (struct _tripledes_ctx *ctx,
 
 
 
+#ifdef USE_AMD64_ASM
+
+/* Assembly implementation of triple-DES. */
+extern void _gcry_3des_amd64_crypt_block(const void *keys, byte *out,
+                                         const byte *in);
+
+/* These assembly implementations process three blocks in parallel. */
+extern void _gcry_3des_amd64_ctr_enc(const void *keys, byte *out,
+                                     const byte *in, byte *ctr);
+
+extern void _gcry_3des_amd64_cbc_dec(const void *keys, byte *out,
+                                     const byte *in, byte *iv);
+
+extern void _gcry_3des_amd64_cfb_dec(const void *keys, byte *out,
+                                     const byte *in, byte *iv);
+
+#define TRIPLEDES_ECB_BURN_STACK (8 * sizeof(void *))
+
+/*
+ * Electronic Codebook Mode Triple-DES encryption/decryption of data
+ * according to 'mode'.  Sometimes this mode is named 'EDE' mode
+ * (Encryption-Decryption-Encryption).
+ */
+static inline int
+tripledes_ecb_crypt (struct _tripledes_ctx *ctx, const byte * from,
+                     byte * to, int mode)
+{
+  u32 *keys;
+
+  keys = mode ? ctx->decrypt_subkeys : ctx->encrypt_subkeys;
+
+  _gcry_3des_amd64_crypt_block(keys, to, from);
+
+  return 0;
+}
+
+#else /*USE_AMD64_ASM*/
+
+#define TRIPLEDES_ECB_BURN_STACK 32
+
 /*
  * Electronic Codebook Mode Triple-DES encryption/decryption of data
  * according to 'mode'.  Sometimes this mode is named 'EDE' mode
 <at>  <at>  -777,8 +841,158  <at>  <at>  tripledes_ecb_crypt (struct _tripledes_ctx *ctx, const byte * from,
   return 0;
 }
 
+#endif /*!USE_AMD64_ASM*/
+
+
+
+/* Bulk encryption of complete blocks in CTR mode.  This function is only
+   intended for the bulk encryption feature of cipher.c.  CTR is expected to be
+   of size DES_BLOCKSIZE. */
+void
+_gcry_3des_ctr_enc(void *context, unsigned char *ctr, void *outbuf_arg,
+                   const void *inbuf_arg, size_t nblocks)
+{
+  struct _tripledes_ctx *ctx = context;
+  unsigned char *outbuf = outbuf_arg;
+  const unsigned char *inbuf = inbuf_arg;
+  unsigned char tmpbuf[DES_BLOCKSIZE];
+  int burn_stack_depth = TRIPLEDES_ECB_BURN_STACK;
+  int i;
+
+#ifdef USE_AMD64_ASM
+  {
+    int asm_burn_depth = 9 * sizeof(void *);
+
+    if (nblocks >= 3 && burn_stack_depth < asm_burn_depth)
+      burn_stack_depth = asm_burn_depth;
+
+    /* Process data in 3 block chunks. */
+    while (nblocks >= 3)
+      {
+        _gcry_3des_amd64_ctr_enc(ctx->encrypt_subkeys, outbuf, inbuf, ctr);
+
+        nblocks -= 3;
+        outbuf += 3 * DES_BLOCKSIZE;
+        inbuf  += 3 * DES_BLOCKSIZE;
+      }
+
+    /* Use generic code to handle smaller chunks... */
+  }
+#endif
+
+  for ( ;nblocks; nblocks-- )
+    {
+      /* Encrypt the counter. */
+      tripledes_ecb_encrypt (ctx, ctr, tmpbuf);
+      /* XOR the input with the encrypted counter and store in output.  */
+      buf_xor(outbuf, tmpbuf, inbuf, DES_BLOCKSIZE);
+      outbuf += DES_BLOCKSIZE;
+      inbuf  += DES_BLOCKSIZE;
+      /* Increment the counter.  */
+      for (i = DES_BLOCKSIZE; i > 0; i--)
+        {
+          ctr[i-1]++;
+          if (ctr[i-1])
+            break;
+        }
+    }
+
+  wipememory(tmpbuf, sizeof(tmpbuf));
+  _gcry_burn_stack(burn_stack_depth);
+}
+
+
+/* Bulk decryption of complete blocks in CBC mode.  This function is only
+   intended for the bulk encryption feature of cipher.c. */
+void
+_gcry_3des_cbc_dec(void *context, unsigned char *iv, void *outbuf_arg,
+                   const void *inbuf_arg, size_t nblocks)
+{
+  struct _tripledes_ctx *ctx = context;
+  unsigned char *outbuf = outbuf_arg;
+  const unsigned char *inbuf = inbuf_arg;
+  unsigned char savebuf[DES_BLOCKSIZE];
+  int burn_stack_depth = TRIPLEDES_ECB_BURN_STACK;
+
+#ifdef USE_AMD64_ASM
+  {
+    int asm_burn_depth = 10 * sizeof(void *);
+
+    if (nblocks >= 3 && burn_stack_depth < asm_burn_depth)
+      burn_stack_depth = asm_burn_depth;
+
+    /* Process data in 3 block chunks. */
+    while (nblocks >= 3)
+      {
+        _gcry_3des_amd64_cbc_dec(ctx->decrypt_subkeys, outbuf, inbuf, iv);
+
+        nblocks -= 3;
+        outbuf += 3 * DES_BLOCKSIZE;
+        inbuf  += 3 * DES_BLOCKSIZE;
+      }
+
+    /* Use generic code to handle smaller chunks... */
+  }
+#endif
+
+  for ( ;nblocks; nblocks-- )
+    {
+      /* INBUF is needed later and it may be identical to OUTBUF, so store
+         the intermediate result to SAVEBUF.  */
+      tripledes_ecb_decrypt (ctx, inbuf, savebuf);
+
+      buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, DES_BLOCKSIZE);
+      inbuf += DES_BLOCKSIZE;
+      outbuf += DES_BLOCKSIZE;
+    }
+
+  wipememory(savebuf, sizeof(savebuf));
+  _gcry_burn_stack(burn_stack_depth);
+}
+
+
+/* Bulk decryption of complete blocks in CFB mode.  This function is only
+   intended for the bulk encryption feature of cipher.c. */
+void
+_gcry_3des_cfb_dec(void *context, unsigned char *iv, void *outbuf_arg,
+		   const void *inbuf_arg, size_t nblocks)
+{
+  struct _tripledes_ctx *ctx = context;
+  unsigned char *outbuf = outbuf_arg;
+  const unsigned char *inbuf = inbuf_arg;
+  int burn_stack_depth = TRIPLEDES_ECB_BURN_STACK;
+
+#ifdef USE_AMD64_ASM
+  {
+    int asm_burn_depth = 9 * sizeof(void *);
+
+    if (nblocks >= 3 && burn_stack_depth < asm_burn_depth)
+      burn_stack_depth = asm_burn_depth;
 
+    /* Process data in 3 block chunks. */
+    while (nblocks >= 3)
+      {
+        _gcry_3des_amd64_cfb_dec(ctx->encrypt_subkeys, outbuf, inbuf, iv);
 
+        nblocks -= 3;
+        outbuf += 3 * DES_BLOCKSIZE;
+        inbuf  += 3 * DES_BLOCKSIZE;
+      }
+
+    /* Use generic code to handle smaller chunks... */
+  }
+#endif
+
+  for ( ;nblocks; nblocks-- )
+    {
+      tripledes_ecb_encrypt (ctx, iv, iv);
+      buf_xor_n_copy(outbuf, iv, inbuf, DES_BLOCKSIZE);
+      outbuf += DES_BLOCKSIZE;
+      inbuf  += DES_BLOCKSIZE;
+    }
+
+  _gcry_burn_stack(burn_stack_depth);
+}
 
 
 /*
 <at>  <at>  -815,6 +1029,67  <at>  <at>  is_weak_key ( const byte *key )
 }
 
 
+/* Alternative setkey for selftests; need larger key than default. */
+static gcry_err_code_t
+bulk_selftest_setkey (void *context, const byte *__key, unsigned __keylen)
+{
+  static const unsigned char key[24] ATTR_ALIGNED_16 = {
+      0x66,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F,
+      0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x22,
+      0x18,0x2A,0x39,0x47,0x5E,0x6F,0x75,0x82
+    };
+
+  (void)__key;
+  (void)__keylen;
+
+  return do_tripledes_setkey(context, key, sizeof(key));
+}
+
+
+/* Run the self-tests for DES-CTR, tests IV increment of bulk CTR
+   encryption.  Returns NULL on success. */
+static const char *
+selftest_ctr (void)
+{
+  const int nblocks = 3+1;
+  const int blocksize = DES_BLOCKSIZE;
+  const int context_size = sizeof(struct _tripledes_ctx);
+
+  return _gcry_selftest_helper_ctr("3DES", &bulk_selftest_setkey,
+           &do_tripledes_encrypt, &_gcry_3des_ctr_enc, nblocks, blocksize,
+           context_size);
+}
+
+
+/* Run the self-tests for DES-CBC, tests bulk CBC decryption.
+   Returns NULL on success. */
+static const char *
+selftest_cbc (void)
+{
+  const int nblocks = 3+2;
+  const int blocksize = DES_BLOCKSIZE;
+  const int context_size = sizeof(struct _tripledes_ctx);
+
+  return _gcry_selftest_helper_cbc("3DES", &bulk_selftest_setkey,
+           &do_tripledes_encrypt, &_gcry_3des_cbc_dec, nblocks, blocksize,
+           context_size);
+}
+
+
+/* Run the self-tests for DES-CFB, tests bulk CBC decryption.
+   Returns NULL on success. */
+static const char *
+selftest_cfb (void)
+{
+  const int nblocks = 3+2;
+  const int blocksize = DES_BLOCKSIZE;
+  const int context_size = sizeof(struct _tripledes_ctx);
+
+  return _gcry_selftest_helper_cfb("3DES", &bulk_selftest_setkey,
+           &do_tripledes_encrypt, &_gcry_3des_cfb_dec, nblocks, blocksize,
+           context_size);
+}
+
 
 /*
  * Performs a selftest of this DES/Triple-DES implementation.
 <at>  <at>  -824,6 +1099,8  <at>  <at>  is_weak_key ( const byte *key )
 static const char *
 selftest (void)
 {
+  const char *r;
+
   /*
    * Check if 'u32' is really 32 bits wide. This DES / 3DES implementation
    * need this.
 <at>  <at>  -1003,6 +1280,15  <at>  <at>  selftest (void)
         return "DES weak key detection failed";
   }
 
+  if ( (r = selftest_cbc ()) )
+    return r;
+
+  if ( (r = selftest_cfb ()) )
+    return r;
+
+  if ( (r = selftest_ctr ()) )
+    return r;
+
   return 0;
 }
 
 <at>  <at>  -1060,7 +1346,7  <at>  <at>  do_tripledes_encrypt( void *context, byte *outbuf, const byte *inbuf )
   struct _tripledes_ctx *ctx = (struct _tripledes_ctx *) context;
 
   tripledes_ecb_encrypt ( ctx, inbuf, outbuf );
-  return /*burn_stack*/ (32);
+  return /*burn_stack*/ TRIPLEDES_ECB_BURN_STACK;
 }
 
 static unsigned int
 <at>  <at>  -1068,7 +1354,7  <at>  <at>  do_tripledes_decrypt( void *context, byte *outbuf, const byte *inbuf )
 {
   struct _tripledes_ctx *ctx = (struct _tripledes_ctx *) context;
   tripledes_ecb_decrypt ( ctx, inbuf, outbuf );
-  return /*burn_stack*/ (32);
+  return /*burn_stack*/ TRIPLEDES_ECB_BURN_STACK;
 }
 
 static gcry_err_code_t
diff --git a/configure.ac b/configure.ac
index a0f75a5..79f79ef 100644
--- a/configure.ac
+++ b/configure.ac
 <at>  <at>  -1671,6 +1671,13  <at>  <at>  LIST_MEMBER(des, $enabled_ciphers)
 if test "$found" = "1" ; then
    GCRYPT_CIPHERS="$GCRYPT_CIPHERS des.lo"
    AC_DEFINE(USE_DES, 1, [Defined if this module should be included])
+
+   case "${host}" in
+      x86_64-*-*)
+         # Build with the assembly implementation
+         GCRYPT_CIPHERS="$GCRYPT_CIPHERS des-amd64.lo"
+      ;;
+   esac
 fi
 
 LIST_MEMBER(aes, $enabled_ciphers)
diff --git a/src/cipher.h b/src/cipher.h
index cd981b3..5d1b5f6 100644
--- a/src/cipher.h
+++ b/src/cipher.h
 <at>  <at>  -173,6 +173,19  <at>  <at>  void _gcry_camellia_cfb_dec (void *context, unsigned char *iv,
                              void *outbuf_arg, const void *inbuf_arg,
                              size_t nblocks);
 
+/*-- des.c --*/
+void _gcry_3des_ctr_enc (void *context, unsigned char *ctr,
+                         void *outbuf_arg, const void *inbuf_arg,
+                         size_t nblocks);
+
+void _gcry_3des_cbc_dec (void *context, unsigned char *iv,
+                         void *outbuf_arg, const void *inbuf_arg,
+                         size_t nblocks);
+
+void _gcry_3des_cfb_dec (void *context, unsigned char *iv,
+                         void *outbuf_arg, const void *inbuf_arg,
+                         size_t nblocks);
+
 /*-- serpent.c --*/
 void _gcry_serpent_ctr_enc (void *context, unsigned char *ctr,
                             void *outbuf_arg, const void *inbuf_arg,

-----------------------------------------------------------------------

Summary of changes:
 cipher/Makefile.am       |    2 +-
 cipher/cipher-selftest.c |   18 +-
 cipher/cipher.c          |    7 +
 cipher/des-amd64.S       | 1030 ++++++++++++++++++++++++++++++++++++++++++++++
 cipher/des.c             |  292 ++++++++++++-
 configure.ac             |    7 +
 src/cipher.h             |   13 +
 7 files changed, 1362 insertions(+), 7 deletions(-)
 create mode 100644 cipher/des-amd64.S


hooks/post-receive
--

-- 
The GNU crypto library
http://git.gnupg.org


_______________________________________________
Gnupg-commits mailing list
Gnupg-commits <at> gnupg.org
http://lists.gnupg.org/mailman/listinfo/gnupg-commits
Hanno Böck | 2 Apr 10:41 2014
Picon

Key import segfault in libgcrypt

Hello,

On my system if I try to import this key
http://pgp.mit.edu/pks/lookup?op=get&search=0x98EEB6F7D87171CF
with gnupg it segfaults.

Backtrace (see below) indicates that the crash happens somewhere in
libgcrypt, so I'm posting it here.

My libgcrypt version is 1.6.1, gnupg is 2.0.22.

I can reproduce it on another system with libgcrypt 1.5.3. Both are
Gentoo.

Can anyone else reproduce? Any more info needed?

cu, Hanno Böck

Backtrace:
0x00007ffff731c130 in _gcry_mpi_get_flag ()
from /usr/lib64/libgcrypt.so.20 (gdb) bt
#0  0x00007ffff731c130 in _gcry_mpi_get_flag ()
from /usr/lib64/libgcrypt.so.20 #1  0x00007ffff7286509 in
do_vsexp_sscan () from /usr/lib64/libgcrypt.so.20 #2
0x00007ffff7287aac in _gcry_sexp_vbuild ()
from /usr/lib64/libgcrypt.so.20 #3  0x00007ffff7281382 in
gcry_sexp_build () from /usr/lib64/libgcrypt.so.20 #4
0x0000000000432fba in pk_verify () #5  0x000000000042e1d8 in do_check
() #6  0x000000000042efc2 in check_key_signature2 () #7
0x000000000042f1bb in check_key_signature () #8  0x000000000044b526 in
import_one.isra () #9  0x000000000044d22d in import ()
#10 0x000000000044dd15 in import_keys_internal ()
#11 0x000000000044de7c in import_keys ()
#12 0x000000000040b77c in main ()

--

-- 
Hanno Böck
http://hboeck.de/

mail/jabber: hanno <at> hboeck.de
GPG: BBB51E42
_______________________________________________
Gcrypt-devel mailing list
Gcrypt-devel <at> gnupg.org
http://lists.gnupg.org/mailman/listinfo/gcrypt-devel
Jussi Kivilinna | 30 Mar 17:27 2014
Picon
Picon

[PATCH] 3des: add amd64 assembly implementation for 3DES

* cipher/Makefile.am: Add 'des-amd64.S'.
* cipher/cipher-selftests.c (_gcry_selftest_helper_cbc)
(_gcry_selftest_helper_cfb, _gcry_selftest_helper_ctr): Handle failures
from 'setkey' function.
* cipher/cipher.c (_gcry_cipher_open_internal) [USE_DES]: Setup bulk
functions for 3DES.
* cipher/des-amd64.S: New file.
* cipher/des.c (USE_AMD64_ASM, ATTR_ALIGNED_16): New macros.
[USE_AMD64_ASM] (_gcry_3des_amd64_crypt_block)
(_gcry_3des_amd64_ctr_enc), _gcry_3des_amd64_cbc_dec)
(_gcry_3des_amd64_cfb_dec): New prototypes.
[USE_AMD64_ASM] (tripledes_ecb_crypt): New function.
(TRIPLEDES_ECB_BURN_STACK): New macro.
(_gcry_3des_ctr_enc, _gcry_3des_cbc_dec, _gcry_3des_cfb_dec)
(bulk_selftest_setkey, selftest_ctr, selftest_cbc, selftest_cfb): New
functions.
(selftest): Add call to CTR, CBC and CFB selftest functions.
(do_tripledes_encrypt, do_tripledes_decrypt): Use
TRIPLEDES_ECB_BURN_STACK.
* configure.ac [host=x86-64]: Add 'des-amd64.lo'.
* src/cipher.h (_gcry_3des_ctr_enc, _gcry_3des_cbc_dec)
(_gcry_3des_cfb_dec): New prototypes.
--

Add non-parallel functions for small speed-up and 3-way parallel functions for
modes of operation that support parallel processing.

Old vs new (Intel Core i5-4570):
================================
        enc    dec
 ECB    1.17x  1.17x
 CBC    1.17x  2.51x
 CFB    1.16x  2.49x
 OFB    1.17x  1.17x
 CTR    2.56x  2.56x

Old vs new (Intel Core i5-2450M):
=================================
        enc    dec
 ECB    1.28x  1.28x
 CBC    1.27x  2.33x
 CFB    1.27x  2.34x
 OFB    1.27x  1.27x
 CTR    2.36x  2.35x

New (Intel Core i5-4570):
=========================
 3DES           |  nanosecs/byte   mebibytes/sec   cycles/byte
        ECB enc |     28.39 ns/B     33.60 MiB/s     90.84 c/B
        ECB dec |     28.27 ns/B     33.74 MiB/s     90.45 c/B
        CBC enc |     29.50 ns/B     32.33 MiB/s     94.40 c/B
        CBC dec |     13.35 ns/B     71.45 MiB/s     42.71 c/B
        CFB enc |     29.59 ns/B     32.23 MiB/s     94.68 c/B
        CFB dec |     13.41 ns/B     71.12 MiB/s     42.91 c/B
        OFB enc |     28.90 ns/B     33.00 MiB/s     92.47 c/B
        OFB dec |     28.90 ns/B     33.00 MiB/s     92.48 c/B
        CTR enc |     13.39 ns/B     71.20 MiB/s     42.86 c/B
        CTR dec |     13.39 ns/B     71.21 MiB/s     42.86 c/B

Old (Intel Core i5-4570):
=========================
 3DES           |  nanosecs/byte   mebibytes/sec   cycles/byte
        ECB enc |     33.24 ns/B     28.69 MiB/s     106.4 c/B
        ECB dec |     33.26 ns/B     28.67 MiB/s     106.4 c/B
        CBC enc |     34.45 ns/B     27.69 MiB/s     110.2 c/B
        CBC dec |     33.45 ns/B     28.51 MiB/s     107.1 c/B
        CFB enc |     34.43 ns/B     27.70 MiB/s     110.2 c/B
        CFB dec |     33.41 ns/B     28.55 MiB/s     106.9 c/B
        OFB enc |     33.79 ns/B     28.22 MiB/s     108.1 c/B
        OFB dec |     33.79 ns/B     28.22 MiB/s     108.1 c/B
        CTR enc |     34.27 ns/B     27.83 MiB/s     109.7 c/B
        CTR dec |     34.27 ns/B     27.83 MiB/s     109.7 c/B

New (Intel Core i5-2450M):
==========================
 3DES           |  nanosecs/byte   mebibytes/sec   cycles/byte
        ECB enc |     42.21 ns/B     22.59 MiB/s     105.5 c/B
        ECB dec |     42.23 ns/B     22.58 MiB/s     105.6 c/B
        CBC enc |     43.70 ns/B     21.82 MiB/s     109.2 c/B
        CBC dec |     23.25 ns/B     41.02 MiB/s     58.12 c/B
        CFB enc |     43.71 ns/B     21.82 MiB/s     109.3 c/B
        CFB dec |     23.23 ns/B     41.05 MiB/s     58.08 c/B
        OFB enc |     42.73 ns/B     22.32 MiB/s     106.8 c/B
        OFB dec |     42.73 ns/B     22.32 MiB/s     106.8 c/B
        CTR enc |     23.31 ns/B     40.92 MiB/s     58.27 c/B
        CTR dec |     23.35 ns/B     40.84 MiB/s     58.38 c/B

Old (Intel Core i5-2450M):
==========================
 3DES           |  nanosecs/byte   mebibytes/sec   cycles/byte
        ECB enc |     53.98 ns/B     17.67 MiB/s     134.9 c/B
        ECB dec |     54.00 ns/B     17.66 MiB/s     135.0 c/B
        CBC enc |     55.43 ns/B     17.20 MiB/s     138.6 c/B
        CBC dec |     54.27 ns/B     17.57 MiB/s     135.7 c/B
        CFB enc |     55.42 ns/B     17.21 MiB/s     138.6 c/B
        CFB dec |     54.35 ns/B     17.55 MiB/s     135.9 c/B
        OFB enc |     54.49 ns/B     17.50 MiB/s     136.2 c/B
        OFB dec |     54.49 ns/B     17.50 MiB/s     136.2 c/B
        CTR enc |     55.02 ns/B     17.33 MiB/s     137.5 c/B
        CTR dec |     55.01 ns/B     17.34 MiB/s     137.5 c/B

Signed-off-by: Jussi Kivilinna <jussi.kivilinna <at> iki.fi>
---
 cipher/Makefile.am       |    2 
 cipher/cipher-selftest.c |   18 +
 cipher/cipher.c          |    7 
 cipher/des-amd64.S       | 1030 ++++++++++++++++++++++++++++++++++++++++++++++
 cipher/des.c             |  292 +++++++++++++
 configure.ac             |    7 
 src/cipher.h             |   13 +
 7 files changed, 1362 insertions(+), 7 deletions(-)
 create mode 100644 cipher/des-amd64.S

diff --git a/cipher/Makefile.am b/cipher/Makefile.am
index 462e6db..3c20d3c 100644
--- a/cipher/Makefile.am
+++ b/cipher/Makefile.am
 <at>  <at>  -60,7 +60,7  <at>  <at>  arcfour.c arcfour-amd64.S \
 blowfish.c blowfish-amd64.S blowfish-arm.S \
 cast5.c cast5-amd64.S cast5-arm.S \
 crc.c \
-des.c \
+des.c des-amd64.S \
 dsa.c \
 elgamal.c \
 ecc.c ecc-curves.c ecc-misc.c ecc-common.h \
diff --git a/cipher/cipher-selftest.c b/cipher/cipher-selftest.c
index 5e95814..852368a 100644
--- a/cipher/cipher-selftest.c
+++ b/cipher/cipher-selftest.c
 <at>  <at>  -82,7 +82,11  <at>  <at>  _gcry_selftest_helper_cbc (const char *cipher, gcry_cipher_setkey_t setkey_func,
   ciphertext = plaintext2 + nblocks * blocksize;
 
   /* Initialize ctx */
-  setkey_func (ctx, key, sizeof(key));
+  if (setkey_func (ctx, key, sizeof(key)) != GPG_ERR_NO_ERROR)
+   {
+     xfree(mem);
+     return "setkey failed";
+   }
 
   /* Test single block code path */
   memset (iv, 0x4e, blocksize);
 <at>  <at>  -199,7 +203,11  <at>  <at>  _gcry_selftest_helper_cfb (const char *cipher, gcry_cipher_setkey_t setkey_func,
   ciphertext = plaintext2 + nblocks * blocksize;
 
   /* Initialize ctx */
-  setkey_func (ctx, key, sizeof(key));
+  if (setkey_func (ctx, key, sizeof(key)) != GPG_ERR_NO_ERROR)
+   {
+     xfree(mem);
+     return "setkey failed";
+   }
 
   /* Test single block code path */
   memset(iv, 0xd3, blocksize);
 <at>  <at>  -316,7 +324,11  <at>  <at>  _gcry_selftest_helper_ctr (const char *cipher, gcry_cipher_setkey_t setkey_func,
   ciphertext2 = ciphertext + nblocks * blocksize;
 
   /* Initialize ctx */
-  setkey_func (ctx, key, sizeof(key));
+  if (setkey_func (ctx, key, sizeof(key)) != GPG_ERR_NO_ERROR)
+   {
+     xfree(mem);
+     return "setkey failed";
+   }
 
   /* Test single block code path */
   memset (iv, 0xff, blocksize);
diff --git a/cipher/cipher.c b/cipher/cipher.c
index baa4720..6552ed3 100644
--- a/cipher/cipher.c
+++ b/cipher/cipher.c
 <at>  <at>  -513,6 +513,13  <at>  <at>  _gcry_cipher_open_internal (gcry_cipher_hd_t *handle,
               h->bulk.ctr_enc = _gcry_camellia_ctr_enc;
               break;
 #endif /*USE_CAMELLIA*/
+#ifdef USE_DES
+            case GCRY_CIPHER_3DES:
+              h->bulk.cbc_dec =  _gcry_3des_cbc_dec;
+              h->bulk.cfb_dec =  _gcry_3des_cfb_dec;
+              h->bulk.ctr_enc =  _gcry_3des_ctr_enc;
+              break;
+#endif /*USE_DES*/
 #ifdef USE_SERPENT
 	    case GCRY_CIPHER_SERPENT128:
 	    case GCRY_CIPHER_SERPENT192:
diff --git a/cipher/des-amd64.S b/cipher/des-amd64.S
new file mode 100644
index 0000000..e8b2c56
--- /dev/null
+++ b/cipher/des-amd64.S
 <at>  <at>  -0,0 +1,1030  <at>  <at> 
+/* des-amd64.S  -  AMD64 assembly implementation of 3DES cipher
+ *
+ * Copyright (C) 2014 Jussi Kivilinna <jussi.kivilinna <at> iki.fi>
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt 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.
+ *
+ * Libgcrypt 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 program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef __x86_64
+#include <config.h>
+#if defined(USE_DES) && defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS)
+
+#ifdef __PIC__
+#  define RIP (%rip)
+#else
+#  define RIP
+#endif
+
+.text
+
+#define s1 0
+#define s2 ((s1) + (64*8))
+#define s3 ((s2) + (64*8))
+#define s4 ((s3) + (64*8))
+#define s5 ((s4) + (64*8))
+#define s6 ((s5) + (64*8))
+#define s7 ((s6) + (64*8))
+#define s8 ((s7) + (64*8))
+
+/* register macros */
+#define CTX %rdi
+#define SBOXES %rbp
+
+#define RL0 %r8
+#define RL1 %r9
+#define RL2 %r10
+
+#define RL0d %r8d
+#define RL1d %r9d
+#define RL2d %r10d
+
+#define RR0 %r11
+#define RR1 %r12
+#define RR2 %r13
+
+#define RR0d %r11d
+#define RR1d %r12d
+#define RR2d %r13d
+
+#define RW0 %rax
+#define RW1 %rbx
+#define RW2 %rcx
+
+#define RW0d %eax
+#define RW1d %ebx
+#define RW2d %ecx
+
+#define RW0bl %al
+#define RW1bl %bl
+#define RW2bl %cl
+
+#define RW0bh %ah
+#define RW1bh %bh
+#define RW2bh %ch
+
+#define RT0 %r15
+#define RT1 %rsi
+#define RT2 %r14
+#define RT3 %rdx
+
+#define RT0d %r15d
+#define RT1d %esi
+#define RT2d %r14d
+#define RT3d %edx
+
+/***********************************************************************
+ * 1-way 3DES
+ ***********************************************************************/
+#define do_permutation(a, b, offset, mask) \
+	movl a, RT0d; \
+	shrl $(offset), RT0d; \
+	xorl b, RT0d; \
+	andl $(mask), RT0d; \
+	xorl RT0d, b; \
+	shll $(offset), RT0d; \
+	xorl RT0d, a;
+
+#define expand_to_64bits(val, mask) \
+	movl val##d, RT0d; \
+	rorl $4, RT0d; \
+	shlq $32, RT0; \
+	orq RT0, val; \
+	andq mask, val;
+
+#define compress_to_64bits(val) \
+	movq val, RT0; \
+	shrq $32, RT0; \
+	roll $4, RT0d; \
+	orl RT0d, val##d;
+
+#define initial_permutation(left, right) \
+	do_permutation(left##d, right##d,  4, 0x0f0f0f0f); \
+	do_permutation(left##d, right##d, 16, 0x0000ffff); \
+	do_permutation(right##d, left##d,  2, 0x33333333); \
+	do_permutation(right##d, left##d,  8, 0x00ff00ff); \
+	movabs $0x3f3f3f3f3f3f3f3f, RT3; \
+	movl left##d, RW0d; \
+	roll $1, right##d; \
+	xorl right##d, RW0d; \
+	andl $0xaaaaaaaa, RW0d; \
+	xorl RW0d, left##d; \
+	xorl RW0d, right##d; \
+	roll $1, left##d; \
+	expand_to_64bits(right, RT3); \
+	expand_to_64bits(left, RT3);
+
+#define final_permutation(left, right) \
+	compress_to_64bits(right); \
+	compress_to_64bits(left); \
+	movl right##d, RW0d; \
+	rorl $1, left##d; \
+	xorl left##d, RW0d; \
+	andl $0xaaaaaaaa, RW0d; \
+	xorl RW0d, right##d; \
+	xorl RW0d, left##d; \
+	rorl $1, right##d; \
+	do_permutation(right##d, left##d,  8, 0x00ff00ff); \
+	do_permutation(right##d, left##d,  2, 0x33333333); \
+	do_permutation(left##d, right##d, 16, 0x0000ffff); \
+	do_permutation(left##d, right##d,  4, 0x0f0f0f0f);
+
+#define round1(n, from, to, load_next_key) \
+	xorq from, RW0; \
+	\
+	movzbl RW0bl, RT0d; \
+	movzbl RW0bh, RT1d; \
+	shrq $16, RW0; \
+	movzbl RW0bl, RT2d; \
+	movzbl RW0bh, RT3d; \
+	shrq $16, RW0; \
+	movq s8(SBOXES, RT0, 8), RT0; \
+	xorq s6(SBOXES, RT1, 8), to; \
+	movzbl RW0bl, RL1d; \
+	movzbl RW0bh, RT1d; \
+	shrl $16, RW0d; \
+	xorq s4(SBOXES, RT2, 8), RT0; \
+	xorq s2(SBOXES, RT3, 8), to; \
+	movzbl RW0bl, RT2d; \
+	movzbl RW0bh, RT3d; \
+	xorq s7(SBOXES, RL1, 8), RT0; \
+	xorq s5(SBOXES, RT1, 8), to; \
+	xorq s3(SBOXES, RT2, 8), RT0; \
+	load_next_key(n, RW0); \
+	xorq RT0, to; \
+	xorq s1(SBOXES, RT3, 8), to; \
+
+#define load_next_key(n, RWx) \
+	movq (((n) + 1) * 8)(CTX), RWx;
+
+#define dummy2(a, b) /*_*/
+
+#define read_block(io, left, right) \
+	movl    (io), left##d; \
+	movl   4(io), right##d; \
+	bswapl left##d; \
+	bswapl right##d;
+
+#define write_block(io, left, right) \
+	bswapl left##d; \
+	bswapl right##d; \
+	movl   left##d,   (io); \
+	movl   right##d, 4(io);
+
+.align 8
+.globl _gcry_3des_amd64_crypt_block
+.type  _gcry_3des_amd64_crypt_block, <at> function;
+
+_gcry_3des_amd64_crypt_block:
+	/* input:
+	 *	%rdi: round keys, CTX
+	 *	%rsi: dst
+	 *	%rdx: src
+	 */
+	pushq %rbp;
+	pushq %rbx;
+	pushq %r12;
+	pushq %r13;
+	pushq %r14;
+	pushq %r15;
+	pushq %rsi; /*dst*/
+
+	leaq .L_s1 RIP, SBOXES;
+
+	read_block(%rdx, RL0, RR0);
+	initial_permutation(RL0, RR0);
+
+	movq (CTX), RW0;
+
+	round1(0, RR0, RL0, load_next_key);
+	round1(1, RL0, RR0, load_next_key);
+	round1(2, RR0, RL0, load_next_key);
+	round1(3, RL0, RR0, load_next_key);
+	round1(4, RR0, RL0, load_next_key);
+	round1(5, RL0, RR0, load_next_key);
+	round1(6, RR0, RL0, load_next_key);
+	round1(7, RL0, RR0, load_next_key);
+	round1(8, RR0, RL0, load_next_key);
+	round1(9, RL0, RR0, load_next_key);
+	round1(10, RR0, RL0, load_next_key);
+	round1(11, RL0, RR0, load_next_key);
+	round1(12, RR0, RL0, load_next_key);
+	round1(13, RL0, RR0, load_next_key);
+	round1(14, RR0, RL0, load_next_key);
+	round1(15, RL0, RR0, load_next_key);
+
+	round1(16+0, RL0, RR0, load_next_key);
+	round1(16+1, RR0, RL0, load_next_key);
+	round1(16+2, RL0, RR0, load_next_key);
+	round1(16+3, RR0, RL0, load_next_key);
+	round1(16+4, RL0, RR0, load_next_key);
+	round1(16+5, RR0, RL0, load_next_key);
+	round1(16+6, RL0, RR0, load_next_key);
+	round1(16+7, RR0, RL0, load_next_key);
+	round1(16+8, RL0, RR0, load_next_key);
+	round1(16+9, RR0, RL0, load_next_key);
+	round1(16+10, RL0, RR0, load_next_key);
+	round1(16+11, RR0, RL0, load_next_key);
+	round1(16+12, RL0, RR0, load_next_key);
+	round1(16+13, RR0, RL0, load_next_key);
+	round1(16+14, RL0, RR0, load_next_key);
+	round1(16+15, RR0, RL0, load_next_key);
+
+	round1(32+0, RR0, RL0, load_next_key);
+	round1(32+1, RL0, RR0, load_next_key);
+	round1(32+2, RR0, RL0, load_next_key);
+	round1(32+3, RL0, RR0, load_next_key);
+	round1(32+4, RR0, RL0, load_next_key);
+	round1(32+5, RL0, RR0, load_next_key);
+	round1(32+6, RR0, RL0, load_next_key);
+	round1(32+7, RL0, RR0, load_next_key);
+	round1(32+8, RR0, RL0, load_next_key);
+	round1(32+9, RL0, RR0, load_next_key);
+	round1(32+10, RR0, RL0, load_next_key);
+	round1(32+11, RL0, RR0, load_next_key);
+	round1(32+12, RR0, RL0, load_next_key);
+	round1(32+13, RL0, RR0, load_next_key);
+	round1(32+14, RR0, RL0, load_next_key);
+	round1(32+15, RL0, RR0, dummy2);
+
+	popq RW2; /*dst*/
+	final_permutation(RR0, RL0);
+	write_block(RW2, RR0, RL0);
+
+	popq %r15;
+	popq %r14;
+	popq %r13;
+	popq %r12;
+	popq %rbx;
+	popq %rbp;
+
+	ret;
+.size _gcry_3des_amd64_crypt_block,.-_gcry_3des_amd64_crypt_block;
+
+/***********************************************************************
+ * 3-way 3DES
+ ***********************************************************************/
+#define expand_to_64bits(val, mask) \
+	movl val##d, RT0d; \
+	rorl $4, RT0d; \
+	shlq $32, RT0; \
+	orq RT0, val; \
+	andq mask, val;
+
+#define compress_to_64bits(val) \
+	movq val, RT0; \
+	shrq $32, RT0; \
+	roll $4, RT0d; \
+	orl RT0d, val##d;
+
+#define initial_permutation3(left, right) \
+	do_permutation(left##0d, right##0d,  4, 0x0f0f0f0f); \
+	do_permutation(left##0d, right##0d, 16, 0x0000ffff); \
+	  do_permutation(left##1d, right##1d,  4, 0x0f0f0f0f); \
+	  do_permutation(left##1d, right##1d, 16, 0x0000ffff); \
+	    do_permutation(left##2d, right##2d,  4, 0x0f0f0f0f); \
+	    do_permutation(left##2d, right##2d, 16, 0x0000ffff); \
+	    \
+	do_permutation(right##0d, left##0d,  2, 0x33333333); \
+	do_permutation(right##0d, left##0d,  8, 0x00ff00ff); \
+	  do_permutation(right##1d, left##1d,  2, 0x33333333); \
+	  do_permutation(right##1d, left##1d,  8, 0x00ff00ff); \
+	    do_permutation(right##2d, left##2d,  2, 0x33333333); \
+	    do_permutation(right##2d, left##2d,  8, 0x00ff00ff); \
+	    \
+	movabs $0x3f3f3f3f3f3f3f3f, RT3; \
+	    \
+	movl left##0d, RW0d; \
+	roll $1, right##0d; \
+	xorl right##0d, RW0d; \
+	andl $0xaaaaaaaa, RW0d; \
+	xorl RW0d, left##0d; \
+	xorl RW0d, right##0d; \
+	roll $1, left##0d; \
+	expand_to_64bits(right##0, RT3); \
+	expand_to_64bits(left##0, RT3); \
+	  movl left##1d, RW1d; \
+	  roll $1, right##1d; \
+	  xorl right##1d, RW1d; \
+	  andl $0xaaaaaaaa, RW1d; \
+	  xorl RW1d, left##1d; \
+	  xorl RW1d, right##1d; \
+	  roll $1, left##1d; \
+	  expand_to_64bits(right##1, RT3); \
+	  expand_to_64bits(left##1, RT3); \
+	    movl left##2d, RW2d; \
+	    roll $1, right##2d; \
+	    xorl right##2d, RW2d; \
+	    andl $0xaaaaaaaa, RW2d; \
+	    xorl RW2d, left##2d; \
+	    xorl RW2d, right##2d; \
+	    roll $1, left##2d; \
+	    expand_to_64bits(right##2, RT3); \
+	    expand_to_64bits(left##2, RT3);
+
+#define final_permutation3(left, right) \
+	compress_to_64bits(right##0); \
+	compress_to_64bits(left##0); \
+	movl right##0d, RW0d; \
+	rorl $1, left##0d; \
+	xorl left##0d, RW0d; \
+	andl $0xaaaaaaaa, RW0d; \
+	xorl RW0d, right##0d; \
+	xorl RW0d, left##0d; \
+	rorl $1, right##0d; \
+	  compress_to_64bits(right##1); \
+	  compress_to_64bits(left##1); \
+	  movl right##1d, RW1d; \
+	  rorl $1, left##1d; \
+	  xorl left##1d, RW1d; \
+	  andl $0xaaaaaaaa, RW1d; \
+	  xorl RW1d, right##1d; \
+	  xorl RW1d, left##1d; \
+	  rorl $1, right##1d; \
+	    compress_to_64bits(right##2); \
+	    compress_to_64bits(left##2); \
+	    movl right##2d, RW2d; \
+	    rorl $1, left##2d; \
+	    xorl left##2d, RW2d; \
+	    andl $0xaaaaaaaa, RW2d; \
+	    xorl RW2d, right##2d; \
+	    xorl RW2d, left##2d; \
+	    rorl $1, right##2d; \
+	    \
+	do_permutation(right##0d, left##0d,  8, 0x00ff00ff); \
+	do_permutation(right##0d, left##0d,  2, 0x33333333); \
+	  do_permutation(right##1d, left##1d,  8, 0x00ff00ff); \
+	  do_permutation(right##1d, left##1d,  2, 0x33333333); \
+	    do_permutation(right##2d, left##2d,  8, 0x00ff00ff); \
+	    do_permutation(right##2d, left##2d,  2, 0x33333333); \
+	    \
+	do_permutation(left##0d, right##0d, 16, 0x0000ffff); \
+	do_permutation(left##0d, right##0d,  4, 0x0f0f0f0f); \
+	  do_permutation(left##1d, right##1d, 16, 0x0000ffff); \
+	  do_permutation(left##1d, right##1d,  4, 0x0f0f0f0f); \
+	    do_permutation(left##2d, right##2d, 16, 0x0000ffff); \
+	    do_permutation(left##2d, right##2d,  4, 0x0f0f0f0f);
+
+#define round3(n, from, to, load_next_key, do_movq) \
+	xorq from##0, RW0; \
+	movzbl RW0bl, RT3d; \
+	movzbl RW0bh, RT1d; \
+	shrq $16, RW0; \
+	xorq s8(SBOXES, RT3, 8), to##0; \
+	xorq s6(SBOXES, RT1, 8), to##0; \
+	movzbl RW0bl, RT3d; \
+	movzbl RW0bh, RT1d; \
+	shrq $16, RW0; \
+	xorq s4(SBOXES, RT3, 8), to##0; \
+	xorq s2(SBOXES, RT1, 8), to##0; \
+	movzbl RW0bl, RT3d; \
+	movzbl RW0bh, RT1d; \
+	shrl $16, RW0d; \
+	xorq s7(SBOXES, RT3, 8), to##0; \
+	xorq s5(SBOXES, RT1, 8), to##0; \
+	movzbl RW0bl, RT3d; \
+	movzbl RW0bh, RT1d; \
+	load_next_key(n, RW0); \
+	xorq s3(SBOXES, RT3, 8), to##0; \
+	xorq s1(SBOXES, RT1, 8), to##0; \
+		xorq from##1, RW1; \
+		movzbl RW1bl, RT3d; \
+		movzbl RW1bh, RT1d; \
+		shrq $16, RW1; \
+		xorq s8(SBOXES, RT3, 8), to##1; \
+		xorq s6(SBOXES, RT1, 8), to##1; \
+		movzbl RW1bl, RT3d; \
+		movzbl RW1bh, RT1d; \
+		shrq $16, RW1; \
+		xorq s4(SBOXES, RT3, 8), to##1; \
+		xorq s2(SBOXES, RT1, 8), to##1; \
+		movzbl RW1bl, RT3d; \
+		movzbl RW1bh, RT1d; \
+		shrl $16, RW1d; \
+		xorq s7(SBOXES, RT3, 8), to##1; \
+		xorq s5(SBOXES, RT1, 8), to##1; \
+		movzbl RW1bl, RT3d; \
+		movzbl RW1bh, RT1d; \
+		do_movq(RW0, RW1); \
+		xorq s3(SBOXES, RT3, 8), to##1; \
+		xorq s1(SBOXES, RT1, 8), to##1; \
+			xorq from##2, RW2; \
+			movzbl RW2bl, RT3d; \
+			movzbl RW2bh, RT1d; \
+			shrq $16, RW2; \
+			xorq s8(SBOXES, RT3, 8), to##2; \
+			xorq s6(SBOXES, RT1, 8), to##2; \
+			movzbl RW2bl, RT3d; \
+			movzbl RW2bh, RT1d; \
+			shrq $16, RW2; \
+			xorq s4(SBOXES, RT3, 8), to##2; \
+			xorq s2(SBOXES, RT1, 8), to##2; \
+			movzbl RW2bl, RT3d; \
+			movzbl RW2bh, RT1d; \
+			shrl $16, RW2d; \
+			xorq s7(SBOXES, RT3, 8), to##2; \
+			xorq s5(SBOXES, RT1, 8), to##2; \
+			movzbl RW2bl, RT3d; \
+			movzbl RW2bh, RT1d; \
+			do_movq(RW0, RW2); \
+			xorq s3(SBOXES, RT3, 8), to##2; \
+			xorq s1(SBOXES, RT1, 8), to##2;
+
+#define __movq(src, dst) \
+	movq src, dst;
+
+#define read_block(io, left, right) \
+	movl    (io), left##d; \
+	movl   4(io), right##d; \
+	bswapl left##d; \
+	bswapl right##d;
+
+#define write_block(io, left, right) \
+	bswapl left##d; \
+	bswapl right##d; \
+	movl   left##d,   (io); \
+	movl   right##d, 4(io);
+
+.align 8
+.type  _gcry_3des_amd64_crypt_blk3, <at> function;
+_gcry_3des_amd64_crypt_blk3:
+	/* input:
+	 *  %rdi: round keys, CTX
+	 *  RL0d, RR0d, RL1d, RR1d, RL2d, RR2d: 3 input blocks
+	 *  RR0d, RL0d, RR1d, RL1d, RR2d, RL2d: 3 output blocks
+	 */
+
+	leaq .L_s1 RIP, SBOXES;
+
+	initial_permutation3(RL, RR);
+
+	movq 0(CTX), RW0;
+	movq RW0, RW1;
+	movq RW0, RW2;
+
+	round3(0, RR, RL, load_next_key, __movq);
+	round3(1, RL, RR, load_next_key, __movq);
+	round3(2, RR, RL, load_next_key, __movq);
+	round3(3, RL, RR, load_next_key, __movq);
+	round3(4, RR, RL, load_next_key, __movq);
+	round3(5, RL, RR, load_next_key, __movq);
+	round3(6, RR, RL, load_next_key, __movq);
+	round3(7, RL, RR, load_next_key, __movq);
+	round3(8, RR, RL, load_next_key, __movq);
+	round3(9, RL, RR, load_next_key, __movq);
+	round3(10, RR, RL, load_next_key, __movq);
+	round3(11, RL, RR, load_next_key, __movq);
+	round3(12, RR, RL, load_next_key, __movq);
+	round3(13, RL, RR, load_next_key, __movq);
+	round3(14, RR, RL, load_next_key, __movq);
+	round3(15, RL, RR, load_next_key, __movq);
+
+	round3(16+0, RL, RR, load_next_key, __movq);
+	round3(16+1, RR, RL, load_next_key, __movq);
+	round3(16+2, RL, RR, load_next_key, __movq);
+	round3(16+3, RR, RL, load_next_key, __movq);
+	round3(16+4, RL, RR, load_next_key, __movq);
+	round3(16+5, RR, RL, load_next_key, __movq);
+	round3(16+6, RL, RR, load_next_key, __movq);
+	round3(16+7, RR, RL, load_next_key, __movq);
+	round3(16+8, RL, RR, load_next_key, __movq);
+	round3(16+9, RR, RL, load_next_key, __movq);
+	round3(16+10, RL, RR, load_next_key, __movq);
+	round3(16+11, RR, RL, load_next_key, __movq);
+	round3(16+12, RL, RR, load_next_key, __movq);
+	round3(16+13, RR, RL, load_next_key, __movq);
+	round3(16+14, RL, RR, load_next_key, __movq);
+	round3(16+15, RR, RL, load_next_key, __movq);
+
+	round3(32+0, RR, RL, load_next_key, __movq);
+	round3(32+1, RL, RR, load_next_key, __movq);
+	round3(32+2, RR, RL, load_next_key, __movq);
+	round3(32+3, RL, RR, load_next_key, __movq);
+	round3(32+4, RR, RL, load_next_key, __movq);
+	round3(32+5, RL, RR, load_next_key, __movq);
+	round3(32+6, RR, RL, load_next_key, __movq);
+	round3(32+7, RL, RR, load_next_key, __movq);
+	round3(32+8, RR, RL, load_next_key, __movq);
+	round3(32+9, RL, RR, load_next_key, __movq);
+	round3(32+10, RR, RL, load_next_key, __movq);
+	round3(32+11, RL, RR, load_next_key, __movq);
+	round3(32+12, RR, RL, load_next_key, __movq);
+	round3(32+13, RL, RR, load_next_key, __movq);
+	round3(32+14, RR, RL, load_next_key, __movq);
+	round3(32+15, RL, RR, dummy2, dummy2);
+
+	final_permutation3(RR, RL);
+
+	ret;
+.size _gcry_3des_amd64_crypt_blk3,.-_gcry_3des_amd64_crypt_blk3;
+
+.align 8
+.globl  _gcry_3des_amd64_cbc_dec
+.type   _gcry_3des_amd64_cbc_dec, <at> function;
+_gcry_3des_amd64_cbc_dec:
+	/* input:
+	 *	%rdi: ctx, CTX
+	 *	%rsi: dst (3 blocks)
+	 *	%rdx: src (3 blocks)
+	 *	%rcx: iv (64bit)
+	 */
+
+	pushq %rbp;
+	pushq %rbx;
+	pushq %r12;
+	pushq %r13;
+	pushq %r14;
+	pushq %r15;
+
+	pushq %rsi; /*dst*/
+	pushq %rdx; /*src*/
+	pushq %rcx; /*iv*/
+
+	/* load input */
+	movl 0 * 4(%rdx), RL0d;
+	movl 1 * 4(%rdx), RR0d;
+	movl 2 * 4(%rdx), RL1d;
+	movl 3 * 4(%rdx), RR1d;
+	movl 4 * 4(%rdx), RL2d;
+	movl 5 * 4(%rdx), RR2d;
+
+	bswapl RL0d;
+	bswapl RR0d;
+	bswapl RL1d;
+	bswapl RR1d;
+	bswapl RL2d;
+	bswapl RR2d;
+
+	call _gcry_3des_amd64_crypt_blk3;
+
+	popq %rcx; /*iv*/
+	popq %rdx; /*src*/
+	popq %rsi; /*dst*/
+
+	bswapl RR0d;
+	bswapl RL0d;
+	bswapl RR1d;
+	bswapl RL1d;
+	bswapl RR2d;
+	bswapl RL2d;
+
+	movq 2 * 8(%rdx), RT0;
+	xorl 0 * 4(%rcx), RR0d;
+	xorl 1 * 4(%rcx), RL0d;
+	xorl 0 * 4(%rdx), RR1d;
+	xorl 1 * 4(%rdx), RL1d;
+	xorl 2 * 4(%rdx), RR2d;
+	xorl 3 * 4(%rdx), RL2d;
+	movq RT0, (%rcx); /* store new IV */
+
+	movl RR0d, 0 * 4(%rsi);
+	movl RL0d, 1 * 4(%rsi);
+	movl RR1d, 2 * 4(%rsi);
+	movl RL1d, 3 * 4(%rsi);
+	movl RR2d, 4 * 4(%rsi);
+	movl RL2d, 5 * 4(%rsi);
+
+	popq %r15;
+	popq %r14;
+	popq %r13;
+	popq %r12;
+	popq %rbx;
+	popq %rbp;
+
+	ret;
+.size _gcry_3des_amd64_cbc_dec,.-_gcry_3des_amd64_cbc_dec;
+
+.align 8
+.globl  _gcry_3des_amd64_ctr_enc
+.type   _gcry_3des_amd64_ctr_enc, <at> function;
+_gcry_3des_amd64_ctr_enc:
+	/* input:
+	 *	%rdi: ctx, CTX
+	 *	%rsi: dst (3 blocks)
+	 *	%rdx: src (3 blocks)
+	 *	%rcx: iv (64bit)
+	 */
+
+	pushq %rbp;
+	pushq %rbx;
+	pushq %r12;
+	pushq %r13;
+	pushq %r14;
+	pushq %r15;
+
+	pushq %rsi; /*dst*/
+	pushq %rdx; /*src*/
+	movq %rcx, RW2;
+
+	/* load IV and byteswap */
+	movq (RW2), RT0;
+	bswapq RT0;
+	movq RT0, RR0;
+
+	/* construct IVs */
+	leaq 1(RT0), RR1;
+	leaq 2(RT0), RR2;
+	leaq 3(RT0), RT0;
+	movq RR0, RL0;
+	movq RR1, RL1;
+	movq RR2, RL2;
+	bswapq RT0;
+	shrq $32, RL0;
+	shrq $32, RL1;
+	shrq $32, RL2;
+
+	/* store new IV */
+	movq RT0, (RW2);
+
+	call _gcry_3des_amd64_crypt_blk3;
+
+	popq %rdx; /*src*/
+	popq %rsi; /*dst*/
+
+	bswapl RR0d;
+	bswapl RL0d;
+	bswapl RR1d;
+	bswapl RL1d;
+	bswapl RR2d;
+	bswapl RL2d;
+
+	xorl 0 * 4(%rdx), RR0d;
+	xorl 1 * 4(%rdx), RL0d;
+	xorl 2 * 4(%rdx), RR1d;
+	xorl 3 * 4(%rdx), RL1d;
+	xorl 4 * 4(%rdx), RR2d;
+	xorl 5 * 4(%rdx), RL2d;
+
+	movl RR0d, 0 * 4(%rsi);
+	movl RL0d, 1 * 4(%rsi);
+	movl RR1d, 2 * 4(%rsi);
+	movl RL1d, 3 * 4(%rsi);
+	movl RR2d, 4 * 4(%rsi);
+	movl RL2d, 5 * 4(%rsi);
+
+	popq %r15;
+	popq %r14;
+	popq %r13;
+	popq %r12;
+	popq %rbx;
+	popq %rbp;
+
+	ret;
+.size _gcry_3des_amd64_cbc_dec,.-_gcry_3des_amd64_cbc_dec;
+
+.align 8
+.globl  _gcry_3des_amd64_cfb_dec
+.type   _gcry_3des_amd64_cfb_dec, <at> function;
+_gcry_3des_amd64_cfb_dec:
+	/* input:
+	 *	%rdi: ctx, CTX
+	 *	%rsi: dst (3 blocks)
+	 *	%rdx: src (3 blocks)
+	 *	%rcx: iv (64bit)
+	 */
+	pushq %rbp;
+	pushq %rbx;
+	pushq %r12;
+	pushq %r13;
+	pushq %r14;
+	pushq %r15;
+
+	pushq %rsi; /*dst*/
+	pushq %rdx; /*src*/
+	movq %rcx, RW2;
+
+	/* Load input */
+	movl 0 * 4(RW2), RL0d;
+	movl 1 * 4(RW2), RR0d;
+	movl 0 * 4(%rdx), RL1d;
+	movl 1 * 4(%rdx), RR1d;
+	movl 2 * 4(%rdx), RL2d;
+	movl 3 * 4(%rdx), RR2d;
+
+	bswapl RL0d;
+	bswapl RR0d;
+	bswapl RL1d;
+	bswapl RR1d;
+	bswapl RL2d;
+	bswapl RR2d;
+
+	/* Update IV */
+	movq 4 * 4(%rdx), RW0;
+	movq RW0, (RW2);
+
+	call _gcry_3des_amd64_crypt_blk3;
+
+	popq %rdx; /*src*/
+	popq %rsi; /*dst*/
+
+	bswapl RR0d;
+	bswapl RL0d;
+	bswapl RR1d;
+	bswapl RL1d;
+	bswapl RR2d;
+	bswapl RL2d;
+
+	xorl 0 * 4(%rdx), RR0d;
+	xorl 1 * 4(%rdx), RL0d;
+	xorl 2 * 4(%rdx), RR1d;
+	xorl 3 * 4(%rdx), RL1d;
+	xorl 4 * 4(%rdx), RR2d;
+	xorl 5 * 4(%rdx), RL2d;
+
+	movl RR0d, 0 * 4(%rsi);
+	movl RL0d, 1 * 4(%rsi);
+	movl RR1d, 2 * 4(%rsi);
+	movl RL1d, 3 * 4(%rsi);
+	movl RR2d, 4 * 4(%rsi);
+	movl RL2d, 5 * 4(%rsi);
+
+	popq %r15;
+	popq %r14;
+	popq %r13;
+	popq %r12;
+	popq %rbx;
+	popq %rbp;
+	ret;
+.size _gcry_3des_amd64_cfb_dec,.-_gcry_3des_amd64_cfb_dec;
+
+.data
+.align 16
+.L_s1:
+	.quad 0x0010100001010400, 0x0000000000000000
+	.quad 0x0000100000010000, 0x0010100001010404
+	.quad 0x0010100001010004, 0x0000100000010404
+	.quad 0x0000000000000004, 0x0000100000010000
+	.quad 0x0000000000000400, 0x0010100001010400
+	.quad 0x0010100001010404, 0x0000000000000400
+	.quad 0x0010000001000404, 0x0010100001010004
+	.quad 0x0010000001000000, 0x0000000000000004
+	.quad 0x0000000000000404, 0x0010000001000400
+	.quad 0x0010000001000400, 0x0000100000010400
+	.quad 0x0000100000010400, 0x0010100001010000
+	.quad 0x0010100001010000, 0x0010000001000404
+	.quad 0x0000100000010004, 0x0010000001000004
+	.quad 0x0010000001000004, 0x0000100000010004
+	.quad 0x0000000000000000, 0x0000000000000404
+	.quad 0x0000100000010404, 0x0010000001000000
+	.quad 0x0000100000010000, 0x0010100001010404
+	.quad 0x0000000000000004, 0x0010100001010000
+	.quad 0x0010100001010400, 0x0010000001000000
+	.quad 0x0010000001000000, 0x0000000000000400
+	.quad 0x0010100001010004, 0x0000100000010000
+	.quad 0x0000100000010400, 0x0010000001000004
+	.quad 0x0000000000000400, 0x0000000000000004
+	.quad 0x0010000001000404, 0x0000100000010404
+	.quad 0x0010100001010404, 0x0000100000010004
+	.quad 0x0010100001010000, 0x0010000001000404
+	.quad 0x0010000001000004, 0x0000000000000404
+	.quad 0x0000100000010404, 0x0010100001010400
+	.quad 0x0000000000000404, 0x0010000001000400
+	.quad 0x0010000001000400, 0x0000000000000000
+	.quad 0x0000100000010004, 0x0000100000010400
+	.quad 0x0000000000000000, 0x0010100001010004
+.L_s2:
+	.quad 0x0801080200100020, 0x0800080000000000
+	.quad 0x0000080000000000, 0x0001080200100020
+	.quad 0x0001000000100000, 0x0000000200000020
+	.quad 0x0801000200100020, 0x0800080200000020
+	.quad 0x0800000200000020, 0x0801080200100020
+	.quad 0x0801080000100000, 0x0800000000000000
+	.quad 0x0800080000000000, 0x0001000000100000
+	.quad 0x0000000200000020, 0x0801000200100020
+	.quad 0x0001080000100000, 0x0001000200100020
+	.quad 0x0800080200000020, 0x0000000000000000
+	.quad 0x0800000000000000, 0x0000080000000000
+	.quad 0x0001080200100020, 0x0801000000100000
+	.quad 0x0001000200100020, 0x0800000200000020
+	.quad 0x0000000000000000, 0x0001080000100000
+	.quad 0x0000080200000020, 0x0801080000100000
+	.quad 0x0801000000100000, 0x0000080200000020
+	.quad 0x0000000000000000, 0x0001080200100020
+	.quad 0x0801000200100020, 0x0001000000100000
+	.quad 0x0800080200000020, 0x0801000000100000
+	.quad 0x0801080000100000, 0x0000080000000000
+	.quad 0x0801000000100000, 0x0800080000000000
+	.quad 0x0000000200000020, 0x0801080200100020
+	.quad 0x0001080200100020, 0x0000000200000020
+	.quad 0x0000080000000000, 0x0800000000000000
+	.quad 0x0000080200000020, 0x0801080000100000
+	.quad 0x0001000000100000, 0x0800000200000020
+	.quad 0x0001000200100020, 0x0800080200000020
+	.quad 0x0800000200000020, 0x0001000200100020
+	.quad 0x0001080000100000, 0x0000000000000000
+	.quad 0x0800080000000000, 0x0000080200000020
+	.quad 0x0800000000000000, 0x0801000200100020
+	.quad 0x0801080200100020, 0x0001080000100000
+.L_s3:
+	.quad 0x0000002000000208, 0x0000202008020200
+	.quad 0x0000000000000000, 0x0000200008020008
+	.quad 0x0000002008000200, 0x0000000000000000
+	.quad 0x0000202000020208, 0x0000002008000200
+	.quad 0x0000200000020008, 0x0000000008000008
+	.quad 0x0000000008000008, 0x0000200000020000
+	.quad 0x0000202008020208, 0x0000200000020008
+	.quad 0x0000200008020000, 0x0000002000000208
+	.quad 0x0000000008000000, 0x0000000000000008
+	.quad 0x0000202008020200, 0x0000002000000200
+	.quad 0x0000202000020200, 0x0000200008020000
+	.quad 0x0000200008020008, 0x0000202000020208
+	.quad 0x0000002008000208, 0x0000202000020200
+	.quad 0x0000200000020000, 0x0000002008000208
+	.quad 0x0000000000000008, 0x0000202008020208
+	.quad 0x0000002000000200, 0x0000000008000000
+	.quad 0x0000202008020200, 0x0000000008000000
+	.quad 0x0000200000020008, 0x0000002000000208
+	.quad 0x0000200000020000, 0x0000202008020200
+	.quad 0x0000002008000200, 0x0000000000000000
+	.quad 0x0000002000000200, 0x0000200000020008
+	.quad 0x0000202008020208, 0x0000002008000200
+	.quad 0x0000000008000008, 0x0000002000000200
+	.quad 0x0000000000000000, 0x0000200008020008
+	.quad 0x0000002008000208, 0x0000200000020000
+	.quad 0x0000000008000000, 0x0000202008020208
+	.quad 0x0000000000000008, 0x0000202000020208
+	.quad 0x0000202000020200, 0x0000000008000008
+	.quad 0x0000200008020000, 0x0000002008000208
+	.quad 0x0000002000000208, 0x0000200008020000
+	.quad 0x0000202000020208, 0x0000000000000008
+	.quad 0x0000200008020008, 0x0000202000020200
+.L_s4:
+	.quad 0x1008020000002001, 0x1000020800002001
+	.quad 0x1000020800002001, 0x0000000800000000
+	.quad 0x0008020800002000, 0x1008000800000001
+	.quad 0x1008000000000001, 0x1000020000002001
+	.quad 0x0000000000000000, 0x0008020000002000
+	.quad 0x0008020000002000, 0x1008020800002001
+	.quad 0x1000000800000001, 0x0000000000000000
+	.quad 0x0008000800000000, 0x1008000000000001
+	.quad 0x1000000000000001, 0x0000020000002000
+	.quad 0x0008000000000000, 0x1008020000002001
+	.quad 0x0000000800000000, 0x0008000000000000
+	.quad 0x1000020000002001, 0x0000020800002000
+	.quad 0x1008000800000001, 0x1000000000000001
+	.quad 0x0000020800002000, 0x0008000800000000
+	.quad 0x0000020000002000, 0x0008020800002000
+	.quad 0x1008020800002001, 0x1000000800000001
+	.quad 0x0008000800000000, 0x1008000000000001
+	.quad 0x0008020000002000, 0x1008020800002001
+	.quad 0x1000000800000001, 0x0000000000000000
+	.quad 0x0000000000000000, 0x0008020000002000
+	.quad 0x0000020800002000, 0x0008000800000000
+	.quad 0x1008000800000001, 0x1000000000000001
+	.quad 0x1008020000002001, 0x1000020800002001
+	.quad 0x1000020800002001, 0x0000000800000000
+	.quad 0x1008020800002001, 0x1000000800000001
+	.quad 0x1000000000000001, 0x0000020000002000
+	.quad 0x1008000000000001, 0x1000020000002001
+	.quad 0x0008020800002000, 0x1008000800000001
+	.quad 0x1000020000002001, 0x0000020800002000
+	.quad 0x0008000000000000, 0x1008020000002001
+	.quad 0x0000000800000000, 0x0008000000000000
+	.quad 0x0000020000002000, 0x0008020800002000
+.L_s5:
+	.quad 0x0000001000000100, 0x0020001002080100
+	.quad 0x0020000002080000, 0x0420001002000100
+	.quad 0x0000000000080000, 0x0000001000000100
+	.quad 0x0400000000000000, 0x0020000002080000
+	.quad 0x0400001000080100, 0x0000000000080000
+	.quad 0x0020001002000100, 0x0400001000080100
+	.quad 0x0420001002000100, 0x0420000002080000
+	.quad 0x0000001000080100, 0x0400000000000000
+	.quad 0x0020000002000000, 0x0400000000080000
+	.quad 0x0400000000080000, 0x0000000000000000
+	.quad 0x0400001000000100, 0x0420001002080100
+	.quad 0x0420001002080100, 0x0020001002000100
+	.quad 0x0420000002080000, 0x0400001000000100
+	.quad 0x0000000000000000, 0x0420000002000000
+	.quad 0x0020001002080100, 0x0020000002000000
+	.quad 0x0420000002000000, 0x0000001000080100
+	.quad 0x0000000000080000, 0x0420001002000100
+	.quad 0x0000001000000100, 0x0020000002000000
+	.quad 0x0400000000000000, 0x0020000002080000
+	.quad 0x0420001002000100, 0x0400001000080100
+	.quad 0x0020001002000100, 0x0400000000000000
+	.quad 0x0420000002080000, 0x0020001002080100
+	.quad 0x0400001000080100, 0x0000001000000100
+	.quad 0x0020000002000000, 0x0420000002080000
+	.quad 0x0420001002080100, 0x0000001000080100
+	.quad 0x0420000002000000, 0x0420001002080100
+	.quad 0x0020000002080000, 0x0000000000000000
+	.quad 0x0400000000080000, 0x0420000002000000
+	.quad 0x0000001000080100, 0x0020001002000100
+	.quad 0x0400001000000100, 0x0000000000080000
+	.quad 0x0000000000000000, 0x0400000000080000
+	.quad 0x0020001002080100, 0x0400001000000100
+.L_s6:
+	.quad 0x0200000120000010, 0x0204000020000000
+	.quad 0x0000040000000000, 0x0204040120000010
+	.quad 0x0204000020000000, 0x0000000100000010
+	.quad 0x0204040120000010, 0x0004000000000000
+	.quad 0x0200040020000000, 0x0004040100000010
+	.quad 0x0004000000000000, 0x0200000120000010
+	.quad 0x0004000100000010, 0x0200040020000000
+	.quad 0x0200000020000000, 0x0000040100000010
+	.quad 0x0000000000000000, 0x0004000100000010
+	.quad 0x0200040120000010, 0x0000040000000000
+	.quad 0x0004040000000000, 0x0200040120000010
+	.quad 0x0000000100000010, 0x0204000120000010
+	.quad 0x0204000120000010, 0x0000000000000000
+	.quad 0x0004040100000010, 0x0204040020000000
+	.quad 0x0000040100000010, 0x0004040000000000
+	.quad 0x0204040020000000, 0x0200000020000000
+	.quad 0x0200040020000000, 0x0000000100000010
+	.quad 0x0204000120000010, 0x0004040000000000
+	.quad 0x0204040120000010, 0x0004000000000000
+	.quad 0x0000040100000010, 0x0200000120000010
+	.quad 0x0004000000000000, 0x0200040020000000
+	.quad 0x0200000020000000, 0x0000040100000010
+	.quad 0x0200000120000010, 0x0204040120000010
+	.quad 0x0004040000000000, 0x0204000020000000
+	.quad 0x0004040100000010, 0x0204040020000000
+	.quad 0x0000000000000000, 0x0204000120000010
+	.quad 0x0000000100000010, 0x0000040000000000
+	.quad 0x0204000020000000, 0x0004040100000010
+	.quad 0x0000040000000000, 0x0004000100000010
+	.quad 0x0200040120000010, 0x0000000000000000
+	.quad 0x0204040020000000, 0x0200000020000000
+	.quad 0x0004000100000010, 0x0200040120000010
+.L_s7:
+	.quad 0x0002000000200000, 0x2002000004200002
+	.quad 0x2000000004000802, 0x0000000000000000
+	.quad 0x0000000000000800, 0x2000000004000802
+	.quad 0x2002000000200802, 0x0002000004200800
+	.quad 0x2002000004200802, 0x0002000000200000
+	.quad 0x0000000000000000, 0x2000000004000002
+	.quad 0x2000000000000002, 0x0000000004000000
+	.quad 0x2002000004200002, 0x2000000000000802
+	.quad 0x0000000004000800, 0x2002000000200802
+	.quad 0x2002000000200002, 0x0000000004000800
+	.quad 0x2000000004000002, 0x0002000004200000
+	.quad 0x0002000004200800, 0x2002000000200002
+	.quad 0x0002000004200000, 0x0000000000000800
+	.quad 0x2000000000000802, 0x2002000004200802
+	.quad 0x0002000000200800, 0x2000000000000002
+	.quad 0x0000000004000000, 0x0002000000200800
+	.quad 0x0000000004000000, 0x0002000000200800
+	.quad 0x0002000000200000, 0x2000000004000802
+	.quad 0x2000000004000802, 0x2002000004200002
+	.quad 0x2002000004200002, 0x2000000000000002
+	.quad 0x2002000000200002, 0x0000000004000000
+	.quad 0x0000000004000800, 0x0002000000200000
+	.quad 0x0002000004200800, 0x2000000000000802
+	.quad 0x2002000000200802, 0x0002000004200800
+	.quad 0x2000000000000802, 0x2000000004000002
+	.quad 0x2002000004200802, 0x0002000004200000
+	.quad 0x0002000000200800, 0x0000000000000000
+	.quad 0x2000000000000002, 0x2002000004200802
+	.quad 0x0000000000000000, 0x2002000000200802
+	.quad 0x0002000004200000, 0x0000000000000800
+	.quad 0x2000000004000002, 0x0000000004000800
+	.quad 0x0000000000000800, 0x2002000000200002
+.L_s8:
+	.quad 0x0100010410001000, 0x0000010000001000
+	.quad 0x0000000000040000, 0x0100010410041000
+	.quad 0x0100000010000000, 0x0100010410001000
+	.quad 0x0000000400000000, 0x0100000010000000
+	.quad 0x0000000400040000, 0x0100000010040000
+	.quad 0x0100010410041000, 0x0000010000041000
+	.quad 0x0100010010041000, 0x0000010400041000
+	.quad 0x0000010000001000, 0x0000000400000000
+	.quad 0x0100000010040000, 0x0100000410000000
+	.quad 0x0100010010001000, 0x0000010400001000
+	.quad 0x0000010000041000, 0x0000000400040000
+	.quad 0x0100000410040000, 0x0100010010041000
+	.quad 0x0000010400001000, 0x0000000000000000
+	.quad 0x0000000000000000, 0x0100000410040000
+	.quad 0x0100000410000000, 0x0100010010001000
+	.quad 0x0000010400041000, 0x0000000000040000
+	.quad 0x0000010400041000, 0x0000000000040000
+	.quad 0x0100010010041000, 0x0000010000001000
+	.quad 0x0000000400000000, 0x0100000410040000
+	.quad 0x0000010000001000, 0x0000010400041000
+	.quad 0x0100010010001000, 0x0000000400000000
+	.quad 0x0100000410000000, 0x0100000010040000
+	.quad 0x0100000410040000, 0x0100000010000000
+	.quad 0x0000000000040000, 0x0100010410001000
+	.quad 0x0000000000000000, 0x0100010410041000
+	.quad 0x0000000400040000, 0x0100000410000000
+	.quad 0x0100000010040000, 0x0100010010001000
+	.quad 0x0100010410001000, 0x0000000000000000
+	.quad 0x0100010410041000, 0x0000010000041000
+	.quad 0x0000010000041000, 0x0000010400001000
+	.quad 0x0000010400001000, 0x0000000400040000
+	.quad 0x0100000010000000, 0x0100010010041000
+
+#endif
+#endif
diff --git a/cipher/des.c b/cipher/des.c
index 6611fd3..bc2a474 100644
--- a/cipher/des.c
+++ b/cipher/des.c
 <at>  <at>  -119,9 +119,27  <at>  <at> 
 #include "g10lib.h"
 #include "cipher.h"
 #include "bufhelp.h"
+#include "cipher-selftest.h"
+
+
+#define DES_BLOCKSIZE 8
+
+
+/* USE_AMD64_ASM indicates whether to use AMD64 assembly code. */
+#undef USE_AMD64_ASM
+#if defined(__x86_64__) && defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS)
+# define USE_AMD64_ASM 1
+#endif
+
+/* Helper macro to force alignment to 16 bytes.  */
+#ifdef HAVE_GCC_ATTRIBUTE_ALIGNED
+# define ATTR_ALIGNED_16  __attribute__ ((aligned (16)))
+#else
+# define ATTR_ALIGNED_16
+#endif
 
 #if defined(__GNUC__) && defined(__GNU_LIBRARY__)
-#define working_memcmp memcmp
+# define working_memcmp memcmp
 #else
 /*
  * According to the SunOS man page, memcmp returns indeterminate sign
 <at>  <at>  -171,6 +189,12  <at>  <at>  static int tripledes_ecb_crypt (struct _tripledes_ctx *,
                                 const byte *, byte *, int);
 static int is_weak_key ( const byte *key );
 static const char *selftest (void);
+static unsigned int do_tripledes_encrypt(void *context, byte *outbuf,
+					 const byte *inbuf );
+static unsigned int do_tripledes_decrypt(void *context, byte *outbuf,
+					 const byte *inbuf );
+static gcry_err_code_t do_tripledes_setkey(void *context, const byte *key,
+                                           unsigned keylen);
 
 static int initialized;
 
 <at>  <at>  -727,6 +751,46  <at>  <at>  tripledes_set3keys (struct _tripledes_ctx *ctx,
 
 
 
+#ifdef USE_AMD64_ASM
+
+/* Assembly implementation of triple-DES. */
+extern void _gcry_3des_amd64_crypt_block(const void *keys, byte *out,
+                                         const byte *in);
+
+/* These assembly implementations process three blocks in parallel. */
+extern void _gcry_3des_amd64_ctr_enc(const void *keys, byte *out,
+                                     const byte *in, byte *ctr);
+
+extern void _gcry_3des_amd64_cbc_dec(const void *keys, byte *out,
+                                     const byte *in, byte *iv);
+
+extern void _gcry_3des_amd64_cfb_dec(const void *keys, byte *out,
+                                     const byte *in, byte *iv);
+
+#define TRIPLEDES_ECB_BURN_STACK (8 * sizeof(void *))
+
+/*
+ * Electronic Codebook Mode Triple-DES encryption/decryption of data
+ * according to 'mode'.  Sometimes this mode is named 'EDE' mode
+ * (Encryption-Decryption-Encryption).
+ */
+static inline int
+tripledes_ecb_crypt (struct _tripledes_ctx *ctx, const byte * from,
+                     byte * to, int mode)
+{
+  u32 *keys;
+
+  keys = mode ? ctx->decrypt_subkeys : ctx->encrypt_subkeys;
+
+  _gcry_3des_amd64_crypt_block(keys, to, from);
+
+  return 0;
+}
+
+#else /*USE_AMD64_ASM*/
+
+#define TRIPLEDES_ECB_BURN_STACK 32
+
 /*
  * Electronic Codebook Mode Triple-DES encryption/decryption of data
  * according to 'mode'.  Sometimes this mode is named 'EDE' mode
 <at>  <at>  -777,8 +841,158  <at>  <at>  tripledes_ecb_crypt (struct _tripledes_ctx *ctx, const byte * from,
   return 0;
 }
 
+#endif /*!USE_AMD64_ASM*/
+
+
+
+/* Bulk encryption of complete blocks in CTR mode.  This function is only
+   intended for the bulk encryption feature of cipher.c.  CTR is expected to be
+   of size DES_BLOCKSIZE. */
+void
+_gcry_3des_ctr_enc(void *context, unsigned char *ctr, void *outbuf_arg,
+                   const void *inbuf_arg, size_t nblocks)
+{
+  struct _tripledes_ctx *ctx = context;
+  unsigned char *outbuf = outbuf_arg;
+  const unsigned char *inbuf = inbuf_arg;
+  unsigned char tmpbuf[DES_BLOCKSIZE];
+  int burn_stack_depth = TRIPLEDES_ECB_BURN_STACK;
+  int i;
+
+#ifdef USE_AMD64_ASM
+  {
+    int asm_burn_depth = 9 * sizeof(void *);
+
+    if (nblocks >= 3 && burn_stack_depth < asm_burn_depth)
+      burn_stack_depth = asm_burn_depth;
+
+    /* Process data in 3 block chunks. */
+    while (nblocks >= 3)
+      {
+        _gcry_3des_amd64_ctr_enc(ctx->encrypt_subkeys, outbuf, inbuf, ctr);
+
+        nblocks -= 3;
+        outbuf += 3 * DES_BLOCKSIZE;
+        inbuf  += 3 * DES_BLOCKSIZE;
+      }
+
+    /* Use generic code to handle smaller chunks... */
+  }
+#endif
+
+  for ( ;nblocks; nblocks-- )
+    {
+      /* Encrypt the counter. */
+      tripledes_ecb_encrypt (ctx, ctr, tmpbuf);
+      /* XOR the input with the encrypted counter and store in output.  */
+      buf_xor(outbuf, tmpbuf, inbuf, DES_BLOCKSIZE);
+      outbuf += DES_BLOCKSIZE;
+      inbuf  += DES_BLOCKSIZE;
+      /* Increment the counter.  */
+      for (i = DES_BLOCKSIZE; i > 0; i--)
+        {
+          ctr[i-1]++;
+          if (ctr[i-1])
+            break;
+        }
+    }
+
+  wipememory(tmpbuf, sizeof(tmpbuf));
+  _gcry_burn_stack(burn_stack_depth);
+}
+
+
+/* Bulk decryption of complete blocks in CBC mode.  This function is only
+   intended for the bulk encryption feature of cipher.c. */
+void
+_gcry_3des_cbc_dec(void *context, unsigned char *iv, void *outbuf_arg,
+                   const void *inbuf_arg, size_t nblocks)
+{
+  struct _tripledes_ctx *ctx = context;
+  unsigned char *outbuf = outbuf_arg;
+  const unsigned char *inbuf = inbuf_arg;
+  unsigned char savebuf[DES_BLOCKSIZE];
+  int burn_stack_depth = TRIPLEDES_ECB_BURN_STACK;
+
+#ifdef USE_AMD64_ASM
+  {
+    int asm_burn_depth = 10 * sizeof(void *);
+
+    if (nblocks >= 3 && burn_stack_depth < asm_burn_depth)
+      burn_stack_depth = asm_burn_depth;
+
+    /* Process data in 3 block chunks. */
+    while (nblocks >= 3)
+      {
+        _gcry_3des_amd64_cbc_dec(ctx->decrypt_subkeys, outbuf, inbuf, iv);
+
+        nblocks -= 3;
+        outbuf += 3 * DES_BLOCKSIZE;
+        inbuf  += 3 * DES_BLOCKSIZE;
+      }
+
+    /* Use generic code to handle smaller chunks... */
+  }
+#endif
+
+  for ( ;nblocks; nblocks-- )
+    {
+      /* INBUF is needed later and it may be identical to OUTBUF, so store
+         the intermediate result to SAVEBUF.  */
+      tripledes_ecb_decrypt (ctx, inbuf, savebuf);
+
+      buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, DES_BLOCKSIZE);
+      inbuf += DES_BLOCKSIZE;
+      outbuf += DES_BLOCKSIZE;
+    }
+
+  wipememory(savebuf, sizeof(savebuf));
+  _gcry_burn_stack(burn_stack_depth);
+}
+
+
+/* Bulk decryption of complete blocks in CFB mode.  This function is only
+   intended for the bulk encryption feature of cipher.c. */
+void
+_gcry_3des_cfb_dec(void *context, unsigned char *iv, void *outbuf_arg,
+		   const void *inbuf_arg, size_t nblocks)
+{
+  struct _tripledes_ctx *ctx = context;
+  unsigned char *outbuf = outbuf_arg;
+  const unsigned char *inbuf = inbuf_arg;
+  int burn_stack_depth = TRIPLEDES_ECB_BURN_STACK;
+
+#ifdef USE_AMD64_ASM
+  {
+    int asm_burn_depth = 9 * sizeof(void *);
+
+    if (nblocks >= 3 && burn_stack_depth < asm_burn_depth)
+      burn_stack_depth = asm_burn_depth;
 
+    /* Process data in 3 block chunks. */
+    while (nblocks >= 3)
+      {
+        _gcry_3des_amd64_cfb_dec(ctx->encrypt_subkeys, outbuf, inbuf, iv);
 
+        nblocks -= 3;
+        outbuf += 3 * DES_BLOCKSIZE;
+        inbuf  += 3 * DES_BLOCKSIZE;
+      }
+
+    /* Use generic code to handle smaller chunks... */
+  }
+#endif
+
+  for ( ;nblocks; nblocks-- )
+    {
+      tripledes_ecb_encrypt (ctx, iv, iv);
+      buf_xor_n_copy(outbuf, iv, inbuf, DES_BLOCKSIZE);
+      outbuf += DES_BLOCKSIZE;
+      inbuf  += DES_BLOCKSIZE;
+    }
+
+  _gcry_burn_stack(burn_stack_depth);
+}
 
 
 /*
 <at>  <at>  -815,6 +1029,67  <at>  <at>  is_weak_key ( const byte *key )
 }
 
 
+/* Alternative setkey for selftests; need larger key than default. */
+static gcry_err_code_t
+bulk_selftest_setkey (void *context, const byte *__key, unsigned __keylen)
+{
+  static const unsigned char key[24] ATTR_ALIGNED_16 = {
+      0x66,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F,
+      0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x22,
+      0x18,0x2A,0x39,0x47,0x5E,0x6F,0x75,0x82
+    };
+
+  (void)__key;
+  (void)__keylen;
+
+  return do_tripledes_setkey(context, key, sizeof(key));
+}
+
+
+/* Run the self-tests for DES-CTR, tests IV increment of bulk CTR
+   encryption.  Returns NULL on success. */
+static const char *
+selftest_ctr (void)
+{
+  const int nblocks = 3+1;
+  const int blocksize = DES_BLOCKSIZE;
+  const int context_size = sizeof(struct _tripledes_ctx);
+
+  return _gcry_selftest_helper_ctr("3DES", &bulk_selftest_setkey,
+           &do_tripledes_encrypt, &_gcry_3des_ctr_enc, nblocks, blocksize,
+           context_size);
+}
+
+
+/* Run the self-tests for DES-CBC, tests bulk CBC decryption.
+   Returns NULL on success. */
+static const char *
+selftest_cbc (void)
+{
+  const int nblocks = 3+2;
+  const int blocksize = DES_BLOCKSIZE;
+  const int context_size = sizeof(struct _tripledes_ctx);
+
+  return _gcry_selftest_helper_cbc("3DES", &bulk_selftest_setkey,
+           &do_tripledes_encrypt, &_gcry_3des_cbc_dec, nblocks, blocksize,
+           context_size);
+}
+
+
+/* Run the self-tests for DES-CFB, tests bulk CBC decryption.
+   Returns NULL on success. */
+static const char *
+selftest_cfb (void)
+{
+  const int nblocks = 3+2;
+  const int blocksize = DES_BLOCKSIZE;
+  const int context_size = sizeof(struct _tripledes_ctx);
+
+  return _gcry_selftest_helper_cfb("3DES", &bulk_selftest_setkey,
+           &do_tripledes_encrypt, &_gcry_3des_cfb_dec, nblocks, blocksize,
+           context_size);
+}
+
 
 /*
  * Performs a selftest of this DES/Triple-DES implementation.
 <at>  <at>  -824,6 +1099,8  <at>  <at>  is_weak_key ( const byte *key )
 static const char *
 selftest (void)
 {
+  const char *r;
+
   /*
    * Check if 'u32' is really 32 bits wide. This DES / 3DES implementation
    * need this.
 <at>  <at>  -1003,6 +1280,15  <at>  <at>  selftest (void)
         return "DES weak key detection failed";
   }
 
+  if ( (r = selftest_cbc ()) )
+    return r;
+
+  if ( (r = selftest_cfb ()) )
+    return r;
+
+  if ( (r = selftest_ctr ()) )
+    return r;
+
   return 0;
 }
 
 <at>  <at>  -1060,7 +1346,7  <at>  <at>  do_tripledes_encrypt( void *context, byte *outbuf, const byte *inbuf )
   struct _tripledes_ctx *ctx = (struct _tripledes_ctx *) context;
 
   tripledes_ecb_encrypt ( ctx, inbuf, outbuf );
-  return /*burn_stack*/ (32);
+  return /*burn_stack*/ TRIPLEDES_ECB_BURN_STACK;
 }
 
 static unsigned int
 <at>  <at>  -1068,7 +1354,7  <at>  <at>  do_tripledes_decrypt( void *context, byte *outbuf, const byte *inbuf )
 {
   struct _tripledes_ctx *ctx = (struct _tripledes_ctx *) context;
   tripledes_ecb_decrypt ( ctx, inbuf, outbuf );
-  return /*burn_stack*/ (32);
+  return /*burn_stack*/ TRIPLEDES_ECB_BURN_STACK;
 }
 
 static gcry_err_code_t
diff --git a/configure.ac b/configure.ac
index a0f75a5..79f79ef 100644
--- a/configure.ac
+++ b/configure.ac
 <at>  <at>  -1671,6 +1671,13  <at>  <at>  LIST_MEMBER(des, $enabled_ciphers)
 if test "$found" = "1" ; then
    GCRYPT_CIPHERS="$GCRYPT_CIPHERS des.lo"
    AC_DEFINE(USE_DES, 1, [Defined if this module should be included])
+
+   case "${host}" in
+      x86_64-*-*)
+         # Build with the assembly implementation
+         GCRYPT_CIPHERS="$GCRYPT_CIPHERS des-amd64.lo"
+      ;;
+   esac
 fi
 
 LIST_MEMBER(aes, $enabled_ciphers)
diff --git a/src/cipher.h b/src/cipher.h
index cd981b3..5d1b5f6 100644
--- a/src/cipher.h
+++ b/src/cipher.h
 <at>  <at>  -173,6 +173,19  <at>  <at>  void _gcry_camellia_cfb_dec (void *context, unsigned char *iv,
                              void *outbuf_arg, const void *inbuf_arg,
                              size_t nblocks);
 
+/*-- des.c --*/
+void _gcry_3des_ctr_enc (void *context, unsigned char *ctr,
+                         void *outbuf_arg, const void *inbuf_arg,
+                         size_t nblocks);
+
+void _gcry_3des_cbc_dec (void *context, unsigned char *iv,
+                         void *outbuf_arg, const void *inbuf_arg,
+                         size_t nblocks);
+
+void _gcry_3des_cfb_dec (void *context, unsigned char *iv,
+                         void *outbuf_arg, const void *inbuf_arg,
+                         size_t nblocks);
+
 /*-- serpent.c --*/
 void _gcry_serpent_ctr_enc (void *context, unsigned char *ctr,
                             void *outbuf_arg, const void *inbuf_arg,
Konstantin Pavlov | 25 Mar 10:55 2014

x86_64 Darwin build fix

This patch fixes build error observed on current Darwin platform with asm
enabled:

libtool: compile:  gcc -DHAVE_CONFIG_H -I. -I.. -I../src -I../src
-g -O2 -MT mpih-mul1-asm.lo -MD -MP -MF .deps/mpih-mul1-asm.Tpo -c
mpih-mul1-asm.S -fno-common -DPIC -o .libs/mpih-mul1-asm.o
mpih-mul1-asm.S:43:9: error: invalid alignment value
 .align 1<<(5)
         ^
make[2]: *** [mpih-mul1-asm.lo] Error 1

--

-- 
VideoLAN
Konstantin Pavlov
http://www.videolan.org
Mobile: +7 926 165 45 31
Skype: cryothresh
Twitter:  <at> cryothresh
_______________________________________________
Gcrypt-devel mailing list
Gcrypt-devel <at> gnupg.org
http://lists.gnupg.org/mailman/listinfo/gcrypt-devel
Dmitry Eremin-Solenikov | 23 Mar 21:18 2014
Picon

Parameters/gcryctl to digest algorithms?

Hello,

I'm trying to extend GOST R 34.11-94 support in libgcrypt.
The problem is a selection of S-box to be used in compression function.
Currently algo is limited to the S-Box defined in the standard itself.

Initially I have hacked a version supporting CryptoPro S-Box (as required
by RFC4357) just by introducing another algorithm using that s-box.
However after looking at Ukrainian (DSTU) standards (order #114 dating
12.06.2007), I decided that it might be not so good idea. That order
defines several more s-boxes, with at least one of them used for
digest calculation. I can add another algo for that s-box, however I fear
that it would be an overkill. I was also thinking about reusing
flags part of md_open() call, but also couldn't come up with a good
enough solution.

What would be your thoughts?

--

-- 
With best wishes
Dmitry

Gmane