[git] GCRYPT - branch, master, updated. libgcrypt-1.5.0-168-gc488509

by Werner Koch cvs at cvs.gnupg.org
Thu Jul 18 22:04:59 CEST 2013


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  c4885092088431e7928e4459fda20cc0e8ceb201 (commit)
       via  f6d6e0200fa823d377a342efacaf3d61e4303dc3 (commit)
       via  364d019e3ffedfcb434576702f73e767cb9389ef (commit)
       via  5940e66cbefea3de5924f494f18aed69bb694bff (commit)
      from  6e1adb05d290aeeb1c230c763970695f4a538526 (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 c4885092088431e7928e4459fda20cc0e8ceb201
Author: Werner Koch <wk at gnupg.org>
Date:   Thu Jul 18 21:32:05 2013 +0200

    Add support for Salsa20.
    
    * src/gcrypt.h.in (GCRY_CIPHER_SALSA20): New.
    * cipher/salsa20.c: New.
    * configure.ac (available_ciphers): Add Salsa20.
    * cipher/cipher.c: Register Salsa20.
    (cipher_setiv): Allow to divert an IV to a cipher module.
    * src/cipher-proto.h (cipher_setiv_func_t): New.
    (cipher_extra_spec): Add field setiv.
    * src/cipher.h: Declare Salsa20 definitions.
    * tests/basic.c (check_stream_cipher): New.
    (check_stream_cipher_large_block): New.
    (check_cipher_modes): Run new test functions.
    (check_ciphers): Add simple test for Salsa20.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/NEWS b/NEWS
index ac60993..b1ad7ac 100644
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,8 @@ Noteworthy changes in version 1.6.0 (unreleased)
 
  * Added support for the IDEA cipher algorithm.
 
+ * Added support for the Salsa20 stream cipher.
+
  * Added a random number generator to directly use the system's RNG.
    Also added an interface to prefer the use of a specified RNG.
 
@@ -70,6 +72,7 @@ Noteworthy changes in version 1.6.0 (unreleased)
  gcry_pubkey_get_sexp            NEW.
  GCRYCTL_DISABLE_LOCKED_SECMEM   NEW.
  GCRYCTL_DISABLE_PRIV_DROP       NEW.
+ GCRY_CIPHER_SALSA20             NEW.
 
 
 Noteworthy changes in version 1.5.0 (2011-06-29)
diff --git a/cipher/Makefile.am b/cipher/Makefile.am
index c2a94c5..75ad987 100644
--- a/cipher/Makefile.am
+++ b/cipher/Makefile.am
@@ -67,6 +67,7 @@ md5.c \
 rijndael.c rijndael-tables.h rijndael-amd64.S \
 rmd160.c \
 rsa.c \
+salsa20.c \
 scrypt.c \
 seed.c \
 serpent.c serpent-sse2-amd64.S serpent-avx2-amd64.S \
diff --git a/cipher/cipher.c b/cipher/cipher.c
index d7ebea8..08d6165 100644
--- a/cipher/cipher.c
+++ b/cipher/cipher.c
@@ -104,6 +104,10 @@ static struct cipher_table_entry
     { &_gcry_cipher_spec_idea,
       &dummy_extra_spec,                  GCRY_CIPHER_IDEA },
 #endif
+#if USE_SALSA20
+    { &_gcry_cipher_spec_salsa20,
+      &_gcry_cipher_extraspec_salsa20,    GCRY_CIPHER_SALSA20 },
+#endif
     { NULL                    }
   };
 
@@ -845,8 +849,16 @@ cipher_setkey (gcry_cipher_hd_t c, byte *key, unsigned int keylen)
 /* Set the IV to be used for the encryption context C to IV with
    length IVLEN.  The length should match the required length. */
 static void
