Skip to content

Commit 8144209

Browse files
committed
add XSalsa20
1 parent 2ffcd17 commit 8144209

File tree

8 files changed

+312
-25
lines changed

8 files changed

+312
-25
lines changed

doc/crypt.tex

Lines changed: 60 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1301,49 +1301,85 @@ \chapter{Stream Ciphers}
13011301
err = chacha_done(&st);
13021302
\end{verbatim}
13031303

1304-
\mysection{Salsa20}
1304+
\mysection{Salsa20 and XSalsa20}
1305+
1306+
\textit{Salsa20} was Daniel Bernstein's submission to the EU eSTREAM
1307+
competition where a reduced-round version, \textit{Salsa20/12}, was named
1308+
one of the winners. A third version, \textit{Salsa20/8}, was also evaluated.
1309+
\vspace{1mm}
1310+
1311+
While 20 rounds is the conservative default number of rounds, eSTREAM deemed
1312+
12 rounds to be a decent balance between strength and better performance.
1313+
The 8-round version, while still secure as of this writing, is faster but
1314+
does not enjoy the same margin of safety. Regardless of the number of rounds,
1315+
\textit{Salsa20} accepts either a 128- or a 256-bit key, a 64-bit IV, and a
1316+
64-bit counter.
1317+
\vspace{1mm}
1318+
1319+
\textit{XSalsa20} is yet another variant of \textit{Salsa20} designed to accept
1320+
only a 256-bit key and a longer 192-bit nonce, initialization being the only
1321+
difference between \textit{XSalsa20} and \textit{Salsa20}. Even the
1322+
\textit{salsa20\_state} is the same. Thereafter, salsa20\_crypt(),
1323+
salsa20\_keystream(), and salsa20\_done() are used unaltered.
1324+
salsa20\_ivctr64() is NOT used with xsalsa20\_setup().
1325+
\vspace{1mm}
1326+
1327+
To initialize \textit{Salsa20} for 8, 12, or 20 rounds with a 128- or a
1328+
256-bit key (16 or 32 bytes), a 64-bit IV (8 bytes), and counter (typically
1329+
zero), use:
13051330

