From 346b8d5050dd66875d1ae15ebff94b25b9694092 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Mon, 7 May 2018 12:56:36 +0200 Subject: [PATCH] chachapoly: split crypt_and_mac() to match GCM API In addition to making the APIs of the various AEAD modules more consistent with each other, it's useful to have an auth_decrypt() function so that we can safely check the tag ourselves, as the user might otherwise do it in an insecure way (or even forget to do it altogether). --- include/mbedtls/chachapoly.h | 51 ++++++++--- library/chachapoly.c | 93 +++++++++++++++------ tests/suites/test_suite_chachapoly.function | 37 +++++--- 3 files changed, 133 insertions(+), 48 deletions(-) diff --git a/include/mbedtls/chachapoly.h b/include/mbedtls/chachapoly.h index 810675ddd..e7413b36f 100644 --- a/include/mbedtls/chachapoly.h +++ b/include/mbedtls/chachapoly.h @@ -31,6 +31,8 @@ #define MBEDTLS_ERR_CHACHAPOLY_BAD_INPUT_DATA -0x00047 /**< Invalid input parameter(s). */ #define MBEDTLS_ERR_CHACHAPOLY_BAD_STATE -0x00049 /**< The requested operation is not permitted in the current state */ +#define MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED -0x00049 /**< Authenticated decryption failed: data was not authentic. */ + #ifdef __cplusplus extern "C" { @@ -192,37 +194,64 @@ int mbedtls_chachapoly_finish( mbedtls_chachapoly_context *ctx, unsigned char mac[16] ); /** - * \brief Encrypt or decrypt data, and produce a MAC with ChaCha20-Poly1305. + * \brief Encrypt or decrypt data, and produce a MAC (tag) with ChaCha20-Poly1305. * - * \param key The 256-bit (32 bytes) encryption key to use. - * \param nonce The 96-bit (12 bytes) nonce/IV to use. + * \param ctx The ChachaPoly context. * \param mode Specifies whether the data in the \p input buffer is to * be encrypted or decrypted. If there is no data to encrypt * or decrypt (i.e. \p ilen is 0) then the value of this * parameter does not matter. - * \param aad_len The length (in bytes) of the AAD data to process. + * \param length The length (in bytes) of the data to encrypt or decrypt. + * \param nonce The 96-bit (12 bytes) nonce/IV to use. * \param aad Buffer containing the additional authenticated data (AAD). * This pointer can be NULL if aad_len == 0. - * \param ilen The length (in bytes) of the data to encrypt or decrypt. + * \param aad_len The length (in bytes) of the AAD data to process. * \param input Buffer containing the data to encrypt or decrypt. * This pointer can be NULL if ilen == 0. * \param output Buffer to where the encrypted or decrypted data is written. * This pointer can be NULL if ilen == 0. - * \param mac Buffer to where the computed 128-bit (16 bytes) MAC is written. + * \param tag Buffer to where the computed 128-bit (16 bytes) MAC is written. * * \return MBEDTLS_ERR_CHACHAPOLY_BAD_INPUT_DATA is returned * if one or more of the required parameters are NULL. * Otherwise, 0 is returned to indicate success. */ -int mbedtls_chachapoly_crypt_and_mac( const unsigned char key[32], - const unsigned char nonce[12], +int mbedtls_chachapoly_crypt_and_tag( mbedtls_chachapoly_context *ctx, mbedtls_chachapoly_mode_t mode, - size_t aad_len, + size_t length, + const unsigned char nonce[12], const unsigned char *aad, - size_t ilen, + size_t aad_len, const unsigned char *input, unsigned char *output, - unsigned char mac[16] ); + unsigned char tag[16] ); + +/** + * \brief Decrypt data and check a MAC (tag) with ChaCha20-Poly1305. + * + * \param ctx The ChachaPoly context. + * \param length The length of the input and output data. + * \param nonce The nonce / initialization vector. + * \param aad The buffer holding the additional authenticated data. + * \param aad_len The length of the additional authenticated data. + * \param tag The buffer holding the tag. + * \param input The buffer holding the input data. + * \param output The buffer for holding the output data. + * + * \return MBEDTLS_ERR_CHACHAPOLY_BAD_INPUT_DATA is returned + * if one or more of the required parameters are NULL. + * MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED if the tag does not + * match. + * Otherwise, 0 is returned to indicate success. + */ +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 ); /** * \brief Checkup routine diff --git a/library/chachapoly.c b/library/chachapoly.c index 35ae99e11..0dba5ed91 100644 --- a/library/chachapoly.c +++ b/library/chachapoly.c @@ -295,44 +295,70 @@ int mbedtls_chachapoly_finish( mbedtls_chachapoly_context *ctx, return( 0 ); } -int mbedtls_chachapoly_crypt_and_mac ( const unsigned char key[32], - const unsigned char nonce[12], - mbedtls_chachapoly_mode_t mode, - size_t aad_len, - const unsigned char *aad, - size_t ilen, - const unsigned char *input, - unsigned char *output, - unsigned char mac[16] ) +int mbedtls_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] ) { - mbedtls_chachapoly_context ctx; int result; - mbedtls_chachapoly_init( &ctx ); - - result = mbedtls_chachapoly_setkey( &ctx, key ); + result = mbedtls_chachapoly_starts( ctx, nonce, mode ); if ( result != 0 ) goto cleanup; - result = mbedtls_chachapoly_starts( &ctx, nonce, mode ); - if ( result != 0 ) - goto cleanup; - - result = mbedtls_chachapoly_update_aad( &ctx, aad_len, aad ); + result = mbedtls_chachapoly_update_aad( ctx, aad_len, aad ); if ( result != 0 ) goto cleanup; - result = mbedtls_chachapoly_update( &ctx, ilen, input, output ); + result = mbedtls_chachapoly_update( ctx, length, input, output ); if ( result != 0 ) goto cleanup; - result = mbedtls_chachapoly_finish( &ctx, mac ); + result = mbedtls_chachapoly_finish( ctx, tag ); cleanup: - mbedtls_chachapoly_free( &ctx ); return( result ); } +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; + + if( ( ret = mbedtls_chachapoly_crypt_and_tag( ctx, + 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 ) + { + mbedtls_zeroize( output, length ); + return( MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED ); + } + + return( 0 ); +} + #endif /* MBEDTLS_CHACHAPOLY_ALT */ #if defined(MBEDTLS_SELF_TEST) @@ -425,6 +451,7 @@ static const unsigned char test_mac[1][16] = int mbedtls_chachapoly_self_test( int verbose ) { + mbedtls_chachapoly_context ctx; unsigned i; int result; unsigned char output[200]; @@ -437,12 +464,24 @@ int mbedtls_chachapoly_self_test( int verbose ) mbedtls_printf( " ChaCha20-Poly1305 test %u ", i ); } - result = mbedtls_chachapoly_crypt_and_mac( test_key[i], - test_nonce[i], + mbedtls_chachapoly_init( &ctx ); + + result = mbedtls_chachapoly_setkey( &ctx, test_key[i] ); + if ( result != 0 ) + { + if ( verbose != 0 ) + { + mbedtls_printf( "setkey() error code: %i\n", result ); + } + return( -1 ); + } + + result = mbedtls_chachapoly_crypt_and_tag( &ctx, MBEDTLS_CHACHAPOLY_ENCRYPT, - test_aad_len[i], - test_aad[i], test_input_len[i], + test_nonce[i], + test_aad[i], + test_aad_len[i], test_input[i], output, mac ); @@ -450,7 +489,7 @@ int mbedtls_chachapoly_self_test( int verbose ) { if ( verbose != 0 ) { - mbedtls_printf( "error code: %i\n", result ); + mbedtls_printf( "crypt_and_tag() error code: %i\n", result ); } return( -1 ); } @@ -473,6 +512,8 @@ int mbedtls_chachapoly_self_test( int verbose ) return( -1 ); } + mbedtls_chachapoly_free( &ctx ); + if ( verbose != 0 ) { mbedtls_printf( "passed\n" ); diff --git a/tests/suites/test_suite_chachapoly.function b/tests/suites/test_suite_chachapoly.function index fb1a738f0..b205c4ce0 100644 --- a/tests/suites/test_suite_chachapoly.function +++ b/tests/suites/test_suite_chachapoly.function @@ -24,6 +24,7 @@ void mbedtls_chachapoly_enc( char *hex_key_string, char *hex_nonce_string, char size_t key_len; size_t nonce_len; size_t mac_len; + mbedtls_chachapoly_context ctx; memset( key_str, 0x00, 32 ); memset( nonce_str, 0x00, 12 ); @@ -43,14 +44,21 @@ void mbedtls_chachapoly_enc( char *hex_key_string, char *hex_nonce_string, char TEST_ASSERT( nonce_len == 12 ); TEST_ASSERT( mac_len == 16 ); - mbedtls_chachapoly_crypt_and_mac( key_str, nonce_str, + mbedtls_chachapoly_init( &ctx ); + + mbedtls_chachapoly_setkey( &ctx, key_str ); + + mbedtls_chachapoly_crypt_and_tag( &ctx, MBEDTLS_CHACHAPOLY_ENCRYPT, - aad_len, aad_str, - input_len, input_str, output, - mac ); + input_len, nonce_str, + aad_str, aad_len, + input_str, output, mac ); TEST_ASSERT( memcmp( output_str, output, output_len ) == 0 ); TEST_ASSERT( memcmp( mac_str, mac, 16U ) == 0 ); + +exit: + mbedtls_chachapoly_free( &ctx ); } /* END_CASE */ @@ -64,13 +72,14 @@ void mbedtls_chachapoly_dec( char *hex_key_string, char *hex_nonce_string, char unsigned char output_str[10000]; unsigned char mac_str[16]; unsigned char output[10000]; - unsigned char mac[16]; size_t input_len; size_t output_len; size_t aad_len; size_t key_len; size_t nonce_len; size_t mac_len; + int ret; + mbedtls_chachapoly_context ctx; memset( key_str, 0x00, 32 ); memset( nonce_str, 0x00, 12 ); @@ -90,14 +99,20 @@ void mbedtls_chachapoly_dec( char *hex_key_string, char *hex_nonce_string, char TEST_ASSERT( nonce_len == 12 ); TEST_ASSERT( mac_len == 16 ); - mbedtls_chachapoly_crypt_and_mac( key_str, nonce_str, - MBEDTLS_CHACHAPOLY_DECRYPT, - aad_len, aad_str, - input_len, input_str, output, - mac ); + mbedtls_chachapoly_init( &ctx ); + mbedtls_chachapoly_setkey( &ctx, key_str ); + + ret = mbedtls_chachapoly_auth_decrypt( &ctx, + input_len, nonce_str, + aad_str, aad_len, + mac_str, input_str, output ); + + TEST_ASSERT( ret == 0 ); TEST_ASSERT( memcmp( output_str, output, output_len ) == 0 ); - TEST_ASSERT( memcmp( mac_str, mac, 16U ) == 0 ); + +exit: + mbedtls_chachapoly_free( &ctx ); } /* END_CASE */