Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
8774 rgimad 1
/**
2
 * \file chachapoly.c
3
 *
4
 * \brief ChaCha20-Poly1305 AEAD construction based on RFC 7539.
5
 *
6
 *  Copyright (C) 2006-2016, ARM Limited, All Rights Reserved
7
 *  SPDX-License-Identifier: GPL-2.0
8
 *
9
 *  This program is free software; you can redistribute it and/or modify
10
 *  it under the terms of the GNU General Public License as published by
11
 *  the Free Software Foundation; either version 2 of the License, or
12
 *  (at your option) any later version.
13
 *
14
 *  This program is distributed in the hope that it will be useful,
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 *  GNU General Public License for more details.
18
 *
19
 *  You should have received a copy of the GNU General Public License along
20
 *  with this program; if not, write to the Free Software Foundation, Inc.,
21
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
 *
23
 *  This file is part of mbed TLS (https://tls.mbed.org)
24
 */
25
#if !defined(MBEDTLS_CONFIG_FILE)
26
#include "mbedtls/config.h"
27
#else
28
#include MBEDTLS_CONFIG_FILE
29
#endif
30
 
31
#if defined(MBEDTLS_CHACHAPOLY_C)
32
 
33
#include "mbedtls/chachapoly.h"
34
#include "mbedtls/platform_util.h"
35
 
36
#include 
37
 
38
#if defined(MBEDTLS_SELF_TEST)
39
#if defined(MBEDTLS_PLATFORM_C)
40
#include "mbedtls/platform.h"
41
#else
42
#include 
43
#define mbedtls_printf printf
44
#endif /* MBEDTLS_PLATFORM_C */
45
#endif /* MBEDTLS_SELF_TEST */
46
 
47
#if !defined(MBEDTLS_CHACHAPOLY_ALT)
48
 
49
/* Parameter validation macros */
50
#define CHACHAPOLY_VALIDATE_RET( cond )                                       \
51
    MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA )
52
#define CHACHAPOLY_VALIDATE( cond )                                           \
53
    MBEDTLS_INTERNAL_VALIDATE( cond )
54
 
55
#define CHACHAPOLY_STATE_INIT       ( 0 )
56
#define CHACHAPOLY_STATE_AAD        ( 1 )
57
#define CHACHAPOLY_STATE_CIPHERTEXT ( 2 ) /* Encrypting or decrypting */
58
#define CHACHAPOLY_STATE_FINISHED   ( 3 )
59
 
60
/**
61
 * \brief           Adds nul bytes to pad the AAD for Poly1305.
62
 *
63
 * \param ctx       The ChaCha20-Poly1305 context.
64
 */
65
static int chachapoly_pad_aad( mbedtls_chachapoly_context *ctx )
66
{
67
    uint32_t partial_block_len = (uint32_t) ( ctx->aad_len % 16U );
68
    unsigned char zeroes[15];
69
 
70
    if( partial_block_len == 0U )
71
        return( 0 );
72
 
73
    memset( zeroes, 0, sizeof( zeroes ) );
74
 
75
    return( mbedtls_poly1305_update( &ctx->poly1305_ctx,
76
                                     zeroes,
77
                                     16U - partial_block_len ) );
78
}
79
 
80
/**
81
 * \brief           Adds nul bytes to pad the ciphertext for Poly1305.
82
 *
83
 * \param ctx       The ChaCha20-Poly1305 context.
84
 */
85
static int chachapoly_pad_ciphertext( mbedtls_chachapoly_context *ctx )
86
{
87
    uint32_t partial_block_len = (uint32_t) ( ctx->ciphertext_len % 16U );
88
    unsigned char zeroes[15];
89
 
90
    if( partial_block_len == 0U )
91
        return( 0 );
92
 
93
    memset( zeroes, 0, sizeof( zeroes ) );
94
    return( mbedtls_poly1305_update( &ctx->poly1305_ctx,
95
                                     zeroes,
96
                                     16U - partial_block_len ) );
97
}
98
 
99
void mbedtls_chachapoly_init( mbedtls_chachapoly_context *ctx )
100
{
101
    CHACHAPOLY_VALIDATE( ctx != NULL );
102
 
103
    mbedtls_chacha20_init( &ctx->chacha20_ctx );
104
    mbedtls_poly1305_init( &ctx->poly1305_ctx );
105
    ctx->aad_len        = 0U;
106
    ctx->ciphertext_len = 0U;
107
    ctx->state          = CHACHAPOLY_STATE_INIT;
108
    ctx->mode           = MBEDTLS_CHACHAPOLY_ENCRYPT;
109
}
110
 
