Hi!  Please find attached a port of DJB's public domain code for Salsa20
to nettle.  The patch is not meant to be applied as-is but to start a
discussion.  Review of the code itself is welcome.

While writing this I noticed a sub-optimal design of Nettle, in that it
overloads the meaning of struct nettle_cipher->block_size as a flag of
whether the cipher is a stream cipher or not.  Before arcfour was the
only stream cipher in nettle, and using block_size=0 to signal that it
is a stream cipher worked fine.  However, Salsa20 has a block size of 8
bytes.  Another odd thing is that Salsa20 requires an IV.  So some
changes to the nettle_cipher struct are required.

This could be resolved better than I have done in the patch below.  I
see two reasonable alternatives:

1) Introduce a new struct 'struct nettle_stream_cipher' that applies to
stream ciphers and use that.

2) Add a flag in 'struct nettle_cipher' to tell whether the cipher is a
stream cipher or not.

I started out strongly prefering 1) because it appeared cleaner.  After
thinking about the changes required to implement that, I am now leaning
towards 2) because of:

A) a lot of code would have to be duplicated if we have both 'struct
nettle_cipher' and 'struct nettle_stream_cipher' for apparently little
gain.  Otherwise, most code could be the same, and where the distinction
matters there could be a simple if-test.

B) it allows for full backwards compatibility in a clean way.  With 1)
we would have a transition period where people switch arcfour usage from
nettle_cipher to nettle_stream_cipher.  With 2) arcfour would continue
to have block_size==0 but it would also set the new stream cipher flag.
External code could incrementally be updated to check the new flag
instead of block_size==0 (if it does that at all) but that is something
that doesn't uglify nettle.

What do you think?  I'd be happy to propose a patch to implement 2) and
then a follow-on patch to add support for Salsa20.

/Simon

>From 600ae2815634ad95c4d2d93821316ce20df19ae3 Mon Sep 17 00:00:00 2001
From: Simon Josefsson <[email protected]>
Date: Wed, 21 Mar 2012 17:06:13 +0100
Subject: [PATCH] Implement Salsa20.

---
 Makefile.in                  |    3 +-
 examples/nettle-benchmark.c  |    3 +
 nettle-meta-ciphers.c        |    2 +
 nettle-meta.h                |    8 ++-
 nettle-types.h               |    5 +
 salsa20-meta.c               |   49 ++++++++++++
 salsa20.c                    |  172 ++++++++++++++++++++++++++++++++++++++++++
 salsa20.h                    |   71 +++++++++++++++++
 testsuite/.gitignore         |    1 +
 testsuite/.test-rules.make   |    3 +
 testsuite/Makefile.in        |    1 +
 testsuite/meta-cipher-test.c |    2 +
 testsuite/salsa20-test.c     |   49 ++++++++++++
 testsuite/testutils.c        |   36 +++++++--
 testsuite/testutils.h        |   10 +++
 15 files changed, 407 insertions(+), 8 deletions(-)
 create mode 100644 salsa20-meta.c
 create mode 100644 salsa20.c
 create mode 100644 salsa20.h
 create mode 100644 testsuite/salsa20-test.c

diff --git a/Makefile.in b/Makefile.in
index 1813a0d..6e2ec60 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -79,6 +79,7 @@ nettle_SOURCES = aes-decrypt-internal.c aes-decrypt.c \
                 md2.c md2-meta.c md4.c md4-meta.c \
                 md5.c md5-compress.c md5-compat.c md5-meta.c \
                 ripemd160.c ripemd160-compress.c ripemd160-meta.c \
+                salsa20.c salsa20-meta.c \
                 sha1.c sha1-compress.c sha1-meta.c \
                 sha256.c sha256-compress.c sha224-meta.c sha256-meta.c \
                 sha512.c sha512-compress.c sha384-meta.c sha512-meta.c \
@@ -113,7 +114,7 @@ hogweed_SOURCES = sexp.c sexp-format.c \
                  pgp-encode.c rsa2openpgp.c \
                  der-iterator.c der2rsa.c der2dsa.c
 
