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).
This commit is contained in:
Manuel Pégourié-Gonnard 2018-05-07 12:56:36 +02:00
parent 56206c4db1
commit 346b8d5050
3 changed files with 133 additions and 48 deletions

View file

@ -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

View file

@ -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" );

View file

@ -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 */