111
void mbedtls_chachapoly_free( mbedtls_chachapoly_context *ctx )
112
{
113
    if( ctx == NULL )
114
        return;
115
 
116
    mbedtls_chacha20_free( &ctx->chacha20_ctx );
117
    mbedtls_poly1305_free( &ctx->poly1305_ctx );
118
    ctx->aad_len        = 0U;
119
    ctx->ciphertext_len = 0U;
120
    ctx->state          = CHACHAPOLY_STATE_INIT;
121
    ctx->mode           = MBEDTLS_CHACHAPOLY_ENCRYPT;
122
}
123
 
124
int mbedtls_chachapoly_setkey( mbedtls_chachapoly_context *ctx,
125
                               const unsigned char key[32] )
126
{
127
    int ret;
128
    CHACHAPOLY_VALIDATE_RET( ctx != NULL );
129
    CHACHAPOLY_VALIDATE_RET( key != NULL );
130
 
131
    ret = mbedtls_chacha20_setkey( &ctx->chacha20_ctx, key );
132
 
133
    return( ret );
134
}
135
 
136
int mbedtls_chachapoly_starts( mbedtls_chachapoly_context *ctx,
137
                               const unsigned char nonce[12],
138
                               mbedtls_chachapoly_mode_t mode  )
139
{
140
    int ret;
141
    unsigned char poly1305_key[64];
142
    CHACHAPOLY_VALIDATE_RET( ctx != NULL );
143
    CHACHAPOLY_VALIDATE_RET( nonce != NULL );
144
 
145
    /* Set counter = 0, will be update to 1 when generating Poly1305 key */
146
    ret = mbedtls_chacha20_starts( &ctx->chacha20_ctx, nonce, 0U );
147
    if( ret != 0 )
148
        goto cleanup;
149
 
150
    /* Generate the Poly1305 key by getting the ChaCha20 keystream output with
151
     * counter = 0.  This is the same as encrypting a buffer of zeroes.
152
     * Only the first 256-bits (32 bytes) of the key is used for Poly1305.
153
     * The other 256 bits are discarded.
154
     */
155
    memset( poly1305_key, 0, sizeof( poly1305_key ) );
156
    ret = mbedtls_chacha20_update( &ctx->chacha20_ctx, sizeof( poly1305_key ),
157
                                      poly1305_key, poly1305_key );
158
    if( ret != 0 )
159
        goto cleanup;
160
 
161
    ret = mbedtls_poly1305_starts( &ctx->poly1305_ctx, poly1305_key );
162
 
163
    if( ret == 0 )
164
    {
165
        ctx->aad_len        = 0U;
166
        ctx->ciphertext_len = 0U;
167
        ctx->state          = CHACHAPOLY_STATE_AAD;
168
        ctx->mode           = mode;
169
    }
170
 
171
cleanup:
172
    mbedtls_platform_zeroize( poly1305_key, 64U );
173
    return( ret );
174
}
175
 
176
int mbedtls_chachapoly_update_aad( mbedtls_chachapoly_context *ctx,
177
                                   const unsigned char *aad,
178
                                   size_t aad_len )
179
{
180
    CHACHAPOLY_VALIDATE_RET( ctx != NULL );
181
    CHACHAPOLY_VALIDATE_RET( aad_len == 0 || aad != NULL );
182
 
183
    if( ctx->state != CHACHAPOLY_STATE_AAD )
184
        return( MBEDTLS_ERR_CHACHAPOLY_BAD_STATE );
185
 
186
    ctx->aad_len += aad_len;
187
 
188
    return( mbedtls_poly1305_update( &ctx->poly1305_ctx, aad, aad_len ) );
189
}
190
 
191
int mbedtls_chachapoly_update( mbedtls_chachapoly_context *ctx,
192
                               size_t len,
193
                               const unsigned char *input,
194
                               unsigned char *output )