-HEADERS = aes.h arcfour.h arctwo.h asn1.h bignum.h blowfish.h \
+HEADERS = aes.h arcfour.h salsa20.h arctwo.h asn1.h bignum.h blowfish.h \
          base16.h base64.h buffer.h camellia.h cast128.h \
          cbc.h ctr.h gcm.h \
          des.h des-compat.h dsa.h \
diff --git a/examples/nettle-benchmark.c b/examples/nettle-benchmark.c
index 424ef19..44fca4e 100644
--- a/examples/nettle-benchmark.c
+++ b/examples/nettle-benchmark.c
@@ -40,6 +40,7 @@
 
 #include "aes.h"
 #include "arcfour.h"
+#include "salsa20.h"
 #include "blowfish.h"
 #include "cast128.h"
 #include "cbc.h"
@@ -612,6 +613,8 @@ main(int argc, char **argv)
       OPENSSL(&nettle_openssl_aes192)
       OPENSSL(&nettle_openssl_aes256)
       &nettle_arcfour128, OPENSSL(&nettle_openssl_arcfour128)
+      &nettle_salsa20_128,
+      &nettle_salsa20_256,
       &nettle_blowfish128, OPENSSL(&nettle_openssl_blowfish128)
       &nettle_camellia128, &nettle_camellia192, &nettle_camellia256,
       &nettle_cast128, OPENSSL(&nettle_openssl_cast128)
diff --git a/nettle-meta-ciphers.c b/nettle-meta-ciphers.c
index 1f07595..aae90f9 100644
--- a/nettle-meta-ciphers.c
+++ b/nettle-meta-ciphers.c
@@ -36,6 +36,8 @@ const struct nettle_cipher * const nettle_ciphers[] = {
   &nettle_camellia192,
   &nettle_camellia256,
   &nettle_cast128,
+  &nettle_salsa20_128,
+  &nettle_salsa20_256,
   &nettle_serpent128,
   &nettle_serpent192,
   &nettle_serpent256,
diff --git a/nettle-meta.h b/nettle-meta.h
index 54cbbd2..c8aabda 100644
--- a/nettle-meta.h
+++ b/nettle-meta.h
@@ -5,6 +5,7 @@
 
 /* nettle, low-level cryptographics library
  *
+ * Copyright (C) 2012 Simon Josefsson
  * Copyright (C) 2002 Niels Möller
  *  
  * The nettle library is free software; you can redistribute it and/or modify
@@ -39,7 +40,7 @@ struct nettle_cipher
   
   unsigned context_size;
   
-  /* Zero for stream ciphers */
+  /* Block size; 0 for byte-oriented stream ciphers. */
   unsigned block_size;
 
   /* Suggested key size; other sizes are sometimes possible. */
@@ -50,6 +51,8 @@ struct nettle_cipher
 
   nettle_crypt_func *encrypt;
   nettle_crypt_func *decrypt;
+
+  nettle_set_iv_func *set_iv;
 };
 
 #define _NETTLE_CIPHER(name, NAME, key_size) { \
@@ -105,6 +108,9 @@ extern const struct nettle_cipher nettle_aes256;
 
 extern const struct nettle_cipher nettle_arcfour128;
 
+extern const struct nettle_cipher nettle_salsa20_128;
+extern const struct nettle_cipher nettle_salsa20_256;
+
 extern const struct nettle_cipher nettle_camellia128;
 extern const struct nettle_cipher nettle_camellia192;
 extern const struct nettle_cipher nettle_camellia256;
