Skip to content

Commit ab32bf4

Browse files
committed
make hsalsa20 a public API function
1 parent 2e441a1 commit ab32bf4

4 files changed

Lines changed: 105 additions & 28 deletions

File tree

doc/crypt.tex

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1437,11 +1437,30 @@ \chapter{Stream Ciphers}
14371437
As always, never ever use the same key + nonce/IV pair more than once.
14381438
\vspace{1mm}
14391439

1440+
\subsection{HSalsa20}
1441+
1442+
\textit{HSalsa20} is the key derivation function underlying \textit{XSalsa20}. It applies the
1443+
Salsa20 core (without the final addition step) to a 256-bit key and a 128-bit input,
1444+
producing a 256-bit derived key. It is also useful as a standalone KDF, for example in NaCl-style
1445+
\textit{crypto\_box} constructions where it derives a symmetric key from an X25519 shared secret.
1446+
1447+
\index{xsalsa20\_hsalsa20()}
1448+
\begin{verbatim}
1449+
int xsalsa20_hsalsa20(unsigned char *out, unsigned long outlen,
1450+
const unsigned char *key, unsigned long keylen,
1451+
const unsigned char *in, unsigned long inlen,
1452+
int rounds);
1453+
\end{verbatim}
1454+
This derives a 32-byte subkey from a 32-byte \textit{key} and a 16-byte \textit{in} using
1455+
\textit{rounds} Salsa20 rounds (0 = default 20). The output is stored in \textit{out}
1456+
(\textit{outlen} must be 32, \textit{keylen} must be 32, \textit{inlen} must be 16).
1457+
\vspace{1mm}
1458+
14401459
For more information about Salsa20 see
14411460
\url{https://en.wikipedia.org/wiki/Salsa20}.
14421461
\vspace{1mm}
14431462

1444-
For more information about XSalsa20 see
1463+
For more information about XSalsa20 and HSalsa20 see
14451464
\url{https://cr.yp.to/snuffle/xsalsa-20081128.pdf}.
14461465
\vspace{1mm}
14471466

src/headers/tomcrypt_cipher.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,6 +1080,10 @@ int salsa20_memory(const unsigned char *key, unsigned long keylen, unsigned
10801080

10811081
#ifdef LTC_XSALSA20
10821082

1083+
int xsalsa20_hsalsa20(unsigned char *out, unsigned long outlen,
1084+
const unsigned char *key, unsigned long keylen,
1085+
const unsigned char *in, unsigned long inlen,
1086+
int rounds);
10831087
int xsalsa20_setup(salsa20_state *st, const unsigned char *key, unsigned long keylen,
10841088
const unsigned char *nonce, unsigned long noncelen,
10851089
int rounds);

src/stream/salsa20/xsalsa20_setup.c

Lines changed: 58 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -40,34 +40,37 @@ static void s_xsalsa20_doubleround(ulong32 *x, int rounds)
4040
#undef QUARTERROUND
4141

4242
/**
43-
Initialize an XSalsa20 context
44-
@param st [out] The destination of the XSalsa20 state
43+
HSalsa20: derive a 256-bit subkey from a 256-bit key and 128-bit input.
44+
This is the Salsa20 core (double-rounds) without the final addition step,
45+
extracting output from state positions {0,5,10,15,6,7,8,9}.
46+
@param out [out] The derived 32-byte subkey
47+
@param outlen The length of the output buffer, must be 32 (octets)
4548
@param key The secret key
4649
@param keylen The length of the secret key, must be 32 (octets)
47-
@param nonce The nonce
48-
@param noncelen The length of the nonce, must be 24 (octets)
50+
@param in The 16-byte input (nonce or constant)
51+
@param inlen The length of the input, must be 16 (octets)
4952
@param rounds Number of rounds (must be evenly divisible by 2, default is 20)
5053
@return CRYPT_OK if successful
5154
*/
52-
int xsalsa20_setup(salsa20_state *st, const unsigned char *key, unsigned long keylen,
53-
const unsigned char *nonce, unsigned long noncelen,
54-
int rounds)
55+
int xsalsa20_hsalsa20(unsigned char *out, unsigned long outlen,
56+
const unsigned char *key, unsigned long keylen,
57+
const unsigned char *in, unsigned long inlen,
58+
int rounds)
5559
{
5660
const char * const constants = "expand 32-byte k";
57-
const int sti[] = {0, 5, 10, 15, 6, 7, 8, 9}; /* indices used to build subkey fm x */
58-
ulong32 x[64]; /* input to & output fm doubleround */
59-
unsigned char subkey[32];
61+
const int sti[] = {0, 5, 10, 15, 6, 7, 8, 9};
62+
ulong32 x[16];
6063
int i;
6164

62-
LTC_ARGCHK(st != NULL);
63-
LTC_ARGCHK(key != NULL);
64-
LTC_ARGCHK(keylen == 32);
65-
LTC_ARGCHK(nonce != NULL);
66-
LTC_ARGCHK(noncelen == 24);
65+
LTC_ARGCHK(out != NULL);
66+
LTC_ARGCHK(outlen == 32);
67+
LTC_ARGCHK(key != NULL);
68+
LTC_ARGCHK(keylen == 32);
69+
LTC_ARGCHK(in != NULL);
70+
LTC_ARGCHK(inlen == 16);
6771
if (rounds == 0) rounds = 20;
68-
LTC_ARGCHK(rounds % 2 == 0); /* number of rounds must be evenly divisible by 2 */
72+
LTC_ARGCHK(rounds % 2 == 0);
6973

70-
/* load the state to "hash" the key */
7174
LOAD32L(x[ 0], constants + 0);
7275
LOAD32L(x[ 5], constants + 4);
7376
LOAD32L(x[10], constants + 8);
@@ -80,20 +83,48 @@ int xsalsa20_setup(salsa20_state *st, const unsigned char *key, unsigned long ke
8083
LOAD32L(x[12], key + 20);
8184
LOAD32L(x[13], key + 24);
8285
LOAD32L(x[14], key + 28);
83-
LOAD32L(x[ 6], nonce + 0);
84-
LOAD32L(x[ 7], nonce + 4);
85-
LOAD32L(x[ 8], nonce + 8);
86-
LOAD32L(x[ 9], nonce + 12);
86+
LOAD32L(x[ 6], in + 0);
87+
LOAD32L(x[ 7], in + 4);
88+
LOAD32L(x[ 8], in + 8);
89+
LOAD32L(x[ 9], in + 12);
8790

88-
/* use modified salsa20 doubleround (no final addition) */
8991
s_xsalsa20_doubleround(x, rounds);
9092

91-
/* extract the subkey */
9293
for (i = 0; i < 8; ++i) {
93-
STORE32L(x[sti[i]], subkey + 4 * i);
94+
STORE32L(x[sti[i]], out + 4 * i);
9495
}
9596

96-
/* load the final initial state */
97+
zeromem(x, sizeof(x));
98+
return CRYPT_OK;
99+
}
100+
101+
/**
102+
Initialize an XSalsa20 context
103+
@param st [out] The destination of the XSalsa20 state
104+
@param key The secret key
105+
@param keylen The length of the secret key, must be 32 (octets)
106+
@param nonce The nonce
107+
@param noncelen The length of the nonce, must be 24 (octets)
108+
@param rounds Number of rounds (must be evenly divisible by 2, default is 20)
109+
@return CRYPT_OK if successful
110+
*/
111+
int xsalsa20_setup(salsa20_state *st, const unsigned char *key, unsigned long keylen,
112+
const unsigned char *nonce, unsigned long noncelen,
113+
int rounds)
114+
{
115+
const char * const constants = "expand 32-byte k";
116+
unsigned char subkey[32];
117+
int err;
118+
119+
LTC_ARGCHK(st != NULL);
120+
LTC_ARGCHK(nonce != NULL);
121+
LTC_ARGCHK(noncelen == 24);
122+
if (rounds == 0) rounds = 20;
123+
124+
/* HSalsa20: derive subkey from key and first 16 bytes of nonce */
125+
if ((err = xsalsa20_hsalsa20(subkey, 32, key, keylen, nonce, 16, rounds)) != CRYPT_OK) goto cleanup;
126+
127+
/* load the final initial state with the derived subkey */
97128
LOAD32L(st->input[ 0], constants + 0);
98129
LOAD32L(st->input[ 5], constants + 4);
99130
LOAD32L(st->input[10], constants + 8);
@@ -114,12 +145,12 @@ int xsalsa20_setup(salsa20_state *st, const unsigned char *key, unsigned long ke
114145
st->ksleft = 0;
115146
st->ivlen = 24; /* set switch to say nonce/IV has been loaded */
116147

148+
cleanup:
117149
#ifdef LTC_CLEAN_STACK
118-
zeromem(x, sizeof(x));
119150
zeromem(subkey, sizeof(subkey));
120151
#endif
121152

122-
return CRYPT_OK;
153+
return err;
123154
}
124155

125156

src/stream/salsa20/xsalsa20_test.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,29 @@ int xsalsa20_test(void)
2828
return CRYPT_NOP;
2929
#else
3030

31+
/***************************************************************************
32+
* TV0: HSalsa20 known-answer test
33+
* From the NaCl test suite / https://cr.yp.to/snuffle/xsalsa-20081128.pdf
34+
*/
35+
{
36+
const unsigned char key[] = {
37+
0x1b,0x27,0x55,0x64,0x73,0xe9,0x85,0xd4,0x62,0xcd,0x51,0x19,0x7a,0x9a,0x46,0xc7,
38+
0x60,0x09,0x54,0x9e,0xac,0x64,0x74,0xf2,0x06,0xc4,0xee,0x08,0x44,0xf6,0x83,0x89
39+
};
40+
const unsigned char in[] = {
41+
0x69,0x69,0x6e,0xe9,0x55,0xb6,0x2b,0x73,0xcd,0x62,0xbd,0xa8,0x75,0xfc,0x73,0xd6
42+
};
43+
const unsigned char expected[] = {
44+
0xdc,0x90,0x8d,0xda,0x0b,0x93,0x44,0xa9,0x53,0x62,0x9b,0x73,0x38,0x20,0x77,0x88,
45+
0x80,0xf3,0xce,0xb4,0x21,0xbb,0x61,0xb9,0x1c,0xbd,0x4c,0x3e,0x66,0x25,0x6c,0xe4
46+
};
47+
unsigned char out[32];
48+
int err;
49+
50+
if ((err = xsalsa20_hsalsa20(out, 32, key, 32, in, 16, 20)) != CRYPT_OK) return err;
51+
if (ltc_compare_testvector(out, 32, expected, 32, "XSALSA20-TV0 (HSalsa20)", 0)) return CRYPT_FAIL_TESTVECTOR;
52+
}
53+
3154
/***************************************************************************
3255
* verify a round trip:
3356
*/

0 commit comments

Comments
 (0)