195
{
196
    int ret;
197
    CHACHAPOLY_VALIDATE_RET( ctx != NULL );
198
    CHACHAPOLY_VALIDATE_RET( len == 0 || input != NULL );
199
    CHACHAPOLY_VALIDATE_RET( len == 0 || output != NULL );
200
 
201
    if( ( ctx->state != CHACHAPOLY_STATE_AAD ) &&
202
        ( ctx->state != CHACHAPOLY_STATE_CIPHERTEXT ) )
203
    {
204
        return( MBEDTLS_ERR_CHACHAPOLY_BAD_STATE );
205
    }
206
 
207
    if( ctx->state == CHACHAPOLY_STATE_AAD )
208
    {
209
        ctx->state = CHACHAPOLY_STATE_CIPHERTEXT;
210
 
211
        ret = chachapoly_pad_aad( ctx );
212
        if( ret != 0 )
213
            return( ret );
214
    }
215
 
216
    ctx->ciphertext_len += len;
217
 
218
    if( ctx->mode == MBEDTLS_CHACHAPOLY_ENCRYPT )
219
    {
220
        ret = mbedtls_chacha20_update( &ctx->chacha20_ctx, len, input, output );
221
        if( ret != 0 )
222
            return( ret );
223
 
224
        ret = mbedtls_poly1305_update( &ctx->poly1305_ctx, output, len );
225
        if( ret != 0 )
226
            return( ret );
227
    }
228
    else /* DECRYPT */
229
    {
230
        ret = mbedtls_poly1305_update( &ctx->poly1305_ctx, input, len );
231
        if( ret != 0 )
232
            return( ret );
233
 
234
        ret = mbedtls_chacha20_update( &ctx->chacha20_ctx, len, input, output );
235
        if( ret != 0 )
236
            return( ret );
237
    }
238
 
239
    return( 0 );
240
}
241
 
242
int mbedtls_chachapoly_finish( mbedtls_chachapoly_context *ctx,
243
                               unsigned char mac[16] )
244
{
245
    int ret;
246
    unsigned char len_block[16];
247
    CHACHAPOLY_VALIDATE_RET( ctx != NULL );
248
    CHACHAPOLY_VALIDATE_RET( mac != NULL );
249
 
250
    if( ctx->state == CHACHAPOLY_STATE_INIT )
251
    {
252
        return( MBEDTLS_ERR_CHACHAPOLY_BAD_STATE );
253
    }
254
 
255
    if( ctx->state == CHACHAPOLY_STATE_AAD )
256
    {
257
        ret = chachapoly_pad_aad( ctx );
258
        if( ret != 0 )
259
            return( ret );
260
    }
261
    else if( ctx->state == CHACHAPOLY_STATE_CIPHERTEXT )
262
    {
263
        ret = chachapoly_pad_ciphertext( ctx );
264
        if( ret != 0 )
265
            return( ret );
266
    }
267
 
268
    ctx->state = CHACHAPOLY_STATE_FINISHED;
269
 
270
    /* The lengths of the AAD and ciphertext are processed by
271
     * Poly1305 as the final 128-bit block, encoded as little-endian integers.
272
     */
273
    len_block[ 0] = (unsigned char)( ctx->aad_len       );
274
    len_block[ 1] = (unsigned char)( ctx->aad_len >>  8 );
275
    len_block[ 2] = (unsigned char)( ctx->aad_len >> 16 );
276
    len_block[ 3] = (unsigned char)( ctx->aad_len >> 24 );
277
    len_block[ 4] = (unsigned char)( ctx->aad_len >> 32 );
278
    len_block[ 5] = (unsigned char)( ctx->aad_len >> 40 );
279
    len_block[ 6] = (unsigned char)( ctx->aad_len >> 48 );
280
    len_block[ 7] = (unsigned char)( ctx->aad_len >> 56 );
281
    len_block[ 8] = (unsigned char)( ctx->ciphertext_len       );
282
    len_block[ 9] = (unsigned char)( ctx->ciphertext_len >>  8 );
283
    len_block[10] = (unsigned char)( ctx->ciphertext_len >> 16 );
284
    len_block[11] = (unsigned char)( ctx->ciphertext_len >> 24 );
285
    len_block[12] = (unsigned char)( ctx->ciphertext_len >> 32 );
286
    len_block[13] = (unsigned char)( ctx->ciphertext_len >> 40 );
287
    len_block[14] = (unsigned char)( ctx->ciphertext_len >> 48 );
288
    len_block[15] = (unsigned char)( ctx->ciphertext_len >> 56 );
289
 
290
    ret = mbedtls_poly1305_update( &ctx->poly1305_ctx, len_block, 16U );
291
    if( ret != 0 )
292
        return( ret );
293
 
294
    ret = mbedtls_poly1305_finish( &ctx->poly1305_ctx, mac );
295
 
296
    return( ret );
297
}
298
 