diff --git a/nettle-types.h b/nettle-types.h
index b694332..e68cacb 100644
--- a/nettle-types.h
+++ b/nettle-types.h
@@ -2,6 +2,7 @@
 
 /* nettle, low-level cryptographics library
  *
+ * Copyright (C) 2012 Simon Josefsson
  * Copyright (C) 2005 Niels Möller
  *  
  * The nettle library is free software; you can redistribute it and/or modify
@@ -44,6 +45,10 @@ typedef void nettle_set_key_func(void *ctx,
                                 unsigned length,
                                 const uint8_t *key);
 
+typedef void nettle_set_iv_func(void *ctx,
+                               unsigned length,
+                               const uint8_t *iv);
+
 /* Uses a void * for cipher contexts.
 
    For block ciphers it would make sense with a const void * for the
diff --git a/salsa20-meta.c b/salsa20-meta.c
new file mode 100644
index 0000000..8278e09
--- /dev/null
+++ b/salsa20-meta.c
@@ -0,0 +1,49 @@
+/* salsa20-meta.c */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2012 Simon Josefsson
+ *  
+ * The nettle library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ * 
+ * The nettle library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the nettle library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "nettle-meta.h"
+
+#include "salsa20.h"
+
+const struct nettle_cipher nettle_salsa20_128 =
+  { "salsa20-128", sizeof(struct salsa20_ctx),
+    8, 16,
+    (nettle_set_key_func *) salsa20_set_key,
+    (nettle_set_key_func *) salsa20_set_key,
+    (nettle_crypt_func *) salsa20_crypt,
+    (nettle_crypt_func *) salsa20_crypt,
+    (nettle_set_iv_func *) salsa20_set_iv
+  };
+
+const struct nettle_cipher nettle_salsa20_256 =
+  { "salsa20-256", sizeof(struct salsa20_ctx),
+    8, 32,
+    (nettle_set_key_func *) salsa20_set_key,
+    (nettle_set_key_func *) salsa20_set_key,
+    (nettle_crypt_func *) salsa20_crypt,
+    (nettle_crypt_func *) salsa20_crypt,
+    (nettle_set_iv_func *) salsa20_set_iv
+  };
diff --git a/salsa20.c b/salsa20.c
new file mode 100644
index 0000000..7885199
--- /dev/null
+++ b/salsa20.c
@@ -0,0 +1,172 @@
+/* salsa20.c
+ *
+ * The Salsa20 stream cipher.
+ */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2012 Simon Josefsson
+ *  
+ * The nettle library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ * 
+ * The nettle library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the nettle library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+
+#include "salsa20.h"
+
+#define ROTL32(x,n) ((((x))<<(n)) | (((x))>>(32-(n))))
+
+#define SWAP32(v)                              \
+  ((ROTL32(v,  8) & 0x00FF00FFUL) |            \
+   (ROTL32(v, 24) & 0xFF00FF00UL))
+
+#ifdef WORDS_BIGENDIAN
+#define U32TO32_LITTLE(v) SWAP32(v)
+#else
+#define U32TO32_LITTLE(v) (v)
+#endif
+
+#define U8TO32_LITTLE(p) U32TO32_LITTLE(((uint32_t*)(p))[0])
+#define U32TO8_LITTLE(p, v) (((uint32_t*)(p))[0] = U32TO32_LITTLE(v))
+
+/*
+salsa20-ref.c version 20051118
+D. J. Bernstein
+Public domain.
+*/
+
+#define ROTATE(v,c) (ROTL32(v,c))
+#define XOR(v,w) ((v) ^ (w))
+#define PLUS(v,w) ((v) + (w))
+#define PLUSONE(v) (PLUS((v),1))
+
+static void salsa20_wordtobyte(uint8_t output[64],const uint32_t input[16])
+{
+  uint32_t x[16];
+  int i;
+
+  for (i = 0;i < 16;++i) x[i] = input[i];
+  for (i = 20;i > 0;i -= 2) {
+    x[ 4] = XOR(x[ 4],ROTATE(PLUS(x[ 0],x[12]), 7));
+    x[ 8] = XOR(x[ 8],ROTATE(PLUS(x[ 4],x[ 0]), 9));
+    x[12] = XOR(x[12],ROTATE(PLUS(x[ 8],x[ 4]),13));
+    x[ 0] = XOR(x[ 0],ROTATE(PLUS(x[12],x[ 8]),18));
+    x[ 9] = XOR(x[ 9],ROTATE(PLUS(x[ 5],x[ 1]), 7));
+    x[13] = XOR(x[13],ROTATE(PLUS(x[ 9],x[ 5]), 9));
+    x[ 1] = XOR(x[ 1],ROTATE(PLUS(x[13],x[ 9]),13));
+    x[ 5] = XOR(x[ 5],ROTATE(PLUS(x[ 1],x[13]),18));
+    x[14] = XOR(x[14],ROTATE(PLUS(x[10],x[ 6]), 7));
+    x[ 2] = XOR(x[ 2],ROTATE(PLUS(x[14],x[10]), 9));
+    x[ 6] = XOR(x[ 6],ROTATE(PLUS(x[ 2],x[14]),13));
+    x[10] = XOR(x[10],ROTATE(PLUS(x[ 6],x[ 2]),18));
+    x[ 3] = XOR(x[ 3],ROTATE(PLUS(x[15],x[11]), 7));
+    x[ 7] = XOR(x[ 7],ROTATE(PLUS(x[ 3],x[15]), 9));
+    x[11] = XOR(x[11],ROTATE(PLUS(x[ 7],x[ 3]),13));
+    x[15] = XOR(x[15],ROTATE(PLUS(x[11],x[ 7]),18));
+    x[ 1] = XOR(x[ 1],ROTATE(PLUS(x[ 0],x[ 3]), 7));
+    x[ 2] = XOR(x[ 2],ROTATE(PLUS(x[ 1],x[ 0]), 9));
+    x[ 3] = XOR(x[ 3],ROTATE(PLUS(x[ 2],x[ 1]),13));
+    x[ 0] = XOR(x[ 0],ROTATE(PLUS(x[ 3],x[ 2]),18));
+    x[ 6] = XOR(x[ 6],ROTATE(PLUS(x[ 5],x[ 4]), 7));
+    x[ 7] = XOR(x[ 7],ROTATE(PLUS(x[ 6],x[ 5]), 9));
+    x[ 4] = XOR(x[ 4],ROTATE(PLUS(x[ 7],x[ 6]),13));
+    x[ 5] = XOR(x[ 5],ROTATE(PLUS(x[ 4],x[ 7]),18));
+    x[11] = XOR(x[11],ROTATE(PLUS(x[10],x[ 9]), 7));
+    x[ 8] = XOR(x[ 8],ROTATE(PLUS(x[11],x[10]), 9));
+    x[ 9] = XOR(x[ 9],ROTATE(PLUS(x[ 8],x[11]),13));
+    x[10] = XOR(x[10],ROTATE(PLUS(x[ 9],x[ 8]),18));
+    x[12] = XOR(x[12],ROTATE(PLUS(x[15],x[14]), 7));
+    x[13] = XOR(x[13],ROTATE(PLUS(x[12],x[15]), 9));
+    x[14] = XOR(x[14],ROTATE(PLUS(x[13],x[12]),13));
+    x[15] = XOR(x[15],ROTATE(PLUS(x[14],x[13]),18));
+  }
+  for (i = 0;i < 16;++i) x[i] = PLUS(x[i],input[i]);
+  for (i = 0;i < 16;++i) U32TO8_LITTLE(output + 4 * i,x[i]);
+}
+
+static const char sigma[16] = "expand 32-byte k";
+static const char tau[16] = "expand 16-byte k";
+
+void
+salsa20_set_key(struct salsa20_ctx *ctx,
+               unsigned length, const uint8_t *key)
+{
+  const char *constants;
+
+  assert (length == SALSA20_MIN_KEY_SIZE || length == SALSA20_MAX_KEY_SIZE);
+
+  ctx->input[1] = U8TO32_LITTLE(key + 0);
+  ctx->input[2] = U8TO32_LITTLE(key + 4);
+  ctx->input[3] = U8TO32_LITTLE(key + 8);
+  ctx->input[4] = U8TO32_LITTLE(key + 12);
+  if (length == SALSA20_MAX_KEY_SIZE) { /* recommended */
+    key += 16;
+    constants = sigma;
+  } else { /* kbits == 128 */
+    constants = tau;
+  }
+  ctx->input[11] = U8TO32_LITTLE(key + 0);
+  ctx->input[12] = U8TO32_LITTLE(key + 4);
+  ctx->input[13] = U8TO32_LITTLE(key + 8);
+  ctx->input[14] = U8TO32_LITTLE(key + 12);
+  ctx->input[0] = U8TO32_LITTLE(constants + 0);
+  ctx->input[5] = U8TO32_LITTLE(constants + 4);
+  ctx->input[10] = U8TO32_LITTLE(constants + 8);
+  ctx->input[15] = U8TO32_LITTLE(constants + 12);
+}
+
+void
+salsa20_set_iv(struct salsa20_ctx *ctx, unsigned length, const uint8_t *iv)
+{
+  assert (length == SALSA20_IV_SIZE);
+
+  ctx->input[6] = U8TO32_LITTLE(iv + 0);
+  ctx->input[7] = U8TO32_LITTLE(iv + 4);
+  ctx->input[8] = 0;
+  ctx->input[9] = 0;
+}
+
+void
+salsa20_crypt(struct salsa20_ctx *ctx,
+             unsigned length,
+             uint8_t *c,
+             const uint8_t *m)
+{
+  uint8_t output[64];
+  unsigned i;
+
+  if (!length) return;
+  for (;;) {
+    salsa20_wordtobyte(output,ctx->input);
+    ctx->input[8] = PLUSONE(ctx->input[8]);
+    if (!ctx->input[8]) {
+      ctx->input[9] = PLUSONE(ctx->input[9]);
+      /* stopping at 2^70 length per nonce is user's responsibility */
+    }
+    if (length <= 64) {
+      for (i = 0;i < length;++i) c[i] = m[i] ^ output[i];
+      return;
+    }
+    for (i = 0;i < 64;++i) c[i] = m[i] ^ output[i];
+    length -= 64;
+    c += 64;
+    m += 64;
+  }
+}
diff --git a/salsa20.h b/salsa20.h
new file mode 100644
index 0000000..79f1505
--- /dev/null
+++ b/salsa20.h
@@ -0,0 +1,71 @@
+/* salsa20.h
+ *
+ * The Salsa20 stream cipher.
+ */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2012 Simon Josefsson
+ * Copyright (C) 2001 Niels Möller
+ *  
+ * The nettle library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ * 
+ * The nettle library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the nettle library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+ 
+#ifndef NETTLE_SALSA20_H_INCLUDED
+#define NETTLE_SALSA20_H_INCLUDED
+
+#include "nettle-types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Name mangling */
+#define salsa20_set_key nettle_salsa20_set_key
+#define salsa20_set_iv nettle_salsa20_set_iv
+#define salsa20_crypt nettle_salsa20_crypt
+
+/* Minimum and maximum keysizes, and a reasonable default. In
+ * octets.*/
+#define SALSA20_MIN_KEY_SIZE 16
+#define SALSA20_MAX_KEY_SIZE 32
+#define SALSA20_KEY_SIZE 32
+
+#define SALSA20_IV_SIZE 8
+
+struct salsa20_ctx
+{
+    uint32_t input[16];
+};
+
+void
+salsa20_set_key(struct salsa20_ctx *ctx,
+               unsigned length, const uint8_t *key);
+
+void
+salsa20_set_iv(struct salsa20_ctx *ctx,
+              unsigned length, const uint8_t *iv);
+
+void
+salsa20_crypt(struct salsa20_ctx *ctx,
+             unsigned length, uint8_t *dst,
+             const uint8_t *src);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETTLE_SALSA20_H_INCLUDED */
diff --git a/testsuite/.gitignore b/testsuite/.gitignore
index 1147cfb..c9f4698 100644
--- a/testsuite/.gitignore
+++ b/testsuite/.gitignore
@@ -36,6 +36,7 @@
 /rsa-keygen-test
 /rsa-test
 /rsa2sexp-test
