chachapoly.c 17.2 KB
Newer Older
1
/**
2
 * \file chachapoly.c
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
 *
 * \brief ChaCha20-Poly1305 AEAD construction based on RFC 7539.
 *
 *  Copyright (C) 2006-2016, ARM Limited, All Rights Reserved
 *  SPDX-License-Identifier: Apache-2.0
 *
 *  Licensed under the Apache License, Version 2.0 (the "License"); you may
 *  not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *  This file is part of mbed TLS (https://tls.mbed.org)
 */
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif

29
#if defined(MBEDTLS_CHACHAPOLY_C)
30

31
#include "mbedtls/chachapoly.h"
32 33
#include "mbedtls/platform_util.h"

34 35 36 37 38 39 40 41 42 43 44
#include <string.h>

#if defined(MBEDTLS_SELF_TEST)
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST */

45
#if !defined(MBEDTLS_CHACHAPOLY_ALT)
46

47 48 49 50 51 52
/* Parameter validation macros */
#define CHACHAPOLY_VALIDATE_RET( cond )                                       \
    MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA )
#define CHACHAPOLY_VALIDATE( cond )                                           \
    MBEDTLS_INTERNAL_VALIDATE( cond )

53 54 55 56
#define CHACHAPOLY_STATE_INIT       ( 0 )
#define CHACHAPOLY_STATE_AAD        ( 1 )
#define CHACHAPOLY_STATE_CIPHERTEXT ( 2 ) /* Encrypting or decrypting */
#define CHACHAPOLY_STATE_FINISHED   ( 3 )
57 58

/**
59
 * \brief           Adds nul bytes to pad the AAD for Poly1305.
60 61 62
 *
 * \param ctx       The ChaCha20-Poly1305 context.
 */
63
static int chachapoly_pad_aad( mbedtls_chachapoly_context *ctx )
64
{
65
    uint32_t partial_block_len = (uint32_t) ( ctx->aad_len % 16U );
66 67
    unsigned char zeroes[15];

68 69 70 71 72 73 74 75
    if( partial_block_len == 0U )
        return( 0 );

    memset( zeroes, 0, sizeof( zeroes ) );

    return( mbedtls_poly1305_update( &ctx->poly1305_ctx,
                                     zeroes,
                                     16U - partial_block_len ) );
76 77 78
}

/**
79
 * \brief           Adds nul bytes to pad the ciphertext for Poly1305.
80 81 82
 *
 * \param ctx       The ChaCha20-Poly1305 context.
 */
83
static int chachapoly_pad_ciphertext( mbedtls_chachapoly_context *ctx )
84
{
85
    uint32_t partial_block_len = (uint32_t) ( ctx->ciphertext_len % 16U );
86 87
    unsigned char zeroes[15];

88 89 90 91 92 93 94
    if( partial_block_len == 0U )
        return( 0 );

    memset( zeroes, 0, sizeof( zeroes ) );
    return( mbedtls_poly1305_update( &ctx->poly1305_ctx,
                                     zeroes,
                                     16U - partial_block_len ) );
95 96
}

97
void mbedtls_chachapoly_init( mbedtls_chachapoly_context *ctx )
98
{
99 100 101 102 103 104 105 106
    CHACHAPOLY_VALIDATE( ctx != NULL );

    mbedtls_chacha20_init( &ctx->chacha20_ctx );
    mbedtls_poly1305_init( &ctx->poly1305_ctx );
    ctx->aad_len        = 0U;
    ctx->ciphertext_len = 0U;
    ctx->state          = CHACHAPOLY_STATE_INIT;
    ctx->mode           = MBEDTLS_CHACHAPOLY_ENCRYPT;
107 108
}

109
void mbedtls_chachapoly_free( mbedtls_chachapoly_context *ctx )
110
{
111
    if( ctx == NULL )
112 113 114 115 116 117 118 119
        return;

    mbedtls_chacha20_free( &ctx->chacha20_ctx );
    mbedtls_poly1305_free( &ctx->poly1305_ctx );
    ctx->aad_len        = 0U;
    ctx->ciphertext_len = 0U;
    ctx->state          = CHACHAPOLY_STATE_INIT;
    ctx->mode           = MBEDTLS_CHACHAPOLY_ENCRYPT;
120 121
}

