Skip to content
Merged
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
5 changes: 2 additions & 3 deletions src/include.am
Original file line number Diff line number Diff line change
Expand Up @@ -992,14 +992,13 @@ src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/blake2s.c
endif

if BUILD_CHACHA
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/chacha.c
if BUILD_ARMASM_NEON
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-chacha.c
else
if BUILD_RISCV_ASM
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/riscv/riscv-64-chacha.c
else
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/chacha.c
endif !BUILD_RISCV_ASM
endif BUILD_RISCV_ASM
if !BUILD_X86_ASM
if BUILD_INTELASM
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/chacha_asm.S
Expand Down
238 changes: 122 additions & 116 deletions wolfcrypt/src/chacha.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,25 +35,56 @@ Public domain.

#include <wolfssl/wolfcrypt/settings.h>

#ifdef HAVE_CHACHA
#include <wolfssl/wolfcrypt/chacha.h>
#include <wolfssl/wolfcrypt/error-crypt.h>

#ifdef NO_INLINE
#include <wolfssl/wolfcrypt/misc.h>
#else
#define WOLFSSL_MISC_INCLUDED
#include <wolfcrypt/src/misc.c>
#endif

#ifdef BIG_ENDIAN_ORDER
#define LITTLE32(x) ByteReverseWord32(x)
#else
#define LITTLE32(x) (x)
#endif

/* Number of rounds */
#define ROUNDS 20

#define U32C(v) (v##U)
#define U32V(v) ((word32)(v) & U32C(0xFFFFFFFF))
#define U8TO32_LITTLE(p) LITTLE32(((word32*)(p))[0])

#define ROTATE(v,c) rotlFixed(v, c)
#define XOR(v,w) ((v) ^ (w))
#define PLUS(v,w) (U32V((v) + (w)))
#define PLUSONE(v) (PLUS((v),1))

#define QUARTERROUND(a,b,c,d) \
x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]),16); \
x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]),12); \
x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]), 8); \
x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]), 7);
#endif /* HAVE_CHACHA */


#if defined(WOLFSSL_ARMASM) && !defined(WOLFSSL_ARMASM_NO_NEON)
/* implementation is located in wolfcrypt/src/port/arm/armv8-chacha.c */

#elif defined(WOLFSSL_RISCV_ASM)
/* implementation located in wolfcrypt/src/port/rsicv/riscv-64-chacha.c */

#else

/* BEGIN ChaCha C implementation */
#if defined(HAVE_CHACHA)

#include <wolfssl/wolfcrypt/chacha.h>
#include <wolfssl/wolfcrypt/error-crypt.h>
#include <wolfssl/wolfcrypt/logging.h>
#include <wolfssl/wolfcrypt/cpuid.h>
#ifdef NO_INLINE
#include <wolfssl/wolfcrypt/misc.h>
#else
#define WOLFSSL_MISC_INCLUDED
#include <wolfcrypt/src/misc.c>
#endif

#ifdef CHACHA_AEAD_TEST
#include <stdio.h>
Expand Down Expand Up @@ -88,31 +119,6 @@ Public domain.
static word32 cpuidFlags = 0;
#endif

#ifdef BIG_ENDIAN_ORDER
#define LITTLE32(x) ByteReverseWord32(x)
#else
#define LITTLE32(x) (x)
#endif

/* Number of rounds */
#define ROUNDS 20

#define U32C(v) (v##U)
#define U32V(v) ((word32)(v) & U32C(0xFFFFFFFF))
#define U8TO32_LITTLE(p) LITTLE32(((word32*)(p))[0])

#define ROTATE(v,c) rotlFixed(v, c)
#define XOR(v,w) ((v) ^ (w))
#define PLUS(v,w) (U32V((v) + (w)))
#define PLUSONE(v) (PLUS((v),1))

#define QUARTERROUND(a,b,c,d) \
x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]),16); \
x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]),12); \
x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]), 8); \
x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]), 7);


/**
* Set up iv(nonce). Earlier versions used 64 bits instead of 96, this version
* uses the typical AEAD 96 bit nonce and can do record sizes of 256 GB.
Expand Down Expand Up @@ -238,86 +244,6 @@ static WC_INLINE void wc_Chacha_wordtobyte(word32 x[CHACHA_CHUNK_WORDS],
}
#endif /* !USE_INTEL_CHACHA_SPEEDUP */


#ifdef HAVE_XCHACHA