299
static int chachapoly_crypt_and_tag( mbedtls_chachapoly_context *ctx,
300
                                     mbedtls_chachapoly_mode_t mode,
301
                                     size_t length,
302
                                     const unsigned char nonce[12],
303
                                     const unsigned char *aad,
304
                                     size_t aad_len,
305
                                     const unsigned char *input,
306
                                     unsigned char *output,
307
                                     unsigned char tag[16] )
308
{
309
    int ret;
310
 
311
    ret = mbedtls_chachapoly_starts( ctx, nonce, mode );
312
    if( ret != 0 )
313
        goto cleanup;
314
 
315
    ret = mbedtls_chachapoly_update_aad( ctx, aad, aad_len );
316
    if( ret != 0 )
317
        goto cleanup;
318
 
319
    ret = mbedtls_chachapoly_update( ctx, length, input, output );
320
    if( ret != 0 )
321
        goto cleanup;
322
 
323
    ret = mbedtls_chachapoly_finish( ctx, tag );
324
 
325
cleanup:
326
    return( ret );
327
}
328
 
329
int mbedtls_chachapoly_encrypt_and_tag( mbedtls_chachapoly_context *ctx,
330
                                        size_t length,
331
                                        const unsigned char nonce[12],
332
                                        const unsigned char *aad,
333
                                        size_t aad_len,
334
                                        const unsigned char *input,
335
                                        unsigned char *output,
336
                                        unsigned char tag[16] )
337
{
338
    CHACHAPOLY_VALIDATE_RET( ctx   != NULL );
339
    CHACHAPOLY_VALIDATE_RET( nonce != NULL );
340
    CHACHAPOLY_VALIDATE_RET( tag   != NULL );
341
    CHACHAPOLY_VALIDATE_RET( aad_len == 0 || aad    != NULL );
342
    CHACHAPOLY_VALIDATE_RET( length  == 0 || input  != NULL );
343
    CHACHAPOLY_VALIDATE_RET( length  == 0 || output != NULL );
344
 
345
    return( chachapoly_crypt_and_tag( ctx, MBEDTLS_CHACHAPOLY_ENCRYPT,
346
                                      length, nonce, aad, aad_len,
347
                                      input, output, tag ) );
348
}
349
 
350
int mbedtls_chachapoly_auth_decrypt( mbedtls_chachapoly_context *ctx,
351
                                     size_t length,
352
                                     const unsigned char nonce[12],
353
                                     const unsigned char *aad,
354
                                     size_t aad_len,
355
                                     const unsigned char tag[16],
356
                                     const unsigned char *input,
357
                                     unsigned char *output )
358
{
359
    int ret;
360
    unsigned char check_tag[16];
361
    size_t i;
362
    int diff;
363
    CHACHAPOLY_VALIDATE_RET( ctx   != NULL );
364
    CHACHAPOLY_VALIDATE_RET( nonce != NULL );
365
    CHACHAPOLY_VALIDATE_RET( tag   != NULL );
366
    CHACHAPOLY_VALIDATE_RET( aad_len == 0 || aad    != NULL );
367
    CHACHAPOLY_VALIDATE_RET( length  == 0 || input  != NULL );
368
    CHACHAPOLY_VALIDATE_RET( length  == 0 || output != NULL );
369
 
370
    if( ( ret = chachapoly_crypt_and_tag( ctx,
371
                        MBEDTLS_CHACHAPOLY_DECRYPT, length, nonce,
372
                        aad, aad_len, input, output, check_tag ) ) != 0 )
373
    {
374
        return( ret );
375
    }
376
 
377
    /* Check tag in "constant-time" */
378
    for( diff = 0, i = 0; i < sizeof( check_tag ); i++ )
379
        diff |= tag[i] ^ check_tag[i];
380
 
381
    if( diff != 0 )
382
    {
383
        mbedtls_platform_zeroize( output, length );
384
        return( MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED );
385
    }
386
 
387
    return( 0 );
388
}
389
 
390
#endif /* MBEDTLS_CHACHAPOLY_ALT */
391
 
392
#if defined(MBEDTLS_SELF_TEST)
393
 
