Coverage Report

Created: 2026-09-28 06:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wolfssl/wolfcrypt/src/chacha.c
Line
Count
Source
1
/* chacha.c
2
 *
3
 * Copyright (C) 2006-2026 wolfSSL Inc.
4
 *
5
 * This file is part of wolfSSL.
6
 *
7
 * wolfSSL is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * wolfSSL is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20
 */
21
/*
22
23
DESCRIPTION
24
This library contains implementation for the ChaCha20 stream cipher.
25
26
Based from chacha-ref.c version 20080118
27
D. J. Bernstein
28
Public domain.
29
30
*/
31
32
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
33
34
#ifdef HAVE_CHACHA
35
    #include <wolfssl/wolfcrypt/chacha.h>
36
37
    #ifdef NO_INLINE
38
        #include <wolfssl/wolfcrypt/misc.h>
39
    #else
40
        #define WOLFSSL_MISC_INCLUDED
41
        #include <wolfcrypt/src/misc.c>
42
    #endif
43
44
    #ifdef BIG_ENDIAN_ORDER
45
        #define LITTLE32(x) ByteReverseWord32(x)
46
    #else
47
0
        #define LITTLE32(x) (x)
48
    #endif
49
50
    /* Number of rounds */
51
0
    #define ROUNDS  20
52
53
0
    #define U32C(v) (v##U)
54
0
    #define U32V(v) ((word32)(v) & U32C(0xFFFFFFFF))
55
0
    #define U8TO32_LITTLE(p) LITTLE32(readUnalignedWord32(p))
56
57
0
    #define ROTATE(v,c) rotlFixed(v, c)
58
    #define XOR(v,w)    ((v) ^ (w))
59
0
    #define PLUS(v,w)   (U32V((v) + (w)))
60
0
    #define PLUSONE(v)  (PLUS((v),1))
61
62
    #define QUARTERROUND(a,b,c,d) \
63
0
        x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]),16); \
64
0
        x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]),12); \
65
0
        x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]), 8); \
66
0
        x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]), 7);
67
#endif /* HAVE_CHACHA */
68
69
70
/* BEGIN ChaCha C implementation */
71
#if defined(HAVE_CHACHA)
72
73
#include <wolfssl/wolfcrypt/cpuid.h>
74
75
#ifdef CHACHA_AEAD_TEST
76
    #include <stdio.h>
77
#endif
78
79
#ifdef USE_INTEL_CHACHA_SPEEDUP
80
    #include <emmintrin.h>
81
    #include <immintrin.h>
82
83
    #if defined(__GNUC__) && ((__GNUC__ < 4) || \
84
                              (__GNUC__ == 4 && __GNUC_MINOR__ <= 8))
85
        #undef  NO_AVX2_SUPPORT
86
        #define NO_AVX2_SUPPORT
87
    #endif
88
    #if defined(__clang__) && ((__clang_major__ < 3) || \
89
                               (__clang_major__ == 3 && __clang_minor__ <= 5))
90
        #undef  NO_AVX2_SUPPORT
91
        #define NO_AVX2_SUPPORT
92
    #elif defined(__clang__) && defined(NO_AVX2_SUPPORT)
93
        #undef NO_AVX2_SUPPORT
94
    #endif
95
    #if defined(_MSC_VER) && (_MSC_VER <= 1900)
96
        #undef  NO_AVX2_SUPPORT
97
        #define NO_AVX2_SUPPORT
98
    #endif
99
100
    #ifndef NO_AVX2_SUPPORT
101
        #define HAVE_INTEL_AVX2
102
    #endif
103
    #if !defined(NO_AVX512_SUPPORT) && !defined(HAVE_INTEL_AVX512)
104
        #define HAVE_INTEL_AVX512
105
    #endif
106
    /* SSSE3 is the baseline SIMD path, used on CPUs that lack AVX. */
107
    #ifndef HAVE_INTEL_SSSE3
108
        #define HAVE_INTEL_SSSE3
109
    #endif
110
111
    static cpuid_flags_t cpuidFlags = WC_CPUID_INITIALIZER;
112
#endif
113
114
/* The aarch64 ChaCha assembly is NEON-only. When NEON might be absent, also
115
 * build the C implementation: dispatch on ASIMD at runtime when NEON is
116
 * compiled in, or use only the C path when NEON is disabled at build time. */
117
#if defined(USE_ARM_CHACHA_SPEEDUP) && defined(__aarch64__)
118
    #ifdef WOLFSSL_ARMASM_NO_NEON
119
        #define WOLFSSL_ARM_CHACHA_C_ONLY