122 123
int mbedtls_chachapoly_setkey( mbedtls_chachapoly_context *ctx,
                               const unsigned char key[32] )
124
{
125
    int ret;
126 127
    CHACHAPOLY_VALIDATE_RET( ctx != NULL );
    CHACHAPOLY_VALIDATE_RET( key != NULL );
128

129
    ret = mbedtls_chacha20_setkey( &ctx->chacha20_ctx, key );
130

131
    return( ret );
132 133
}

134 135 136
int mbedtls_chachapoly_starts( mbedtls_chachapoly_context *ctx,
                               const unsigned char nonce[12],
                               mbedtls_chachapoly_mode_t mode  )
137
{
138
    int ret;
139
    unsigned char poly1305_key[64];
140 141
    CHACHAPOLY_VALIDATE_RET( ctx != NULL );
    CHACHAPOLY_VALIDATE_RET( nonce != NULL );
142

143
    /* Set counter = 0, will be update to 1 when generating Poly1305 key */
144 145
    ret = mbedtls_chacha20_starts( &ctx->chacha20_ctx, nonce, 0U );
    if( ret != 0 )
146 147
        goto cleanup;

148 149
    /* Generate the Poly1305 key by getting the ChaCha20 keystream output with
     * counter = 0.  This is the same as encrypting a buffer of zeroes.
150 151 152
     * Only the first 256-bits (32 bytes) of the key is used for Poly1305.
     * The other 256 bits are discarded.
     */
153
    memset( poly1305_key, 0, sizeof( poly1305_key ) );
154
    ret = mbedtls_chacha20_update( &ctx->chacha20_ctx, sizeof( poly1305_key ),
155
                                      poly1305_key, poly1305_key );
156
    if( ret != 0 )
157 158
        goto cleanup;

159
    ret = mbedtls_poly1305_starts( &ctx->poly1305_ctx, poly1305_key );
160

161
    if( ret == 0 )
162 163 164
    {
        ctx->aad_len        = 0U;
        ctx->ciphertext_len = 0U;
165
        ctx->state          = CHACHAPOLY_STATE_AAD;
166 167 168 169
        ctx->mode           = mode;
    }

cleanup:
170
    mbedtls_platform_zeroize( poly1305_key, 64U );
171
    return( ret );
172 173
}

174
int mbedtls_chachapoly_update_aad( mbedtls_chachapoly_context *ctx,
175 176
                                   const unsigned char *aad,
                                   size_t aad_len )
177
{
178 179 180 181
    CHACHAPOLY_VALIDATE_RET( ctx != NULL );
    CHACHAPOLY_VALIDATE_RET( aad_len == 0 || aad != NULL );

    if( ctx->state != CHACHAPOLY_STATE_AAD )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
182
        return( MBEDTLS_ERR_CHACHAPOLY_BAD_STATE );
183 184 185

    ctx->aad_len += aad_len;

186
    return( mbedtls_poly1305_update( &ctx->poly1305_ctx, aad, aad_len ) );
187 188
}

189 190 191 192
int mbedtls_chachapoly_update( mbedtls_chachapoly_context *ctx,
                               size_t len,
                               const unsigned char *input,
                               unsigned char *output )