1306-
\textit{Salsa20} is the forerunner of the ChaCha stream cipher. The ChaCha cipher is
1307-
Salsa20 with a few minor tweaks to further improve its strength, and in so doing, increase its
1308-
speed performance by about 5 percent. Unless you need Salsa20 for some reason, you should
1309-
probably choose ChaCha instead.
1310-
1311-
In April 2008 \textit{Salsa20/12} was named one of the winners in the EU eSTREAM competition.
1312-
Salsa20 was originally submitted by Daniel Bernstein with 20 rounds of strength but the
1313-
12-round reduced-round version was deemed to have sufficient strength and declared a winner.
1314-
Even the 8-round reduced-round version, Salsa20/8, has withstood attack.
1315-
1316-
For more information about Salsa20 see \url{https://en.wikipedia.org/wiki/Salsa20}.
1317-
1318-
Supported key size: 16 or 32 bytes (128 or 256 bits).
1319-
1320-
You can initialize Salsa20 with 64bit \textit{nonce} + 64bit \textit{counter}:
13211331
\begin{verbatim}
13221332
salsa20_state st;
1333+
ulong64 counter = 0;
13231334
err = salsa20_setup(&st, key, key_len, rounds);
1324-
err = salsa20_ivctr64(&st, nonce, 8, initial_64bit_ctr);
1335+
err = salsa20_ivctr64(&st, nonce, 8, counter);
13251336
\end{verbatim}
13261337

1327-
The \textit{salsa20\_setup} takes the number of rounds as a parameter -- choose 20 (the default)
1328-
if you are not sure. As always never ever use the same key + nonce pair more than once.
1338+
To initialize \textit{XSalsa20} for the recommended 20 rounds with a 256-bit
1339+
key (32 bytes) and a 192-bit nonce (24 bytes), use:
13291340

1330-
For the actual encryption or decryption you have to call:
1341+
\begin{verbatim}
1342+
salsa20_state st;
1343+
err = xsalsa20_setup(&st, key, key_len, nonce, nonce_len, rounds);
1344+
\end{verbatim}
1345+
1346+
Both \textit{Salsa20} and \textit{XSalsa20} use the following functions. To
1347+
encrypt or decrypt call:
13311348
\begin{verbatim}
13321349
err = salsa20_crypt(&st, in_buffer, in_len, out_buffer);
13331350
\end{verbatim}
13341351

1335-
If you just want a random stream of bytes initialize the cipher with a truly random \textit{key}
1336-
(32 bytes), a truly random \textit{nonce} (8 bytes) and zero initial counter. After that you can
1337-
get a stream of pseudo--random bytes via:
1352+
For a random keystream initialize the cipher with a truly random \textit{key}
1353+
and random \textit{nonce} after which you can get a stream of
1354+
pseudo--random bytes via:
13381355
\begin{verbatim}
13391356
err = salsa20_keystream(&st, out_buffer, out_len);
13401357
\end{verbatim}
13411358

1342-
When finished you should wipe the state:
1359+
Finally, when finished you should wipe the state.
13431360
\begin{verbatim}
13441361
err = salsa20_done(&st);
13451362
\end{verbatim}
13461363

1364+
For both \textit{Salsa20} and \textit{XSalsa20} rounds must be an even number
1365+
and if set to 0 the default number of rounds, 20, will be used.
1366+
\vspace{1mm}
1367+
1368+
If you define \textit{LTC_XSALSA20} to include \textit{XSalsa20} in a minimal
1369+
\textit{libtomcrypt} library build, you must also define \textit{LTC_SALSA20}.
1370+
\vspace{1mm}
1371+
1372+
As always, never ever use the same key + nonce/IV pair more than once.
1373+
\vspace{1mm}
1374+
1375+
For more information about Salsa20 see
1376+
\url{https://en.wikipedia.org/wiki/Salsa20}.
1377+
\vspace{1mm}
1378+
1379+
For more information about XSalsa20 see
1380+
\url{https://cr.yp.to/snuffle/xsalsa-20081128.pdf}.
1381+
\vspace{1mm}
1382+
13471383
\mysection{Sosemanuk}
13481384

13491385
\textit{Sosemanuk}, along with Salsa20, HC-128, and Rabbit, was named one of the winners in

src/headers/tomcrypt_cipher.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,6 +1031,15 @@ int salsa20_test(void);
10311031

10321032
#endif /* LTC_SALSA20 */
10331033

1034+
#ifdef LTC_XSALSA20
1035+
1036+
int xsalsa20_setup(salsa20_state *st, const unsigned char *key, unsigned long keylen,
1037+
const unsigned char *nonce, unsigned long noncelen,
1038+
int rounds);
1039+
int xsalsa20_test(void);
1040+
1041+
#endif /* LTC_XSALSA20 */
1042+
10341043
#ifdef LTC_SOSEMANUK
10351044

10361045
typedef struct {

src/headers/tomcrypt_custom.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@
208208
/* stream ciphers */
209209
#define LTC_CHACHA
210210
#define LTC_SALSA20
211+
#define LTC_XSALSA20
211212
#define LTC_SOSEMANUK
212213
#define LTC_RABBIT
213214
#define LTC_RC4_STREAM
@@ -589,6 +590,10 @@
589590
#error LTC_CHACHA20_PRNG requires LTC_CHACHA
590591
#endif
591592

593+
#if defined(LTC_XSALSA20) && !defined(LTC_SALSA20)
594+
#error LTC_XSALSA20 requires LTC_SALSA20
595+
#endif
596+
592597
#if defined(LTC_RC4) && !defined(LTC_RC4_STREAM)
593598
#error LTC_RC4 requires LTC_RC4_STREAM
594599
#endif

src/misc/crypt/crypt.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@ const char *crypt_build_settings =
135135
#if defined(LTC_SALSA20)
136136
" Salsa20\n"
137137
#endif
138+
#if defined(LTC_XSALSA20)
139+
" XSalsa20\n"
140+
#endif
138141
#if defined(LTC_SOSEMANUK)
139142
" Sosemanuk\n"
140143
#endif

src/stream/salsa20/salsa20_crypt.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ int salsa20_crypt(salsa20_state *st, const unsigned char *in, unsigned long inle
6262
LTC_ARGCHK(st != NULL);
6363
LTC_ARGCHK(in != NULL);
6464
LTC_ARGCHK(out != NULL);
65-
LTC_ARGCHK(st->ivlen == 8);
65+
LTC_ARGCHK(st->ivlen == 8 || st->ivlen == 24);
6666

6767
if (st->ksleft > 0) {
6868
j = MIN(st->ksleft, inlen);
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
2+
*
3+
* LibTomCrypt is a library that provides various cryptographic
4+
* algorithms in a highly modular and flexible manner.
5+
*
6+
* The library is free for all purposes without any express
7+
* guarantee it works.
8+
*/
9+
10+
/* The implementation is based on:
11+
* "Extending the Salsa20 nonce", https://cr.yp.to/snuffle/xsalsa-20081128.pdf
12+
* "Salsa20 specification", http://cr.yp.to/snuffle/spec.pdf
13+
* and salsa20-ref.c version 20051118
14+
* Public domain from D. J. Bernstein
15+
*/
16+
17+
#include "tomcrypt.h"
18+
19+
#ifdef LTC_XSALSA20
20+
21+
static const char * const constants = "expand 32-byte k";
22+
23+
#define QUARTERROUND(a,b,c,d) \
24+
x[b] ^= (ROL((x[a] + x[d]), 7)); \
25+
x[c] ^= (ROL((x[b] + x[a]), 9)); \
26+
x[d] ^= (ROL((x[c] + x[b]), 13)); \
27+
x[a] ^= (ROL((x[d] + x[c]), 18));
28+
29+
/* use modified salsa20 doubleround (no final addition as in salsa20) */
30+
static void _xsalsa20_doubleround(ulong32 *x, int rounds)
31+
{
32+
int i = 0;
33+
34+
for (i = rounds; i > 0; i -= 2) {
35+
/* columnround */
36+
QUARTERROUND( 0, 4, 8,12)
37+
QUARTERROUND( 5, 9,13, 1)
38+
QUARTERROUND(10,14, 2, 6)
39+
QUARTERROUND(15, 3, 7,11)
40+
/* rowround */
41+
QUARTERROUND( 0, 1, 2, 3)
42+
QUARTERROUND( 5, 6, 7, 4)
43+
QUARTERROUND(10,11, 8, 9)
44+
QUARTERROUND(15,12,13,14)
45+
}
46+
}
47+
48+
#undef QUARTERROUND
49+
50+
/**
51+
Initialize an XSalsa20 context
52+
@param st [out] The destination of the XSalsa20 state
53+
@param key The secret key
54+
@param keylen The length of the secret key, must be 32 (octets)
55+
@param nonce The nonce
56+
@param noncelen The length of the nonce, must be 24 (octets)
57+
@param rounds Number of rounds (must be evenly divisible by 2, default is 20)
58+
@return CRYPT_OK if successful
59+
*/
60+
int xsalsa20_setup(salsa20_state *st, const unsigned char *key, unsigned long keylen,
61+
const unsigned char *nonce, unsigned long noncelen,
62+
int rounds)
63+
{
64+
const int sti[] = {0, 5, 10, 15, 6, 7, 8, 9}; /* indices used to build subkey fm x */
65+
ulong32 x[64]; /* input to & output fm doubleround */
66+
unsigned char subkey[32];
67+
int i = 0;
68+
69+
LTC_ARGCHK(st != NULL);
70+
LTC_ARGCHK(key != NULL);
71+
LTC_ARGCHK(keylen == 32);
72+
LTC_ARGCHK(nonce != NULL);
73+
LTC_ARGCHK(noncelen == 24);
74+
if (rounds == 0) rounds = 20;
75+
LTC_ARGCHK(rounds % 2 == 0); /* number of rounds must be evenly divisible by 2 */
76+
77+
/* load the state to "hash" the key */
78+
LOAD32L(x[ 0], constants + 0);
79+
LOAD32L(x[ 5], constants + 4);
80+
LOAD32L(x[10], constants + 8);
81+
LOAD32L(x[15], constants + 12);
82+
LOAD32L(x[ 1], key + 0);
83+
LOAD32L(x[ 2], key + 4);
84+
LOAD32L(x[ 3], key + 8);
85+
LOAD32L(x[ 4], key + 12);
86+
LOAD32L(x[11], key + 16);
87+
LOAD32L(x[12], key + 20);
88+
LOAD32L(x[13], key + 24);
89+
LOAD32L(x[14], key + 28);
90+
LOAD32L(x[ 6], nonce + 0);
91+
LOAD32L(x[ 7], nonce + 4);
92+
LOAD32L(x[ 8], nonce + 8);
93+
LOAD32L(x[ 9], nonce + 12);
94+
95+
/* use modified salsa20 doubleround (no final addition) */
96+
_xsalsa20_doubleround(x, rounds);
97+
98+
/* extract the subkey */
99+
for (i = 0; i < 8; ++i) {
100+
STORE32L(x[sti[i]], subkey + 4 * i);
101+
}
102+
103+
/* load the final initial state */
104+
LOAD32L(st->input[ 0], constants + 0);
105+
LOAD32L(st->input[ 5], constants + 4);
106+
LOAD32L(st->input[10], constants + 8);
107+
LOAD32L(st->input[15], constants + 12);
108+
LOAD32L(st->input[ 1], subkey + 0);
109+
LOAD32L(st->input[ 2], subkey + 4);
110+
LOAD32L(st->input[ 3], subkey + 8);
111+
LOAD32L(st->input[ 4], subkey + 12);
112+
LOAD32L(st->input[11], subkey + 16);
113+
LOAD32L(st->input[12], subkey + 20);
114+
LOAD32L(st->input[13], subkey + 24);
115+
LOAD32L(st->input[14], subkey + 28);
116+
LOAD32L(st->input[ 6], &(nonce[16]) + 0);
117+
LOAD32L(st->input[ 7], &(nonce[16]) + 4);
118+
st->input[ 8] = 0;
119+
st->input[ 9] = 0;
120+
st->rounds = rounds;
121+
st->ksleft = 0;
122+
st->ivlen = 24; /* set switch to say nonce/IV has been loaded */
123+
124+
#ifdef LTC_CLEAN_STACK
125+
zeromem(x, sizeof(x));
126+
zeromem(subkey, sizeof(subkey));
127+
#endif
128+
129+
return CRYPT_OK;
130+
}
131+
132+
133+
#endif
134+
135+
/* ref: $Format:%D$ */
136+
/* git commit: $Format:%H$ */
137+
/* commit time: $Format:%ai$ */

src/stream/salsa20/xsalsa20_test.c

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
2+
*
3+
* LibTomCrypt is a library that provides various cryptographic
4+
* algorithms in a highly modular and flexible manner.
5+
*
6+
* The library is free for all purposes without any express
7+
* guarantee it works.
8+
*/
9+
10+
/* The implementation is based on:
11+
* "Extending the Salsa20 nonce", https://cr.yp.to/snuffle/xsalsa-20081128.pdf
12+
* "Salsa20 specification", http://cr.yp.to/snuffle/spec.pdf
13+
* and salsa20-ref.c version 20051118
14+
* Public domain from D. J. Bernstein
15+
*/
16+
17+
#include "tomcrypt.h"
18+
19+
#ifdef LTC_XSALSA20
20+
21+
#ifdef LTC_SHA256
22+
int _sha256(unsigned char *hash, const unsigned char *data, const int datalen) {
23+
hash_state md;
24+
sha256_init(&md);
25+
sha256_process(&md, data, datalen);
26+
sha256_done(&md, hash);
27+
return CRYPT_OK;
28+
}
29+
#endif
30+
31+
int xsalsa20_test(void)
32+
{
33+
#ifndef LTC_TEST
34+
return CRYPT_NOP;
35+
#else
36+
37+
/***************************************************************************
38+
* verify a round trip:
39+
*/
40+
{
41+
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};
42+
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};
43+
const void *msg = "Kilroy was here!";
44+
unsigned char msglen = 17; /* includes trailing NULL */
45+
int rounds = 20;
46+
unsigned char ciphertext[17];
47+
unsigned char msg2[17];
48+
salsa20_state st;
49+
int err;
50+
51+
if ((err = xsalsa20_setup(&st, key, 32, nonce, 24, rounds)) != CRYPT_OK) return err;
52+
if ((err = salsa20_crypt(&st, msg, msglen, ciphertext)) != CRYPT_OK) return err;
53+
if ((err = salsa20_done(&st)) != CRYPT_OK) return err;
54+
55+
if ((err = xsalsa20_setup(&st, key, 32, nonce, 24, rounds)) != CRYPT_OK) return err;
56+
if ((err = salsa20_crypt(&st, ciphertext, msglen, msg2)) != CRYPT_OK) return err;
57+
if ((err = salsa20_done(&st)) != CRYPT_OK) return err;
58+
59+
if (compare_testvector(msg, msglen, msg2, msglen, "XSALSA20-TV1", 1)) return CRYPT_FAIL_TESTVECTOR;
60+
}
61+
62+
#ifdef LTC_SHA256
63+
/***************************************************************************
64+
* verify correct generation of a keystream
65+
*/
66+
{
67+
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};
68+
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};
69+
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};
70+
int rounds = 20;
71+
unsigned char keystream[91101];
72+
unsigned long keystreamlen = 91101;
73+
unsigned char hash[32];
74+
salsa20_state st;
75+
int err;
76+
77+
if ((err = xsalsa20_setup(&st, key, 32, nonce, 24, rounds)) != CRYPT_OK) return err;
78+
if ((err = salsa20_keystream(&st, keystream, keystreamlen)) != CRYPT_OK) return err;
79+
if ((err = salsa20_done(&st)) != CRYPT_OK) return err;
80+
if ((err = _sha256(hash, keystream, keystreamlen)) != CRYPT_OK) return err;
81+
if (compare_testvector(hash, sizeof(hash), expecthash, sizeof(expecthash), "XSALSA20-TV2", 1)) return CRYPT_FAIL_TESTVECTOR;
82+
}
83+
84+
return CRYPT_OK;
85+
#endif
86+
87+
#endif
88+
}
89+
90+
#endif
91+
92+
/* ref: $Format:%D$ */
93+
/* git commit: $Format:%H$ */
94+
/* commit time: $Format:%ai$ */

0 commit comments

Comments
 (0)