buggywhip hace 7 años
padre
commit
8144209695

+ 60 - 24
doc/crypt.tex

@@ -1301,49 +1301,85 @@ At the end you have to terminate the state:
 err = chacha_done(&st);
 \end{verbatim}
 
-\mysection{Salsa20}
+\mysection{Salsa20 and XSalsa20}
+
+\textit{Salsa20} was Daniel Bernstein's submission to the EU eSTREAM
+competition where a reduced-round version, \textit{Salsa20/12}, was named
+one of the winners.  A third version, \textit{Salsa20/8}, was also evaluated.
+\vspace{1mm}
+
+While 20 rounds is the conservative default number of rounds, eSTREAM deemed
+12 rounds to be a decent balance between strength and better performance.
+The 8-round version, while still secure as of this writing, is faster but
+does not enjoy the same margin of safety.  Regardless of the number of rounds,
+\textit{Salsa20} accepts either a 128- or a 256-bit key, a 64-bit IV, and a
+64-bit counter.
+\vspace{1mm}
+
+\textit{XSalsa20} is yet another variant of \textit{Salsa20} designed to accept
+only a 256-bit key and a longer 192-bit nonce, initialization being the only
+difference between \textit{XSalsa20} and \textit{Salsa20}.  Even the
+\textit{salsa20\_state} is the same.  Thereafter, salsa20\_crypt(),
+salsa20\_keystream(), and salsa20\_done() are used unaltered.
+salsa20\_ivctr64() is NOT used with xsalsa20\_setup().
+\vspace{1mm}
+
+To initialize \textit{Salsa20} for 8, 12, or 20 rounds with a 128- or a
+256-bit key (16 or 32 bytes), a 64-bit IV (8 bytes), and counter (typically
+zero), use:
 
-\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;
+ulong64 counter = 0;
 err = salsa20_setup(&st, key, key_len, rounds);
-err = salsa20_ivctr64(&st, nonce, 8, initial_64bit_ctr);
+err = salsa20_ivctr64(&st, nonce, 8, counter);
 \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.
+To initialize \textit{XSalsa20} for the recommended 20 rounds with a 256-bit
+key (32 bytes) and a 192-bit nonce (24 bytes), use: 
 
-For the actual encryption or decryption you have to call:
+\begin{verbatim}
+salsa20_state st;
+err = xsalsa20_setup(&st, key, key_len, nonce, nonce_len, rounds);
+\end{verbatim}
+
+Both \textit{Salsa20} and \textit{XSalsa20} use the following functions.  To
+encrypt or decrypt 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:
+For a random keystream initialize the cipher with a truly random \textit{key}
+and random \textit{nonce} after which you can get a stream of
+pseudo--random bytes via:
 \begin{verbatim}
 err = salsa20_keystream(&st, out_buffer, out_len);
 \end{verbatim}
 
-When finished you should wipe the state:
+Finally, when finished you should wipe the state.
 \begin{verbatim}
 err = salsa20_done(&st);
 \end{verbatim}
 