193
{
194
    int ret;
195 196 197
    CHACHAPOLY_VALIDATE_RET( ctx != NULL );
    CHACHAPOLY_VALIDATE_RET( len == 0 || input != NULL );
    CHACHAPOLY_VALIDATE_RET( len == 0 || output != NULL );
198

199 200
    if( ( ctx->state != CHACHAPOLY_STATE_AAD ) &&
        ( ctx->state != CHACHAPOLY_STATE_CIPHERTEXT ) )
201
    {
202
        return( MBEDTLS_ERR_CHACHAPOLY_BAD_STATE );
203 204
    }

205
    if( ctx->state == CHACHAPOLY_STATE_AAD )
206
    {
207
        ctx->state = CHACHAPOLY_STATE_CIPHERTEXT;
208

209 210 211
        ret = chachapoly_pad_aad( ctx );
        if( ret != 0 )
            return( ret );
212 213 214 215
    }

    ctx->ciphertext_len += len;

216
    if( ctx->mode == MBEDTLS_CHACHAPOLY_ENCRYPT )
217
    {
218 219 220 221 222 223 224
        ret = mbedtls_chacha20_update( &ctx->chacha20_ctx, len, input, output );
        if( ret != 0 )
            return( ret );

        ret = mbedtls_poly1305_update( &ctx->poly1305_ctx, output, len );
        if( ret != 0 )
            return( ret );
225 226 227
    }
    else /* DECRYPT */
    {
228 229 230 231 232 233 234
        ret = mbedtls_poly1305_update( &ctx->poly1305_ctx, input, len );
        if( ret != 0 )
            return( ret );

        ret = mbedtls_chacha20_update( &ctx->chacha20_ctx, len, input, output );
        if( ret != 0 )
            return( ret );
235 236 237 238 239
    }

    return( 0 );
}

240 241
int mbedtls_chachapoly_finish( mbedtls_chachapoly_context *ctx,
                               unsigned char mac[16] )
242
{
243
    int ret;
244
    unsigned char len_block[16];
245 246
    CHACHAPOLY_VALIDATE_RET( ctx != NULL );
    CHACHAPOLY_VALIDATE_RET( mac != NULL );
247

248
    if( ctx->state == CHACHAPOLY_STATE_INIT )
249
    {
250
        return( MBEDTLS_ERR_CHACHAPOLY_BAD_STATE );
251 252
    }

253
    if( ctx->state == CHACHAPOLY_STATE_AAD )
254
    {
255 256 257
        ret = chachapoly_pad_aad( ctx );
        if( ret != 0 )
            return( ret );
258
    }
259
    else if( ctx->state == CHACHAPOLY_STATE_CIPHERTEXT )
260
    {
261 262 263
        ret = chachapoly_pad_ciphertext( ctx );
        if( ret != 0 )
            return( ret );
264 265
    }

266
    ctx->state = CHACHAPOLY_STATE_FINISHED;
267 268 269 270

    /* The lengths of the AAD and ciphertext are processed by
     * Poly1305 as the final 128-bit block, encoded as little-endian integers.
     */
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
    len_block[ 0] = (unsigned char)( ctx->aad_len       );
    len_block[ 1] = (unsigned char)( ctx->aad_len >>  8 );
    len_block[ 2] = (unsigned char)( ctx->aad_len >> 16 );
    len_block[ 3] = (unsigned char)( ctx->aad_len >> 24 );
    len_block[ 4] = (unsigned char)( ctx->aad_len >> 32 );
    len_block[ 5] = (unsigned char)( ctx->aad_len >> 40 );
    len_block[ 6] = (unsigned char)( ctx->aad_len >> 48 );
    len_block[ 7] = (unsigned char)( ctx->aad_len >> 56 );
    len_block[ 8] = (unsigned char)( ctx->ciphertext_len       );
    len_block[ 9] = (unsigned char)( ctx->ciphertext_len >>  8 );
    len_block[10] = (unsigned char)( ctx->ciphertext_len >> 16 );
    len_block[11] = (unsigned char)( ctx->ciphertext_len >> 24 );
    len_block[12] = (unsigned char)( ctx->ciphertext_len >> 32 );
    len_block[13] = (unsigned char)( ctx->ciphertext_len >> 40 );
    len_block[14] = (unsigned char)( ctx->ciphertext_len >> 48 );
    len_block[15] = (unsigned char)( ctx->ciphertext_len >> 56 );
287

288 289 290
    ret = mbedtls_poly1305_update( &ctx->poly1305_ctx, len_block, 16U );
    if( ret != 0 )
        return( ret );
291

292 293 294
    ret = mbedtls_poly1305_finish( &ctx->poly1305_ctx, mac );

    return( ret );
295 296
}