/*
* wc_HChacha_block - half a ChaCha block, for XChaCha
*
* see https://tools.ietf.org/html/draft-arciszewski-xchacha-03
*/
static WC_INLINE void wc_HChacha_block(ChaCha* ctx, word32 stream[CHACHA_CHUNK_WORDS/2], word32 nrounds)
{
word32 x[CHACHA_CHUNK_WORDS];
word32 i;

for (i = 0; i < CHACHA_CHUNK_WORDS; i++) {
x[i] = ctx->X[i];
}

for (i = nrounds; i > 0; i -= 2) {
QUARTERROUND(0, 4, 8, 12)
QUARTERROUND(1, 5, 9, 13)
QUARTERROUND(2, 6, 10, 14)
QUARTERROUND(3, 7, 11, 15)
QUARTERROUND(0, 5, 10, 15)
QUARTERROUND(1, 6, 11, 12)
QUARTERROUND(2, 7, 8, 13)
QUARTERROUND(3, 4, 9, 14)
}

for (i = 0; i < CHACHA_CHUNK_WORDS/4; ++i)
stream[i] = x[i];
for (i = CHACHA_CHUNK_WORDS/4; i < CHACHA_CHUNK_WORDS/2; ++i)
stream[i] = x[i + CHACHA_CHUNK_WORDS/2];
}

/* XChaCha -- https://tools.ietf.org/html/draft-arciszewski-xchacha-03 */
int wc_XChacha_SetKey(ChaCha *ctx,
const byte *key, word32 keySz,
const byte *nonce, word32 nonceSz,
word32 counter) {
word32 k[CHACHA_MAX_KEY_SZ];
byte iv[CHACHA_IV_BYTES];
int ret;

if (nonceSz != XCHACHA_NONCE_BYTES)
return BAD_FUNC_ARG;

if ((ret = wc_Chacha_SetKey(ctx, key, keySz)) < 0)
return ret;

/* form a first chacha IV from the first 16 bytes of the nonce.
* the first word is supplied in the "counter" arg, and
* the result is a full 128 bit nonceful IV for the one-time block
* crypto op that follows.
*/
if ((ret = wc_Chacha_SetIV(ctx, nonce + 4, U8TO32_LITTLE(nonce))) < 0)
return ret;

wc_HChacha_block(ctx, k, 20); /* 20 rounds, but keeping half the output. */

/* the HChacha output is used as a 256 bit key for the main cipher. */
XMEMCPY(&ctx->X[4], k, 8 * sizeof(word32));

/* use 8 bytes from the end of the 24 byte nonce, padded up to 12 bytes,
* to form the IV for the main cipher.
*/
XMEMSET(iv, 0, 4);
XMEMCPY(iv + 4, nonce + 16, 8);

if ((ret = wc_Chacha_SetIV(ctx, iv, counter)) < 0)
return ret;

ForceZero(k, sizeof k);
ForceZero(iv, sizeof iv);

return 0;
}

#endif /* HAVE_XCHACHA */