120
    #else
121
        #define WOLFSSL_ARM_CHACHA_NEON_FALLBACK
122
    #endif
123
#endif
124
#if defined(WOLFSSL_ARM_CHACHA_NEON_FALLBACK) || \
125
    defined(WOLFSSL_ARM_CHACHA_C_ONLY)
126
    #define WOLFSSL_ARM_CHACHA_NEED_C
127
#endif
128
129
#ifdef WOLFSSL_ARM_CHACHA_NEON_FALLBACK
130
    static cpuid_flags_t chacha_cpuid_flags = WC_CPUID_INITIALIZER;
131
    /* Return non-zero when NEON/ASIMD is present and the asm path should run. */
132
    static WC_INLINE int chacha_use_neon(void)
133
    {
134
        cpuid_get_flags_ex(&chacha_cpuid_flags);
135
        return IS_AARCH64_ASIMD(chacha_cpuid_flags);
136
    }
137
#endif
138
139
/**
140
  * Set up iv(nonce). Earlier versions used 64 bits instead of 96, this version
141
  * uses the typical AEAD 96 bit nonce and can do record sizes of 256 GB.
142
  */
143
int wc_Chacha_SetIV(ChaCha* ctx, const byte* inIv, word32 counter)
144
0
{
145
0
#if (!defined(USE_ARM_CHACHA_SPEEDUP) || defined(WOLFSSL_ARM_CHACHA_NEED_C)) && \
146
0
    !defined(USE_RISCV_CHACHA_SPEEDUP) && !defined(WOLFSSL_WIDE_BYTE)
147
0
    word32 temp[CHACHA_IV_WORDS];/* used for alignment of memory */
148
0
#endif
149
150
0
    if (ctx == NULL || inIv == NULL)
151
0
        return BAD_FUNC_ARG;
152
153
0
    ctx->left = 0; /* resets state */
154
155
#ifdef WOLFSSL_ARM_CHACHA_NEON_FALLBACK
156
    if (chacha_use_neon())
157
        wc_chacha_setiv(ctx->X, inIv, counter);
158
    else
159
#elif (defined(USE_ARM_CHACHA_SPEEDUP) && !defined(WOLFSSL_ARM_CHACHA_C_ONLY)) || \
160
    defined(USE_RISCV_CHACHA_SPEEDUP)
161
    wc_chacha_setiv(ctx->X, inIv, counter);
162
#endif
163
0
#if (!defined(USE_ARM_CHACHA_SPEEDUP) || defined(WOLFSSL_ARM_CHACHA_NEED_C)) && \
164
0
    !defined(USE_RISCV_CHACHA_SPEEDUP)
165
0
    {
166
#ifdef WOLFSSL_WIDE_BYTE
167
        /* inIv holds one octet per cell, so XMEMCPY into a word32[] would
168
         * overflow; load the three little-endian nonce/counter words
169
         * octet-wise instead. */
170
        ctx->X[CHACHA_MATRIX_CNT_IV+0] = counter;
171
        ctx->X[CHACHA_MATRIX_CNT_IV+1] = U8TO32_LITTLE(inIv + 0);
172
        ctx->X[CHACHA_MATRIX_CNT_IV+2] = U8TO32_LITTLE(inIv + 4);
173
        ctx->X[CHACHA_MATRIX_CNT_IV+3] = U8TO32_LITTLE(inIv + 8);
174
#else
175
0
        XMEMCPY(temp, inIv, CHACHA_IV_BYTES);
176
        /* block counter */
177
0
        ctx->X[CHACHA_MATRIX_CNT_IV+0] = counter;
178
        /* fixed variable from nonce */
179
0
        ctx->X[CHACHA_MATRIX_CNT_IV+1] = LITTLE32(temp[0]);
180
        /* counter from nonce */
181
0
        ctx->X[CHACHA_MATRIX_CNT_IV+2] = LITTLE32(temp[1]);
182
        /* counter from nonce */
183
0
        ctx->X[CHACHA_MATRIX_CNT_IV+3] = LITTLE32(temp[2]);
184
0
#endif
185
0
    }
186
0
#endif
187
188
0
    return 0;
189
0
}
190
191
#if (!defined(USE_ARM_CHACHA_SPEEDUP) || defined(WOLFSSL_ARM_CHACHA_NEED_C)) && \
192
    !defined(USE_RISCV_CHACHA_SPEEDUP)
193
/* "expand 32-byte k" as unsigned 32 byte */
194
static const word32 sigma[4] = {0x61707865, 0x3320646e, 0x79622d32, 0x6b206574};
195
/* "expand 16-byte k" as unsigned 16 byte */
196
static const word32 tau[4] = {0x61707865, 0x3120646e, 0x79622d36, 0x6b206574};
197
#endif
198
199
/**
200
  * Key setup. 8 word iv (nonce)
201
  */
202
int wc_Chacha_SetKey(ChaCha* ctx, const byte* key, word32 keySz)
203
0
{
204
0
#if (!defined(USE_ARM_CHACHA_SPEEDUP) || defined(WOLFSSL_ARM_CHACHA_NEED_C)) && \
205
0
    !defined(USE_RISCV_CHACHA_SPEEDUP)
206
0
    const word32* constants;
207
0
    const byte*   k;
208
#ifdef XSTREAM_ALIGN
209
    word32 alignKey[8];
210
#endif
211
0
#endif
212
213
0
    if (ctx == NULL || key == NULL)
214
0
        return BAD_FUNC_ARG;
215
216
0
    if (keySz != (CHACHA_MAX_KEY_SZ/2) && keySz != CHACHA_MAX_KEY_SZ)
217
0
        return BAD_FUNC_ARG;
218
219
#ifdef WOLFSSL_ARM_CHACHA_NEON_FALLBACK
220
    if (chacha_use_neon())
221
        wc_chacha_setkey(ctx->X, key, keySz);
222
    else
223
#elif (defined(USE_ARM_CHACHA_SPEEDUP) && !defined(WOLFSSL_ARM_CHACHA_C_ONLY)) || \
224
    defined(USE_RISCV_CHACHA_SPEEDUP)
225
    wc_chacha_setkey(ctx->X, key, keySz);
226
#endif
227
0
#if (!defined(USE_ARM_CHACHA_SPEEDUP) || defined(WOLFSSL_ARM_CHACHA_NEED_C)) && \
228
0
    !defined(USE_RISCV_CHACHA_SPEEDUP)
229
0
    {
230
#ifdef XSTREAM_ALIGN
231
    if ((wc_ptr_t)key % 4) {
232
        WOLFSSL_MSG("wc_ChachaSetKey unaligned key");
233
        XMEMCPY(alignKey, key, keySz);
234
        k = (byte*)alignKey;
235
    }
236
    else {
237
        k = key;
238
    }
239
#else
240
0
    k = key;
241
0
#endif /* XSTREAM_ALIGN */
242
243
#ifdef CHACHA_AEAD_TEST
244
    word32 i;
245
    printf("ChaCha key used :\n");
246
    for (i = 0; i < keySz; i++) {
247
        printf("%02x", key[i]);
248
        if ((i + 1) % 8 == 0)
249
           printf("\n");
250
    }
251
    printf("\n\n");
252
#endif
253
254
0
    ctx->X[4] = U8TO32_LITTLE(k +  0);
255
0
    ctx->X[5] = U8TO32_LITTLE(k +  4);
256
0
    ctx->X[6] = U8TO32_LITTLE(k +  8);
257
0
    ctx->X[7] = U8TO32_LITTLE(k + 12);
258
0
    if (keySz == CHACHA_MAX_KEY_SZ) {
259
0
        k += 16;
260
0
        constants = sigma;
261
0
    }
262
0
    else {
263
0
        constants = tau;
264
0
    }
265
0
    ctx->X[ 8] = U8TO32_LITTLE(k +  0);
266
0
    ctx->X[ 9] = U8TO32_LITTLE(k +  4);
267
0
    ctx->X[10] = U8TO32_LITTLE(k +  8);
268
0
    ctx->X[11] = U8TO32_LITTLE(k + 12);
269
0
    ctx->X[ 0] = constants[0];
270
0
    ctx->X[ 1] = constants[1];
271
0
    ctx->X[ 2] = constants[2];
272
0
    ctx->X[ 3] = constants[3];
273
0
    }
274
0
#endif
275
276
0
    ctx->left = 0; /* resets state */
277
0
    ctx->keySet = 1;
278
279
0
    return 0;
280
0
}
281
282
#if (!defined(USE_INTEL_CHACHA_SPEEDUP) && !defined(USE_ARM_CHACHA_SPEEDUP) && \
283
    !defined(USE_RISCV_CHACHA_SPEEDUP)) || defined(WOLFSSL_ARM_CHACHA_NEED_C)
284
/**
285
  * Converts word into bytes with rotations having been done.
286
  */
287
static WC_INLINE void wc_Chacha_wordtobyte(word32 x[CHACHA_CHUNK_WORDS],
288
        word32 state[CHACHA_CHUNK_WORDS])
289
0
{
290
0
    word32 i;
291
292
    /* Copy the word32[] state array by its cell size, not CHACHA_CHUNK_BYTES:
293
     * that macro is an octet count (=64) for serialized keystream buffers, and
294
     * XMEMCPY works in CHAR_BIT-sized cells, so using it here would over-copy
295
     * (2x) on CHAR_BIT == 16 targets. See chacha.h CHACHA_CHUNK_BYTES note. */
296
0
    XMEMCPY(x, state, CHACHA_CHUNK_WORDS * sizeof(word32));
297
298
0
    for (i = (ROUNDS); i > 0; i -= 2) {
299
0
        QUARTERROUND(0, 4,  8, 12)
300
0
        QUARTERROUND(1, 5,  9, 13)
301
0
        QUARTERROUND(2, 6, 10, 14)
302
0
        QUARTERROUND(3, 7, 11, 15)
303
0
        QUARTERROUND(0, 5, 10, 15)
304
0
        QUARTERROUND(1, 6, 11, 12)
305
0
        QUARTERROUND(2, 7,  8, 13)
306
0
        QUARTERROUND(3, 4,  9, 14)
307
0
    }
308
309
0
    for (i = 0; i < CHACHA_CHUNK_WORDS; i++) {
310
0
        x[i] = PLUS(x[i], state[i]);
311
#ifdef BIG_ENDIAN_ORDER
312
        x[i] = LITTLE32(x[i]);
313
#endif
314
0
    }
315
0
}
316
#endif /* !USE_INTEL_CHACHA_SPEEDUP */
317
318
#ifdef __cplusplus
319
    extern "C" {
320
#endif
321
322
extern void chacha_encrypt_x64(ChaCha* ctx, const byte* m, byte* c,
323
                               word32 bytes);
324
extern void chacha_encrypt_avx1(ChaCha* ctx, const byte* m, byte* c,
325
                                word32 bytes);
326
extern void chacha_encrypt_avx2(ChaCha* ctx, const byte* m, byte* c,
327
                                word32 bytes);
328
extern void chacha_encrypt_avx512(ChaCha* ctx, const byte* m, byte* c,
329
                                  word32 bytes);
330
extern void chacha_encrypt_avx512vl(ChaCha* ctx, const byte* m, byte* c,
331
                                    word32 bytes);
332
extern void chacha_encrypt_sse3(ChaCha* ctx, const byte* m, byte* c,
333
                                word32 bytes);
334
335
#ifdef __cplusplus
336
    }  /* extern "C" */
337
#endif
338
339
#if defined(USE_INTEL_CHACHA_SPEEDUP) && defined(HAVE_INTEL_AVX512)
340
/* Decide whether to use the 512-bit (zmm) ChaCha path for this CPU.
341
 *
342
 * The zmm path processes 16 blocks at a time and is the fastest option on
343
 * microarchitectures that run 512-bit code at full clock: AMD Zen 4/5 (no
344
 * AVX-512 license) and Intel Ice Lake and later.  On Intel Skylake-SP /
345
 * Cascade Lake-class parts, sustained 512-bit instructions trip the AVX-512
346
 * frequency license and downclock the core - enough that the 256-bit AVX2 path
347
 * is faster in practice (this matches OpenSSL, which suppresses its 16x zmm
348
 * ChaCha there, and the Linux kernel, which uses only 256-bit AVX-512VL).
349
 *
350
 * There is no direct "does this core downclock" CPUID bit, so VAES presence is
351
 * used as a generational proxy: the throttling parts (Skylake-SP / Skylake-X /
352
 * Cascade Lake) predate VAES, whereas every microarchitecture that runs 512-bit
353
 * without penalty (AMD Zen 4/5, Intel Ice Lake+) implements it.  A missing VAES
354
 * only costs a little throughput (fall back to AVX2), never correctness.
355
 *
356
 * Override the heuristic with:
357
 *   WOLFSSL_CHACHA20_AVX512_ALWAYS - use zmm whenever AVX-512 is present
358
 *   WOLFSSL_CHACHA20_AVX512_NEVER  - never use zmm (always AVX2 or below)
359
 */
360
static WC_INLINE int chacha_avx512_beneficial(cpuid_flags_t flags)
361
{
362
#if defined(WOLFSSL_CHACHA20_AVX512_NEVER)
363
    (void)flags;
364
    return 0;
365
#elif defined(WOLFSSL_CHACHA20_AVX512_ALWAYS)
366
    return IS_INTEL_AVX512(flags) != 0;
367
#else
368
    return (IS_INTEL_AVX512(flags) != 0) && (IS_INTEL_VAES(flags) != 0);
369
#endif
370
}
371
#endif /* USE_INTEL_CHACHA_SPEEDUP && HAVE_INTEL_AVX512 */
372
373
374
#if (!defined(USE_INTEL_CHACHA_SPEEDUP) && !defined(USE_ARM_CHACHA_SPEEDUP) && \
375
    !defined(USE_RISCV_CHACHA_SPEEDUP)) || defined(WOLFSSL_ARM_CHACHA_NEED_C)
376
/**
377
  * Encrypt a stream of bytes
378
  */
379
static void wc_Chacha_encrypt_bytes(ChaCha* ctx, const byte* m, byte* c,
380
                                    word32 bytes)
381
0
{
382
#ifdef WOLFSSL_WIDE_BYTE
383
    /* A C byte is wider than an octet here, so the keystream cannot be aliased
384
     * as both word32 and byte through a union; generate the 16 state words and
385
     * serialize them little-endian into a one-octet-per-cell byte buffer. */
386
    word32 ks32[CHACHA_CHUNK_WORDS];
387
    byte   sbuf[CHACHA_CHUNK_BYTES];
388
    byte*  state = sbuf;
389
    #define WC_CHACHA_GEN_STREAM()                                  \
390
        do {                                                        \
391
            wc_Chacha_wordtobyte(ks32, ctx->X);                     \
392
            BytesFromWordsLE32(sbuf, ks32, CHACHA_CHUNK_BYTES);     \
393
        } while (0)
394
#else
395
0
    union {
396
0
        byte state[CHACHA_CHUNK_BYTES];
397
0
        word32 state32[CHACHA_CHUNK_WORDS];
398
0
        wolfssl_word align_word; /* align for xorbufout */
399
0
    } tmp;
400
0
    byte* state = tmp.state;
401
0
    #define WC_CHACHA_GEN_STREAM() wc_Chacha_wordtobyte(tmp.state32, ctx->X)
402
0
#endif
403
404
    /* handle left overs */
405
0
    if (bytes > 0 && ctx->left > 0) {
406
0
        word32 processed = min(bytes, ctx->left);
407
0
        WC_CHACHA_GEN_STREAM(); /* recreate the stream */
408
0
        xorbufout(c, m, state + CHACHA_CHUNK_BYTES - ctx->left, processed);
409
0
        ctx->left -= processed;
410
411
        /* Used up all of the stream that was left, increment the counter */
412
0
        if (ctx->left == 0) {
413
0
            ctx->X[CHACHA_MATRIX_CNT_IV] =
414
0
                                          PLUSONE(ctx->X[CHACHA_MATRIX_CNT_IV]);
415
0
        }
416
0
        bytes -= processed;
417
0
        c += processed;
418
0
        m += processed;
419
0
    }
420
421
0
    while (bytes >= CHACHA_CHUNK_BYTES) {
422
0
        WC_CHACHA_GEN_STREAM();
423
0
        ctx->X[CHACHA_MATRIX_CNT_IV] = PLUSONE(ctx->X[CHACHA_MATRIX_CNT_IV]);
424
0
        xorbufout(c, m, state, CHACHA_CHUNK_BYTES);
425
0
        bytes -= CHACHA_CHUNK_BYTES;
426
0
        c += CHACHA_CHUNK_BYTES;
427
0
        m += CHACHA_CHUNK_BYTES;
428
0
    }
429
430
0
    if (bytes) {
431
        /* in this case there will always be some left over since bytes is less
432
         * than CHACHA_CHUNK_BYTES, so do not increment counter after getting
433
         * stream in order for the stream to be recreated on next call */
434
0
        WC_CHACHA_GEN_STREAM();
435
0
        xorbufout(c, m, state, bytes);
436
0
        ctx->left = CHACHA_CHUNK_BYTES - bytes;
437
0
    }
438
0
    #undef WC_CHACHA_GEN_STREAM
439
0
}
440
#endif /* !USE_INTEL_CHACHA_SPEEDUP */
441
442
443
/**
444
  * API to encrypt/decrypt a message of any size.
445
  */
446
int wc_Chacha_Process(ChaCha* ctx, byte* output, const byte* input,
447
                      word32 msglen)
448
0
{
449
0
    if (ctx == NULL || input == NULL || output == NULL)
450
0
        return BAD_FUNC_ARG;
451
452
0
    if (!ctx->keySet)
453
0
        return MISSING_KEY;
454
455
#ifdef USE_INTEL_CHACHA_SPEEDUP
456
    /* handle left overs */
457
    if (msglen > 0 && ctx->left > 0) {
458
        byte*  out;
459
        word32 processed = min(msglen, ctx->left);
460
461
        out = (byte*)ctx->over + CHACHA_CHUNK_BYTES - ctx->left;
462
        xorbufout(output, input, out, processed);
463
        ctx->left -= processed;
464
        msglen -= processed;
465
        output += processed;
466
        input += processed;
467
    }
468
469
    if (msglen == 0) {
470
        return 0;
471
    }
472
473
    cpuid_get_flags_ex(&cpuidFlags);
474
475
    /* One block or less. */
476
#if defined(HAVE_INTEL_AVX1) && !defined(WOLFSSL_LINUXKM)
477
    /* In userspace SAVE_VECTOR_REGISTERS is free, so a single AVX block (~285
478
     * cyc) beats the scalar block (~435) - e.g. the per-record Poly1305 key
479
     * derivation (a 32-byte ChaCha) in the ChaCha20-Poly1305 two-pass path.
480
     * The AVX-512VL path already uses SIMD for one block; match that here. */
481
    if (msglen <= CHACHA_CHUNK_BYTES && IS_INTEL_AVX512_VL(cpuidFlags) == 0 &&
482
            IS_INTEL_AVX1(cpuidFlags)) {
483
        SAVE_VECTOR_REGISTERS(return _svr_ret;);
484
        chacha_encrypt_avx1(ctx, input, output, msglen);
485
        RESTORE_VECTOR_REGISTERS();
486
        return 0;
487
    }
488
#endif
489
    /* At most one block: the scalar path avoids the SIMD broadcast/transpose
490
     * setup and (in the Linux kernel module) the costly vector-register
491
     * save/restore. */
492
    if (msglen <= CHACHA_CHUNK_BYTES) {
493
        chacha_encrypt_x64(ctx, input, output, msglen);
494
        return 0;
495
    }
496
497
    /* 65..255 bytes without AVX-512VL: use the SSSE3 128-bit exact-block path.
498
     * It is ~1.8x the scalar path and beats the 8-block AVX2 kernel (which
499
     * always emits a full 512-byte key stream) below 256 bytes - e.g. a
500
     * 192-byte key stream is 735 vs 1335 (scalar) vs 836 (AVX2) cycles on
501
     * Coffee Lake.  This is the ChaCha20-Poly1305 short-record hot path (poly
502
     * key + <=2 data blocks).  At >=256 bytes the four-block AVX2/AVX1 kernels
503
     * take over below. */
504
#ifdef HAVE_INTEL_SSSE3
505
    if (IS_INTEL_AVX512_VL(cpuidFlags) == 0 &&
506
            msglen < 4 * CHACHA_CHUNK_BYTES &&
507
            IS_INTEL_SSSE3(cpuidFlags)) {
508
        SAVE_VECTOR_REGISTERS(return _svr_ret;);
509
        chacha_encrypt_sse3(ctx, input, output, msglen);
510
        RESTORE_VECTOR_REGISTERS();
511
        return 0;
512
    }
513
#endif
514
    if (IS_INTEL_AVX512_VL(cpuidFlags) == 0 &&
515
            msglen < 4 * CHACHA_CHUNK_BYTES) {
516
        chacha_encrypt_x64(ctx, input, output, msglen);
517
        return 0;
518
    }
519
520
    #ifdef HAVE_INTEL_AVX512
521
    /* Below one 16-block chunk (1024 bytes) the zmm path does no work and
522
     * just tail-calls AVX2, so dispatch straight to AVX2 for smaller input. */
523
    if (chacha_avx512_beneficial(cpuidFlags) &&
524
            msglen >= 16 * CHACHA_CHUNK_BYTES) {
525
        SAVE_VECTOR_REGISTERS(return _svr_ret;);
526
        chacha_encrypt_avx512(ctx, input, output, msglen);
527
        RESTORE_VECTOR_REGISTERS();
528
        return 0;
529
    }
530
    /* Everything below the AVX2 512-byte minimum (1..511 bytes) is handled by
531
     * the AVX-512VL path itself - whole 256-byte four-block chunks plus a
532
     * partial four-block tail - using single-instruction vprold rotations on
533
     * 128-bit registers (no AVX-512 frequency penalty).  It does not fall back
534
     * to any other implementation. */
535
    if (IS_INTEL_AVX512_VL(cpuidFlags) && msglen < 8 * CHACHA_CHUNK_BYTES) {
536
        SAVE_VECTOR_REGISTERS(return _svr_ret;);
537
        chacha_encrypt_avx512vl(ctx, input, output, msglen);
538
        RESTORE_VECTOR_REGISTERS();
539
        return 0;
540
    }
541
    #endif
542
    #ifdef HAVE_INTEL_AVX2
543
    if (IS_INTEL_AVX2(cpuidFlags)) {
544
        SAVE_VECTOR_REGISTERS(return _svr_ret;);
545
        chacha_encrypt_avx2(ctx, input, output, msglen);
546
        RESTORE_VECTOR_REGISTERS();
547
        return 0;
548
    }
549
    #endif
550
    if (IS_INTEL_AVX1(cpuidFlags)) {
551
        SAVE_VECTOR_REGISTERS(return _svr_ret;);
552
        chacha_encrypt_avx1(ctx, input, output, msglen);
553
        RESTORE_VECTOR_REGISTERS();
554
        return 0;
555
    }
556
    #ifdef HAVE_INTEL_SSSE3
557
    else if (IS_INTEL_SSSE3(cpuidFlags)) {
558
        SAVE_VECTOR_REGISTERS(return _svr_ret;);
559
        chacha_encrypt_sse3(ctx, input, output, msglen);
560
        RESTORE_VECTOR_REGISTERS();
561
        return 0;
562
    }
563
    #endif
564
    else {
565
        chacha_encrypt_x64(ctx, input, output, msglen);
566
        return 0;
567
    }
568
#elif defined(USE_ARM_CHACHA_SPEEDUP) || defined(USE_RISCV_CHACHA_SPEEDUP)
569
#ifdef WOLFSSL_ARM_CHACHA_NEON_FALLBACK
570
    if (chacha_use_neon())
571
#endif
572
#ifndef WOLFSSL_ARM_CHACHA_C_ONLY
573
    {
574
        /* Handle left over bytes from last block. */
575
        if ((msglen > 0) && (ctx->left > 0)) {
576
            byte* over = ((byte*)ctx->over) + CHACHA_CHUNK_BYTES - ctx->left;
577
            word32 l = min(msglen, ctx->left);
578
579
            wc_chacha_use_over(over, output, input, l);
580
581
            ctx->left -= l;
582
            input += l;
583
            output += l;
584
            msglen -= l;
585
        }
586
587
        if (msglen != 0) {
588
            wc_chacha_crypt_bytes(ctx, output, input, msglen);
589
        }
590
        return 0;
591
    }
592
#endif
593
#ifdef WOLFSSL_ARM_CHACHA_NEED_C
594
#ifdef WOLFSSL_ARM_CHACHA_NEON_FALLBACK
595
    else
596
#endif
597
    {
598
        wc_Chacha_encrypt_bytes(ctx, input, output, msglen);
599
        return 0;
600
    }
601
#endif
602
#else
603
0
    wc_Chacha_encrypt_bytes(ctx, input, output, msglen);
604
0
    return 0;
605
0
#endif
606
0
}
607
#endif /* HAVE_CHACHA */
608
/* END ChaCha C implementation */
609
610
#if defined(HAVE_CHACHA) && defined(HAVE_XCHACHA)
611
612
void wc_Chacha_purge_current_block(ChaCha* ctx)
613
{
614
    if (ctx->left > 0) {
615
        byte scratch[CHACHA_CHUNK_BYTES];
616
        XMEMSET(scratch, 0, sizeof(scratch));
617
        (void)wc_Chacha_Process(ctx, scratch, scratch, CHACHA_CHUNK_BYTES - ctx->left);
618
    }
619
}
620
621
/*
622
 * wc_HChacha_block - half a ChaCha block, for XChaCha
623
 *
624
 * see https://tools.ietf.org/html/draft-arciszewski-xchacha-03
625
 */