297 298 299 300 301 302 303 304 305
static int chachapoly_crypt_and_tag( mbedtls_chachapoly_context *ctx,
                                     mbedtls_chachapoly_mode_t mode,
                                     size_t length,
                                     const unsigned char nonce[12],
                                     const unsigned char *aad,
                                     size_t aad_len,
                                     const unsigned char *input,
                                     unsigned char *output,
                                     unsigned char tag[16] )
306
{
307
    int ret;
308

309 310
    ret = mbedtls_chachapoly_starts( ctx, nonce, mode );
    if( ret != 0 )
311 312
        goto cleanup;

313 314 315
    ret = mbedtls_chachapoly_update_aad( ctx, aad, aad_len );
    if( ret != 0 )
        goto cleanup;
316

317 318 319
    ret = mbedtls_chachapoly_update( ctx, length, input, output );
    if( ret != 0 )
        goto cleanup;
320

321
    ret = mbedtls_chachapoly_finish( ctx, tag );
322 323

cleanup:
324
    return( ret );
325 326
}

327 328 329 330 331 332 333 334 335
int mbedtls_chachapoly_encrypt_and_tag( mbedtls_chachapoly_context *ctx,
                                        size_t length,
                                        const unsigned char nonce[12],
                                        const unsigned char *aad,
                                        size_t aad_len,
                                        const unsigned char *input,
                                        unsigned char *output,
                                        unsigned char tag[16] )
{
336 337 338 339 340 341 342
    CHACHAPOLY_VALIDATE_RET( ctx   != NULL );
    CHACHAPOLY_VALIDATE_RET( nonce != NULL );
    CHACHAPOLY_VALIDATE_RET( tag   != NULL );
    CHACHAPOLY_VALIDATE_RET( aad_len == 0 || aad    != NULL );
    CHACHAPOLY_VALIDATE_RET( length  == 0 || input  != NULL );
    CHACHAPOLY_VALIDATE_RET( length  == 0 || output != NULL );

343 344 345 346 347
    return( chachapoly_crypt_and_tag( ctx, MBEDTLS_CHACHAPOLY_ENCRYPT,
                                      length, nonce, aad, aad_len,
                                      input, output, tag ) );
}

348 349 350 351 352 353 354 355 356 357 358 359 360
int mbedtls_chachapoly_auth_decrypt( mbedtls_chachapoly_context *ctx,
                                     size_t length,
                                     const unsigned char nonce[12],
                                     const unsigned char *aad,
                                     size_t aad_len,
                                     const unsigned char tag[16],
                                     const unsigned char *input,
                                     unsigned char *output )
{
    int ret;
    unsigned char check_tag[16];
    size_t i;
    int diff;
361 362 363 364 365 366
    CHACHAPOLY_VALIDATE_RET( ctx   != NULL );
    CHACHAPOLY_VALIDATE_RET( nonce != NULL );
    CHACHAPOLY_VALIDATE_RET( tag   != NULL );
    CHACHAPOLY_VALIDATE_RET( aad_len == 0 || aad    != NULL );
    CHACHAPOLY_VALIDATE_RET( length  == 0 || input  != NULL );
    CHACHAPOLY_VALIDATE_RET( length  == 0 || output != NULL );
367

368
    if( ( ret = chachapoly_crypt_and_tag( ctx,
369 370 371 372 373 374 375 376 377 378 379 380
                        MBEDTLS_CHACHAPOLY_DECRYPT, length, nonce,
                        aad, aad_len, input, output, check_tag ) ) != 0 )
    {
        return( ret );
    }

    /* Check tag in "constant-time" */
    for( diff = 0, i = 0; i < sizeof( check_tag ); i++ )
        diff |= tag[i] ^ check_tag[i];

    if( diff != 0 )
    {
381
        mbedtls_platform_zeroize( output, length );
382 383 384 385 386 387
        return( MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED );
    }

    return( 0 );
}

