Add Salsa20

This commit is contained in:
Larry Bugbee 2017-10-23 15:41:42 -07:00
parent aa5a2e5a26
commit 4341424ce9
13 changed files with 429 additions and 2 deletions

6
.gitignore vendored
View file

@ -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

View file

@ -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}.

View file

@ -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 {

View file

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

View file

@ -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

View file

@ -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

View file

@ -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$ */

View file

@ -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$ */

View file

@ -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$ */

View file

@ -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$ */

View file

@ -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$ */

View file

@ -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$ */

View file

@ -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