mirror of
https://github.com/libtom/libtomcrypt
synced 2026-08-25 20:26:07 -04:00
make hsalsa20 a public API function
This commit is contained in:
parent
02788482af
commit
c8ac4fc11c
4 changed files with 115 additions and 38 deletions
|
|
@ -1493,11 +1493,30 @@ If you define \textit{LTC\_XSALSA20} to include \textit{XSalsa20} in a minimal
|
|||
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}
|
||||
|
||||
|
|
|
|||
|
|
@ -1116,6 +1116,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);
|
||||
|
|
|
|||
|
|
@ -39,6 +39,65 @@ static void s_xsalsa20_doubleround(ulong32 *x, int rounds)
|
|||
|
||||
#undef QUARTERROUND
|
||||
|
||||
/**
|
||||
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 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_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};
|
||||
ulong32 x[16];
|
||||
int i;
|
||||
|
||||
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);
|
||||
|
||||
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], in + 0);
|
||||
LOAD32L(x[ 7], in + 4);
|
||||
LOAD32L(x[ 8], in + 8);
|
||||
LOAD32L(x[ 9], in + 12);
|
||||
|
||||
s_xsalsa20_doubleround(x, rounds);
|
||||
|
||||
for (i = 0; i < 8; ++i) {
|
||||
STORE32L(x[sti[i]], out + 4 * i);
|
||||
}
|
||||
|
||||
zeromem(x, sizeof(x));
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
Initialize an XSalsa20 context
|
||||
@param st [out] The destination of the XSalsa20 state
|
||||
|
|
@ -54,46 +113,18 @@ int xsalsa20_setup(salsa20_state *st, const unsigned char *key, unsigned long ke
|
|||
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];
|
||||
int i;
|
||||
int err;
|
||||
|
||||
LTC_ARGCHK(st != NULL);
|
||||
LTC_ARGCHK(key != NULL);
|
||||
LTC_ARGCHK(keylen == 32);
|
||||
LTC_ARGCHK(nonce != NULL);
|
||||
LTC_ARGCHK(noncelen == 24);
|
||||
LTC_ARGCHK(st != NULL);
|
||||
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);
|
||||
/* 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;
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* load the final initial state */
|
||||
/* 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);
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
*/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue