Coverage Report

Created: 2022-08-24 06:37

/src/wolfssl-disable-fastmath/wolfcrypt/src/chacha20_poly1305.c
Line
Count
Source (jump to first uncovered line)
1
/* chacha.c
2
 *
3
 * Copyright (C) 2006-2022 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 2 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 and
25
the Poly1305 authenticator, both as as combined-mode,
26
or Authenticated Encryption with Additional Data (AEAD) algorithm.
27
28
*/
29
30
#ifdef HAVE_CONFIG_H
31
    #include <config.h>
32
#endif
33
34
#include <wolfssl/wolfcrypt/settings.h>
35
36
#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
37
38
#include <wolfssl/wolfcrypt/chacha20_poly1305.h>
39
#include <wolfssl/wolfcrypt/error-crypt.h>
40
#include <wolfssl/wolfcrypt/logging.h>
41
42
#ifdef NO_INLINE
43
#include <wolfssl/wolfcrypt/misc.h>
44
#else
45
#define WOLFSSL_MISC_INCLUDED
46
#include <wolfcrypt/src/misc.c>
47
#endif
48
49
0
#define CHACHA20_POLY1305_AEAD_INITIAL_COUNTER  0
50
WOLFSSL_ABI
51
int wc_ChaCha20Poly1305_Encrypt(
52
                const byte inKey[CHACHA20_POLY1305_AEAD_KEYSIZE],
53
                const byte inIV[CHACHA20_POLY1305_AEAD_IV_SIZE],
54
                const byte* inAAD, const word32 inAADLen,
55
                const byte* inPlaintext, const word32 inPlaintextLen,
56
                byte* outCiphertext,
57
                byte outAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE])
58
0
{
59
0
    int ret;
60
0
    ChaChaPoly_Aead aead;
61
62
    /* Validate function arguments */
63
0
    if (!inKey || !inIV ||
64
0
        (inPlaintextLen > 0 && inPlaintext == NULL) ||
65
0
        !outCiphertext ||
66
0
        !outAuthTag)
67
0
    {
68
0
        return BAD_FUNC_ARG;
69
0
    }
70
71
0
    ret = wc_ChaCha20Poly1305_Init(&aead, inKey, inIV,
72
0
        CHACHA20_POLY1305_AEAD_ENCRYPT);
73
0
    if (ret == 0)
74
0
        ret = wc_ChaCha20Poly1305_UpdateAad(&aead, inAAD, inAADLen);
75
0
    if (ret == 0)
76
0
        ret = wc_ChaCha20Poly1305_UpdateData(&aead, inPlaintext, outCiphertext,
77
0
            inPlaintextLen);
78
0
    if (ret == 0)
79
0
        ret = wc_ChaCha20Poly1305_Final(&aead, outAuthTag);
80
0
    return ret;
81
0
}
82
83
WOLFSSL_ABI
84
int wc_ChaCha20Poly1305_Decrypt(
85
                const byte inKey[CHACHA20_POLY1305_AEAD_KEYSIZE],
86
                const byte inIV[CHACHA20_POLY1305_AEAD_IV_SIZE],
87
                const byte* inAAD, const word32 inAADLen,
88
                const byte* inCiphertext, const word32 inCiphertextLen,
89
                const byte inAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE],
90
                byte* outPlaintext)
91
0
{
92
0
    int ret;
93
0
    ChaChaPoly_Aead aead;
94
0
    byte calculatedAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE];
95
96
    /* Validate function arguments */
97
0
    if (!inKey || !inIV ||
98
0
        (inCiphertextLen > 0 && inCiphertext == NULL) ||
99
0
        !inAuthTag ||
100
0
        !outPlaintext)
101
0
    {
102
0
        return BAD_FUNC_ARG;
103
0
    }
104
105
0
    XMEMSET(calculatedAuthTag, 0, sizeof(calculatedAuthTag));
106
107
0
    ret = wc_ChaCha20Poly1305_Init(&aead, inKey, inIV,
108
0
        CHACHA20_POLY1305_AEAD_DECRYPT);
109
0
    if (ret == 0)
110
0
        ret = wc_ChaCha20Poly1305_UpdateAad(&aead, inAAD, inAADLen);
111
0
    if (ret == 0)
112
0
        ret = wc_ChaCha20Poly1305_UpdateData(&aead, inCiphertext, outPlaintext,
113
0
            inCiphertextLen);
114
0
    if (ret == 0)
115
0
        ret = wc_ChaCha20Poly1305_Final(&aead, calculatedAuthTag);
116
0
    if (ret == 0)
117
0
        ret = wc_ChaCha20Poly1305_CheckTag(inAuthTag, calculatedAuthTag);
118
0
    return ret;
119
0
}
120
121
int wc_ChaCha20Poly1305_CheckTag(
122
    const byte authTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE],
123
    const byte authTagChk[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE])
124
0
{
125
0
    int ret = 0;
126
0
    if (authTag == NULL || authTagChk == NULL) {
127
0
        return BAD_FUNC_ARG;
128
0
    }
129
0
    if (ConstantCompare(authTag, authTagChk,
130
0
            CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE) != 0) {
131
0
        ret = MAC_CMP_FAILED_E;
132
0
    }
133
0
    return ret;
134
0
}
135
136
int wc_ChaCha20Poly1305_Init(ChaChaPoly_Aead* aead,
137
    const byte inKey[CHACHA20_POLY1305_AEAD_KEYSIZE],
138
    const byte inIV[CHACHA20_POLY1305_AEAD_IV_SIZE],
139
    int isEncrypt)
140
0
{
141
0
    int ret;
142
0
    byte authKey[CHACHA20_POLY1305_AEAD_KEYSIZE];
143
144
    /* check arguments */
145
0
    if (aead == NULL || inKey == NULL || inIV == NULL) {
146
0
        return BAD_FUNC_ARG;
147
0
    }
148
149
    /* setup aead context */
150
0
    XMEMSET(aead, 0, sizeof(ChaChaPoly_Aead));
151
0
    XMEMSET(authKey, 0, sizeof(authKey));
152
0
    aead->isEncrypt = (byte)isEncrypt;
153
154
    /* Initialize the ChaCha20 context (key and iv) */
155
0
    ret = wc_Chacha_SetKey(&aead->chacha, inKey,
156
0
        CHACHA20_POLY1305_AEAD_KEYSIZE);
157
0
    if (ret == 0) {
158
0
        ret = wc_Chacha_SetIV(&aead->chacha, inIV,
159
0
            CHACHA20_POLY1305_AEAD_INITIAL_COUNTER);
160
0
    }
161
162
    /* Create the Poly1305 key */
163
0
    if (ret == 0) {
164
0
        ret = wc_Chacha_Process(&aead->chacha, authKey, authKey,
165
0
            CHACHA20_POLY1305_AEAD_KEYSIZE);
166
0
    }
167
168
    /* Initialize Poly1305 context */
169
0
    if (ret == 0) {
170
0
        ret = wc_Poly1305SetKey(&aead->poly, authKey,
171
0
            CHACHA20_POLY1305_AEAD_KEYSIZE);
172
0
    }
173
174
    /* advance counter by 1 after creating Poly1305 key */
175
0
    if (ret == 0) {
176
0
        ret = wc_Chacha_SetIV(&aead->chacha, inIV,
177
0
            CHACHA20_POLY1305_AEAD_INITIAL_COUNTER + 1);
178
0
    }
179
180
0
    if (ret == 0) {
181
0
        aead->state = CHACHA20_POLY1305_STATE_READY;
182
0
    }
183
184
0
    return ret;
185
0
}
186
187
/* optional additional authentication data */
188
int wc_ChaCha20Poly1305_UpdateAad(ChaChaPoly_Aead* aead,
189
    const byte* inAAD, word32 inAADLen)
190
0
{
191
0
    int ret = 0;
192
193
0
    if (aead == NULL || (inAAD == NULL && inAADLen > 0)) {
194
0
        return BAD_FUNC_ARG;
195
0
    }
196
0
    if (aead->state != CHACHA20_POLY1305_STATE_READY &&
197
0
        aead->state != CHACHA20_POLY1305_STATE_AAD) {
198
0
        return BAD_STATE_E;
199
0
    }
200
0
    if (inAADLen > CHACHA20_POLY1305_MAX - aead->aadLen)
201
0
        return CHACHA_POLY_OVERFLOW;
202
203
0
    if (inAAD && inAADLen > 0) {
204
0
        ret = wc_Poly1305Update(&aead->poly, inAAD, inAADLen);
205
0
        if (ret == 0) {
206
0
            aead->aadLen += inAADLen;
207
0
            aead->state = CHACHA20_POLY1305_STATE_AAD;
208
0
        }
209
0
    }
210
211
0
    return ret;
212
0
}
213
214
/* inData and outData can be same pointer (inline) */
215
int wc_ChaCha20Poly1305_UpdateData(ChaChaPoly_Aead* aead,
216
    const byte* inData, byte* outData, word32 dataLen)
217
0
{
218
0
    int ret = 0;
219
220
0
    if (aead == NULL || inData == NULL || outData == NULL) {
221
0
        return BAD_FUNC_ARG;
222
0
    }
223
0
    if (aead->state != CHACHA20_POLY1305_STATE_READY &&
224
0
        aead->state != CHACHA20_POLY1305_STATE_AAD &&
225
0
        aead->state != CHACHA20_POLY1305_STATE_DATA) {
226
0
        return BAD_STATE_E;
227
0
    }
228
0
    if (dataLen > CHACHA20_POLY1305_MAX - aead->dataLen)
229
0
        return CHACHA_POLY_OVERFLOW;
230
231
    /* Pad the AAD */
232
0
    if (aead->state == CHACHA20_POLY1305_STATE_AAD) {
233
0
        ret = wc_Poly1305_Pad(&aead->poly, aead->aadLen);
234
0
    }
235
236
    /* advance state */
237
0
    aead->state = CHACHA20_POLY1305_STATE_DATA;
238
239
    /* Perform ChaCha20 encrypt/decrypt and Poly1305 auth calc */
240
0
    if (ret == 0) {
241
0
        if (aead->isEncrypt) {
242
0
            ret = wc_Chacha_Process(&aead->chacha, outData, inData, dataLen);
243
0
            if (ret == 0)
244
0
                ret = wc_Poly1305Update(&aead->poly, outData, dataLen);
245
0
        }
246
0
        else {
247
0
            ret = wc_Poly1305Update(&aead->poly, inData, dataLen);
248
0
            if (ret == 0)
249
0
                ret = wc_Chacha_Process(&aead->chacha, outData, inData, dataLen);
250
0
        }
251
0
    }
252
0
    if (ret == 0) {
253
0
        aead->dataLen += dataLen;
254
0
    }
255
0
    return ret;
256
0
}
257
258
int wc_ChaCha20Poly1305_Final(ChaChaPoly_Aead* aead,
259
    byte outAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE])
260
0
{
261
0
    int ret = 0;
262
263
0
    if (aead == NULL || outAuthTag == NULL) {
264
0
        return BAD_FUNC_ARG;
265
0
    }
266
0
    if (aead->state != CHACHA20_POLY1305_STATE_AAD &&
267
0
        aead->state != CHACHA20_POLY1305_STATE_DATA) {
268
0
        return BAD_STATE_E;
269
0
    }
270
271
    /* Pad the AAD - Make sure it is done */
272
0
    if (aead->state == CHACHA20_POLY1305_STATE_AAD) {
273
0
        ret = wc_Poly1305_Pad(&aead->poly, aead->aadLen);
274
0
    }
275
276
    /* Pad the plaintext/ciphertext to 16 bytes */
277
0
    if (ret == 0) {
278
0
        ret = wc_Poly1305_Pad(&aead->poly, aead->dataLen);
279
0
    }
280
281
    /* Add the aad length and plaintext/ciphertext length */
282
0
    if (ret == 0) {
283
0
        ret = wc_Poly1305_EncodeSizes(&aead->poly, aead->aadLen,
284
0
            aead->dataLen);
285
0
    }
286
287
    /* Finalize the auth tag */
288
0
    if (ret == 0) {
289
0
        ret = wc_Poly1305Final(&aead->poly, outAuthTag);
290
0
    }
291
292
    /* reset and cleanup sensitive context */
293
0
    ForceZero(aead, sizeof(ChaChaPoly_Aead));
294
295
0
    return ret;
296
0
}
297
298
#ifdef HAVE_XCHACHA
299
300
int wc_XChaCha20Poly1305_Init(
301
    ChaChaPoly_Aead *aead,
302
    const byte *ad, word32 ad_len,
303
    const byte *nonce, word32 nonce_len,
304
    const byte *key, word32 key_len,
305
    int isEncrypt)
306
0
{
307
0
    byte authKey[CHACHA20_POLY1305_AEAD_KEYSIZE];
308
0
    int ret;
309
310
0
    if ((ad == NULL) || (nonce == NULL) || (key == NULL))
311
0
        return BAD_FUNC_ARG;
312
313
0
    if ((key_len != CHACHA20_POLY1305_AEAD_KEYSIZE) ||
314
0
        (nonce_len != XCHACHA20_POLY1305_AEAD_NONCE_SIZE))
315
0
        return BAD_FUNC_ARG;
316
317
0
    if ((ret = wc_XChacha_SetKey(&aead->chacha,
318
0
                                 key, key_len,
319
0
                                 nonce, nonce_len,
320
0
                                 0 /* counter */)) < 0)
321
0
        return ret;
322
323
0
    XMEMSET(authKey, 0, sizeof authKey);
324
325
    /* Create the Poly1305 key */
326
0
    if ((ret = wc_Chacha_Process(&aead->chacha, authKey, authKey,
327
0
                                 (word32)sizeof authKey)) < 0)
328
0
        return ret;
329
    /* advance to start of the next ChaCha block. */
330
0
    wc_Chacha_purge_current_block(&aead->chacha);
331
332
    /* Initialize Poly1305 context */
333
0
    if ((ret = wc_Poly1305SetKey(&aead->poly, authKey,
334
0
                                 (word32)sizeof authKey)) < 0)
335
0
        return ret;
336
337
0
    if ((ret = wc_Poly1305Update(&aead->poly, ad, (word32)ad_len)) < 0)
338
0
        return ret;
339
340
0
    if ((ret = wc_Poly1305_Pad(&aead->poly, (word32)ad_len)) < 0)
341
0
        return ret;
342
343
0
    aead->isEncrypt = (byte)isEncrypt;
344
0
    aead->state = CHACHA20_POLY1305_STATE_AAD;
345
346
0
    return 0;
347
0
}
348
349
static WC_INLINE int wc_XChaCha20Poly1305_crypt_oneshot(
350
    byte *dst, const size_t dst_space,
351
    const byte *src, const size_t src_len,
352
    const byte *ad, const size_t ad_len,
353
    const byte *nonce, const size_t nonce_len,
354
    const byte *key, const size_t key_len,
355
    int isEncrypt)
356
0
{
357
0
    int ret;
358
0
    ssize_t dst_len = isEncrypt ?
359
0
        (ssize_t)src_len + POLY1305_DIGEST_SIZE :
360
0
        (ssize_t)src_len - POLY1305_DIGEST_SIZE;
361
0
    const byte *src_i;
362
0
    byte *dst_i;
363
0
    size_t src_len_rem;
364
0
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
365
0
    ChaChaPoly_Aead *aead = (ChaChaPoly_Aead *)XMALLOC(sizeof *aead, NULL, DYNAMIC_TYPE_TMP_BUFFER);
366
367
0
    if (aead == NULL)
368
0
        return MEMORY_E;
369
#else
370
    ChaChaPoly_Aead aead_buf, *aead = &aead_buf;
371
#endif
372
373
0
    if ((dst == NULL) || (src == NULL)) {
374
0
        ret = BAD_FUNC_ARG;
375
0
        goto out;
376
0
    }
377
378
0
    if ((ssize_t)dst_space < dst_len) {
379
0
        ret = BUFFER_E;
380
0
        goto out;
381
0
    }
382
383
0
    if ((ret = wc_XChaCha20Poly1305_Init(aead, ad, (word32)ad_len,
384
0
                                         nonce, (word32)nonce_len,
385
0
                                         key, (word32)key_len, 1)) < 0)
386
0
        goto out;
387
388
#ifdef WOLFSSL_CHECK_MEM_ZERO
389
    wc_MemZero_Add("wc_XChaCha20Poly1305_crypt_oneshot aead", aead,
390
        sizeof(ChaChaPoly_Aead));
391
#endif
392
393
    /* process the input in 16k pieces to accommodate src_lens that don't fit in a word32,
394
     * and to exploit hot cache for the input data.
395
     */
396
0
    src_i = src;
397
0
    src_len_rem = isEncrypt ? src_len : (size_t)dst_len;
398
0
    dst_i = dst;
399
0
    while (src_len_rem > 0) {
400
0
        word32 this_src_len =
401
0
            (src_len_rem > 16384) ?
402
0
            16384 :
403
0
            (word32)src_len_rem;
404
405
0
        if ((ret = wc_Chacha_Process(&aead->chacha, dst_i, src_i, this_src_len)) < 0)
406
0
            goto out;
407
408
0
        if ((ret = wc_Poly1305Update(&aead->poly, isEncrypt ? dst_i : src_i, this_src_len)) < 0)
409
0
            goto out;
410
411
0
        src_len_rem -= (size_t)this_src_len;
412
0
        src_i += this_src_len;
413
0
        dst_i += this_src_len;
414
0
    }
415
416
0
    if (aead->poly.leftover) {
417
0
        if ((ret = wc_Poly1305_Pad(&aead->poly, (word32)aead->poly.leftover)) < 0)
418
0
            return ret;
419
0
    }
420
421
0
#ifdef WORD64_AVAILABLE
422
0
    ret = wc_Poly1305_EncodeSizes64(&aead->poly, ad_len, isEncrypt ? src_len : (size_t)dst_len);
423
#else
424
    ret = wc_Poly1305_EncodeSizes(&aead->poly, ad_len, isEncrypt ? src_len : (size_t)dst_len);
425
#endif
426
0
    if (ret < 0)
427
0
        goto out;
428
429
0
    if (isEncrypt)
430
0
        ret = wc_Poly1305Final(&aead->poly, dst + src_len);
431
0
    else {
432
0
        byte outAuthTag[POLY1305_DIGEST_SIZE];
433
434
0
        if ((ret = wc_Poly1305Final(&aead->poly, outAuthTag)) < 0)
435
0
            goto out;
436
437
0
        if (ConstantCompare(outAuthTag, src + dst_len, POLY1305_DIGEST_SIZE) != 0) {
438
0
            ret = MAC_CMP_FAILED_E;
439
0
            goto out;
440
0
        }
441
0
    }
442
443
0
  out:
444
445
0
    ForceZero(aead, sizeof *aead);
446
447
0
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
448
0
    XFREE(aead, NULL, DYNAMIC_TYPE_TMP_BUFFER);
449
#elif defined(WOLFSSL_CHECK_MEM_ZERO)
450
    wc_MemZero_Check(aead, sizeof(ChaChaPoly_Aead));
451
#endif
452
453
0
    return ret;
454
0
}
455
456
int wc_XChaCha20Poly1305_Encrypt(
457
    byte *dst, const size_t dst_space,
458
    const byte *src, const size_t src_len,
459
    const byte *ad, const size_t ad_len,
460
    const byte *nonce, const size_t nonce_len,
461
    const byte *key, const size_t key_len)
462
0
{
463
0
    return wc_XChaCha20Poly1305_crypt_oneshot(dst, dst_space, src, src_len, ad, ad_len, nonce, nonce_len, key, key_len, 1);
464
0
}
465
466
int wc_XChaCha20Poly1305_Decrypt(
467
    byte *dst, const size_t dst_space,
468
    const byte *src, const size_t src_len,
469
    const byte *ad, const size_t ad_len,
470
    const byte *nonce, const size_t nonce_len,
471
    const byte *key, const size_t key_len)
472
0
{
473
0
    return wc_XChaCha20Poly1305_crypt_oneshot(dst, dst_space, src, src_len, ad, ad_len, nonce, nonce_len, key, key_len, 0);
474
0
}
475
476
#endif /* HAVE_XCHACHA */
477
478
#endif /* HAVE_CHACHA && HAVE_POLY1305 */