394
static const unsigned char test_key[1][32] =
395
{
396
    {
397
        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
398
        0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
399
        0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
400
        0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
401
    }
402
};
403
 
404
static const unsigned char test_nonce[1][12] =
405
{
406
    {
407
        0x07, 0x00, 0x00, 0x00,                         /* 32-bit common part */
408
        0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47  /* 64-bit IV */
409
    }
410
};
411
 
412
static const unsigned char test_aad[1][12] =
413
{
414
    {
415
        0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3,
416
        0xc4, 0xc5, 0xc6, 0xc7
417
    }
418
};
419
 
420
static const size_t test_aad_len[1] =
421
{
422
    12U
423
};
424
 
425
static const unsigned char test_input[1][114] =
426
{
427
    {
428
        0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61,
429
        0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c,
430
        0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20,
431
        0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73,
432
        0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39,
433
        0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63,
434
        0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66,
435
        0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f,
436
        0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20,
437
        0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20,
438
        0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75,
439
        0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73,
440
        0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f,
441
        0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69,
442
        0x74, 0x2e
443
    }
444
};
445
 
446
static const unsigned char test_output[1][114] =
447
{
448
    {
449
        0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb,
450
        0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2,
451
        0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe,
452
        0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6,
453
        0x3d, 0xbe, 0xa4, 0x5e, 0x8c, 0xa9, 0x67, 0x12,
454
        0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b,
455
        0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29,
456
        0x05, 0xd6, 0xa5, 0xb6, 0x7e, 0xcd, 0x3b, 0x36,
457
        0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c,
458
        0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58,
459
        0xfa, 0xb3, 0x24, 0xe4, 0xfa, 0xd6, 0x75, 0x94,
460
        0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc,
461
        0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d,
462
        0xe5, 0x76, 0xd2, 0x65, 0x86, 0xce, 0xc6, 0x4b,
463
        0x61, 0x16
464
    }
465
};
466
 
467
static const size_t test_input_len[1] =
468
{
469
    114U
470
};
471
 
472
static const unsigned char test_mac[1][16] =
473
{
474
    {
475
        0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a,
476
        0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91
477
    }
478
};
479
 
480
#define ASSERT( cond, args )            \
481
    do                                  \
482
    {                                   \
483
        if( ! ( cond ) )                \
484
        {                               \
485
            if( verbose != 0 )          \
486
                mbedtls_printf args;    \
487
                                        \
488
            return( -1 );               \
489
        }                               \
490
    }                                   \
491
    while( 0 )
492
 
493
int mbedtls_chachapoly_self_test( int verbose )
494
{
495
    mbedtls_chachapoly_context ctx;
496
    unsigned i;
497
    int ret;
498
    unsigned char output[200];
499
    unsigned char mac[16];
500
 
501
    for( i = 0U; i < 1U; i++ )
502
    {
503
        if( verbose != 0 )
504
            mbedtls_printf( "  ChaCha20-Poly1305 test %u ", i );
505
 
506
        mbedtls_chachapoly_init( &ctx );
507
 
508
        ret = mbedtls_chachapoly_setkey( &ctx, test_key[i] );
509
        ASSERT( 0 == ret, ( "setkey() error code: %i\n", ret ) );
510
 
511
        ret = mbedtls_chachapoly_encrypt_and_tag( &ctx,
512
                                                  test_input_len[i],
513
                                                  test_nonce[i],
514
                                                  test_aad[i],
515
                                                  test_aad_len[i],
516
                                                  test_input[i],
517
                                                  output,
518
                                                  mac );
519
 
520
        ASSERT( 0 == ret, ( "crypt_and_tag() error code: %i\n", ret ) );
521
 
522
        ASSERT( 0 == memcmp( output, test_output[i], test_input_len[i] ),
523
                ( "failure (wrong output)\n" ) );
524
 
525
        ASSERT( 0 == memcmp( mac, test_mac[i], 16U ),
526
                ( "failure (wrong MAC)\n" ) );
527
 
528
        mbedtls_chachapoly_free( &ctx );
529
 
530
        if( verbose != 0 )
531
            mbedtls_printf( "passed\n" );
532
    }
533
 
534
    if( verbose != 0 )
535
        mbedtls_printf( "\n" );
536
 
537
    return( 0 );
538
}
539
 
540
#endif /* MBEDTLS_SELF_TEST */
541
 
542
#endif /* MBEDTLS_CHACHAPOLY_C */