626
static WC_INLINE void wc_HChacha_block(ChaCha* ctx,
627
    word32 stream[CHACHA_CHUNK_WORDS/2], word32 nrounds)
628
{
629
    word32 x[CHACHA_CHUNK_WORDS];
630
    word32 i;
631
632
    for (i = 0; i < CHACHA_CHUNK_WORDS; i++) {
633
        x[i] = ctx->X[i];
634
    }
635
636
    for (i = nrounds; i > 0; i -= 2) {
637
        QUARTERROUND(0, 4,  8, 12)
638
        QUARTERROUND(1, 5,  9, 13)
639
        QUARTERROUND(2, 6, 10, 14)
640
        QUARTERROUND(3, 7, 11, 15)
641
        QUARTERROUND(0, 5, 10, 15)
642
        QUARTERROUND(1, 6, 11, 12)
643
        QUARTERROUND(2, 7,  8, 13)
644
        QUARTERROUND(3, 4,  9, 14)
645
    }
646
647
    for (i = 0; i < CHACHA_CHUNK_WORDS/4; ++i)
648
        stream[i] = x[i];
649
    for (i = CHACHA_CHUNK_WORDS/4; i < CHACHA_CHUNK_WORDS/2; ++i)
650
        stream[i] = x[i + CHACHA_CHUNK_WORDS/2];
651
}
652
653
/* XChaCha -- https://tools.ietf.org/html/draft-arciszewski-xchacha-03 */
654
int wc_XChacha_SetKey(ChaCha *ctx,
655
                      const byte *key, word32 keySz,
656
                      const byte *nonce, word32 nonceSz,
657
                      word32 counter)