-cipher_setiv( gcry_cipher_hd_t c, const byte *iv, unsigned ivlen )
+cipher_setiv (gcry_cipher_hd_t c, const byte *iv, unsigned ivlen)
 {
+  /* If the cipher has its own IV handler, we use only this one.  This
+     is currently used for stream ciphers requiring a nonce.  */
+  if (c->extraspec && c->extraspec->setiv)
+    {
+      c->extraspec->setiv (&c->context.c, iv, ivlen);
+      return;
+    }
+
   memset (c->u_iv.iv, 0, c->cipher->blocksize);
   if (iv)
     {
diff --git a/cipher/salsa20.c b/cipher/salsa20.c
new file mode 100644
index 0000000..e26c328
--- /dev/null
+++ b/cipher/salsa20.c
@@ -0,0 +1,380 @@
+/* salsa20.c  -  Bernstein's Salsa20 cipher
+ * Copyright (C) 2012 Simon Josefsson, Niels Möller
+ * Copyright (C) 2013 g10 Code GmbH
+ *
+ * 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/>.
+ *
+ * For a description of the algorithm, see:
+ *   http://cr.yp.to/snuffle/spec.pdf
+ *   http://cr.yp.to/snuffle/design.pdf
+ */
+
+/* The code is based on the code in Nettle
+   (git commit id 9d2d8ddaee35b91a4e1a32ae77cba04bea3480e7)
+   which in turn is based on
+   salsa20-ref.c version 20051118
+   D. J. Bernstein
+   Public domain.
+*/
+
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "types.h"
+#include "g10lib.h"
+#include "cipher.h"
+#include "bufhelp.h"
+
+#define SALSA20_MIN_KEY_SIZE 16  /* Bytes.  */
+#define SALSA20_MAX_KEY_SIZE 32  /* Bytes.  */
+#define SALSA20_BLOCK_SIZE   64  /* Bytes.  */
+#define SALSA20_IV_SIZE       8  /* Bytes.  */
+#define SALSA20_INPUT_LENGTH 16  /* Bytes.  */
+
+/* Number of rounds.  The standard uses 20 rounds.  In any case the
+   number of rounds must be even.  */
+#define SALSA20_ROUNDS       20
+
+
+typedef struct
+{
+  /* Indices 1-4 and 11-14 holds the key (two identical copies for the
+     shorter key size), indices 0, 5, 10, 15 are constant, indices 6, 7
+     are the IV, and indices 8, 9 are the block counter:
+
+     C K K K
+     K C I I
+     B B C K
+     K K K C
+  */
+  u32 input[SALSA20_INPUT_LENGTH];
+  u32 pad[SALSA20_INPUT_LENGTH];
+  unsigned int unused; /* bytes in the pad.  */
+} SALSA20_context_t;
+
+
+/* The masking of the right shift is needed to allow n == 0 (using
+   just 32 - n and 64 - n results in undefined behaviour). Most uses
+   of these macros use a constant and non-zero rotation count. */
+#define ROTL32(n,x) (((x)<<(n)) | ((x)>>((-(n)&31))))
+
+
+#ifdef WORDS_BIGENDIAN
+# define LE_SWAP32(v)              \
+  ( (ROTL32( 8, v) & 0x00FF00FFul) \
+   |(ROTL32(24, v) & 0xFF00FF00ul))
+#else
+# define LE_SWAP32(v) (v)
+#endif
+
+#define LE_READ_UINT32(p)                 \
+  (  (((u32)(p)[3]) << 24)                \
+   | (((u32)(p)[2]) << 16)                \
+   | (((u32)(p)[1]) << 8)                 \
+   |  ((u32)(p)[0]))
+
+
+static void salsa20_setiv (void *context, const byte *iv, unsigned int ivlen);
+static const char *selftest (void);
+
+

+
+#if 0
+# define SALSA20_CORE_DEBUG(i) do {		\
+    unsigned debug_j;				\
+    for (debug_j = 0; debug_j < 16; debug_j++)	\
+      {						\
+	if (debug_j == 0)			\
+	  fprintf(stderr, "%2d:", (i));		\
+	else if (debug_j % 4 == 0)		\
+	  fprintf(stderr, "\n   ");		\
+	fprintf(stderr, " %8x", pad[debug_j]);	\
+      }						\
+    fprintf(stderr, "\n");			\
+  } while (0)
+#else
+# define SALSA20_CORE_DEBUG(i)
+#endif
+
+#define QROUND(x0, x1, x2, x3)      \
+  do {                              \
+    x1 ^= ROTL32 ( 7, x0 + x3);	    \
+    x2 ^= ROTL32 ( 9, x1 + x0);	    \
+    x3 ^= ROTL32 (13, x2 + x1);	    \
+    x0 ^= ROTL32 (18, x3 + x2);	    \
+  } while(0)
+
+static void
+salsa20_core (u32 *dst, const u32 *src)
+{
+  u32 pad[SALSA20_INPUT_LENGTH];
+  unsigned int i;
+
+  memcpy (pad, src, sizeof(pad));
+  for (i = 0; i < SALSA20_ROUNDS; i += 2)
+    {
+      SALSA20_CORE_DEBUG (i);
+      QROUND (pad[0],  pad[4],  pad[8],  pad[12]);
+      QROUND (pad[5],  pad[9],  pad[13], pad[1] );
+      QROUND (pad[10], pad[14], pad[2],  pad[6] );
+      QROUND (pad[15], pad[3],  pad[7],  pad[11]);
+
+      SALSA20_CORE_DEBUG (i+1);
+      QROUND (pad[0],  pad[1],  pad[2],  pad[3] );
+      QROUND (pad[5],  pad[6],  pad[7],  pad[4] );
+      QROUND (pad[10], pad[11], pad[8],  pad[9] );
+      QROUND (pad[15], pad[12], pad[13], pad[14]);
+    }
+  SALSA20_CORE_DEBUG (i);
+
+  for (i = 0; i < SALSA20_INPUT_LENGTH; i++)
+    {
+      u32 t = pad[i] + src[i];
+      dst[i] = LE_SWAP32 (t);
+    }
+}
+#undef QROUND
+#undef SALSA20_CORE_DEBUG
+
+static gcry_err_code_t
+salsa20_do_setkey (SALSA20_context_t *ctx,
+                   const byte *key, unsigned int keylen)
+{
+  static int initialized;
+  static const char *selftest_failed;
+
+  if (!initialized )
+    {
+      initialized = 1;
+      selftest_failed = selftest ();
+      if (selftest_failed)
+        log_error ("SALSA20 selftest failed (%s)\n", selftest_failed );
+    }
+  if (selftest_failed)
+    return GPG_ERR_SELFTEST_FAILED;
+
+  if (keylen != SALSA20_MIN_KEY_SIZE
+      && keylen != SALSA20_MAX_KEY_SIZE)
+    return GPG_ERR_INV_KEYLEN;
+
+  /* These constants are the little endian encoding of the string
+     "expand 32-byte k".  For the 128 bit variant, the "32" in that
+     string will be fixed up to "16".  */
+  ctx->input[0]  = 0x61707865; /* "apxe"  */
+  ctx->input[5]  = 0x3320646e; /* "3 dn"  */
+  ctx->input[10] = 0x79622d32; /* "yb-2"  */
+  ctx->input[15] = 0x6b206574; /* "k et"  */
+
+  ctx->input[1] = LE_READ_UINT32(key + 0);
+  ctx->input[2] = LE_READ_UINT32(key + 4);
+  ctx->input[3] = LE_READ_UINT32(key + 8);
+  ctx->input[4] = LE_READ_UINT32(key + 12);
+  if (keylen == SALSA20_MAX_KEY_SIZE) /* 256 bits */
+    {
+      ctx->input[11] = LE_READ_UINT32(key + 16);
+      ctx->input[12] = LE_READ_UINT32(key + 20);
+      ctx->input[13] = LE_READ_UINT32(key + 24);
+      ctx->input[14] = LE_READ_UINT32(key + 28);
+    }
+  else  /* 128 bits */
+    {
+      ctx->input[11] = ctx->input[1];
+      ctx->input[12] = ctx->input[2];
+      ctx->input[13] = ctx->input[3];
+      ctx->input[14] = ctx->input[4];
+
+      ctx->input[5]  -= 0x02000000; /* Change to "1 dn".  */
+      ctx->input[10] += 0x00000004; /* Change to "yb-6".  */
+    }
+
+  /* We default to a zero nonce.  */
+  salsa20_setiv (ctx, NULL, 0);
+
+  return 0;
+}
+
+
+static gcry_err_code_t
+salsa20_setkey (void *context, const byte *key, unsigned int keylen)
+{
+  SALSA20_context_t *ctx = (SALSA20_context_t *)context;
+  gcry_err_code_t rc = salsa20_do_setkey (ctx, key, keylen);
+  _gcry_burn_stack (300/* FIXME*/);
+  return rc;
+}
+
+
+static void
+salsa20_setiv (void *context, const byte *iv, unsigned int ivlen)
+{
+  SALSA20_context_t *ctx = (SALSA20_context_t *)context;
+
+  if (!iv)
+    {
+      ctx->input[6] = 0;
+      ctx->input[7] = 0;
+    }
+  else if (ivlen == SALSA20_IV_SIZE)
+    {
+      ctx->input[6] = LE_READ_UINT32(iv + 0);
+      ctx->input[7] = LE_READ_UINT32(iv + 4);
+    }
+  else
+    {
+      log_info ("WARNING: salsa20_setiv: bad ivlen=%u\n", ivlen);
+      ctx->input[6] = 0;
+      ctx->input[7] = 0;
+    }
+  /* Reset the block counter.  */
+  ctx->input[8] = 0;
+  ctx->input[9] = 0;
+  /* Reset the unused pad bytes counter.  */
+  ctx->unused = 0;
+}
+
+
+

+/* Note: This function requires LENGTH > 0.  */
+static void
+salsa20_do_encrypt_stream (SALSA20_context_t *ctx,
+                           byte *outbuf, const byte *inbuf,
+                           unsigned int length)
+{
+  if (ctx->unused)
+    {
+      unsigned char *p = (void*)ctx->pad;
+      unsigned int n;
+
+      gcry_assert (ctx->unused < SALSA20_BLOCK_SIZE);
+
+      n = ctx->unused;
+      if (n > length)
+        n = length;
+      buf_xor (outbuf, inbuf, p + SALSA20_BLOCK_SIZE - ctx->unused, n);
+      length -= n;
+      outbuf += n;
+      inbuf  += n;
+      ctx->unused -= n;
+      if (!length)
+        return;
+      gcry_assert (!ctx->unused);
+    }
+
+  for (;;)
+    {
+      /* Create the next pad and bump the block counter.  Note that it
+         is the user's duty to change to another nonce not later than
+         after 2^70 processed bytes.  */
+      salsa20_core (ctx->pad, ctx->input);
+      if (!++ctx->input[8])
+        ctx->input[9]++;
+
+      if (length <= SALSA20_BLOCK_SIZE)
+	{
+	  buf_xor (outbuf, inbuf, ctx->pad, length);
+          ctx->unused = SALSA20_BLOCK_SIZE - length;
+	  return;
+	}
+      buf_xor (outbuf, inbuf, ctx->pad, SALSA20_BLOCK_SIZE);
+      length -= SALSA20_BLOCK_SIZE;
+      outbuf += SALSA20_BLOCK_SIZE;
+      inbuf  += SALSA20_BLOCK_SIZE;
+  }
+}
+
+
+static void
+salsa20_encrypt_stream (void *context,
+                        byte *outbuf, const byte *inbuf, unsigned int length)
+{
+  SALSA20_context_t *ctx = (SALSA20_context_t *)context;
+
+  if (length)
+    {
+      salsa20_do_encrypt_stream (ctx, outbuf, inbuf, length);
+      _gcry_burn_stack (/* salsa20_do_encrypt_stream: */
+                        2*sizeof (void*)
+                        + 3*sizeof (void*) + sizeof (unsigned int)
+                        /* salsa20_core: */
+                        + 2*sizeof (void*)
+                        + 2*sizeof (void*)
+                        + 64
+                        + sizeof (unsigned int)
+                        + sizeof (u32)
+                        );
+    }
+}
+
+
+
+static const char*
+selftest (void)
+{
+  SALSA20_context_t ctx;
+  byte scratch[8+1];
+
+  static byte key_1[] =
+    { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+  static const byte nonce_1[] =
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+  static const byte plaintext_1[] =
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+  static const byte ciphertext_1[] =
+    { 0xE3, 0xBE, 0x8F, 0xDD, 0x8B, 0xEC, 0xA2, 0xE3};
+
+  salsa20_setkey (&ctx, key_1, sizeof key_1);
+  salsa20_setiv  (&ctx, nonce_1, sizeof nonce_1);
+  scratch[8] = 0;
+  salsa20_encrypt_stream (&ctx, scratch, plaintext_1, sizeof plaintext_1);
+  if (memcmp (scratch, ciphertext_1, sizeof ciphertext_1))
+    return "Salsa20 encryption test 1 failed.";
+  if (scratch[8])
+    return "Salsa20 wrote too much.";
+  salsa20_setkey( &ctx, key_1, sizeof(key_1));
+  salsa20_setiv  (&ctx, nonce_1, sizeof nonce_1);
+  salsa20_encrypt_stream (&ctx, scratch, scratch, sizeof plaintext_1);
+  if (memcmp (scratch, plaintext_1, sizeof plaintext_1))
+    return "Salsa20 decryption test 1 failed.";
+  return NULL;
+}
+
+
+gcry_cipher_spec_t _gcry_cipher_spec_salsa20 =
+  {
+    "SALSA20",  /* name */
+    NULL,       /* aliases */
+    NULL,       /* oids */
+    1,          /* blocksize in bytes. */
+    SALSA20_MAX_KEY_SIZE*8,  /* standard key length in bits. */
+    sizeof (SALSA20_context_t),
+    salsa20_setkey,
+    NULL,
+    NULL,
+    salsa20_encrypt_stream,
+    salsa20_encrypt_stream
+  };
+
+cipher_extra_spec_t _gcry_cipher_extraspec_salsa20 =
+  {
+    NULL,
+    NULL,
+    salsa20_setiv
+  };
diff --git a/configure.ac b/configure.ac
index 13541bb..06c0b79 100644
--- a/configure.ac
+++ b/configure.ac
@@ -184,7 +184,7 @@ LIBGCRYPT_CONFIG_HOST="$host"
 
 # Definitions for symmetric ciphers.
 available_ciphers="arcfour blowfish cast5 des aes twofish serpent rfc2268 seed"
-available_ciphers="$available_ciphers camellia idea"
+available_ciphers="$available_ciphers camellia idea salsa20"
 enabled_ciphers=""
 
 # Definitions for public-key ciphers.
@@ -1356,6 +1356,12 @@ if test "$found" = "1" ; then
    AC_DEFINE(USE_IDEA, 1, [Defined if this module should be included])
 fi
 
+LIST_MEMBER(salsa20, $enabled_ciphers)
+if test "$found" = "1" ; then
+   GCRYPT_CIPHERS="$GCRYPT_CIPHERS salsa20.lo"
+   AC_DEFINE(USE_SALSA20, 1, [Defined if this module should be included])
+fi
+
 LIST_MEMBER(dsa, $enabled_pubkey_ciphers)
 if test "$found" = "1" ; then
    GCRYPT_PUBKEY_CIPHERS="$GCRYPT_PUBKEY_CIPHERS dsa.lo"
diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
index 4d24475..cfc0174 100644
--- a/doc/gcrypt.texi
+++ b/doc/gcrypt.texi
@@ -1487,8 +1487,7 @@ The value always evaluates to false.
 
 @item GCRY_CIPHER_IDEA
 @cindex IDEA
-This is the IDEA algorithm.  The constant is provided but there is
-currently no implementation for it because the algorithm is patented.
+This is the IDEA algorithm.
 
 @item GCRY_CIPHER_3DES
 @cindex 3DES
@@ -1576,6 +1575,10 @@ A 128 bit cipher as described by RFC4269.
 The Camellia cipher by NTT.  See
 @uref{http://info.isl.ntt.co.jp/@/crypt/@/eng/@/camellia/@/specifications.html}.
 
+ at item GCRY_CIPHER_SALSA20
+ at cindex Salsa20
+This is the Salsa20 stream cipher.
+
 @end table
 
 @node Available cipher modes
@@ -1717,6 +1720,10 @@ Set the initialization vector used for encryption or decryption. The
 vector is passed as the buffer @var{K} of length @var{l} bytes and
 copied to internal data structures.  The function checks that the IV
 matches the requirement of the selected algorithm and mode.
+
+This function is also used with the Salsa20 stream cipher to set or
+update the required nonce.  In this case it needs to be called after
+setting the key.
 @end deftypefun
 
 @deftypefun gcry_error_t gcry_cipher_setctr (gcry_cipher_hd_t @var{h}, const void *@var{c}, size_t @var{l})
@@ -2356,6 +2363,34 @@ format should be used:
 Here, the data to be signed is directly given as an @var{MPI}.
 
 @noindent
+For DSA the input data is expected in this format:
+ at example
+(data
+  (flags raw)
+  (value @var{mpi}))
+ at end example
+
+ at noindent
+Here, the data to be signed is directly given as an @var{MPI}.  It is
+expect that this MPI is the the hash value.  For the standard DSA
+using a MPI is not a problem in regard to leading zeroes because the
+hash value is directly used as an MPI.  For better standard
+conformance it would be better to explicit use a memory string (like
+with pkcs1) but that is currently not supported.  However, for
+deterministic DSA as specified in RFC6979 this can't be used.  Instead
+the following input is expected.
+
+ at example
+(data
+  (flags rfc6979)
+  (hash @var{hash-algo} @var{block}))
+ at end example
+
+Note that the provided hash-algo is used for the internal HMAC; it
+should match the hash-algo used to create @var{block}.
+
+
+ at noindent
 The signature is returned as a newly allocated S-expression in
 @var{r_sig} using this format for RSA:
 
@@ -2380,6 +2415,7 @@ operation.  For Elgamal signing (which is slow, yields large numbers
 and probably is not as secure as the other algorithms), the same format is
 used with "elg" replacing "dsa"; for ECDSA signing, the same format is used
 with "ecdsa" replacing "dsa".
+
 @end deftypefun
 @c end gcry_pk_sign
 
@@ -4115,7 +4151,10 @@ value.  Two functions implement this kludge:
 Store @var{nbits} of the value @var{p} points to in @var{a} and mark
 @var{a} as an opaque value (i.e. an value that can't be used for any
 math calculation and is only used to store an arbitrary bit pattern in
- at var{a}).
+ at var{a}).  Ownership of @var{p} is taken by this function and thus the
+user may not use dereference the passed value anymore.  It is required
+that them memory referenced by @var{p} has been allocated in a way
+that @code{gcry_free} is able to release it.
 
 WARNING: Never use an opaque MPI for actual math operations.  The only
 valid functions are gcry_mpi_get_opaque and gcry_mpi_release.  Use
diff --git a/src/cipher-proto.h b/src/cipher-proto.h
index e2f913d..e9f4bab 100644
--- a/src/cipher-proto.h
+++ b/src/cipher-proto.h
@@ -68,6 +68,9 @@ typedef gcry_sexp_t (*pk_get_curve_param_t)(const char *name);
 typedef gpg_err_code_t (*cipher_set_extra_info_t)
      (void *c, int what, const void *buffer, size_t buflen);
 
+/* The type used to set an IV directly in the algorithm module.  */
+typedef void (*cipher_setiv_func_t)(void *c,
+                                    const byte *iv, unsigned int ivlen);
 
 /* Extra module specification structures.  These are used for internal
    modules which provide more functions than available through the
@@ -76,6 +79,7 @@ typedef struct cipher_extra_spec
 {
   selftest_func_t selftest;
   cipher_set_extra_info_t set_extra_info;
+  cipher_setiv_func_t setiv;
 } cipher_extra_spec_t;
 
 typedef struct md_extra_spec
diff --git a/src/cipher.h b/src/cipher.h
index 2620613..bb92758 100644
--- a/src/cipher.h
+++ b/src/cipher.h
@@ -27,6 +27,7 @@
 #include "../random/random.h"
 
 #define PUBKEY_FLAG_NO_BLINDING    (1 << 0)
+#define PUBKEY_FLAG_RFC6979        (1 << 1)
 
 enum pk_operation
   {
@@ -194,12 +195,13 @@ extern gcry_cipher_spec_t _gcry_cipher_spec_camellia128;
 extern gcry_cipher_spec_t _gcry_cipher_spec_camellia192;
 extern gcry_cipher_spec_t _gcry_cipher_spec_camellia256;
 extern gcry_cipher_spec_t _gcry_cipher_spec_idea;
+extern gcry_cipher_spec_t _gcry_cipher_spec_salsa20;
 
 extern cipher_extra_spec_t _gcry_cipher_extraspec_tripledes;
 extern cipher_extra_spec_t _gcry_cipher_extraspec_aes;
 extern cipher_extra_spec_t _gcry_cipher_extraspec_aes192;
 extern cipher_extra_spec_t _gcry_cipher_extraspec_aes256;
-
+extern cipher_extra_spec_t _gcry_cipher_extraspec_salsa20;
 
 /* Declarations for the digest specifications.  */
 extern gcry_md_spec_t _gcry_digest_spec_crc32;
diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in
index 2292832..6bd615d 100644
--- a/src/gcrypt.h.in
+++ b/src/gcrypt.h.in
@@ -812,7 +812,8 @@ enum gcry_cipher_algos
     GCRY_CIPHER_SEED        = 309,  /* 128 bit cipher described in RFC4269. */
     GCRY_CIPHER_CAMELLIA128 = 310,
     GCRY_CIPHER_CAMELLIA192 = 311,
-    GCRY_CIPHER_CAMELLIA256 = 312
+    GCRY_CIPHER_CAMELLIA256 = 312,
+    GCRY_CIPHER_SALSA20     = 313
   };
 
 /* The Rijndael algorithm is basically AES, so provide some macros. */
diff --git a/tests/basic.c b/tests/basic.c
index d1b4002..88ae131 100644
--- a/tests/basic.c
+++ b/tests/basic.c
@@ -1,6 +1,7 @@
 /* basic.c  -  basic regression tests
  * Copyright (C) 2001, 2002, 2003, 2005, 2008,
  *               2009 Free Software Foundation, Inc.
+ * Copyright (C) 2013 g10 Code GmbH
  *
  * This file is part of Libgcrypt.
  *
@@ -1137,6 +1138,567 @@ check_ofb_cipher (void)
 }
 
 
+static void
+check_stream_cipher (void)
+{
+  struct tv
+  {
+    const char *name;
+    int algo;
+    int keylen;
+    int ivlen;
+    const char *key;
+    const char *iv;
+    struct data
+    {
+      int inlen;
+      const char *plaintext;
+      const char *out;
+    } data[MAX_DATA_LEN];
+  } tv[] = {
+#ifdef USE_SALSA20
+    {
+      "Salsa20 128 bit, test 1",
+      GCRY_CIPHER_SALSA20, 16, 8,
+      "\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+      "\x00\x00\x00\x00\x00\x00\x00\x00",
+      {
+        { 8,
+          "\x00\x00\x00\x00\x00\x00\x00\x00",
+          "\x4D\xFA\x5E\x48\x1D\xA2\x3E\xA0"
+        }
+      }
+    },
+    {
+      "Salsa20 128 bit, test 2",
+      GCRY_CIPHER_SALSA20, 16, 8,
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+      "\x80\x00\x00\x00\x00\x00\x00\x00",
+      {
+        { 8,
+          "\x00\x00\x00\x00\x00\x00\x00\x00",
+          "\xB6\x6C\x1E\x44\x46\xDD\x95\x57"
+        }
+      }
+    },
+    {
+      "Salsa20 128 bit, test 3",
+      GCRY_CIPHER_SALSA20, 16, 8,
+      "\x00\x53\xA6\xF9\x4C\x9F\xF2\x45\x98\xEB\x3E\x91\xE4\x37\x8A\xDD",
+      "\x0D\x74\xDB\x42\xA9\x10\x77\xDE",
+      {
+        { 8,
+          "\x00\x00\x00\x00\x00\x00\x00\x00",
+          "\x05\xE1\xE7\xBE\xB6\x97\xD9\x99"
+        }
+      }
+    },
+    {
+      "Salsa20 256 bit, test 1",
+      GCRY_CIPHER_SALSA20, 32, 8,
+      "\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+      "\x00\x00\x00\x00\x00\x00\x00\x00",
+      {
+        { 8,
+          "\x00\x00\x00\x00\x00\x00\x00\x00",
+          "\xE3\xBE\x8F\xDD\x8B\xEC\xA2\xE3"
+        }
+      }
+    },
+    {
+      "Salsa20 256 bit, test 2",
+      GCRY_CIPHER_SALSA20, 32, 8,
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+      "\x80\x00\x00\x00\x00\x00\x00\x00",
+      {
+        { 8,
+          "\x00\x00\x00\x00\x00\x00\x00\x00",
+          "\x2A\xBA\x3D\xC4\x5B\x49\x47\x00"
+        }
+      }
+    },
+    {
+      "Salsa20 256 bit, ecrypt verified, set 6, vector 0",
+      GCRY_CIPHER_SALSA20, 32, 8,
+      "\x00\x53\xA6\xF9\x4C\x9F\xF2\x45\x98\xEB\x3E\x91\xE4\x37\x8A\xDD"
+      "\x30\x83\xD6\x29\x7C\xCF\x22\x75\xC8\x1B\x6E\xC1\x14\x67\xBA\x0D",
+      "\x0D\x74\xDB\x42\xA9\x10\x77\xDE",
+      {
+        { 8,
+          "\x00\x00\x00\x00\x00\x00\x00\x00",
+          "\xF5\xFA\xD5\x3F\x79\xF9\xDF\x58"
+        },
+        { 64,
+          "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+          "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+          "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+          "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+          "\xF5\xFA\xD5\x3F\x79\xF9\xDF\x58\xC4\xAE\xA0\xD0\xED\x9A\x96\x01"
+          "\xF2\x78\x11\x2C\xA7\x18\x0D\x56\x5B\x42\x0A\x48\x01\x96\x70\xEA"
+          "\xF2\x4C\xE4\x93\xA8\x62\x63\xF6\x77\xB4\x6A\xCE\x19\x24\x77\x3D"
+          "\x2B\xB2\x55\x71\xE1\xAA\x85\x93\x75\x8F\xC3\x82\xB1\x28\x0B\x71"
+        }
+      }
+    }
+#endif /*USE_SALSA20*/
+  };
+
+  gcry_cipher_hd_t hde, hdd;
+  unsigned char out[MAX_DATA_LEN];
+  int i, j;
+  gcry_error_t err = 0;
+
+
+  if (verbose)
+    fprintf (stderr, "  Starting stream cipher checks.\n");
+
+  for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
+    {
+      if (verbose)
+        fprintf (stderr, "    checking stream mode for %s [%i] (%s)\n",
+		 gcry_cipher_algo_name (tv[i].algo), tv[i].algo, tv[i].name);
+
+      if (gcry_cipher_get_algo_blklen(tv[i].algo) != 1)
+        {
+          fail ("stream, gcry_cipher_get_algo_blklen: bad block length\n");
+          continue;
+        }
+
+      err = gcry_cipher_open (&hde, tv[i].algo, GCRY_CIPHER_MODE_STREAM, 0);
+      if (!err)
+        err = gcry_cipher_open (&hdd, tv[i].algo, GCRY_CIPHER_MODE_STREAM, 0);
+      if (err)
+        {
+          fail ("stream, gcry_cipher_open for stream mode failed: %s\n",
+                gpg_strerror (err));
+          continue;
+        }
+
+      /* Now loop over all the data samples.  */
+      for (j = 0; tv[i].data[j].inlen; j++)
+        {
+          err = gcry_cipher_setkey (hde, tv[i].key, tv[i].keylen);
+          if (!err)
+            err = gcry_cipher_setkey (hdd, tv[i].key, tv[i].keylen);
+          if (err)
+            {
+              fail ("stream, gcry_cipher_setkey failed: %s\n",
+                    gpg_strerror (err));
+              goto next;
+            }
+
+          err = gcry_cipher_setiv (hde, tv[i].iv, tv[i].ivlen);
+          if (!err)
+            err = gcry_cipher_setiv (hdd, tv[i].iv, tv[i].ivlen);
+          if (err)
+            {
+              fail ("stream, gcry_cipher_setiv failed: %s\n",
+                    gpg_strerror (err));
+              goto next;
+            }
+
+          err = gcry_cipher_encrypt (hde, out, MAX_DATA_LEN,
+                                     tv[i].data[j].plaintext,
+                                     tv[i].data[j].inlen);
+          if (err)
+            {
+              fail ("stream, gcry_cipher_encrypt (%d, %d) failed: %s\n",
+                    i, j, gpg_strerror (err));
+              goto next;
+            }
+
+          if (memcmp (tv[i].data[j].out, out, tv[i].data[j].inlen))
+            {
+              fail ("stream, encrypt mismatch entry %d:%d\n", i, j);
+              mismatch (tv[i].data[j].out, tv[i].data[j].inlen,
+                        out, tv[i].data[j].inlen);
+            }
+
+          err = gcry_cipher_decrypt (hdd, out, tv[i].data[j].inlen, NULL, 0);
+          if (err)
+            {
+              fail ("stream, gcry_cipher_decrypt (%d, %d) failed: %s\n",
+                    i, j, gpg_strerror (err));
+              goto next;
+            }
+
+          if (memcmp (tv[i].data[j].plaintext, out, tv[i].data[j].inlen))
+            fail ("stream, decrypt mismatch entry %d:%d\n", i, j);
+        }
+
+
+      /* This time we encrypt and decrypt one byte at a time */
+      for (j = 0; tv[i].data[j].inlen; j++)
+        {
+          int byteNum;
+
+          err = gcry_cipher_setkey (hde, tv[i].key, tv[i].keylen);
+          if (!err)
+            err = gcry_cipher_setkey (hdd, tv[i].key, tv[i].keylen);
+          if (err)
+            {
+              fail ("stream, gcry_cipher_setkey failed: %s\n",
+                    gpg_strerror (err));
+              goto next;
+            }
+
+          err = gcry_cipher_setiv (hde, tv[i].iv, tv[i].ivlen);
+          if (!err)
+            err = gcry_cipher_setiv (hdd, tv[i].iv, tv[i].ivlen);
+          if (err)
+            {
+              fail ("stream, gcry_cipher_setiv failed: %s\n",
+                    gpg_strerror (err));
+              goto next;
+            }
+
+          for (byteNum = 0; byteNum < tv[i].data[j].inlen; ++byteNum)
+            {
+              err = gcry_cipher_encrypt (hde, out+byteNum, 1,
+                                         (tv[i].data[j].plaintext) + byteNum,
+                                         1);
+              if (err)
+                {
+                  fail ("stream, gcry_cipher_encrypt (%d, %d) failed: %s\n",
+                        i, j, gpg_strerror (err));
+                  goto next;
+                }
+            }
+
+          if (memcmp (tv[i].data[j].out, out, tv[i].data[j].inlen))
+            fail ("stream, encrypt mismatch entry %d:%d (byte-wise)\n", i, j);
+
+          for (byteNum = 0; byteNum < tv[i].data[j].inlen; ++byteNum)
+            {
+              err = gcry_cipher_decrypt (hdd, out+byteNum, 1, NULL, 0);
+              if (err)
+                {
+                  fail ("stream, gcry_cipher_decrypt (%d, %d) failed: %s\n",
+                        i, j, gpg_strerror (err));
+                  goto next;
+                }
+            }
+
+          if (memcmp (tv[i].data[j].plaintext, out, tv[i].data[j].inlen))
+            fail ("stream, decrypt mismatch entry %d:%d (byte-wise)\n", i, j);
+        }
+
+    next:
+      gcry_cipher_close (hde);
+      gcry_cipher_close (hdd);
+    }
+  if (verbose)
+    fprintf (stderr, "  Completed stream cipher checks.\n");
+}
+
+
+static void
+check_stream_cipher_large_block (void)
+{
+  struct tv
+  {
+    const char *name;
+    int algo;
+    int keylen;
+    int ivlen;
+    const char *key;
+    const char *iv;
+    struct data
+    {
+      int offset, length;
+      const char *result;
+    } data[MAX_DATA_LEN];
+  } tv[] = {
+#ifdef USE_SALSA20
+    {
+      "Salsa20 256 bit, ecrypt verified, set 6, vector 0",
+      GCRY_CIPHER_SALSA20, 32, 8,
+      "\x00\x53\xA6\xF9\x4C\x9F\xF2\x45\x98\xEB\x3E\x91\xE4\x37\x8A\xDD"
+      "\x30\x83\xD6\x29\x7C\xCF\x22\x75\xC8\x1B\x6E\xC1\x14\x67\xBA\x0D",
+      "\x0D\x74\xDB\x42\xA9\x10\x77\xDE",
+      {
+        { 0, 64,
+          "\xF5\xFA\xD5\x3F\x79\xF9\xDF\x58\xC4\xAE\xA0\xD0\xED\x9A\x96\x01"
+          "\xF2\x78\x11\x2C\xA7\x18\x0D\x56\x5B\x42\x0A\x48\x01\x96\x70\xEA"
+          "\xF2\x4C\xE4\x93\xA8\x62\x63\xF6\x77\xB4\x6A\xCE\x19\x24\x77\x3D"
+          "\x2B\xB2\x55\x71\xE1\xAA\x85\x93\x75\x8F\xC3\x82\xB1\x28\x0B\x71"
+        },
+        { 65472, 64,
+         "\xB7\x0C\x50\x13\x9C\x63\x33\x2E\xF6\xE7\x7A\xC5\x43\x38\xA4\x07"
+         "\x9B\x82\xBE\xC9\xF9\xA4\x03\xDF\xEA\x82\x1B\x83\xF7\x86\x07\x91"
+         "\x65\x0E\xF1\xB2\x48\x9D\x05\x90\xB1\xDE\x77\x2E\xED\xA4\xE3\xBC"
+         "\xD6\x0F\xA7\xCE\x9C\xD6\x23\xD9\xD2\xFD\x57\x58\xB8\x65\x3E\x70"
+        },
+        { 65536, 64,
+         "\x81\x58\x2C\x65\xD7\x56\x2B\x80\xAE\xC2\xF1\xA6\x73\xA9\xD0\x1C"
+         "\x9F\x89\x2A\x23\xD4\x91\x9F\x6A\xB4\x7B\x91\x54\xE0\x8E\x69\x9B"
+         "\x41\x17\xD7\xC6\x66\x47\x7B\x60\xF8\x39\x14\x81\x68\x2F\x5D\x95"
+         "\xD9\x66\x23\xDB\xC4\x89\xD8\x8D\xAA\x69\x56\xB9\xF0\x64\x6B\x6E"
+        },
+        { 131008, 64,
+         "\xA1\x3F\xFA\x12\x08\xF8\xBF\x50\x90\x08\x86\xFA\xAB\x40\xFD\x10"
+         "\xE8\xCA\xA3\x06\xE6\x3D\xF3\x95\x36\xA1\x56\x4F\xB7\x60\xB2\x42"
+         "\xA9\xD6\xA4\x62\x8C\xDC\x87\x87\x62\x83\x4E\x27\xA5\x41\xDA\x2A"
+         "\x5E\x3B\x34\x45\x98\x9C\x76\xF6\x11\xE0\xFE\xC6\xD9\x1A\xCA\xCC"
+        }
+      }
+    },
+    {
+      "Salsa20 256 bit, ecrypt verified, set 6, vector 1",
+      GCRY_CIPHER_SALSA20, 32, 8,
+      "\x05\x58\xAB\xFE\x51\xA4\xF7\x4A\x9D\xF0\x43\x96\xE9\x3C\x8F\xE2"
+      "\x35\x88\xDB\x2E\x81\xD4\x27\x7A\xCD\x20\x73\xC6\x19\x6C\xBF\x12",
+      "\x16\x7D\xE4\x4B\xB2\x19\x80\xE7",
+      {
+        { 0, 64,
+          "\x39\x44\xF6\xDC\x9F\x85\xB1\x28\x08\x38\x79\xFD\xF1\x90\xF7\xDE"
+          "\xE4\x05\x3A\x07\xBC\x09\x89\x6D\x51\xD0\x69\x0B\xD4\xDA\x4A\xC1"
+          "\x06\x2F\x1E\x47\xD3\xD0\x71\x6F\x80\xA9\xB4\xD8\x5E\x6D\x60\x85"
+          "\xEE\x06\x94\x76\x01\xC8\x5F\x1A\x27\xA2\xF7\x6E\x45\xA6\xAA\x87"
+        },
+        { 65472, 64,
+          "\x36\xE0\x3B\x4B\x54\xB0\xB2\xE0\x4D\x06\x9E\x69\x00\x82\xC8\xC5"
+          "\x92\xDF\x56\xE6\x33\xF5\xD8\xC7\x68\x2A\x02\xA6\x5E\xCD\x13\x71"
+          "\x8C\xA4\x35\x2A\xAC\xCB\x0D\xA2\x0E\xD6\xBB\xBA\x62\xE1\x77\xF2"
+          "\x10\xE3\x56\x0E\x63\xBB\x82\x2C\x41\x58\xCA\xA8\x06\xA8\x8C\x82"
+        },
+        { 65536, 64,
+          "\x1B\x77\x9E\x7A\x91\x7C\x8C\x26\x03\x9F\xFB\x23\xCF\x0E\xF8\xE0"
+          "\x8A\x1A\x13\xB4\x3A\xCD\xD9\x40\x2C\xF5\xDF\x38\x50\x10\x98\xDF"
+          "\xC9\x45\xA6\xCC\x69\xA6\xA1\x73\x67\xBC\x03\x43\x1A\x86\xB3\xED"
+          "\x04\xB0\x24\x5B\x56\x37\x9B\xF9\x97\xE2\x58\x00\xAD\x83\x7D\x7D"
+        },
+        { 131008, 64,
+          "\x7E\xC6\xDA\xE8\x1A\x10\x5E\x67\x17\x2A\x0B\x8C\x4B\xBE\x7D\x06"
+          "\xA7\xA8\x75\x9F\x91\x4F\xBE\xB1\xAF\x62\xC8\xA5\x52\xEF\x4A\x4F"
+          "\x56\x96\x7E\xA2\x9C\x74\x71\xF4\x6F\x3B\x07\xF7\xA3\x74\x6E\x95"
+          "\x3D\x31\x58\x21\xB8\x5B\x6E\x8C\xB4\x01\x22\xB9\x66\x35\x31\x3C"
+        }
+      }
+    },
+    {
+      "Salsa20 256 bit, ecrypt verified, set 6, vector 2",
+      GCRY_CIPHER_SALSA20, 32, 8,
+      "\x0A\x5D\xB0\x03\x56\xA9\xFC\x4F\xA2\xF5\x48\x9B\xEE\x41\x94\xE7"
+      "\x3A\x8D\xE0\x33\x86\xD9\x2C\x7F\xD2\x25\x78\xCB\x1E\x71\xC4\x17",
+      "\x1F\x86\xED\x54\xBB\x22\x89\xF0",
+      {
+        { 0, 64,
+          "\x3F\xE8\x5D\x5B\xB1\x96\x0A\x82\x48\x0B\x5E\x6F\x4E\x96\x5A\x44"
+          "\x60\xD7\xA5\x45\x01\x66\x4F\x7D\x60\xB5\x4B\x06\x10\x0A\x37\xFF"
+          "\xDC\xF6\xBD\xE5\xCE\x3F\x48\x86\xBA\x77\xDD\x5B\x44\xE9\x56\x44"
+          "\xE4\x0A\x8A\xC6\x58\x01\x15\x5D\xB9\x0F\x02\x52\x2B\x64\x40\x23"
+        },
+        { 65472, 64,
+          "\xC8\xD6\xE5\x4C\x29\xCA\x20\x40\x18\xA8\x30\xE2\x66\xCE\xEE\x0D"
+          "\x03\x7D\xC4\x7E\x92\x19\x47\x30\x2A\xCE\x40\xD1\xB9\x96\xA6\xD8"
+          "\x0B\x59\x86\x77\xF3\x35\x2F\x1D\xAA\x6D\x98\x88\xF8\x91\xAD\x95"
+          "\xA1\xC3\x2F\xFE\xB7\x1B\xB8\x61\xE8\xB0\x70\x58\x51\x51\x71\xC9"
+        },
+        { 65536, 64,
+          "\xB7\x9F\xD7\x76\x54\x2B\x46\x20\xEF\xCB\x88\x44\x95\x99\xF2\x34"
+          "\x03\xE7\x4A\x6E\x91\xCA\xCC\x50\xA0\x5A\x8F\x8F\x3C\x0D\xEA\x8B"
+          "\x00\xE1\xA5\xE6\x08\x1F\x55\x26\xAE\x97\x5B\x3B\xC0\x45\x0F\x1A"
+          "\x0C\x8B\x66\xF8\x08\xF1\x90\x4B\x97\x13\x61\x13\x7C\x93\x15\x6F"
+        },
+        { 131008, 64,
+          "\x79\x98\x20\x4F\xED\x70\xCE\x8E\x0D\x02\x7B\x20\x66\x35\xC0\x8C"
+          "\x8B\xC4\x43\x62\x26\x08\x97\x0E\x40\xE3\xAE\xDF\x3C\xE7\x90\xAE"
+          "\xED\xF8\x9F\x92\x26\x71\xB4\x53\x78\xE2\xCD\x03\xF6\xF6\x23\x56"
+          "\x52\x9C\x41\x58\xB7\xFF\x41\xEE\x85\x4B\x12\x35\x37\x39\x88\xC8"
+        }
+      }
+    },
+    {
+      "Salsa20 256 bit, ecrypt verified, set 6, vector 3",
+      GCRY_CIPHER_SALSA20, 32, 8,
+      "\x0F\x62\xB5\x08\x5B\xAE\x01\x54\xA7\xFA\x4D\xA0\xF3\x46\x99\xEC"
+      "\x3F\x92\xE5\x38\x8B\xDE\x31\x84\xD7\x2A\x7D\xD0\x23\x76\xC9\x1C",
+      "\x28\x8F\xF6\x5D\xC4\x2B\x92\xF9",
+      {
+        { 0, 64,
+          "\x5E\x5E\x71\xF9\x01\x99\x34\x03\x04\xAB\xB2\x2A\x37\xB6\x62\x5B"
+          "\xF8\x83\xFB\x89\xCE\x3B\x21\xF5\x4A\x10\xB8\x10\x66\xEF\x87\xDA"
+          "\x30\xB7\x76\x99\xAA\x73\x79\xDA\x59\x5C\x77\xDD\x59\x54\x2D\xA2"
+          "\x08\xE5\x95\x4F\x89\xE4\x0E\xB7\xAA\x80\xA8\x4A\x61\x76\x66\x3F"
+        },
+        { 65472, 64,
+          "\x2D\xA2\x17\x4B\xD1\x50\xA1\xDF\xEC\x17\x96\xE9\x21\xE9\xD6\xE2"
+          "\x4E\xCF\x02\x09\xBC\xBE\xA4\xF9\x83\x70\xFC\xE6\x29\x05\x6F\x64"
+          "\x91\x72\x83\x43\x6E\x2D\x3F\x45\x55\x62\x25\x30\x7D\x5C\xC5\xA5"
+          "\x65\x32\x5D\x89\x93\xB3\x7F\x16\x54\x19\x5C\x24\x0B\xF7\x5B\x16"
+        },
+        { 65536, 64,
+          "\xAB\xF3\x9A\x21\x0E\xEE\x89\x59\x8B\x71\x33\x37\x70\x56\xC2\xFE"
+          "\xF4\x2D\xA7\x31\x32\x75\x63\xFB\x67\xC7\xBE\xDB\x27\xF3\x8C\x7C"
+          "\x5A\x3F\xC2\x18\x3A\x4C\x6B\x27\x7F\x90\x11\x52\x47\x2C\x6B\x2A"
+          "\xBC\xF5\xE3\x4C\xBE\x31\x5E\x81\xFD\x3D\x18\x0B\x5D\x66\xCB\x6C"
+        },
+        { 131008, 64,
+          "\x1B\xA8\x9D\xBD\x3F\x98\x83\x97\x28\xF5\x67\x91\xD5\xB7\xCE\x23"
+          "\x50\x36\xDE\x84\x3C\xCC\xAB\x03\x90\xB8\xB5\x86\x2F\x1E\x45\x96"
+          "\xAE\x8A\x16\xFB\x23\xDA\x99\x7F\x37\x1F\x4E\x0A\xAC\xC2\x6D\xB8"
+          "\xEB\x31\x4E\xD4\x70\xB1\xAF\x6B\x9F\x8D\x69\xDD\x79\xA9\xD7\x50"
+        }
+      }
+    }
+#endif /*USE_SALSA20*/
+  };
+
+
+  char zeroes[512];
+  gcry_cipher_hd_t hde;
+  unsigned char *buffer;
+  unsigned char *p;
+  size_t buffersize;
+  unsigned int n;
+  int i, j;
+  gcry_error_t err = 0;
+
+  if (verbose)
+    fprintf (stderr, "  Starting large block stream cipher checks.\n");
+
+  memset (zeroes, 0, 512);
+
+  buffersize = 128 * 1024;
+  buffer = gcry_xmalloc (buffersize+1024);
+  memset (buffer+buffersize, 0x5a, 1024);
+
+  for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
+    {
+      if (verbose)
+        fprintf (stderr, "    checking large block stream for %s [%i] (%s)\n",
+		 gcry_cipher_algo_name (tv[i].algo), tv[i].algo, tv[i].name);
+
+      err = gcry_cipher_open (&hde, tv[i].algo, GCRY_CIPHER_MODE_STREAM, 0);
+      if (err)
+        {
+          fail ("large stream, gcry_cipher_open for stream mode failed: %s\n",
+                gpg_strerror (err));
+          continue;
+        }
+
+      err = gcry_cipher_setkey (hde, tv[i].key, tv[i].keylen);
+      if (err)
+        {
+          fail ("large stream, gcry_cipher_setkey failed: %s\n",
+                gpg_strerror (err));
+          goto next;
+        }
+
+      err = gcry_cipher_setiv (hde, tv[i].iv, tv[i].ivlen);
+      if (err)
+        {
+          fail ("large stream, gcry_cipher_setiv failed: %s\n",
+                gpg_strerror (err));
+          goto next;
+        }
+
+      for (j=0, p=buffer; j < buffersize/512; j++, p += 512)
+        {
+          err = gcry_cipher_encrypt (hde, p, 512, zeroes, 512);
+          if (err)
+            {
+              fail ("large stream, "
+                    "gcry_cipher_encrypt (%d) block %d failed: %s\n",
+                    i, j, gpg_strerror (err));
+              goto next;
+            }
+        }
+      for (j=0, p=buffer+buffersize; j < 1024; j++, p++)
+        if (*p != 0x5a)
+          die ("large stream, buffer corrupted at j=%d\n", j);
+
+      /* Now loop over all the data samples.  */
+      for (j = 0; tv[i].data[j].length; j++)
+        {
+          assert (tv[i].data[j].offset + tv[i].data[j].length <= buffersize);
+
+          if (memcmp (tv[i].data[j].result,
+                      buffer + tv[i].data[j].offset, tv[i].data[j].length))
+            {
+              fail ("large stream, encrypt mismatch entry %d:%d\n", i, j);
+              mismatch (tv[i].data[j].result, tv[i].data[j].length,
+                        buffer + tv[i].data[j].offset, tv[i].data[j].length);
+            }
+        }
+
+      /*
+       *  Let's do the same thing again but using changing block sizes.
+       */
+      err = gcry_cipher_setkey (hde, tv[i].key, tv[i].keylen);
+      if (err)
+        {
+          fail ("large stream, gcry_cipher_setkey failed: %s\n",
+                gpg_strerror (err));
+          goto next;
+        }
+
+      err = gcry_cipher_setiv (hde, tv[i].iv, tv[i].ivlen);
+      if (err)
+        {
+          fail ("large stream, gcry_cipher_setiv failed: %s\n",
+                gpg_strerror (err));
+          goto next;
+        }
+
+      for (n=0, p=buffer, j = 0; n < buffersize; n += j, p += j)
+        {
+          switch (j)
+            {
+            case   0: j =   1;  break;
+            case   1: j =  64; break;
+            case  64: j=  384; break;
+            case 384: j =  63; break;
+            case  63: j = 512; break;
+            case 512: j =  32; break;
+            case  32: j = 503; break;
+            default:  j = 509; break;
+            }
+          if ( n + j >= buffersize )
+            j = buffersize - n;
+          assert (j <= 512);
+          err = gcry_cipher_encrypt (hde, p, j, zeroes, j);
+          if (err)
+            {
+              fail ("large stream, "
+                    "gcry_cipher_encrypt (%d) offset %u failed: %s\n",
+                    i, n, gpg_strerror (err));
+              goto next;
+            }
+        }
+      for (j=0, p=buffer+buffersize; j < 1024; j++, p++)
+        if (*p != 0x5a)
+          die ("large stream, buffer corrupted at j=%d (line %d)\n",
+               j, __LINE__);
+
+      /* Now loop over all the data samples.  */
+      for (j = 0; tv[i].data[j].length; j++)
+        {
+          assert (tv[i].data[j].offset + tv[i].data[j].length <= buffersize);
+
+          if (memcmp (tv[i].data[j].result,
+                      buffer + tv[i].data[j].offset, tv[i].data[j].length))
+            {
+              fail ("large stream var, encrypt mismatch entry %d:%d\n", i, j);
+              mismatch (tv[i].data[j].result, tv[i].data[j].length,
+                        buffer + tv[i].data[j].offset, tv[i].data[j].length);
+            }
+        }
+
+    next:
+      gcry_cipher_close (hde);
+    }
+
+  gcry_free (buffer);
+  if (verbose)
+    fprintf (stderr, "  Completed large block stream cipher checks.\n");
+}
+
+
+
 /* Check that our bulk encryption fucntions work properly.  */
 static void
 check_bulk_cipher_modes (void)