+/salsa20-test
 /serpent-test
 /sexp-format-test
 /sexp-test
diff --git a/testsuite/.test-rules.make b/testsuite/.test-rules.make
index e8f6650..10c993f 100644
--- a/testsuite/.test-rules.make
+++ b/testsuite/.test-rules.make
@@ -49,6 +49,9 @@ memxor-test$(EXEEXT): memxor-test.$(OBJEXT)
 ripemd160-test$(EXEEXT): ripemd160-test.$(OBJEXT)
        $(LINK) ripemd160-test.$(OBJEXT) $(TEST_OBJS) -o ripemd160-test$(EXEEXT)
 
+salsa20-test$(EXEEXT): salsa20-test.$(OBJEXT)
+       $(LINK) salsa20-test.$(OBJEXT) $(TEST_OBJS) -o salsa20-test$(EXEEXT)
+
 sha1-test$(EXEEXT): sha1-test.$(OBJEXT)
        $(LINK) sha1-test.$(OBJEXT) $(TEST_OBJS) -o sha1-test$(EXEEXT)
 
diff --git a/testsuite/Makefile.in b/testsuite/Makefile.in
index 8dfc62b..10ffae9 100644
--- a/testsuite/Makefile.in
+++ b/testsuite/Makefile.in
@@ -18,6 +18,7 @@ TS_NETTLE_SOURCES = aes-test.c arcfour-test.c arctwo-test.c \
                    md2-test.c md4-test.c md5-test.c md5-compat-test.c \
                    memxor-test.c \
                    ripemd160-test.c \