658
{
659
    int ret;
660
    word32 k[CHACHA_MAX_KEY_SZ];
661
    byte   iv[CHACHA_IV_BYTES];
662
663
    /* k will hold the HChacha-derived subkey and iv the derived IV. Register
664
     * from the top with a zero baseline so every exit (including the arg/setup
665
     * error returns below, where the buffers are still zero) is covered. */
666
#ifdef WOLFSSL_CHECK_MEM_ZERO
667
    XMEMSET(k, 0, sizeof k);
668
    XMEMSET(iv, 0, sizeof iv);
669
    wc_MemZero_Add("wc_XChacha_SetKey k", k, sizeof k);
670
    wc_MemZero_Add("wc_XChacha_SetKey iv", iv, sizeof iv);
671
#endif
672
673
    if (nonceSz != XCHACHA_NONCE_BYTES) {
674
    #ifdef WOLFSSL_CHECK_MEM_ZERO
675
        wc_MemZero_Check(k, sizeof k);
676
        wc_MemZero_Check(iv, sizeof iv);
677
    #endif
678
        return BAD_FUNC_ARG;
679
    }
680
681
    if ((ret = wc_Chacha_SetKey(ctx, key, keySz)) < 0) {
682
    #ifdef WOLFSSL_CHECK_MEM_ZERO
683
        wc_MemZero_Check(k, sizeof k);
684
        wc_MemZero_Check(iv, sizeof iv);
685
    #endif
686
        return ret;
687
    }
688
689
    /* form a first chacha IV from the first 16 bytes of the nonce.
690
     * the first word is supplied in the "counter" arg, and
691
     * the result is a full 128 bit nonceful IV for the one-time block
692
     * crypto op that follows.
693
     */
694
    if ((ret = wc_Chacha_SetIV(ctx, nonce + 4, U8TO32_LITTLE(nonce))) < 0) {
695
    #ifdef WOLFSSL_CHECK_MEM_ZERO
696
        wc_MemZero_Check(k, sizeof k);
697
        wc_MemZero_Check(iv, sizeof iv);
698
    #endif
699
        return ret;
700
    }
701
702
    wc_HChacha_block(ctx, k, 20); /* 20 rounds, but keeping half the output. */
703
704
    /* the HChacha output is used as a 256 bit key for the main cipher. */
705
    XMEMCPY(&ctx->X[4], k, 8 * sizeof(word32));
706
707
    /* use 8 bytes from the end of the 24 byte nonce, padded up to 12 bytes,
708
     * to form the IV for the main cipher.
709
     */
710
    XMEMSET(iv, 0, 4);
711
    XMEMCPY(iv + 4, nonce + 16, 8);
712
713
    if ((ret = wc_Chacha_SetIV(ctx, iv, counter)) < 0) {
714
        /* k and iv hold derived key material - wipe before erroring out. */
715
        ForceZero(k, sizeof k);
716
        ForceZero(iv, sizeof iv);
717
    #ifdef WOLFSSL_CHECK_MEM_ZERO
718
        wc_MemZero_Check(k, sizeof k);
719
        wc_MemZero_Check(iv, sizeof iv);
720
    #endif
721
        return ret;
722
    }
723
724
    ForceZero(k, sizeof k);
725
    ForceZero(iv, sizeof iv);
726
#ifdef WOLFSSL_CHECK_MEM_ZERO
727
    wc_MemZero_Check(k, sizeof k);
728
    wc_MemZero_Check(iv, sizeof iv);
729
#endif
730
731
    return 0;
732
}
733
734
#endif /* HAVE_CHACHA && HAVE_XCHACHA */