@@ -1606,6 +2168,9 @@ check_ciphers (void)
 #if USE_ARCFOUR
     GCRY_CIPHER_ARCFOUR,
 #endif
+#if USE_SALSA20
+    GCRY_CIPHER_SALSA20,
+#endif
     0
   };
   int i;
@@ -1644,7 +2209,7 @@ check_ciphers (void)
           continue;
         }
       if (verbose)
-	fprintf (stderr, "  checking `%s'\n",
+	fprintf (stderr, "  checking %s\n",
 		 gcry_cipher_algo_name (algos2[i]));
 
       check_one_cipher (algos2[i], GCRY_CIPHER_MODE_STREAM, 0);
@@ -1669,6 +2234,8 @@ check_cipher_modes(void)
   check_ctr_cipher ();
   check_cfb_cipher ();
   check_ofb_cipher ();
+  check_stream_cipher ();
+  check_stream_cipher_large_block ();
 
   if (verbose)
     fprintf (stderr, "Completed Cipher Mode checks.\n");

commit f6d6e0200fa823d377a342efacaf3d61e4303dc3
Author: Werner Koch <wk at gnupg.org>
Date:   Wed Jul 17 16:55:37 2013 +0200

    Typo fix in comment.
    
    --

diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in
index 27a29ec..2292832 100644
--- a/src/gcrypt.h.in
+++ b/src/gcrypt.h.in
@@ -680,7 +680,7 @@ void     gcry_mpi_rshift (gcry_mpi_t x, gcry_mpi_t a, unsigned int n);
 void     gcry_mpi_lshift (gcry_mpi_t x, gcry_mpi_t a, unsigned int n);
 
 /* Store NBITS of the value P points to in A and mark A as an opaque
-   value.  WARNING: Never use an opaque MPI for anything thing else then
+   value.  WARNING: Never use an opaque MPI for anything thing else than
    gcry_mpi_release, gcry_mpi_get_opaque. */
 gcry_mpi_t gcry_mpi_set_opaque (gcry_mpi_t a, void *p, unsigned int nbits);
 

commit 364d019e3ffedfcb434576702f73e767cb9389ef
Author: Werner Koch <wk at gnupg.org>
Date:   Wed Jul 17 16:55:02 2013 +0200

    Allow gcry_mpi_dump to print opaque MPIs.
    
    * mpi/mpicoder.c (gcry_mpi_dump): Detect abd print opaque MPIs.
    * tests/mpitests.c (test_opaque): New.
    (main): Call new test.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/mpi/mpicoder.c b/mpi/mpicoder.c
index 06d5553..aca3710 100644
--- a/mpi/mpicoder.c
+++ b/mpi/mpicoder.c
@@ -187,6 +187,17 @@ gcry_mpi_dump (const gcry_mpi_t a)
   log_printf (" ");
   if (!a)
     log_printf ("[MPI_NULL]");
+  else if (mpi_is_opaque (a))
+    {
+      unsigned int nbits;
+      const unsigned char *p;
+
+      p = gcry_mpi_get_opaque (a, &nbits);
+      log_printf ("[%u bit: ", nbits);
+      for (i=0; i < (nbits + 7)/8; i++)
+        log_printf ("%02x", p[i]);
+      log_printf ("]");
+    }
   else
     {
       if (a->sign)
diff --git a/tests/mpitests.c b/tests/mpitests.c
index 5643c1b..432f3e8 100644
--- a/tests/mpitests.c
+++ b/tests/mpitests.c
@@ -150,6 +150,38 @@ test_const_and_immutable (void)
 }
 
 
+static void
+test_opaque (void)
+{
+  gcry_mpi_t a;
+  char *p;
+  unsigned int nbits;
+
+  p = gcry_xstrdup ("This is a test buffer");
+  a = gcry_mpi_set_opaque (NULL, p, 21*8+1); /* (a non byte aligned length) */
+
+  if (!gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
+    die ("opaque flag not set\n");
+
+  p = gcry_mpi_get_opaque (a, &nbits);
+  if (!p)
+    die ("gcry_mpi_get_opaque returned NULL\n");
+  if (nbits != 21*8+1)
+    die ("gcry_mpi_get_opaque returned a changed bit size\n");
+  if (strcmp (p, "This is a test buffer"))
+    die ("gcry_mpi_get_opaque returned a changed buffer\n");
+
+  if (verbose)
+    {
+      fprintf (stderr, "mpi: ");
+      gcry_mpi_dump (a);
+      putc ('\n', stderr);
+    }
+
+  gcry_mpi_release (a);
+}
+
+
 static int
 test_add (void)
 {
@@ -354,6 +386,7 @@ main (int argc, char* argv[])
   gcry_control(GCRYCTL_DISABLE_SECMEM);
 
   test_const_and_immutable ();
+  test_opaque ();
   test_add ();
   test_sub ();
   test_mul ();

commit 5940e66cbefea3de5924f494f18aed69bb694bff
Author: Werner Koch <wk at gnupg.org>
Date:   Wed Jul 17 15:54:32 2013 +0200

    cipher: Prepare to pass extra info to the sign functions.
    
    * src/gcrypt-module.h (gcry_pk_sign_t): Add parms flags and hashalgo.
    * cipher/rsa.c (rsa_sign): Add parms and mark them as unused.
    * cipher/dsa.c (dsa_sign): Ditto.
    * cipher/elgamal.c (elg_sign): Ditto.
    * cipher/pubkey.c (dummy_sign): Ditto.
    (pubkey_sign): Pass 0 for the new args.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/cipher/dsa.c b/cipher/dsa.c
index 90edeb5..55805e2 100644
--- a/cipher/dsa.c
+++ b/cipher/dsa.c
@@ -906,12 +906,15 @@ dsa_check_secret_key (int algo, gcry_mpi_t *skey)
 
 
 static gcry_err_code_t
-dsa_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey)
+dsa_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey,
+          int flags, int hashalgo)
 {
   gcry_err_code_t err = GPG_ERR_NO_ERROR;
   DSA_secret_key sk;
 
   (void)algo;
+  (void)flags;
+  (void)hashalgo;
 
   if ((! data)
       || (! skey[0]) || (! skey[1]) || (! skey[2])
diff --git a/cipher/ecc.c b/cipher/ecc.c
index e5a925b..e4b1799 100644
--- a/cipher/ecc.c
+++ b/cipher/ecc.c
@@ -1317,12 +1317,15 @@ ecc_check_secret_key (int algo, gcry_mpi_t *skey)
 
 
 static gcry_err_code_t
-ecc_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey)
+ecc_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey,
+          int flags, int hashalgo)
 {
   gpg_err_code_t err;
   ECC_secret_key sk;
 
   (void)algo;
+  (void)flags;
+  (void)hashalgo;
 
   if (!data || !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4]
       || !skey[6] )
diff --git a/cipher/elgamal.c b/cipher/elgamal.c
index ce4be85..128dd99 100644
--- a/cipher/elgamal.c
+++ b/cipher/elgamal.c
@@ -753,12 +753,15 @@ elg_decrypt (int algo, gcry_mpi_t *result,
 
 
 static gcry_err_code_t
-elg_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey)
+elg_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey,
+          int flags, int hashalgo)
 {
   gcry_err_code_t err = GPG_ERR_NO_ERROR;
   ELG_secret_key sk;
 
   (void)algo;
+  (void)flags;
+  (void)hashalgo;
 
   if ((! data)
       || (! skey[0]) || (! skey[1]) || (! skey[2]) || (! skey[3]))
diff --git a/cipher/pubkey.c b/cipher/pubkey.c
index 378e072..23a4358 100644
--- a/cipher/pubkey.c
+++ b/cipher/pubkey.c
@@ -161,12 +161,16 @@ dummy_decrypt (int algorithm, gcry_mpi_t *result, gcry_mpi_t *data,
 
 static gcry_err_code_t
 dummy_sign (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data,
-            gcry_mpi_t *skey)
+            gcry_mpi_t *skey,
+            int flags, int hashalgo)
+
 {
   (void)algorithm;
   (void)resarr;
   (void)data;
   (void)skey;
+  (void)flags;
+  (void)hashalgo;
   fips_signal_error ("using dummy public key function");
   return GPG_ERR_NOT_IMPLEMENTED;
 }
@@ -728,7 +732,7 @@ pubkey_sign (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data,
   if (module)
     {
       pubkey = (gcry_pk_spec_t *) module->spec;
-      rc = pubkey->sign (algorithm, resarr, data, skey);
+      rc = pubkey->sign (algorithm, resarr, data, skey, 0, 0);
       _gcry_module_release (module);
       goto ready;
     }
diff --git a/cipher/rsa.c b/cipher/rsa.c
index ccc9f96..4787f81 100644
--- a/cipher/rsa.c
+++ b/cipher/rsa.c
@@ -993,11 +993,14 @@ rsa_decrypt (int algo, gcry_mpi_t *result, gcry_mpi_t *data,
 
 
 static gcry_err_code_t
-rsa_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey)
+rsa_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey,
+          int flags, int hashalgo)
 {
   RSA_secret_key sk;
 
   (void)algo;
+  (void)flags;
+  (void)hashalgo;
 
   sk.n = skey[0];
   sk.e = skey[1];
diff --git a/src/gcrypt-module.h b/src/gcrypt-module.h
index 93f6162..cd55207 100644
--- a/src/gcrypt-module.h
+++ b/src/gcrypt-module.h
@@ -127,7 +127,9 @@ typedef gcry_err_code_t (*gcry_pk_decrypt_t) (int algo,
 typedef gcry_err_code_t (*gcry_pk_sign_t) (int algo,
 					   gcry_mpi_t *resarr,
 					   gcry_mpi_t data,
-					   gcry_mpi_t *skey);
+					   gcry_mpi_t *skey,
+                                           int flags,
+                                           int hashalgo);
 
 /* Type for the pk_verify function.  */
 typedef gcry_err_code_t (*gcry_pk_verify_t) (int algo,

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

Summary of changes:
 NEWS                |    3 +
 cipher/Makefile.am  |    1 +
 cipher/cipher.c     |   14 ++-
 cipher/dsa.c        |    5 +-
 cipher/ecc.c        |    5 +-
 cipher/elgamal.c    |    5 +-
 cipher/pubkey.c     |    8 +-
 cipher/rsa.c        |    5 +-
 cipher/salsa20.c    |  380 ++++++++++++++++++++++++++++++++++
 configure.ac        |    8 +-
 doc/gcrypt.texi     |   45 ++++-
 mpi/mpicoder.c      |   11 +
 src/cipher-proto.h  |    4 +
 src/cipher.h        |    4 +-
 src/gcrypt-module.h |    4 +-
 src/gcrypt.h.in     |    5 +-
 tests/basic.c       |  569 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 tests/mpitests.c    |   33 +++
 18 files changed, 1093 insertions(+), 16 deletions(-)
 create mode 100644 cipher/salsa20.c


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




More information about the Gnupg-commits mailing list