Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion doc/crypt.tex
Original file line number Diff line number Diff line change
Expand Up @@ -1437,11 +1437,30 @@ \chapter{Stream Ciphers}
As always, never ever use the same key + nonce/IV pair more than once.
\vspace{1mm}

\subsection{HSalsa20}

\textit{HSalsa20} is the key derivation function underlying \textit{XSalsa20}. It applies the
Salsa20 core (without the final addition step) to a 256-bit key and a 128-bit input,
producing a 256-bit derived key. It is also useful as a standalone KDF, for example in NaCl-style
\textit{crypto\_box} constructions where it derives a symmetric key from an X25519 shared secret.

\index{xsalsa20\_hsalsa20()}
\begin{verbatim}
int xsalsa20_hsalsa20(unsigned char *out, unsigned long outlen,
const unsigned char *key, unsigned long keylen,
const unsigned char *in, unsigned long inlen,
int rounds);
\end{verbatim}
This derives a 32-byte subkey from a 32-byte \textit{key} and a 16-byte \textit{in} using
\textit{rounds} Salsa20 rounds (0 = default 20). The output is stored in \textit{out}
(\textit{outlen} must be 32, \textit{keylen} must be 32, \textit{inlen} must be 16).
\vspace{1mm}

For more information about Salsa20 see
\url{https://en.wikipedia.org/wiki/Salsa20}.
\vspace{1mm}

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

Expand Down
4 changes: 4 additions & 0 deletions src/headers/tomcrypt_cipher.h
Original file line number Diff line number Diff line change
Expand Up @@ -1080,6 +1080,10 @@ int salsa20_memory(const unsigned char *key, unsigned long keylen, unsigned

#ifdef LTC_XSALSA20

int xsalsa20_hsalsa20(unsigned char *out, unsigned long outlen,
const unsigned char *key, unsigned long keylen,
const unsigned char *in, unsigned long inlen,
int rounds);
int xsalsa20_setup(salsa20_state *st, const unsigned char *key, unsigned long keylen,
const unsigned char *nonce, unsigned long noncelen,
int rounds);
Expand Down
2 changes: 1 addition & 1 deletion src/mac/blake2/blake2bmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
int blake2bmac_init(blake2bmac_state *st, unsigned long outlen, const unsigned char *key, unsigned long keylen)
{
LTC_ARGCHK(st != NULL);
LTC_ARGCHK(key != NULL);
LTC_ARGCHK(key != NULL || keylen == 0);
return blake2b_init(st, outlen, key, keylen);
}

Expand Down
2 changes: 1 addition & 1 deletion src/mac/blake2/blake2smac.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
int blake2smac_init(blake2smac_state *st, unsigned long outlen, const unsigned char *key, unsigned long keylen)
{
LTC_ARGCHK(st != NULL);
LTC_ARGCHK(key != NULL);
LTC_ARGCHK(key != NULL || keylen == 0);
return blake2s_init(st, outlen, key, keylen);
}

Expand Down
85 changes: 58 additions & 27 deletions src/stream/salsa20/xsalsa20_setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,34 +40,37 @@ static void s_xsalsa20_doubleround(ulong32 *x, int rounds)
#undef QUARTERROUND

/**
Initialize an XSalsa20 context
@param st [out] The destination of the XSalsa20 state
HSalsa20: derive a 256-bit subkey from a 256-bit key and 128-bit input.
This is the Salsa20 core (double-rounds) without the final addition step,
extracting output from state positions {0,5,10,15,6,7,8,9}.
@param out [out] The derived 32-byte subkey
@param outlen The length of the output buffer, must be 32 (octets)
@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 in The 16-byte input (nonce or constant)
@param inlen The length of the input, must be 16 (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)
int xsalsa20_hsalsa20(unsigned char *out, unsigned long outlen,
const unsigned char *key, unsigned long keylen,
const unsigned char *in, unsigned long inlen,
int rounds)
{
const char * const constants = "expand 32-byte k";
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];
const int sti[] = {0, 5, 10, 15, 6, 7, 8, 9};
ulong32 x[16];
int i;

LTC_ARGCHK(st != NULL);
LTC_ARGCHK(key != NULL);
LTC_ARGCHK(keylen == 32);
LTC_ARGCHK(nonce != NULL);
LTC_ARGCHK(noncelen == 24);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen == 32);
LTC_ARGCHK(key != NULL);
LTC_ARGCHK(keylen == 32);
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(inlen == 16);
if (rounds == 0) rounds = 20;
LTC_ARGCHK(rounds % 2 == 0); /* number of rounds must be evenly divisible by 2 */
LTC_ARGCHK(rounds % 2 == 0);

/* load the state to "hash" the key */
LOAD32L(x[ 0], constants + 0);
LOAD32L(x[ 5], constants + 4);
LOAD32L(x[10], constants + 8);
Expand All @@ -80,20 +83,48 @@ int xsalsa20_setup(salsa20_state *st, const unsigned char *key, unsigned long ke
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);
LOAD32L(x[ 6], in + 0);
LOAD32L(x[ 7], in + 4);
LOAD32L(x[ 8], in + 8);
LOAD32L(x[ 9], in + 12);

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

/* extract the subkey */
for (i = 0; i < 8; ++i) {
STORE32L(x[sti[i]], subkey + 4 * i);
STORE32L(x[sti[i]], out + 4 * i);
}

/* load the final initial state */
zeromem(x, sizeof(x));
return CRYPT_OK;
}

/**
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 char * const constants = "expand 32-byte k";
unsigned char subkey[32];
int err;

LTC_ARGCHK(st != NULL);
LTC_ARGCHK(nonce != NULL);
LTC_ARGCHK(noncelen == 24);
if (rounds == 0) rounds = 20;

/* HSalsa20: derive subkey from key and first 16 bytes of nonce */
if ((err = xsalsa20_hsalsa20(subkey, 32, key, keylen, nonce, 16, rounds)) != CRYPT_OK) goto cleanup;

/* load the final initial state with the derived subkey */
LOAD32L(st->input[ 0], constants + 0);
LOAD32L(st->input[ 5], constants + 4);
LOAD32L(st->input[10], constants + 8);
Expand All @@ -114,12 +145,12 @@ int xsalsa20_setup(salsa20_state *st, const unsigned char *key, unsigned long ke
st->ksleft = 0;
st->ivlen = 24; /* set switch to say nonce/IV has been loaded */

cleanup:
#ifdef LTC_CLEAN_STACK
zeromem(x, sizeof(x));
zeromem(subkey, sizeof(subkey));
#endif

return CRYPT_OK;
return err;
}


Expand Down
23 changes: 23 additions & 0 deletions src/stream/salsa20/xsalsa20_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,29 @@ int xsalsa20_test(void)
return CRYPT_NOP;
#else

/***************************************************************************
* TV0: HSalsa20 known-answer test
* From the NaCl test suite / https://cr.yp.to/snuffle/xsalsa-20081128.pdf
*/
{
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 in[] = {
0x69,0x69,0x6e,0xe9,0x55,0xb6,0x2b,0x73,0xcd,0x62,0xbd,0xa8,0x75,0xfc,0x73,0xd6
};
const unsigned char expected[] = {
0xdc,0x90,0x8d,0xda,0x0b,0x93,0x44,0xa9,0x53,0x62,0x9b,0x73,0x38,0x20,0x77,0x88,
0x80,0xf3,0xce,0xb4,0x21,0xbb,0x61,0xb9,0x1c,0xbd,0x4c,0x3e,0x66,0x25,0x6c,0xe4
};
unsigned char out[32];
int err;

if ((err = xsalsa20_hsalsa20(out, 32, key, 32, in, 16, 20)) != CRYPT_OK) return err;
if (ltc_compare_testvector(out, 32, expected, 32, "XSALSA20-TV0 (HSalsa20)", 0)) return CRYPT_FAIL_TESTVECTOR;
}

/***************************************************************************
* verify a round trip:
*/
Expand Down
Loading