388
#endif /* MBEDTLS_CHACHAPOLY_ALT */
389

390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477
#if defined(MBEDTLS_SELF_TEST)

static const unsigned char test_key[1][32] =
{
    {
        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
        0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
        0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
        0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
    }
};

static const unsigned char test_nonce[1][12] =
{
    {
        0x07, 0x00, 0x00, 0x00,                         /* 32-bit common part */
        0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47  /* 64-bit IV */
    }
};

static const unsigned char test_aad[1][12] =
{
    {
        0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3,
        0xc4, 0xc5, 0xc6, 0xc7
    }
};

static const size_t test_aad_len[1] =
{
    12U
};

static const unsigned char test_input[1][114] =
{
    {
        0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61,
        0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c,
        0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20,
        0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73,
        0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39,
        0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63,
        0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66,
        0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f,
        0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20,
        0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20,
        0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75,
        0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73,
        0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f,
        0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69,
        0x74, 0x2e
    }
};

static const unsigned char test_output[1][114] =
{
    {
        0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb,
        0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2,
        0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe,
        0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6,
        0x3d, 0xbe, 0xa4, 0x5e, 0x8c, 0xa9, 0x67, 0x12,
        0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b,
        0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29,
        0x05, 0xd6, 0xa5, 0xb6, 0x7e, 0xcd, 0x3b, 0x36,
        0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c,
        0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58,
        0xfa, 0xb3, 0x24, 0xe4, 0xfa, 0xd6, 0x75, 0x94,
        0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc,
        0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d,
        0xe5, 0x76, 0xd2, 0x65, 0x86, 0xce, 0xc6, 0x4b,
        0x61, 0x16
    }
};

static const size_t test_input_len[1] =
{
    114U
};

static const unsigned char test_mac[1][16] =
{
    {
        0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a,
        0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91
    }
};

478 479 480 481 482 483 484 485 486 487 488 489 490
#define ASSERT( cond, args )            \
    do                                  \
    {                                   \
        if( ! ( cond ) )                \
        {                               \
            if( verbose != 0 )          \
                mbedtls_printf args;    \
                                        \
            return( -1 );               \
        }                               \
    }                                   \
    while( 0 )

491
int mbedtls_chachapoly_self_test( int verbose )
492
{
493
    mbedtls_chachapoly_context ctx;
494
    unsigned i;
495
    int ret;
496 497 498
    unsigned char output[200];
    unsigned char mac[16];

499
    for( i = 0U; i < 1U; i++ )
500
    {
501
        if( verbose != 0 )
502
            mbedtls_printf( "  ChaCha20-Poly1305 test %u ", i );
503

504 505
        mbedtls_chachapoly_init( &ctx );

506 507
        ret = mbedtls_chachapoly_setkey( &ctx, test_key[i] );
        ASSERT( 0 == ret, ( "setkey() error code: %i\n", ret ) );
508

509 510 511 512 513 514 515 516
        ret = mbedtls_chachapoly_encrypt_and_tag( &ctx,
                                                  test_input_len[i],
                                                  test_nonce[i],
                                                  test_aad[i],
                                                  test_aad_len[i],
                                                  test_input[i],
                                                  output,
                                                  mac );
517

518
        ASSERT( 0 == ret, ( "crypt_and_tag() error code: %i\n", ret ) );
519 520 521 522 523 524

        ASSERT( 0 == memcmp( output, test_output[i], test_input_len[i] ),
                ( "failure (wrong output)\n" ) );

        ASSERT( 0 == memcmp( mac, test_mac[i], 16U ),
                ( "failure (wrong MAC)\n" ) );
525

526 527
        mbedtls_chachapoly_free( &ctx );

528
        if( verbose != 0 )
529 530 531 532 533
            mbedtls_printf( "passed\n" );
    }

    if( verbose != 0 )
        mbedtls_printf( "\n" );
534 535 536 537 538 539

    return( 0 );
}

#endif /* MBEDTLS_SELF_TEST */

540
#endif /* MBEDTLS_CHACHAPOLY_C */