+For both \textit{Salsa20} and \textit{XSalsa20} rounds must be an even number
+and if set to 0 the default number of rounds, 20, will be used.
+\vspace{1mm}
+
+If you define \textit{LTC_XSALSA20} to include \textit{XSalsa20} in a minimal
+\textit{libtomcrypt} library build, you must also define \textit{LTC_SALSA20}.
+\vspace{1mm}
+
+As always, never ever use the same key + nonce/IV pair more than once.
+\vspace{1mm}
+
+For more information about Salsa20 see
+\url{https://en.wikipedia.org/wiki/Salsa20}.
+\vspace{1mm}
+
+For more information about XSalsa20 see
+\url{https://cr.yp.to/snuffle/xsalsa-20081128.pdf}.
+\vspace{1mm}
+
 \mysection{Sosemanuk}
 
 \textit{Sosemanuk}, along with Salsa20, HC-128, and Rabbit, was named one of the winners in

+ 9 - 0
src/headers/tomcrypt_cipher.h

@@ -1031,6 +1031,15 @@ int salsa20_test(void);
 
 #endif /* LTC_SALSA20 */
 
+#ifdef LTC_XSALSA20
+
+int xsalsa20_setup(salsa20_state *st, const unsigned char *key,   unsigned long keylen,
+                                      const unsigned char *nonce, unsigned long noncelen,
+                                      int rounds);
+int xsalsa20_test(void);
+
+#endif /* LTC_XSALSA20 */
+
 #ifdef LTC_SOSEMANUK
 
 typedef struct {

+ 5 - 0
src/headers/tomcrypt_custom.h

@@ -208,6 +208,7 @@
 /* stream ciphers */
 #define LTC_CHACHA
 #define LTC_SALSA20
+#define LTC_XSALSA20
 #define LTC_SOSEMANUK
 #define LTC_RABBIT
 #define LTC_RC4_STREAM
@@ -589,6 +590,10 @@
    #error LTC_CHACHA20_PRNG requires LTC_CHACHA
 #endif
 
+#if defined(LTC_XSALSA20) && !defined(LTC_SALSA20)
+   #error LTC_XSALSA20 requires LTC_SALSA20
+#endif
+
 #if defined(LTC_RC4) && !defined(LTC_RC4_STREAM)
    #error LTC_RC4 requires LTC_RC4_STREAM
 #endif

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

@@ -135,6 +135,9 @@ const char *crypt_build_settings =
 #if defined(LTC_SALSA20)
    "   Salsa20\n"
 #endif
+#if defined(LTC_XSALSA20)
+   "   XSalsa20\n"
+#endif
 #if defined(LTC_SOSEMANUK)
    "   Sosemanuk\n"
 #endif

+ 1 - 1
src/stream/salsa20/salsa20_crypt.c

@@ -62,7 +62,7 @@ int salsa20_crypt(salsa20_state *st, const unsigned char *in, unsigned long inle
    LTC_ARGCHK(st        != NULL);
    LTC_ARGCHK(in        != NULL);
    LTC_ARGCHK(out       != NULL);
-   LTC_ARGCHK(st->ivlen == 8);
+   LTC_ARGCHK(st->ivlen == 8 || st->ivlen == 24);
 
    if (st->ksleft > 0) {
       j = MIN(st->ksleft, inlen);

+ 137 - 0
src/stream/salsa20/xsalsa20_setup.c

@@ -0,0 +1,137 @@
+/* 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:
+ * "Extending the Salsa20 nonce", https://cr.yp.to/snuffle/xsalsa-20081128.pdf
+ * "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_XSALSA20
+
+static const char * const constants = "expand 32-byte k";
+
+#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));
+
+/* use modified salsa20 doubleround (no final addition as in salsa20) */
+static void _xsalsa20_doubleround(ulong32 *x, int rounds)
+{
+   int i = 0;
+
+   for (i = rounds; i > 0; i -= 2) {
+      /* columnround */
+      QUARTERROUND( 0, 4, 8,12)
+      QUARTERROUND( 5, 9,13, 1)
+      QUARTERROUND(10,14, 2, 6)
+      QUARTERROUND(15, 3, 7,11)
+      /* rowround */
+      QUARTERROUND( 0, 1, 2, 3)
+      QUARTERROUND( 5, 6, 7, 4)
+      QUARTERROUND(10,11, 8, 9)
+      QUARTERROUND(15,12,13,14)
+   }
+}
+
+#undef QUARTERROUND
+
+/**
+   Initialize an XSalsa20 context
+   @param st        [out] The destination of the XSalsa20 state
+   @param key       The secret key
+   @param keylen    The length of the secret key, must be 32 (octets)
+   @param nonce     The nonce
+   @param noncelen  The length of the nonce, must be 24 (octets)
+   @param rounds    Number of rounds (must be evenly divisible by 2, default is 20)
+   @return CRYPT_OK if successful
+*/
+int xsalsa20_setup(salsa20_state *st, const unsigned char *key, unsigned long keylen,
+                                      const unsigned char *nonce, unsigned long noncelen,
+                                      int rounds)
+{
+   const int sti[] = {0, 5, 10, 15, 6, 7, 8, 9};  /* indices used to build subkey fm x */
+   ulong32       x[64];                           /* input to & output fm doubleround */
+   unsigned char subkey[32];
+   int i = 0;
+
+   LTC_ARGCHK(st        != NULL);
+   LTC_ARGCHK(key       != NULL);
+   LTC_ARGCHK(keylen    == 32);
+   LTC_ARGCHK(nonce     != NULL);
+   LTC_ARGCHK(noncelen  == 24);
+   if (rounds == 0) rounds = 20;
+   LTC_ARGCHK(rounds % 2 == 0);     /* number of rounds must be evenly divisible by 2 */
+
+   /* load the state to "hash" the key */
+   LOAD32L(x[ 0], constants +  0);
+   LOAD32L(x[ 5], constants +  4);
+   LOAD32L(x[10], constants +  8);
+   LOAD32L(x[15], constants + 12);
+   LOAD32L(x[ 1], key +  0);
+   LOAD32L(x[ 2], key +  4);
+   LOAD32L(x[ 3], key +  8);
+   LOAD32L(x[ 4], key + 12);
+   LOAD32L(x[11], key + 16);
+   LOAD32L(x[12], key + 20);
+   LOAD32L(x[13], key + 24);
+   LOAD32L(x[14], key + 28);
+   LOAD32L(x[ 6], nonce +  0);
+   LOAD32L(x[ 7], nonce +  4);
+   LOAD32L(x[ 8], nonce +  8);
+   LOAD32L(x[ 9], nonce + 12);
+
+   /* use modified salsa20 doubleround (no final addition) */
+   _xsalsa20_doubleround(x, rounds);
+
+   /* extract the subkey */
+   for (i = 0; i < 8; ++i) {
+     STORE32L(x[sti[i]], subkey + 4 * i);
+   }
+
+   /* load the final initial state */
+   LOAD32L(st->input[ 0], constants +  0);
+   LOAD32L(st->input[ 5], constants +  4);
+   LOAD32L(st->input[10], constants +  8);
+   LOAD32L(st->input[15], constants + 12);
+   LOAD32L(st->input[ 1], subkey +  0);
+   LOAD32L(st->input[ 2], subkey +  4);
+   LOAD32L(st->input[ 3], subkey +  8);
+   LOAD32L(st->input[ 4], subkey + 12);
+   LOAD32L(st->input[11], subkey + 16);
+   LOAD32L(st->input[12], subkey + 20);
+   LOAD32L(st->input[13], subkey + 24);
+   LOAD32L(st->input[14], subkey + 28);
+   LOAD32L(st->input[ 6], &(nonce[16]) + 0);
+   LOAD32L(st->input[ 7], &(nonce[16]) + 4);
+   st->input[ 8] = 0;
+   st->input[ 9] = 0;
+   st->rounds = rounds;
+   st->ksleft = 0;
+   st->ivlen  = 24;           /* set switch to say nonce/IV has been loaded */
+
+#ifdef LTC_CLEAN_STACK
+   zeromem(x, sizeof(x));
+   zeromem(subkey, sizeof(subkey));
+#endif
+
+   return CRYPT_OK;
+}
+
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */

+ 94 - 0
src/stream/salsa20/xsalsa20_test.c

@@ -0,0 +1,94 @@
+/* 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:
+ * "Extending the Salsa20 nonce", https://cr.yp.to/snuffle/xsalsa-20081128.pdf
+ * "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_XSALSA20
+
+#ifdef LTC_SHA256
+int _sha256(unsigned char *hash, const unsigned char *data, const int datalen) {
+   hash_state md;
+   sha256_init(&md);
+   sha256_process(&md, data, datalen);
+   sha256_done(&md, hash);
+   return CRYPT_OK;
+}
+#endif
+
+int xsalsa20_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+
+    /***************************************************************************
+     * verify a round trip:
+     */
+    {
+        const unsigned char key[]   = {0x1b,0x27,0x55,0x64,0x73,0xe9,0x85,0xd4,0x62,0xcd,0x51,0x19,0x7a,0x9a,0x46,0xc7,0x60,0x09,0x54,0x9e,0xac,0x64,0x74,0xf2,0x06,0xc4,0xee,0x08,0x44,0xf6,0x83,0x89};
+        const unsigned char nonce[] = {0x69,0x69,0x6e,0xe9,0x55,0xb6,0x2b,0x73,0xcd,0x62,0xbd,0xa8,0x75,0xfc,0x73,0xd6,0x82,0x19,0xe0,0x03,0x6b,0x7a,0x0b,0x37};
+        const void *msg             = "Kilroy was here!";
+        unsigned char msglen = 17;                  /* includes trailing NULL */
+        int rounds = 20;
+        unsigned char ciphertext[17];
+        unsigned char msg2[17];
+        salsa20_state st;
+        int err;
+
+        if ((err = xsalsa20_setup(&st, key, 32, nonce, 24, rounds)) != CRYPT_OK)  return err;
+        if ((err = salsa20_crypt(&st, msg, msglen, ciphertext))     != CRYPT_OK)  return err;
+        if ((err = salsa20_done(&st))                               != CRYPT_OK)  return err;
+
+        if ((err = xsalsa20_setup(&st, key, 32, nonce, 24, rounds)) != CRYPT_OK)  return err;
+        if ((err = salsa20_crypt(&st, ciphertext, msglen, msg2))    != CRYPT_OK)  return err;
+        if ((err = salsa20_done(&st))                               != CRYPT_OK)  return err;
+
+        if (compare_testvector(msg, msglen, msg2, msglen, "XSALSA20-TV1", 1))  return CRYPT_FAIL_TESTVECTOR;
+    }
+
+#ifdef LTC_SHA256
+   /***************************************************************************
+    * verify correct generation of a keystream
+    */
+   {
+       const unsigned char key[]        = {0x1b,0x27,0x55,0x64,0x73,0xe9,0x85,0xd4,0x62,0xcd,0x51,0x19,0x7a,0x9a,0x46,0xc7,0x60,0x09,0x54,0x9e,0xac,0x64,0x74,0xf2,0x06,0xc4,0xee,0x08,0x44,0xf6,0x83,0x89};
+       const unsigned char nonce[]      = {0x69,0x69,0x6e,0xe9,0x55,0xb6,0x2b,0x73,0xcd,0x62,0xbd,0xa8,0x75,0xfc,0x73,0xd6,0x82,0x19,0xe0,0x03,0x6b,0x7a,0x0b,0x37};
+       const unsigned char expecthash[] = {0x6a,0x60,0x57,0x65,0x27,0xe0,0x00,0x51,0x6d,0xb0,0xda,0x60,0x46,0x20,0xf6,0xd0,0x95,0x65,0x45,0x39,0xf4,0x86,0x83,0x43,0x64,0xdf,0xd9,0x5a,0x6f,0x3f,0xbe,0xb7};
+       int rounds = 20;
+       unsigned char keystream[91101];
+       unsigned long keystreamlen = 91101;
+       unsigned char hash[32];
+       salsa20_state st;
+       int err;
+
+       if ((err = xsalsa20_setup(&st, key, 32, nonce, 24, rounds))   != CRYPT_OK)  return err;
+       if ((err = salsa20_keystream(&st, keystream, keystreamlen))   != CRYPT_OK)  return err;
+       if ((err = salsa20_done(&st))                                 != CRYPT_OK)  return err;
+       if ((err = _sha256(hash, keystream, keystreamlen))            != CRYPT_OK)  return err;
+       if (compare_testvector(hash, sizeof(hash), expecthash, sizeof(expecthash),   "XSALSA20-TV2", 1))  return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   return CRYPT_OK;
+#endif
+
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */

+ 3 - 0
tests/cipher_hash_test.c

@@ -26,6 +26,9 @@ int cipher_hash_test(void)
 #ifdef LTC_SALSA20
    DO(salsa20_test());
 #endif
+#ifdef LTC_XSALSA20
+   DO(xsalsa20_test());
+#endif
 #ifdef LTC_SOSEMANUK
    DO(sosemanuk_test());
 #endif