+                   salsa20-test.c \
                    sha1-test.c sha224-test.c sha256-test.c \
                    sha384-test.c sha512-test.c \
                    serpent-test.c twofish-test.c \
diff --git a/testsuite/meta-cipher-test.c b/testsuite/meta-cipher-test.c
index 1bb74d8..50a02ba 100644
--- a/testsuite/meta-cipher-test.c
+++ b/testsuite/meta-cipher-test.c
@@ -14,6 +14,8 @@ const char* ciphers[] = {
   "camellia192",
   "camellia256",
   "cast128",
+  "salsa20-128",
+  "salsa20-256",
   "serpent128",
   "serpent192",
   "serpent256",
diff --git a/testsuite/salsa20-test.c b/testsuite/salsa20-test.c
new file mode 100644
index 0000000..e1c13dd
--- /dev/null
+++ b/testsuite/salsa20-test.c
@@ -0,0 +1,49 @@
+#include "testutils.h"
+#include "salsa20.h"
+
+int
+test_main(void)
+{
+  /* 
http://www.ecrypt.eu.org/stream/svn/viewcvs.cgi/ecrypt/trunk/submissions/salsa20/full/verified.test-vectors?logsort=rev&rev=210&view=markup
 */
+
+  test_cipher_iv(&nettle_salsa20_128,
+                HL("80000000 00000000 00000000 00000000"),
+                HL("00000000 00000000"),
+                HL("00000000 00000000"),
+                H("4DFA5E48 1DA23EA0"));
+
+  test_cipher_iv(&nettle_salsa20_128,
+                HL("00000000 00000000 00000000 00000000"),
+                HL("80000000 00000000"),
+                HL("00000000 00000000"),
+                H("B66C1E44 46DD9557"));
+
+  test_cipher_iv(&nettle_salsa20_128,
+                HL("0053A6F94C9FF24598EB3E91E4378ADD"),
+                HL("0D74DB42A91077DE"),
+                HL("00000000 00000000"),
+                H("05E1E7BE B697D999"));
+
+  test_cipher_iv(&nettle_salsa20_256,
+                HL("80000000 00000000 00000000 00000000"
+                   "00000000 00000000 00000000 00000000"),
+                HL("00000000 00000000"),
+                HL("00000000 00000000"),
+                H("E3BE8FDD 8BECA2E3"));
+
+  test_cipher_iv(&nettle_salsa20_256,
+                HL("00000000 00000000 00000000 00000000"
+                   "00000000 00000000 00000000 00000000"),
+                HL("80000000 00000000"),
+                HL("00000000 00000000"),
+                H("2ABA3DC45B494700"));
+
+  test_cipher_iv(&nettle_salsa20_256,
+                HL("0053A6F94C9FF24598EB3E91E4378ADD"
+                   "3083D6297CCF2275C81B6EC11467BA0D"),
+                HL("0D74DB42A91077DE"),
+                HL("00000000 00000000"),
+                H("F5FAD53F 79F9DF58"));
+
+  SUCCESS();
+}
diff --git a/testsuite/testutils.c b/testsuite/testutils.c
index d77bb7e..8f5dab0 100644
--- a/testsuite/testutils.c
+++ b/testsuite/testutils.c
@@ -162,17 +162,21 @@ main(int argc, char **argv)
 }
 
 void