#ifdef __cplusplus
extern "C" {
#endif
Expand Down Expand Up @@ -441,14 +367,94 @@ int wc_Chacha_Process(ChaCha* ctx, byte* output, const byte* input,
#endif
}

void wc_Chacha_purge_current_block(ChaCha* ctx) {
#endif /* HAVE_CHACHA */
#endif /* END ChaCha C implementation */

#if defined(HAVE_CHACHA) && defined(HAVE_XCHACHA)

void wc_Chacha_purge_current_block(ChaCha* ctx)
{
if (ctx->left > 0) {
byte scratch[CHACHA_CHUNK_BYTES];
XMEMSET(scratch, 0, sizeof(scratch));
(void)wc_Chacha_Process(ctx, scratch, scratch, CHACHA_CHUNK_BYTES - ctx->left);
}
}

#endif /* HAVE_CHACHA */
/*
* wc_HChacha_block - half a ChaCha block, for XChaCha
*
* see https://tools.ietf.org/html/draft-arciszewski-xchacha-03
*/
static WC_INLINE void wc_HChacha_block(ChaCha* ctx,
word32 stream[CHACHA_CHUNK_WORDS/2], word32 nrounds)
{
word32 x[CHACHA_CHUNK_WORDS];
word32 i;

for (i = 0; i < CHACHA_CHUNK_WORDS; i++) {
x[i] = ctx->X[i];
}

for (i = nrounds; i > 0; i -= 2) {
QUARTERROUND(0, 4, 8, 12)
QUARTERROUND(1, 5, 9, 13)
QUARTERROUND(2, 6, 10, 14)
QUARTERROUND(3, 7, 11, 15)
QUARTERROUND(0, 5, 10, 15)
QUARTERROUND(1, 6, 11, 12)
QUARTERROUND(2, 7, 8, 13)
QUARTERROUND(3, 4, 9, 14)
}

for (i = 0; i < CHACHA_CHUNK_WORDS/4; ++i)
stream[i] = x[i];
for (i = CHACHA_CHUNK_WORDS/4; i < CHACHA_CHUNK_WORDS/2; ++i)
stream[i] = x[i + CHACHA_CHUNK_WORDS/2];
}

/* XChaCha -- https://tools.ietf.org/html/draft-arciszewski-xchacha-03 */
int wc_XChacha_SetKey(ChaCha *ctx,
const byte *key, word32 keySz,
const byte *nonce, word32 nonceSz,
word32 counter)
{
int ret;
word32 k[CHACHA_MAX_KEY_SZ];
byte iv[CHACHA_IV_BYTES];

if (nonceSz != XCHACHA_NONCE_BYTES)
return BAD_FUNC_ARG;

if ((ret = wc_Chacha_SetKey(ctx, key, keySz)) < 0)
return ret;

/* form a first chacha IV from the first 16 bytes of the nonce.
* the first word is supplied in the "counter" arg, and
* the result is a full 128 bit nonceful IV for the one-time block
* crypto op that follows.
*/
if ((ret = wc_Chacha_SetIV(ctx, nonce + 4, U8TO32_LITTLE(nonce))) < 0)
return ret;

wc_HChacha_block(ctx, k, 20); /* 20 rounds, but keeping half the output. */

/* the HChacha output is used as a 256 bit key for the main cipher. */
XMEMCPY(&ctx->X[4], k, 8 * sizeof(word32));

/* use 8 bytes from the end of the 24 byte nonce, padded up to 12 bytes,
* to form the IV for the main cipher.
*/
XMEMSET(iv, 0, 4);
XMEMCPY(iv + 4, nonce + 16, 8);

if ((ret = wc_Chacha_SetIV(ctx, iv, counter)) < 0)
return ret;

ForceZero(k, sizeof k);
ForceZero(iv, sizeof iv);

return 0;
}

#endif /* WOLFSSL_ARMASM && !WOLFSSL_ARMASM_NO_NEON */
#endif /* HAVE_CHACHA && HAVE_XCHACHA */
2 changes: 1 addition & 1 deletion wolfcrypt/src/port/riscv/riscv-64-sha512.c
Original file line number Diff line number Diff line change
Expand Up @@ -1216,7 +1216,7 @@ int wc_Sha512Transform(wc_Sha512* sha512, const unsigned char* data)
ret = BAD_FUNC_ARG;
}
else {
ByteReverseWords(sha512->buffer, (word32*)data, WC_SHA512_BLOCK_SIZE);
ByteReverseWords((word32*)sha512->buffer, (word32*)data, WC_SHA512_BLOCK_SIZE);
Sha512Transform(sha512, (byte*)sha512->buffer, 1);
}

Expand Down
4 changes: 2 additions & 2 deletions wolfssl/wolfcrypt/chacha.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,11 @@ WOLFSSL_API int wc_Chacha_SetIV(ChaCha* ctx, const byte* inIv, word32 counter);
WOLFSSL_API int wc_Chacha_Process(ChaCha* ctx, byte* cipher, const byte* plain,
word32 msglen);

WOLFSSL_LOCAL void wc_Chacha_purge_current_block(ChaCha* ctx);

WOLFSSL_API int wc_Chacha_SetKey(ChaCha* ctx, const byte* key, word32 keySz);

#ifdef HAVE_XCHACHA
WOLFSSL_LOCAL void wc_Chacha_purge_current_block(ChaCha* ctx);

WOLFSSL_API int wc_XChacha_SetKey(ChaCha *ctx, const byte *key, word32 keySz,
const byte *nonce, word32 nonceSz,
word32 counter);
Expand Down
4 changes: 2 additions & 2 deletions wolfssl/wolfcrypt/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -3281,8 +3281,8 @@ extern void uITRON4_free(void *p) ;
#define WOLFSSL_NO_HASH_RAW
#endif

/* XChacha not implemented with ARM assembly ChaCha */
#if defined(WOLFSSL_ARMASM)
#if defined(HAVE_XCHACHA) && !defined(HAVE_CHACHA)
/* XChacha requires ChaCha */
#undef HAVE_XCHACHA
#endif

Expand Down