chiark / gitweb /
lib/: Use Salsa20/8 for random bits, rather than RC4.
authorMark Wooding <mdw@distorted.org.uk>
Tue, 17 Jul 2018 12:00:26 +0000 (13:00 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Fri, 20 Jul 2018 11:07:53 +0000 (12:07 +0100)
It's faster and produces better quality random bits; RC4's biases are
somewhat notorious.

12 files changed:
.gitignore
lib/Makefile.am
lib/arcfour.c [deleted file]
lib/arcfour.h [deleted file]
lib/lib.vcxproj
lib/lib.vcxproj.filters
lib/random.c
lib/salsa208.c [new file with mode: 0644]
lib/salsa208.h [new file with mode: 0644]
libtests/Makefile.am
libtests/t-arcfour.c [deleted file]
libtests/t-salsa208.c [new file with mode: 0644]

index fa6129097b0b8c6fb9418c4d8ba2169d54931f66..ba1f52b1ac886214adde344897184a4e24d35e3d 100644 (file)
@@ -178,7 +178,6 @@ doc/disorder_options.5
 doc/disorder_options.5.html
 doc/disorder_actions.5.in
 doc/disorder_templates.5.in
-libtests/t-arcfour
 libtests/t-charset
 libtests/t-event
 libtests/t-dateparse
@@ -221,3 +220,4 @@ server/disorder-gstdecode
 .dirstamp
 tests/*.trs
 /common/Makefile
+libtests/t-salsa208
index 279f073a48f78278356423eb38de065bff1b8e92..a6a362fb9406fe96663d309d2e105712d7908d68 100644 (file)
@@ -29,7 +29,6 @@ endif
 
 libdisorder_a_SOURCES=charset.c charsetf.c charset.h   \
        addr.c addr.h                                   \
-       arcfour.c arcfour.h                             \
        authhash.c authhash.h                           \
        basen.c basen.h                                 \
        base64.c base64.h                               \
@@ -72,6 +71,7 @@ libdisorder_a_SOURCES=charset.c charsetf.c charset.h  \
        resample.c resample.h                           \
        rights.c queue-rights.c rights.h                \
        rtp.h                                           \
+       salsa208.c salsa208.h                           \
        selection.c selection.h                         \
        sendmail.c sendmail.h                           \
        signame.c signame.h                             \
diff --git a/lib/arcfour.c b/lib/arcfour.c
deleted file mode 100644 (file)
index 3450562..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/* arcfour.c --- The arcfour stream cipher
- * Copyright (C) 2000, 2001, 2002, 2003, 2005, 2006 Free Software
- * Foundation, Inc.
- *
- * This file is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * This file is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this file; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- */
-/** @file lib/arcfour.c
- * @brief Arcfour (RC4-compatible) stream cipher implementation
- *
- * Code from Libgcrypt adapted for gnulib by Simon Josefsson.
- *
- * For a description of the algorithm, see:
- * 
- *   Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996.
- *   ISBN 0-471-11709-9. Pages 397 ff.
- */
-
-#include "arcfour.h"
-
-/** @brief Encrypt using Arcfour stream cipher
- * @param context Context structure
- * @param inbuf Input buffer
- * @param outbuf Output buffer
- * @param length Number of bytes in @p inbuf
- *
- * Copies from @p inbuf to @p outbuf, encrypting (or decrypting) using
- * the stream controlled by @p context.
- */
-void
-arcfour_stream (arcfour_context * context, const char *inbuf, char *outbuf,
-               size_t length)
-{
-  uint8_t i = context->idx_i;
-  uint8_t j = context->idx_j;
-  char *sbox = context->sbox;
-
-  for (; length > 0; length--)
-    {
-      char t;
-
-      i++;
-      j += sbox[i];
-      t = sbox[i];
-      sbox[i] = sbox[j];
-      sbox[j] = t;
-      *outbuf++ = (*inbuf++
-                  ^ sbox[(0U + sbox[i] + sbox[j]) % ARCFOUR_SBOX_SIZE]);
-    }
-
-  context->idx_i = i;
-  context->idx_j = j;
-}
-
-/** @brief Initialize an @ref arcfour_context
- * @param context Context structure
- * @param key Key data
- * @param keylen Length of key
- *
- * Initializes @p context using @p key.
- */
-void
-arcfour_setkey (arcfour_context * context, const char *key, size_t keylen)
-{
-  size_t i, j, k;
-  char *sbox = context->sbox;
-
-  context->idx_i = context->idx_j = 0;
-  for (i = 0; i < ARCFOUR_SBOX_SIZE; i++)
-    sbox[i] = i;
-  for (i = j = k = 0; i < ARCFOUR_SBOX_SIZE; i++)
-    {
-      char t;
-      j = (j + sbox[i] + key[k]) % ARCFOUR_SBOX_SIZE;
-      t = sbox[i];
-      sbox[i] = sbox[j];
-      sbox[j] = t;
-      if (++k == keylen)
-       k = 0;
-    }
-}
diff --git a/lib/arcfour.h b/lib/arcfour.h
deleted file mode 100644 (file)
index 4993961..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/* arcfour.h --- The arcfour stream cipher
- * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005
- *    Free Software Foundation, Inc.
- *
- * This file is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * This file is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this file; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- */
-/** @file lib/arcfour.h
- * @brief Arcfour (RC4-compatible) stream cipher implementation
- */
-
-/* Code from Libgcrypt adapted for gnulib by Simon Josefsson. */
-
-#ifndef ARCFOUR_H
-# define ARCFOUR_H
-
-# include <stddef.h>
-# include <stdint.h>
-
-#define ARCFOUR_SBOX_SIZE 256
-
-/** @brief Context structture for Arcfour stream cipher */
-typedef struct
-{
-  char sbox[ARCFOUR_SBOX_SIZE];
-  uint8_t idx_i, idx_j;
-} arcfour_context;
-
-/* Apply ARCFOUR stream to INBUF placing the result in OUTBUF, both of
-   LENGTH size.  CONTEXT must be initialized with arcfour_setkey
-   before this function is called. */
-extern void
-arcfour_stream (arcfour_context * context,
-               const char *inbuf, char *outbuf, size_t length);
-
-/* Initialize CONTEXT using encryption KEY of KEYLEN bytes.  KEY
-   should be 40 bits (5 bytes) or longer.  The KEY cannot be zero
-   length.  */
-extern void
-arcfour_setkey (arcfour_context * context, const char *key, size_t keylen);
-
-#endif /* ARCFOUR_H */
index f9087d1811a85f2d43f42182702319b665c861f7..5a122474ec74262a0807470c58fe5f4e970b1d5e 100644 (file)
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup Label="ProjectConfigurations">
     <ProjectConfiguration Include="Debug|Win32">
@@ -72,7 +72,6 @@
   </ItemDefinitionGroup>
   <ItemGroup>
     <ClCompile Include="addr.c" />
-    <ClCompile Include="arcfour.c" />
     <ClCompile Include="asprintf.c" />
     <ClCompile Include="authhash.c" />
     <ClCompile Include="base64.c" />
     <ClCompile Include="queue-rights.c" />
     <ClCompile Include="queue.c" />
     <ClCompile Include="rights.c" />
+    <ClCompile Include="salsa208.c" />
     <ClCompile Include="selection.c" />
     <ClCompile Include="signame.c" />
     <ClCompile Include="sink.c" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="addr.h" />
-    <ClInclude Include="arcfour.h" />
     <ClInclude Include="authhash.h" />
     <ClInclude Include="base64.h" />
     <ClInclude Include="basen.h" />
     <ClInclude Include="printf.h" />
     <ClInclude Include="queue.h" />
     <ClInclude Include="rights.h" />
+    <ClInclude Include="salsa208.h" />
     <ClInclude Include="selection.h" />
     <ClInclude Include="signame.h" />
     <ClInclude Include="sink.h" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
-</Project>
\ No newline at end of file
+</Project>
index 281a5851539d81e5381c893f5dd64cb7773252f2..a4f24582230fb12ec93db39813feea742c8d7aab 100644 (file)
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
     <Filter Include="Source Files">
@@ -48,9 +48,6 @@
     <ClCompile Include="table.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="arcfour.c">
-      <Filter>Source Files</Filter>
-    </ClCompile>
     <ClCompile Include="asprintf.c">
       <Filter>Source Files</Filter>
     </ClCompile>
     <ClCompile Include="versionstring.c">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="salsa208.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="common.h">
     <ClInclude Include="table.h">
       <Filter>Header Files</Filter>
     </ClInclude>
-    <ClInclude Include="arcfour.h">
-      <Filter>Header Files</Filter>
-    </ClInclude>
     <ClInclude Include="authhash.h">
       <Filter>Header Files</Filter>
     </ClInclude>
     <ClInclude Include="defs.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="salsa208.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
-</Project>
\ No newline at end of file
+</Project>
index e9933a2a1a2b5ec236f63ca614da329eb6442df1..ee53a9acc0fcf5206fe0d1dcfce8374cb19d9f88 100644 (file)
 
 #include "random.h"
 #include "log.h"
-#include "arcfour.h"
+#include "salsa208.h"
 #include "basen.h"
 #include "mem.h"
 
 static int random_count;
 static int random_fd = -1;
-static arcfour_context random_ctx[1];
+static salsa208_context random_ctx[1];
 
 /** @brief Rekey the RNG
  *
  * Resets the RNG's key to a random one read from /dev/urandom
  */
 static void random__rekey(void) {
-  char key[128];
+  char key[32];
   int n;
 
   if(random_fd < 0) {
@@ -53,8 +53,8 @@ static void random__rekey(void) {
     disorder_fatal(errno, "reading from /dev/urandom");
   if((size_t)n < sizeof key)
     disorder_fatal(0, "reading from /dev/urandom: short read");
-  arcfour_setkey(random_ctx, key, sizeof key);
-  random_count = 8 * 1024 * 1024;
+  salsa208_setkey(random_ctx, key, sizeof key);
+  random_count = 256 * 1024 * 1024;
 }
 
 /** @brief Get random bytes
@@ -64,9 +64,7 @@ static void random__rekey(void) {
 void random_get(void *ptr, size_t bytes) {
   if(random_count == 0)
     random__rekey();
-  /* Encrypting 0s == just returning the keystream */
-  memset(ptr, 0, bytes);
-  arcfour_stream(random_ctx, (char *)ptr, (char *)ptr, bytes);
+  salsa208_stream(random_ctx, 0, ptr, bytes);
   if(bytes > (size_t)random_count)
     random_count = 0;
   else
diff --git a/lib/salsa208.c b/lib/salsa208.c
new file mode 100644 (file)
index 0000000..a8adff4
--- /dev/null
@@ -0,0 +1,258 @@
+/* salsa208.c --- The Salsa20/8 stream cipher
+ * Copyright (C) Mark Wooding
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this file; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+/** @file lib/salsa208.c
+ * @brief Salsa20/8 stream cipher implementation
+ *
+ * For a description of the algorithm, see:
+ *
+ *   Daniel J. Bernstein, `The Salsa20 family of stream ciphers', in Matthew
+ *   Robshaw and Olivier Billet (eds.), `New Stream Cipher Designs',
+ *   Springer--Verlag 2008, pp. 84--97;
+ *   http://cr.yp.to/snuffle/salsafamily-20071225.pdf
+ *
+ * As far as I know, the best attack against all 8 rounds of Salsa20/8 is by
+ * Aumasson, Fischer, Khazaei, Meier, and Rechberger, which takes 2^251
+ * operations to recover a 256-bit key, which is hopelessly impractical.
+ * Much more effective attacks are known against Salsa20/7, so we would have
+ * a tiny security margin if we were trying for security -- but we aren't.
+ * Instead, we want high-quality randomness for queue ids and for selecting
+ * random tracks.  (The cookie machinery, which does want cryptographic
+ * security, makes its own arrangements.)  Specifically, the intention is to
+ * replace RC4, which (a) is slow because it has a long dependency chain
+ * which plays badly with the deep pipelines in modern CPUs, and (b) has
+ * well-known and rather embarassing biases.  On the other hand, Salsa20/8
+ * has no known biases, and admits considerable instruction-level
+ * parallelism.  In practice, Salsa20/8 is about 30% faster than RC4 even
+ * without a fancy SIMD implementation (which is good, because this isn't one
+ * of those); a vectorized implementation acting on multiple blocks at a time
+ * would be even faster.
+ *
+ * Salsa20/8 has a number of other attractive features, such as being
+ * trivially seekable, but we don't need those here and the necessary
+ * machinery is not implemented.
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include "salsa208.h"
+
+static inline uint32_t ld16(const void *p) {
+  const unsigned char *q = p;
+  return ((uint32_t)q[0] <<  0) | ((uint32_t)q[1] <<  8);
+}
+
+static inline uint32_t ld32(const void *p) {
+  const unsigned char *q = p;
+  return ((uint32_t)q[0] <<  0) | ((uint32_t)q[1] <<  8) |
+        ((uint32_t)q[2] << 16) | ((uint32_t)q[3] << 24);
+}
+
+static inline void st32(void *p, uint32_t x) {
+  unsigned char *q = p;
+  q[0] = (x >>  0)&0xff; q[1] = (x >>  8)&0xff;
+  q[2] = (x >> 16)&0xff; q[3] = (x >> 24)&0xff;
+}
+
+static inline uint32_t rol32(uint32_t x, unsigned n)
+  { return (x << n) | (x >> (32 - n)); }
+
+static inline void quarterround(uint32_t m[16], int a, int b, int c, int d) {
+  m[b] ^= rol32(m[a] + m[d],  7); m[c] ^= rol32(m[b] + m[a],  9);
+  m[d] ^= rol32(m[c] + m[b], 13); m[a] ^= rol32(m[d] + m[c], 18);
+}
+
+static void core(salsa208_context *context) {
+  unsigned i;
+  uint32_t t[16];
+
+  /* Copy the state. */
+  for(i = 0; i < 16; i++) t[i] = context->m[i];
+
+  /* Hack on the state. */
+  for(i = 0; i < 4; i++) {
+
+    /* Vertical quarter-rounds. */
+    quarterround(t,  0,  4,  8, 12);
+    quarterround(t,  5,  9, 13,  1);
+    quarterround(t, 10, 14,  2,  6);
+    quarterround(t, 15,  3,  7, 11);
+
+    /* Horizontal quarter-rounds. */
+    quarterround(t,  0,  1,  2,  3);
+    quarterround(t,  5,  6,  7,  4);
+    quarterround(t, 10, 11,  8,  9);
+    quarterround(t, 15, 12, 13, 14);
+  }
+
+  /* Final feedforward. */
+  for(i = 0; i < 16; i++) t[i] += context->m[i];
+
+  /* Output. */
+  for(i = 0; i < 16; i++) st32(context->buf + 4*i, t[i]);
+}
+
+static inline void xorbuf(void *z, const void *x, const void *y, size_t sz) {
+  unsigned char *zz = z;
+  const unsigned char *xx = x, *yy = y;
+
+  if(!xx) memcpy(zz, yy, sz);
+  else while(sz--) *zz++ = *xx++ ^ *yy++;
+}
+
+static inline void step(salsa208_context *context)
+  { if(!++context->m[8]) context->m[9]++; }
+
+/** @brief Encrypt or decrypt data using Salsa20/8.
+ *
+ * @param context The Salsa20/8 context, initialized using salsa208_setkey().
+ * @param inbuf Pointer to input buffer
+ * @param outbuf Pointer to output buffer
+ * @param length Common size of both buffers
+ *
+ * Encrypt or decrypt (the operations are the same) @p length bytes of input
+ * data, writing the result, of the same length, to @p outbuf.  The input and
+ * output pointers may be equal; the two buffers may not otherwise overlap.
+ *
+ * If @p inbuf is null, then simply write the next @p length bytes of
+ * Salsa20/8 output to @p outbuf.
+ */
+void salsa208_stream(salsa208_context *context,
+                    const void *inbuf, void *outbuf, size_t length) {
+  size_t left = 64 - context->i;
+  unsigned char *z = outbuf;
+  const unsigned char *x = inbuf;
+
+  /* If we can satisfy the request from our buffer then we should do that. */
+  if(length <= left) {
+    xorbuf(z, x, context->buf + context->i, length);
+    context->i += length;
+    return;
+  }
+
+  /* Drain the buffer of what we currently have and cycle the state. */
+  xorbuf(z, x, context->buf + context->i, left);
+  length -= left; z += left; if(x) x += left;
+  core(context); step(context);
+
+  /* Take multiple complete blocks directly. */
+  while(length > 64) {
+    xorbuf(z, x, context->buf, 64);
+    length -= 64; z += 64; if(x) x += 64;
+    core(context); step(context);
+  }
+
+  /* And the final tail end. */
+  xorbuf(z, x, context->buf, length);
+  context->i = length;
+}
+
+/** @brief Initialize a Salsa20/8 context.
+ *
+ * @param context The Salsa20/8 context to initialize
+ * @param key A pointer to the key material
+ * @param keylen The length of the key data, in bytes (must be 10, 16, or 32)
+ *
+ * The context is implicitly initialized with a zero nonce, which is fine if
+ * the key will be used only for a single message.  Otherwise, a fresh nonce
+ * should be chosen somehow and set using salsa208_setnonce().
+ */
+void salsa208_setkey(salsa208_context *context,
+                    const void *key, size_t keylen) {
+  const unsigned char *k = key;
+  switch(keylen) {
+  case 32:
+    context->m[ 0] = 0x61707865;
+    context->m[ 1] = ld32(k +  0);
+    context->m[ 2] = ld32(k +  4);
+    context->m[ 3] = ld32(k +  8);
+    context->m[ 4] = ld32(k + 12);
+    context->m[ 5] = 0x3320646e;
+    context->m[ 6] = 0;
+    context->m[ 7] = 0;
+    context->m[ 8] = 0;
+    context->m[ 9] = 0;
+    context->m[10] = 0x79622d32;
+    context->m[11] = ld32(k + 16);
+    context->m[12] = ld32(k + 20);
+    context->m[13] = ld32(k + 24);
+    context->m[14] = ld32(k + 28);
+    context->m[15] = 0x6b206574;
+    break;
+  case 16:
+    context->m[ 0] = 0x61707865;
+    context->m[ 1] = ld32(k +  0);
+    context->m[ 2] = ld32(k +  4);
+    context->m[ 3] = ld32(k +  8);
+    context->m[ 4] = ld32(k + 12);
+    context->m[ 5] = 0x3120646e;
+    context->m[ 6] = 0;
+    context->m[ 7] = 0;
+    context->m[ 8] = 0;
+    context->m[ 9] = 0;
+    context->m[10] = 0x79622d36;
+    context->m[11] = context->m[1];
+    context->m[12] = context->m[2];
+    context->m[13] = context->m[3];
+    context->m[14] = context->m[4];
+    context->m[15] = 0x6b206574;
+    break;
+  case 10:
+    context->m[ 0] = 0x61707865;
+    context->m[ 1] = ld32(k +  0);
+    context->m[ 2] = ld32(k +  4);
+    context->m[ 3] = ld16(k +  8);
+    context->m[ 4] = 0;
+    context->m[ 5] = 0x3120646e;
+    context->m[ 6] = 0;
+    context->m[ 7] = 0;
+    context->m[ 8] = 0;
+    context->m[ 9] = 0;
+    context->m[10] = 0x79622d30;
+    context->m[11] = context->m[1];
+    context->m[12] = context->m[2];
+    context->m[13] = context->m[3];
+    context->m[14] = 0;
+    context->m[15] = 0x6b206574;
+    break;
+  default:
+    assert(!"bad Salsa20 key length");
+  }
+  context->i = 64;
+}
+
+/** @brief Set the Salsa20/8 nonce.
+ *
+ * @param context The Salsa20/8 context
+ * @param nonce A pointer to the nonce
+ * @param noncelen The length of the nonce data, in bytes (must be exactly 8)
+ *
+ * The context is automatically rewound to the start of the stream
+ * corresponding to this nonce.
+ */
+void salsa208_setnonce(salsa208_context *context,
+                      const void *nonce, size_t noncelen) {
+  const unsigned char *n = nonce;
+  assert(noncelen == 8);
+  context->m[6] = ld32(n +  0);
+  context->m[7] = ld32(n +  4);
+  context->m[8] = context->m[9] = 0;
+  context->i = 64;
+}
diff --git a/lib/salsa208.h b/lib/salsa208.h
new file mode 100644 (file)
index 0000000..3a4c230
--- /dev/null
@@ -0,0 +1,44 @@
+/* salsa208.h --- The Salsa20/8 stream cipher
+ * Copyright (C) 2018 Mark Wooding
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this file; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+/** @file lib/salsa208.h
+ * @brief Salsa20/8 stream cipher implementation
+ */
+
+#ifndef SALSA208_H
+# define SALSA208_H
+
+# include <stddef.h>
+# include <stdint.h>
+
+/** @brief Context structure for Salsa208 stream cipher */
+typedef struct {
+  uint32_t m[16];                      /* the raw state matrix */
+  uint8_t buf[64];                     /* current output buffer */
+  unsigned i;                          /* cursor in output buffer */
+} salsa208_context;
+
+extern void salsa208_stream(salsa208_context *context,
+                           const void *inbuf, void *outbuf, size_t length);
+extern void salsa208_setkey(salsa208_context *context,
+                           const void *key, size_t keylen);
+extern void salsa208_setnonce(salsa208_context *context,
+                             const void *nonce, size_t noncelen);
+
+#endif /* SALSA208_H */
index 83a7f97e52184ed63d98725e7cec3a21a29dde32..e6fdaa7a43d9c6a357947d3491c24ca5a394c557 100644 (file)
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
 
-TESTS=t-addr t-arcfour t-basen t-bits t-cache t-casefold t-charset     \
+TESTS=t-addr t-basen t-bits t-cache t-casefold t-charset               \
        t-cookies t-dateparse t-event t-filepart t-hash t-heap t-hex    \
        t-kvp t-mime t-printf t-regsub t-selection t-signame t-sink     \
        t-split t-syscalls t-trackname t-unicode t-url t-utf8 t-vector  \
        t-words t-wstat t-macros t-cgi t-eventdist t-resample           \
-       t-configuration t-timeval
+       t-configuration t-timeval t-salsa208
 
 noinst_PROGRAMS=$(TESTS)
 
@@ -29,7 +29,6 @@ AM_CPPFLAGS=-I${top_srcdir}/lib -I../lib
 LDADD=../lib/libdisorder.a $(LIBPCRE) $(LIBICONV) $(LIBGC)
 
 t_addr_SOURCES=t-addr.c test.c test.h
-t_arcfour_SOURCES=t-arcfour.c test.c test.h
 t_basen_SOURCES=t-basen.c test.c test.h
 t_bits_SOURCES=t-bits.c test.c test.h
 t_cache_SOURCES=t-cache.c test.c test.h
@@ -68,6 +67,7 @@ t_resample_LDADD=$(LDADD) $(LIBSAMPLERATE)
 t_configuration_SOURCES=t-configuration.c test.c test.h
 t_configuration_LDADD=$(LDADD) $(LIBGCRYPT)
 t_timeval_SOURCES=t-timeval.c test.c test.h
+t_salsa208_SOURCES=t-salsa208.c test.c test.h
 
 check-report: before-check check make-coverage-reports
 before-check:
diff --git a/libtests/t-arcfour.c b/libtests/t-arcfour.c
deleted file mode 100644 (file)
index 3ae26fb..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * This file is part of DisOrder.
- * Copyright (C) 2008 Richard Kettlewell
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-#include "test.h"
-#include "arcfour.h"
-
-#define TEST_ARCFOUR(K, P, C) do {                     \
-  arcfour_setkey(ac, K, strlen(K));                    \
-  arcfour_stream(ac, P, (char *)output, strlen(P));    \
-  output_hex = hex(output, strlen(P));                 \
-  check_string(output_hex, C);                         \
-} while(0)
-  
-static void test_arcfour(void) {
-  arcfour_context ac[1];
-  uint8_t output[64];
-  char *output_hex;
-
-  /* from wikipedia */
-  TEST_ARCFOUR("Key", "Plaintext", "bbf316e8d940af0ad3");
-  TEST_ARCFOUR("Wiki", "pedia", "1021bf0420");
-  TEST_ARCFOUR("Secret", "Attack at dawn", "45a01f645fc35b383552544b9bf5");
-
-}
-
-TEST(arcfour);
-
-/*
-Local Variables:
-c-basic-offset:2
-comment-column:40
-fill-column:79
-indent-tabs-mode:nil
-End:
-*/
diff --git a/libtests/t-salsa208.c b/libtests/t-salsa208.c
new file mode 100644 (file)
index 0000000..47779d2
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * This file is part of DisOrder.
+ * Copyright (C) 2008 Richard Kettlewell, 2018 Mark Wooding
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "test.h"
+#include "salsa208.h"
+
+#define TEST_SALSA208(K, N, P, C) do {                                  \
+  Kbytes = unhex(K, &Klen);                                             \
+  salsa208_setkey(ac, Kbytes, Klen);                                    \
+  Nbytes = unhex(N, &Nlen);                                             \
+  salsa208_setnonce(ac, Nbytes, Nlen);                                  \
+  Pbytes = unhex(P, &Plen);                                             \
+  salsa208_stream(ac, Pbytes, output, Plen);                            \
+  output_hex = hex(output, Plen);                                       \
+  check_string(output_hex, C);                                          \
+} while(0)
+  
+static void test_salsa208(void) {
+  salsa208_context ac[1];
+  uint8_t output[80], *Kbytes, *Nbytes, *Pbytes;
+  char *output_hex;
+  size_t Klen, Nlen, Plen;
+
+  /* from the eStream submission */
+  TEST_SALSA208("0f62b5085bae0154a7fa4da0f34699ec3f92e5388bde3184d72a7dd02376c91c",
+                "288ff65dc42b92f9",
+                "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+                "36ceb42e23ce2fed61d1a4e5a6e0a600dcca12ce4f1316c175c0bde0825d90972f574a7a25665fe6c3b91a70f1b83795330f5cfa8922c8f9b0589beade0b1432");
+
+  /* test against Catacomb implementation; checks XOR, state stepping */
+  TEST_SALSA208("ce9b04eeb18bb1434d6f534880d8516ff65158f60832325269b5c5e517adb27e",
+                "41f4e1e0db3ef6f2",
+                "d3df3ab24ce7ef617148fdd461757d81b1b3abecb808b4e3ebb542675597c0ab6a4ae3888a7717a8eb2f80b8a3ca33e8c4280757b2f71d409c8618ee50648e35810dfdcbb3ad9436368fde5e645ef019",
+                "3132381a28814d1989bcf09656e64a0ee8c6dd723a3ba5f6a02111f86f5156321ea7300976b2393821d44c425754f6cc08b755ea07287cc77fead40c581259d24d127880b7597fc6a9ea8fba89dd3f4c");
+}
+
+TEST(salsa208);
+
+/*
+Local Variables:
+c-basic-offset:2
+comment-column:40
+fill-column:79
+indent-tabs-mode:nil
+End:
+*/