-test_cipher(const struct nettle_cipher *cipher,
-           unsigned key_length,
-           const uint8_t *key,
-           unsigned length,
-           const uint8_t *cleartext,
-           const uint8_t *ciphertext)
+test_cipher_iv(const struct nettle_cipher *cipher,
+              unsigned key_length,
+              const uint8_t *key,
+              unsigned iv_length,
+              const uint8_t *iv,
+              unsigned length,
+              const uint8_t *cleartext,
+              const uint8_t *ciphertext)
 {
   void *ctx = xalloc(cipher->context_size);
   uint8_t *data = xalloc(length);
 
   cipher->set_encrypt_key(ctx, key_length, key);
+  if (iv_length > 0 && iv)
+    cipher->set_iv(ctx, iv_length, iv);
   cipher->encrypt(ctx, length, data, cleartext);
 
   if (!MEMEQ(length, data, ciphertext))
@@ -187,6 +191,8 @@ test_cipher(const struct nettle_cipher *cipher,
       FAIL();
     }
   cipher->set_decrypt_key(ctx, key_length, key);
+  if (iv_length > 0 && iv)
+    cipher->set_iv(ctx, iv_length, iv);
   cipher->decrypt(ctx, length, data, data);
 
   if (!MEMEQ(length, data, cleartext))
@@ -206,6 +212,24 @@ test_cipher(const struct nettle_cipher *cipher,
 }
 
 void
+test_cipher(const struct nettle_cipher *cipher,
+           unsigned key_length,
+           const uint8_t *key,
+           unsigned length,
+           const uint8_t *cleartext,
+           const uint8_t *ciphertext)
+{
+  test_cipher_iv(cipher,
+                key_length,
+                key,
+                0,
+                NULL,
+                length,
+                cleartext,
+                ciphertext);
+}
+
+void
 test_cipher_cbc(const struct nettle_cipher *cipher,
                unsigned key_length,
                const uint8_t *key,
diff --git a/testsuite/testutils.h b/testsuite/testutils.h
index d7ced9a..9d13dff 100644
--- a/testsuite/testutils.h
+++ b/testsuite/testutils.h
@@ -91,6 +91,16 @@ test_cipher(const struct nettle_cipher *cipher,
            const uint8_t *ciphertext);
 
 void
+test_cipher_iv(const struct nettle_cipher *cipher,
+              unsigned key_length,
+              const uint8_t *key,
+              unsigned iv_length,
+              const uint8_t *iv,
+              unsigned length,
+              const uint8_t *cleartext,
+              const uint8_t *ciphertext);
+
+void
 test_cipher_cbc(const struct nettle_cipher *cipher,
                unsigned key_length,
                const uint8_t *key,
-- 
1.7.2.5

_______________________________________________
nettle-bugs mailing list
[email protected]
http://lists.lysator.liu.se/mailman/listinfo/nettle-bugs

Reply via email to