Browse Source

Add Salsa20

Larry Bugbee 8 years ago
parent
commit
4341424ce9

+ 6 - 0
.gitignore

@@ -58,6 +58,12 @@ timing.exe
 .cproject
 .settings/
 
+# macOS special files
+.DS_Store
+
+# other special files
+showlibs      # symlink to .libs
+
 # oops ;) but we don't want them to appear in the repository...
 *.stackdump
 *.core

+ 43 - 0
doc/crypt.tex

@@ -1301,6 +1301,49 @@ At the end you have to terminate the state:
 err = chacha_done(&st);
 \end{verbatim}
 
+\mysection{Salsa20}
+
+\textit{Salsa20} is the forerunner of the ChaCha stream cipher.  The ChaCha cipher is
+Salsa20 with a few minor tweaks to further improve its strength, and in so doing, increase its
+speed performance by about 5 percent.  Unless you need Salsa20 for some reason, you should
+probably choose ChaCha instead.
+
+In April 2008 \textit{Salsa20/12} was named one of the winners in the EU eSTREAM competition.
+Salsa20 was originally submitted by Daniel Bernstein with 20 rounds of strength but the
+12-round reduced-round version was deemed to have sufficient strength and declared a winner.
+Even the 8-round reduced-round version, Salsa20/8, has withstood attack.
+
+For more information about Salsa20 see \url{https://en.wikipedia.org/wiki/Salsa20}.
+
+Supported key size: 16 or 32 bytes (128 or 256 bits).
+
+You can initialize Salsa20 with 64bit \textit{nonce} + 64bit \textit{counter}:
+\begin{verbatim}
+salsa20_state st;
+err = salsa20_setup(&st, key, key_len, rounds);
+err = salsa20_ivctr64(&st, nonce, 8, initial_64bit_ctr);
+\end{verbatim}
+
+The \textit{salsa20\_setup} takes the number of rounds as a parameter -- choose 20 (the default)
+if you are not sure.  As always never ever use the same key + nonce pair more than once.
+
+For the actual encryption or decryption you have to call:
+\begin{verbatim}
+err = salsa20_crypt(&st, in_buffer, in_len, out_buffer);
+\end{verbatim}
+
+If you just want a random stream of bytes initialize the cipher with a truly random \textit{key}
+(32 bytes), a truly random \textit{nonce} (8 bytes) and zero initial counter. After that you can
+get a stream of pseudo--random bytes via:
+\begin{verbatim}
+err = salsa20_keystream(&st, out_buffer, out_len);
+\end{verbatim}
+
+At the end you have to terminate the state:
+\begin{verbatim}
+err = salsa20_done(&st);
+\end{verbatim}
+
 \mysection{RC4}
 
 For more information about RC4 see \url{https://en.wikipedia.org/wiki/RC4}.

+ 19 - 0
src/headers/tomcrypt_cipher.h

@@ -1012,6 +1012,25 @@ int chacha_test(void);
 
 #endif /* LTC_CHACHA */
 
+#ifdef LTC_SALSA20
+
+typedef struct {
+   ulong32 input[16];
+   unsigned char kstream[64];
+   unsigned long ksleft;
+   unsigned long ivlen;
+   int rounds;
+} salsa20_state;
+
+int salsa20_setup(salsa20_state *st, const unsigned char *key, unsigned long keylen, int rounds);
+int salsa20_ivctr64(salsa20_state *st, const unsigned char *iv, unsigned long ivlen, ulong64 counter);
+int salsa20_crypt(salsa20_state *st, const unsigned char *in, unsigned long inlen, unsigned char *out);
+int salsa20_keystream(salsa20_state *st, unsigned char *out, unsigned long outlen);
+int salsa20_done(salsa20_state *st);
+int salsa20_test(void);
+
+#endif /* LTC_SALSA20 */
+
 #ifdef LTC_RC4_STREAM
 
 typedef struct {

+ 1 - 0
src/headers/tomcrypt_custom.h

@@ -207,6 +207,7 @@
 
 /* stream ciphers */
 #define LTC_CHACHA
+#define LTC_SALSA20
 #define LTC_RC4_STREAM
 #define LTC_SOBER128_STREAM
 

+ 3 - 0
src/misc/crypt/crypt.c

@@ -132,6 +132,9 @@ const char *crypt_build_settings =
 #if defined(LTC_CHACHA)
    "   ChaCha\n"
 #endif
+#if defined(LTC_SALSA20)
+   "   Salsa20\n"
+#endif
 #if defined(LTC_RC4_STREAM)
    "   RC4\n"
 #endif

+ 3 - 0
src/misc/crypt/crypt_sizes.c

@@ -177,6 +177,9 @@ static const crypt_size _crypt_sizes[] = {
 #ifdef LTC_CHACHA
     _SZ_STRINGIFY_T(chacha_state),
 #endif
+#ifdef LTC_SALSA20
+    _SZ_STRINGIFY_T(salsa20_state),
+#endif
 #ifdef LTC_RC4_STREAM
     _SZ_STRINGIFY_T(rc4_state),
 #endif

+ 96 - 0
src/stream/salsa20/salsa20_crypt.c

@@ -0,0 +1,96 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* The implementation is based on:
+ * "Salsa20 specification", http://cr.yp.to/snuffle/spec.pdf
+ * and salsa20-ref.c version 20051118
+ * Public domain from D. J. Bernstein
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_SALSA20
+
+#define QUARTERROUND(a,b,c,d) \
+    x[b] ^= (ROL((x[a] + x[d]),  7)); \
+    x[c] ^= (ROL((x[b] + x[a]),  9)); \
+    x[d] ^= (ROL((x[c] + x[b]), 13)); \
+    x[a] ^= (ROL((x[d] + x[c]), 18));
+
+static void _salsa20_block(unsigned char *output, const ulong32 *input, int rounds)
+{
+   ulong32 x[16];
+   int i;
+   XMEMCPY(x, input, sizeof(x));
+   for (i = rounds; i > 0; i -= 2) {
+      QUARTERROUND( 0, 4, 8,12)
+      QUARTERROUND( 5, 9,13, 1)
+      QUARTERROUND(10,14, 2, 6)
+      QUARTERROUND(15, 3, 7,11)
+      QUARTERROUND( 0, 1, 2, 3)
+      QUARTERROUND( 5, 6, 7, 4)
+      QUARTERROUND(10,11, 8, 9)
+      QUARTERROUND(15,12,13,14)
+   }
+   for (i = 0; i < 16; ++i) {
+     x[i] += input[i];
+     STORE32L(x[i], output + 4 * i);
+   }
+}
+
+/**
+   Encrypt (or decrypt) bytes of ciphertext (or plaintext) with Salsa20
+   @param st      The Salsa20 state
+   @param in      The plaintext (or ciphertext)
+   @param inlen   The length of the input (octets)
+   @param out     [out] The ciphertext (or plaintext), length inlen
+   @return CRYPT_OK if successful
+*/
+int salsa20_crypt(salsa20_state *st, const unsigned char *in, unsigned long inlen, unsigned char *out)
+{
+   unsigned char buf[64];
+   unsigned long i, j;
+
+   if (inlen == 0) return CRYPT_OK; /* nothing to do */
+
+   LTC_ARGCHK(st        != NULL);
+   LTC_ARGCHK(in        != NULL);
+   LTC_ARGCHK(out       != NULL);
+   LTC_ARGCHK(st->ivlen == 8);
+
+   if (st->ksleft > 0) {
+      j = MIN(st->ksleft, inlen);
+      for (i = 0; i < j; ++i, st->ksleft--) out[i] = in[i] ^ st->kstream[64 - st->ksleft];
+      inlen -= j;
+      if (inlen == 0) return CRYPT_OK;
+      out += j;
+      in  += j;
+   }
+   for (;;) {
+     _salsa20_block(buf, st->input, st->rounds);
+     /* Salsa20: 64-bit IV, increment 64-bit counter */
+     if (0 == ++st->input[8] && 0 == ++st->input[9]) return CRYPT_OVERFLOW;
+     if (inlen <= 64) {
+       for (i = 0; i < inlen; ++i) out[i] = in[i] ^ buf[i];
+       st->ksleft = 64 - inlen;
+       for (i = inlen; i < 64; ++i) st->kstream[i] = buf[i];
+       return CRYPT_OK;
+     }
+     for (i = 0; i < 64; ++i) out[i] = in[i] ^ buf[i];
+     inlen -= 64;
+     out += 64;
+     in  += 64;
+   }
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */

+ 30 - 0
src/stream/salsa20/salsa20_done.c

@@ -0,0 +1,30 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_SALSA20
+
+/**
+  Terminate and clear Salsa20 state
+  @param st      The Salsa20 state
+  @return CRYPT_OK on success
+*/
+int salsa20_done(salsa20_state *st)
+{
+   LTC_ARGCHK(st != NULL);
+   XMEMSET(st, 0, sizeof(salsa20_state));
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */

+ 48 - 0
src/stream/salsa20/salsa20_ivctr64.c

@@ -0,0 +1,48 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* The implementation is based on:
+ * "Salsa20 specification", http://cr.yp.to/snuffle/spec.pdf
+ * and salsa20-ref.c version 20051118
+ * Public domain from D. J. Bernstein
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_SALSA20
+
+/**
+  Set IV + counter data to the Salsa20 state
+  @param st      The Salsa20 state
+  @param iv      The IV data to add
+  @param ivlen   The length of the IV (must be 8)
+  @param counter 64bit (unsigned) initial counter value
+  @return CRYPT_OK on success
+ */
+int salsa20_ivctr64(salsa20_state *st, const unsigned char *iv, unsigned long ivlen, ulong64 counter)
+{
+   LTC_ARGCHK(st != NULL);
+   LTC_ARGCHK(iv != NULL);
+   /* Salsa20: 64-bit IV (nonce) + 64-bit counter */
+   LTC_ARGCHK(ivlen == 8);
+
+   LOAD32L(st->input[6], iv + 0);
+   LOAD32L(st->input[7], iv + 4);
+   st->input[8] = (ulong32)(counter & 0xFFFFFFFF);
+   st->input[9] = (ulong32)(counter >> 32);
+   st->ksleft = 0;
+   st->ivlen = ivlen;
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */

+ 39 - 0
src/stream/salsa20/salsa20_keystream.c

@@ -0,0 +1,39 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* The implementation is based on:
+ * "Salsa20 specification", http://cr.yp.to/snuffle/spec.pdf
+ * and salsa20-ref.c version 20051118
+ * Public domain from D. J. Bernstein
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_SALSA20
+
+/**
+  Generate a stream of random bytes via Salsa20
+  @param st      The Salsa20 state
+  @param out     [out] The output buffer
+  @param outlen  The output length
+  @return CRYPT_OK on success
+ */
+int salsa20_keystream(salsa20_state *st, unsigned char *out, unsigned long outlen)
+{
+   if (outlen == 0) return CRYPT_OK; /* nothing to do */
+   LTC_ARGCHK(out != NULL);
+   XMEMSET(out, 0, outlen);
+   return salsa20_crypt(st, out, outlen, out);
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */

+ 69 - 0
src/stream/salsa20/salsa20_setup.c

@@ -0,0 +1,69 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* The implementation is based on:
+ * "Salsa20 specification", http://cr.yp.to/snuffle/spec.pdf
+ * and salsa20-ref.c version 20051118
+ * Public domain from D. J. Bernstein
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_SALSA20
+
+static const char * const sigma = "expand 32-byte k";
+static const char * const tau   = "expand 16-byte k";
+
+/**
+   Initialize an Salsa20 context (only the key)
+   @param st        [out] The destination of the Salsa20 state
+   @param key       The secret key
+   @param keylen    The length of the secret key (octets)
+   @param rounds    Number of rounds (e.g. 20 for Salsa20)
+   @return CRYPT_OK if successful
+*/
+int salsa20_setup(salsa20_state *st, const unsigned char *key, unsigned long keylen, int rounds)
+{
+   const char *constants;
+
+   LTC_ARGCHK(st  != NULL);
+   LTC_ARGCHK(key != NULL);
+   LTC_ARGCHK(keylen == 32 || keylen == 16);
+
+   if (rounds == 0) rounds = 20;
+   LTC_ARGCHK(rounds % 2 == 0); /* number of rounds must be evenly divisible by 2 */
+
+   LOAD32L(st->input[1],  key + 0);
+   LOAD32L(st->input[2],  key + 4);
+   LOAD32L(st->input[3],  key + 8);
+   LOAD32L(st->input[4],  key + 12);
+   if (keylen == 32) { /* 256bit */
+      key += 16;
+      constants = sigma;
+   } else { /* 128bit */
+      constants = tau;
+   }
+   LOAD32L(st->input[11], key + 0);
+   LOAD32L(st->input[12], key + 4);
+   LOAD32L(st->input[13], key + 8);
+   LOAD32L(st->input[14], key + 12);
+   LOAD32L(st->input[ 0],  constants + 0);
+   LOAD32L(st->input[ 5],  constants + 4);
+   LOAD32L(st->input[10],  constants + 8);
+   LOAD32L(st->input[15],  constants + 12);
+   st->rounds = rounds;     /* default is 20 for salsa20 */
+   st->ivlen = 0;           /* will be set later by salsa20_ivctr(32|64) */
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */

+ 67 - 0
src/stream/salsa20/salsa20_test.c

@@ -0,0 +1,67 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* The implementation is based on:
+ * "Salsa20 specification", http://cr.yp.to/snuffle/spec.pdf
+ * and salsa20-ref.c version 20051118
+ * Public domain from D. J. Bernstein
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_SALSA20
+
+int salsa20_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   int  counter = 0;
+   int  rounds  = 0;
+   unsigned long len;
+   unsigned char out[1000];
+   unsigned char k[]   = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+                           0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f };
+   unsigned char n[]   = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a };
+   unsigned char ct[]  = { 0x37, 0x37, 0x2e, 0x60, 0xb8, 0xae, 0x88, 0x1f, 0xf8, 0xdf, 0x00, 0x26, 0x6c, 0x30, 0x34, 0x2d,
+                           0xa1, 0xd7, 0x79, 0x60, 0x67, 0x72, 0xe0, 0x67, 0x26, 0x22, 0xad, 0x00, 0x9e, 0xd5, 0x59, 0x44,
+                           0x51, 0xd9, 0xe6, 0xaa, 0xc9, 0x59, 0x9e, 0x60, 0xff, 0x87, 0x90, 0xc1, 0xc9, 0x1e };
+   unsigned char ct2[] = { 0xec, 0x06, 0x32, 0xb3, 0x83, 0x5c, 0xae, 0x91, 0x01, 0x82, 0x7a, 0x71, 0xd9, 0x7d, 0x45, 0xd7,
+                           0xa6, 0x5b, 0xa0, 0x89, 0x9d, 0xd2, 0x6c, 0xaa, 0xbb, 0x2f, 0x5f, 0x30, 0x89, 0x54, 0xff, 0x3e,
+                           0x83, 0xc3, 0x34, 0x10, 0xb6, 0xe1, 0xab, 0xe7, 0xf5, 0xab, 0xab, 0xed, 0xa4, 0xff };
+   char pt[]    = "Kilroy was here, and there. ...and everywhere!";    /* len = 46 bytes */
+   salsa20_state st;
+   int err;
+
+   len = strlen(pt);
+   /* crypt piece by piece */
+   rounds  = 12;
+   if ((err = salsa20_setup(&st, k, sizeof(k), rounds)) != CRYPT_OK)                        return err;
+   if ((err = salsa20_ivctr64(&st, n, sizeof(n), counter)) != CRYPT_OK)                     return err;
+   if ((err = salsa20_crypt(&st, (unsigned char*)pt,       5,       out)) != CRYPT_OK)      return err;
+   if ((err = salsa20_crypt(&st, (unsigned char*)pt +  5, 25,       out +  5)) != CRYPT_OK) return err;
+   if ((err = salsa20_crypt(&st, (unsigned char*)pt + 30, 10,       out + 30)) != CRYPT_OK) return err;
+   if ((err = salsa20_crypt(&st, (unsigned char*)pt + 40, len - 40, out + 40)) != CRYPT_OK) return err;
+   if (compare_testvector(out, len, ct, sizeof(ct), "SALSA20-TV1", 1))                      return CRYPT_FAIL_TESTVECTOR;
+   /* crypt in one go - using salsa20_ivctr64() */
+   rounds  = 20;
+   if ((err = salsa20_setup(&st, k, sizeof(k), rounds)) != CRYPT_OK)                        return err;
+   if ((err = salsa20_ivctr64(&st, n, sizeof(n), counter)) != CRYPT_OK)                     return err;
+   if ((err = salsa20_crypt(&st, (unsigned char*)pt, len, out)) != CRYPT_OK)                return err;
+   if (compare_testvector(out, len, ct2, sizeof(ct), "SALSA20-TV2", 1))                     return CRYPT_FAIL_TESTVECTOR;
+
+   return CRYPT_OK;
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */

+ 5 - 2
tests/cipher_hash_test.c

@@ -14,15 +14,18 @@ int cipher_hash_test(void)
 {
    int           x;
 
-   /* test ciphers */
+   /* test block ciphers */
    for (x = 0; cipher_descriptor[x].name != NULL; x++) {
       DOX(cipher_descriptor[x].test(), cipher_descriptor[x].name);
    }
 
-   /* stream ciphers */
+   /* test stream ciphers */
 #ifdef LTC_CHACHA
    DO(chacha_test());
 #endif
+#ifdef LTC_SALSA20
+   DO(salsa20_test());
+#endif
 #ifdef LTC_RC4_STREAM
    DO(rc4_stream_test());
 #endif