diff --git a/include/psa/crypto_struct.h b/include/psa/crypto_struct.h index a1182c48db..6c93814be3 100644 --- a/include/psa/crypto_struct.h +++ b/include/psa/crypto_struct.h @@ -154,10 +154,32 @@ static inline struct psa_mac_operation_s psa_mac_operation_init( void ) struct psa_aead_operation_s { psa_algorithm_t alg; + psa_key_type_t key_type; + unsigned int key_set : 1; unsigned int nonce_set : 1; + unsigned int lengths_set : 1; + unsigned int is_encrypt : 1; + unsigned int ad_started : 1; + unsigned int body_started : 1; uint8_t tag_length; + uint8_t nonce_length; + + size_t ad_remaining; + size_t body_remaining; + + /* Buffers for AD/data - only required until CCM gets proper multipart + support. */ + uint8_t* ad_buffer; + size_t ad_length; + + uint8_t* data_buffer; + size_t data_length; + + /* buffer to store Nonce - only required until CCM and GCM get proper + multipart support. */ + uint8_t nonce[PSA_AEAD_NONCE_MAX_SIZE]; union { @@ -175,7 +197,7 @@ struct psa_aead_operation_s } ctx; }; -#define PSA_AEAD_OPERATION_INIT {0, 0, 0, 0, {0}} +#define PSA_AEAD_OPERATION_INIT {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0}, {0}} static inline struct psa_aead_operation_s psa_aead_operation_init( void ) { const struct psa_aead_operation_s v = PSA_AEAD_OPERATION_INIT; diff --git a/library/psa_crypto_aead.c b/library/psa_crypto_aead.c index 07c52d433a..47b0e7b3e2 100644 --- a/library/psa_crypto_aead.c +++ b/library/psa_crypto_aead.c @@ -20,39 +20,40 @@ #include "common.h" + #if defined(MBEDTLS_PSA_CRYPTO_C) #include "psa_crypto_aead.h" #include "psa_crypto_core.h" +#include +#include "mbedtls/platform.h" +#if !defined(MBEDTLS_PLATFORM_C) +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + #include "mbedtls/ccm.h" #include "mbedtls/chachapoly.h" #include "mbedtls/cipher.h" #include "mbedtls/gcm.h" +#include "mbedtls/error.h" - -static void psa_aead_abort_internal( psa_aead_operation_t *operation ) +/* Constant-time buffer comparison. This is duplication of code from + * psa_crypto.c, but has nowhere private I can put it for the minute. Really + belongs in the constant time module, when that gets implemented */ +static inline int safer_memcmp( const uint8_t *a, const uint8_t *b, size_t n ) { - switch( operation->alg ) - { -#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM) - case PSA_ALG_CCM: - mbedtls_ccm_free( &operation->ctx.ccm ); - break; -#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */ -#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM) - case PSA_ALG_GCM: - mbedtls_gcm_free( &operation->ctx.gcm ); - break; -#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */ -#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305) - case PSA_ALG_CHACHA20_POLY1305: - mbedtls_chachapoly_free( &operation->ctx.chachapoly ); - break; -#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */ - } + size_t i; + unsigned char diff = 0; + + for( i = 0; i < n; i++ ) + diff |= a[i] ^ b[i]; + + return( diff ); } + static psa_status_t psa_aead_setup( psa_aead_operation_t *operation, const psa_key_attributes_t *attributes, @@ -65,6 +66,12 @@ static psa_status_t psa_aead_setup( mbedtls_cipher_id_t cipher_id; size_t full_tag_length = 0; + if( operation->key_set || operation->nonce_set || + operation->ad_started || operation->body_started ) + { + return( PSA_ERROR_BAD_STATE ); + } + key_bits = attributes->core.bits; cipher_info = mbedtls_cipher_info_from_psa( alg, @@ -143,6 +150,8 @@ static psa_status_t psa_aead_setup( key_bits, alg ); + operation->key_set = 1; + return( PSA_SUCCESS ); } @@ -230,7 +239,7 @@ psa_status_t mbedtls_psa_aead_encrypt( *ciphertext_length = plaintext_length + operation.tag_length; exit: - psa_aead_abort_internal( &operation ); + mbedtls_psa_aead_abort( &operation ); return( status ); } @@ -336,12 +345,715 @@ psa_status_t mbedtls_psa_aead_decrypt( *plaintext_length = ciphertext_length - operation.tag_length; exit: - psa_aead_abort_internal( &operation ); + mbedtls_psa_aead_abort( &operation ); if( status == PSA_SUCCESS ) *plaintext_length = ciphertext_length - operation.tag_length; return( status ); } +/* Set the key and algorithm for a multipart authenticated encryption + * operation. */ +psa_status_t mbedtls_psa_aead_encrypt_setup( psa_aead_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg ) +{ + psa_status_t status; + + (void) key_buffer_size; + + status = psa_aead_setup( operation, attributes, key_buffer, alg ); + + if( status == PSA_SUCCESS ) + { + operation->is_encrypt = 1; + } + + return ( status ); +} + +/* Set the key and algorithm for a multipart authenticated decryption + * operation. */ +psa_status_t mbedtls_psa_aead_decrypt_setup( psa_aead_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg ) +{ + psa_status_t status; + + (void) key_buffer_size; + + status = psa_aead_setup( operation, attributes, key_buffer, alg ); + + if( status == PSA_SUCCESS ) + { + operation->is_encrypt = 0; + } + + return ( status ); +} + +/* Generate a random nonce / IV for multipart AEAD operation */ +psa_status_t mbedtls_psa_aead_generate_nonce( psa_aead_operation_t *operation, + uint8_t *nonce, + size_t nonce_size, + size_t *nonce_length ) +{ + psa_status_t status; + size_t required_nonce_size = nonce_size; + + if( !operation->key_set || operation->nonce_set || + operation->ad_started || operation->body_started ) + { + return( PSA_ERROR_BAD_STATE ); + } + + required_nonce_size = PSA_AEAD_NONCE_LENGTH(operation->key_type, operation->alg); + + if( nonce_size == 0 || nonce_size < required_nonce_size ) + { + return( PSA_ERROR_BUFFER_TOO_SMALL ); + } + + status = psa_generate_random( nonce, required_nonce_size ); + + if( status != PSA_SUCCESS ) + { + return status; + } + + status = mbedtls_psa_aead_set_nonce( operation, nonce, required_nonce_size ); + + if( status == PSA_SUCCESS ) + { + *nonce_length = required_nonce_size; + } + + return status; +} + +/* Set a nonce for the multipart AEAD operation*/ +psa_status_t mbedtls_psa_aead_set_nonce( psa_aead_operation_t *operation, + const uint8_t *nonce, + size_t nonce_length ) +{ + psa_status_t status; + + if( !operation->key_set || operation->nonce_set || + operation->ad_started || operation->body_started ) + { + return( PSA_ERROR_BAD_STATE ); + } + + /* Restricting to a nominal safe length for nonces even though some + algorithms can handle longer nonces, but not without collision */ + if( nonce_length > PSA_AEAD_NONCE_MAX_SIZE ) + { + return( PSA_ERROR_INVALID_ARGUMENT ); + } + + #if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM) + if( operation->alg == PSA_ALG_GCM ) + { + /* GCM sets nonce once additional data has been supplied */ + memcpy(operation->nonce, nonce, nonce_length); + + /* We know that nonce size cannot exceed the uint8_t size */ + operation->nonce_length = ( uint8_t ) nonce_length; + status = PSA_SUCCESS; + } + else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM) + if( operation->alg == PSA_ALG_CCM ) + { + /* Multipart CCM not supported as yet, so CCM is basically operating + in oneshot mode. Store the nonce as we need this later */ + memcpy(operation->nonce, nonce, nonce_length); + + /* We know that nonce size cannot exceed the uint8_t size */ + operation->nonce_length = ( uint8_t ) nonce_length; + status = PSA_SUCCESS; + } + else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305) + if( operation->alg == PSA_ALG_CHACHA20_POLY1305 ) + { + if( nonce_length != 12 && nonce_length != 8) + { + return( PSA_ERROR_INVALID_ARGUMENT ); + } + + status = mbedtls_to_psa_error(mbedtls_chachapoly_starts( &operation->ctx.chachapoly, + nonce, + operation->is_encrypt ? + MBEDTLS_CHACHAPOLY_ENCRYPT : + MBEDTLS_CHACHAPOLY_DECRYPT ) ); + } + else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */ + { + ( void ) nonce; + ( void ) nonce_length; + + return ( PSA_ERROR_NOT_SUPPORTED ); + } + + if( status == PSA_SUCCESS ) + { + operation->nonce_set = 1; + } + + return( status ); +} + /* Declare the lengths of the message and additional data for AEAD. */ +psa_status_t mbedtls_psa_aead_set_lengths( psa_aead_operation_t *operation, + size_t ad_length, + size_t plaintext_length ) +{ + + if( !operation->key_set || operation->lengths_set ) + { + return( PSA_ERROR_BAD_STATE ); + } + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM) + if( operation->alg == PSA_ALG_GCM ) + { +#if SIZE_MAX > UINT32_MAX + if( ( (uint64_t) ad_length ) >> 61 != 0 || + ( (uint64_t) plaintext_length ) > 0xFFFFFFFE0ull ) + { + return ( PSA_ERROR_INVALID_ARGUMENT ); + } +#endif + } + else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM) + if( operation->alg == PSA_ALG_CCM ) + { + if( ad_length > 0xFF00 ) + { + return ( PSA_ERROR_INVALID_ARGUMENT ); + } + } + else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305) + if( operation->alg == PSA_ALG_CHACHA20_POLY1305 ) + { + /* No length restrictions for ChaChaPoly. */ + } + else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */ + { + ( void ) ad_length; + ( void ) plaintext_length; + + return ( PSA_ERROR_NOT_SUPPORTED ); + } + + operation->ad_remaining = ad_length; + operation->body_remaining = plaintext_length; + operation->lengths_set = 1; + + return ( PSA_SUCCESS ); +} + +/* Pass additional data to an active multipart AEAD operation. */ +psa_status_t mbedtls_psa_aead_update_ad( psa_aead_operation_t *operation, + const uint8_t *input, + size_t input_length ) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + if( !operation->nonce_set || !operation->key_set ) + { + return( PSA_ERROR_BAD_STATE ); + } + + if( operation->lengths_set ) + { + if ( operation->ad_remaining < input_length ) + { + return( PSA_ERROR_INVALID_ARGUMENT ); + } + + operation->ad_remaining -= input_length; + } + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM) + if( operation->alg == PSA_ALG_GCM ) + { + if( !operation->lengths_set || operation->ad_started ) + { + return( PSA_ERROR_BAD_STATE ); + } + + /* GCM currently requires all the additional data to be passed in in + * one contigious buffer, so until that is re-done, we have to enforce + * this, as we cannot allocate a buffer to collate multiple calls into. + */ + if( input_length != operation->ad_remaining ) + { + return ( PSA_ERROR_INVALID_ARGUMENT ); + } + + status = mbedtls_to_psa_error( mbedtls_gcm_starts( &operation->ctx.gcm, + operation->is_encrypt ? + MBEDTLS_GCM_ENCRYPT : MBEDTLS_GCM_DECRYPT, + operation->nonce, + operation->nonce_length, + input, + input_length ) ); + + } + else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM) + if( operation->alg == PSA_ALG_CCM ) + { + /* CCM requires all additional data to be passed in in one go at the + minute, as we are basically operating in oneshot mode. */ + if( !operation->lengths_set || operation->ad_started ) + { + return( PSA_ERROR_BAD_STATE ); + } + + /* Save the additional data for later, this will be passed in + when we have the body. */ + operation->ad_buffer = ( uint8_t * ) mbedtls_calloc(1, input_length ); + + if( operation->ad_buffer ) + { + memcpy( operation->ad_buffer, input, input_length ); + operation->ad_length = input_length; + } + else + { + return ( PSA_ERROR_INSUFFICIENT_MEMORY ); + } + } + else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305) + if( operation->alg == PSA_ALG_CHACHA20_POLY1305 ) + { + status = mbedtls_to_psa_error( mbedtls_chachapoly_update_aad( &operation->ctx.chachapoly, + input, + input_length ) ); + } + else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */ + { + (void) input; + (void) input_length; + + return ( PSA_ERROR_NOT_SUPPORTED ); + } + + if( status == PSA_SUCCESS ) + { + operation->ad_started = 1; + } + + return ( status ); +} + +/* Encrypt or decrypt a message fragment in an active multipart AEAD + * operation.*/ +psa_status_t mbedtls_psa_aead_update( psa_aead_operation_t *operation, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length ) +{ + size_t update_output_size; + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + if( !operation->nonce_set || !operation->key_set || !operation->ad_started ) + { + return( PSA_ERROR_BAD_STATE ); + } + + update_output_size = PSA_AEAD_UPDATE_OUTPUT_SIZE(operation->key_type, + operation->alg, input_length); + + if(update_output_size > output_size ) + { + return ( PSA_ERROR_BUFFER_TOO_SMALL ); + } + + if( operation->lengths_set) + { + /* Additional data length was supplied, but not all the additional + data was supplied.*/ + if( operation->ad_remaining != 0 ) + { + return ( PSA_ERROR_INVALID_ARGUMENT ); + } + + /* Too much data provided. */ + if( operation->body_remaining < input_length ) + { + return ( PSA_ERROR_INVALID_ARGUMENT ); + } + + operation->body_remaining -= input_length; + } + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM) + if( operation->alg == PSA_ALG_GCM ) + { + /* For the time being set the requirement that all of the body data + * must be passed in in one update, rather than deal with the complexity + * of non block size aligned updates. This will be fixed in 3.0 when + we can change the signature of the GCM multipart functions */ + if( !operation->lengths_set || operation->body_remaining != 0 ) + { + return( PSA_ERROR_BAD_STATE ); + } + + if( operation->ad_started ) + { + return( PSA_ERROR_BAD_STATE ); + } + + status = mbedtls_to_psa_error( mbedtls_gcm_update( &operation->ctx.gcm, + input_length, + input, + output ) ); + } + else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM) + if( operation->alg == PSA_ALG_CCM ) + { + /* CCM dooes not support multipart yet, so all the input has to be + passed in in one go. Store the data for the final step.*/ + if( operation->ad_started ) + { + return( PSA_ERROR_BAD_STATE ); + } + + /* Save the additional data for later, this will be passed in + when we have the body. */ + operation->data_buffer = ( uint8_t * ) mbedtls_calloc(1, input_length ); + + if( operation->data_buffer ) + { + memcpy( operation->data_buffer, input, input_length ); + operation->data_length = input_length; + } + else + { + return ( PSA_ERROR_INSUFFICIENT_MEMORY ); + } + + } + else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305) + if( operation->alg == PSA_ALG_CHACHA20_POLY1305 ) + { + status = mbedtls_to_psa_error( mbedtls_chachapoly_update( &operation->ctx.chachapoly, + input_length, + input, + output ) ); + } + else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */ + { + (void) input; + (void) input_length; + + return ( PSA_ERROR_NOT_SUPPORTED ); + } + + if( status == PSA_SUCCESS ) + { + *output_length = update_output_size; + operation->body_started = 1; + } + + return( status ); +} + +/* Common checks for both mbedtls_psa_aead_finish() and + mbedtls_psa_aead_verify() */ +static psa_status_t mbedtls_psa_aead_finish_checks( psa_aead_operation_t *operation, + size_t output_size, + size_t tag_size, + size_t *finish_output_size, + size_t *output_tag_length ) +{ + if( !operation->key_set || !operation->nonce_set + || !operation->ad_started || !operation->body_started) + { + return( PSA_ERROR_BAD_STATE ); + } + + if( operation->lengths_set ) + { + if( operation->ad_remaining != 0 || operation->body_remaining != 0 ) + { + return( PSA_ERROR_BAD_STATE ); + } + } + + *output_tag_length = operation->tag_length; + + if( tag_size < *output_tag_length) + { + return ( PSA_ERROR_BUFFER_TOO_SMALL ); + } + + if( operation->is_encrypt ) + { + *finish_output_size = PSA_AEAD_FINISH_OUTPUT_SIZE(operation->key_type, + operation->alg); + } + else + { + *finish_output_size = PSA_AEAD_VERIFY_OUTPUT_SIZE(operation->key_type, + operation->alg); + } + + if( output_size < *finish_output_size ) + { + return ( PSA_ERROR_BUFFER_TOO_SMALL ); + } + + return ( PSA_SUCCESS ); + +} + +/* Finish encrypting a message in a multipart AEAD operation. */ +psa_status_t mbedtls_psa_aead_finish( psa_aead_operation_t *operation, + uint8_t *ciphertext, + size_t ciphertext_size, + size_t *ciphertext_length, + uint8_t *tag, + size_t tag_size, + size_t *tag_length ) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + size_t output_tag_length; + size_t finish_output_size; + + status = mbedtls_psa_aead_finish_checks( operation, ciphertext_size, tag_size, &finish_output_size, + &output_tag_length); + + if( status != PSA_SUCCESS ) + { + return status; + } + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM) + if( operation->alg == PSA_ALG_GCM ) + { + /* We will need to do final GCM pass in here when multipart is done. */ + status = mbedtls_to_psa_error( mbedtls_gcm_finish( &operation->ctx.gcm, + tag, + tag_size ) ); + } + else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM) + if( operation->alg == PSA_ALG_CCM ) + { + if( !operation->ad_buffer || !operation->data_buffer ) + { + return( PSA_ERROR_BAD_STATE ); + } + + /* Perform oneshot CCM encryption with data already stored, as + CCM does not support multipart yet.*/ + status = mbedtls_to_psa_error( mbedtls_ccm_encrypt_and_tag( &operation->ctx.ccm, + operation->data_length, + operation->nonce, + operation->nonce_length, + operation->ad_buffer, + operation->ad_length, + operation->data_buffer, + ciphertext, + tag, tag_size ) ); + + /* Even if the above operation fails, we no longer need the data */ + mbedtls_free(operation->ad_buffer); + operation->ad_buffer = NULL; + operation->ad_length = 0; + + mbedtls_free(operation->data_buffer); + operation->data_buffer = NULL; + operation->data_length = 0; + } + else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305) + if( operation->alg == PSA_ALG_CHACHA20_POLY1305 ) + { + status = mbedtls_to_psa_error( mbedtls_chachapoly_finish( &operation->ctx.chachapoly, + tag ) ); + } + else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */ + { + ( void ) ciphertext; + ( void ) ciphertext_size; + ( void ) ciphertext_length; + ( void ) tag; + ( void ) tag_size; + ( void ) tag_length; + + return ( PSA_ERROR_NOT_SUPPORTED ); + } + + if( status == PSA_SUCCESS ) + { + *ciphertext_length = finish_output_size; + *tag_length = output_tag_length; + } + + mbedtls_psa_aead_abort(operation); + + return ( status ); +} + +/* Finish authenticating and decrypting a message in a multipart AEAD + * operation.*/ +psa_status_t mbedtls_psa_aead_verify( psa_aead_operation_t *operation, + uint8_t *plaintext, + size_t plaintext_size, + size_t *plaintext_length, + const uint8_t *tag, + size_t tag_length ) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + size_t finish_output_size; + size_t output_tag_length; + + int do_tag_check = 1; + uint8_t check_tag[16]; + + status = mbedtls_psa_aead_finish_checks( operation, plaintext_size, tag_length, &finish_output_size, + &output_tag_length); + + if( status != PSA_SUCCESS ) + { + return status; + } + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM) + if( operation->alg == PSA_ALG_GCM ) + { + /* Call finish to get the tag for comparison */ + status = mbedtls_to_psa_error( mbedtls_gcm_finish( &operation->ctx.gcm, + check_tag, + 16 ) ); + } + else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM) + if( operation->alg == PSA_ALG_CCM ) + { + if( !operation->ad_buffer || !operation->data_buffer ) + { + return( PSA_ERROR_BAD_STATE ); + } + + /* Perform oneshot CCM decryption with data already stored, as + CCM does not support multipart yet.*/ + + ret = mbedtls_ccm_auth_decrypt( &operation->ctx.ccm, operation->data_length, + operation->nonce, operation->nonce_length, + operation->ad_buffer, operation->ad_length, + operation->data_buffer, plaintext, + tag, tag_length ); + + if( ret == MBEDTLS_ERR_CCM_AUTH_FAILED ) + { + status = PSA_ERROR_INVALID_SIGNATURE; + } + else + { + status = mbedtls_to_psa_error( ret ); + do_tag_check = 0; + } + + /* Even if the above operation fails, we no longer need the data */ + mbedtls_free(operation->ad_buffer); + operation->ad_buffer = NULL; + operation->ad_length = 0; + + mbedtls_free(operation->data_buffer); + operation->data_buffer = NULL; + operation->data_length = 0; + } + else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305) + if( operation->alg == PSA_ALG_CHACHA20_POLY1305 ) + { + // call finish to get the tag for comparison. + status = mbedtls_to_psa_error( mbedtls_chachapoly_finish( &operation->ctx.chachapoly, + check_tag ) ); + } + else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */ + { + ( void ) plaintext; + ( void ) plaintext_size; + ( void ) plaintext_length; + ( void ) tag; + ( void ) tag_length; + + return ( PSA_ERROR_NOT_SUPPORTED ); + } + + if( status == PSA_SUCCESS ) + { + if( do_tag_check && safer_memcmp(tag, check_tag, tag_length) != 0 ) + { + status = MBEDTLS_ERR_GCM_AUTH_FAILED; + } + } + + mbedtls_psa_aead_abort(operation); + + return ( status ); +} + +/* Abort an AEAD operation */ +psa_status_t mbedtls_psa_aead_abort( psa_aead_operation_t *operation ) +{ + switch( operation->alg ) + { +#if defined(MBEDTLS_CCM_C) + case MBEDTLS_PSA_BUILTIN_ALG_CCM: + mbedtls_ccm_free( &operation->ctx.ccm ); + break; +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM) + case PSA_ALG_GCM: + mbedtls_gcm_free( &operation->ctx.gcm ); + break; +#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305) + case PSA_ALG_CHACHA20_POLY1305: + mbedtls_chachapoly_free( &operation->ctx.chachapoly ); + break; +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */ + } + + return( PSA_SUCCESS ); +} + #endif /* MBEDTLS_PSA_CRYPTO_C */ diff --git a/library/psa_crypto_aead.h b/library/psa_crypto_aead.h index aab0f835c4..d7aac24ed0 100644 --- a/library/psa_crypto_aead.h +++ b/library/psa_crypto_aead.h @@ -148,4 +148,644 @@ psa_status_t mbedtls_psa_aead_decrypt( const uint8_t *ciphertext, size_t ciphertext_length, uint8_t *plaintext, size_t plaintext_size, size_t *plaintext_length ); +/** Set the key for a multipart authenticated encryption operation. + * + * \note The signature of this function is that of a PSA driver + * aead_encrypt_setup entry point. This function behaves as an + * aead_encrypt_setup entry point as defined in the PSA driver interface + * specification for transparent drivers. + * + * The sequence of operations to encrypt a message with authentication + * is as follows: + * -# Allocate an operation object which will be passed to all the functions + * listed here. + * -# Initialize the operation object with one of the methods described in the + * documentation for #psa_aead_operation_t, e.g. + * #PSA_AEAD_OPERATION_INIT. + * -# Call mbedtls_psa_aead_encrypt_setup() to specify the algorithm and key. + * -# If needed, call mbedtls_psa_aead_set_lengths() to specify the length of + * the inputs to the subsequent calls to mbedtls_psa_aead_update_ad() and + * mbedtls_psa_aead_update(). See the documentation of mbedtls_psa_aead_set_lengths() + * for details. + * -# Call either mbedtls_psa_aead_generate_nonce() or mbedtls_psa_aead_set_nonce() to + * generate or set the nonce. You should use + * mbedtls_psa_aead_generate_nonce() unless the protocol you are implementing + * requires a specific nonce value. + * -# Call mbedtls_psa_aead_update_ad() zero, one or more times, passing a fragment + * of the non-encrypted additional authenticated data each time. + * -# Call mbedtls_psa_aead_update() zero, one or more times, passing a fragment + * of the message to encrypt each time. + * -# Call mbedtls_psa_aead_finish(). + * + * If an error occurs at any step after a call to mbedtls_psa_aead_encrypt_setup(), + * the operation will need to be reset by a call to mbedtls_psa_aead_abort(). The + * application may call mbedtls_psa_aead_abort() at any time after the operation + * has been initialized. + * + * After a successful call to mbedtls_psa_aead_encrypt_setup(), the application must + * eventually terminate the operation. The following events terminate an + * operation: + * - A successful call to mbedtls_psa_aead_finish(). + * - A call to mbedtls_psa_aead_abort(). + * + * \param[in,out] operation The operation object to set up. It must have + * been initialized as per the documentation for + * #mbedtls_psa_aead_operation_t and not yet in use. + * \param[in] attributes The attributes of the key to use for the + * operation. + * \param[in] key_buffer The buffer containing the key context. + * \param key_buffer_size Size of the \p key_buffer buffer in bytes. + * \param alg The AEAD algorithm to compute + * (\c PSA_ALG_XXX value such that + * #PSA_ALG_IS_AEAD(\p alg) is true). + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_BAD_STATE + * The operation state is not valid (it must be inactive). + * \retval #PSA_ERROR_INVALID_HANDLE + * \retval #PSA_ERROR_NOT_PERMITTED + * \retval #PSA_ERROR_INVALID_ARGUMENT + * \p key is not compatible with \p alg. + * \retval #PSA_ERROR_NOT_SUPPORTED + * \p alg is not supported or is not an AEAD algorithm. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY + * \retval #PSA_ERROR_COMMUNICATION_FAILURE + * \retval #PSA_ERROR_HARDWARE_FAILURE + * \retval #PSA_ERROR_CORRUPTION_DETECTED + * \retval #PSA_ERROR_STORAGE_FAILURE + * \retval #PSA_ERROR_BAD_STATE + * The library has not been previously initialized by psa_crypto_init(). + * It is implementation-dependent whether a failure to initialize + * results in this error code. + */ +psa_status_t mbedtls_psa_aead_encrypt_setup(psa_aead_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg); + +/** Set the key for a multipart authenticated decryption operation. + * + * \note The signature of this function is that of a PSA driver + * aead_decrypt_setup entry point. This function behaves as an + * aead_decrypt_setup entry point as defined in the PSA driver interface + * specification for transparent drivers. + * + * The sequence of operations to decrypt a message with authentication + * is as follows: + * -# Allocate an operation object which will be passed to all the functions + * listed here. + * -# Initialize the operation object with one of the methods described in the + * documentation for #psa_aead_operation_t, e.g. + * #PSA_AEAD_OPERATION_INIT. + * -# Call mbedtls_psa_aead_decrypt_setup() to specify the algorithm and key. + * -# If needed, call mbedtls_psa_aead_set_lengths() to specify the length of the + * inputs to the subsequent calls to mbedtls_psa_aead_update_ad() and + * mbedtls_psa_aead_update(). See the documentation of mbedtls_psa_aead_set_lengths() + * for details. + * -# Call mbedtls_psa_aead_set_nonce() with the nonce for the decryption. + * -# Call mbedtls_psa_aead_update_ad() zero, one or more times, passing a fragment + * of the non-encrypted additional authenticated data each time. + * -# Call mbedtls_psa_aead_update() zero, one or more times, passing a fragment + * of the ciphertext to decrypt each time. + * -# Call mbedtls_psa_aead_verify(). + * + * If an error occurs at any step after a call to mbedtls_psa_aead_decrypt_setup(), + * the operation will need to be reset by a call to mbedtls_psa_aead_abort(). The + * application may call mbedtls_psa_aead_abort() at any time after the operation + * has been initialized. + * + * After a successful call to mbedtls_psa_aead_decrypt_setup(), the application must + * eventually terminate the operation. The following events terminate an + * operation: + * - A successful call to mbedtls_psa_aead_verify(). + * - A call to mbedtls_psa_aead_abort(). + * + * \param[in,out] operation The operation object to set up. It must have + * been initialized as per the documentation for + * #psa_aead_operation_t and not yet in use. + * \param[in] attributes The attributes of the key to use for the + * operation. + * \param[in] key_buffer The buffer containing the key context. + * \param key_buffer_size Size of the \p key_buffer buffer in bytes. + * \param alg The AEAD algorithm to compute + * (\c PSA_ALG_XXX value such that + * #PSA_ALG_IS_AEAD(\p alg) is true). + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_BAD_STATE + * The operation state is not valid (it must be inactive). + * \retval #PSA_ERROR_INVALID_HANDLE + * \retval #PSA_ERROR_NOT_PERMITTED + * \retval #PSA_ERROR_INVALID_ARGUMENT + * \p key is not compatible with \p alg. + * \retval #PSA_ERROR_NOT_SUPPORTED + * \p alg is not supported or is not an AEAD algorithm. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY + * \retval #PSA_ERROR_COMMUNICATION_FAILURE + * \retval #PSA_ERROR_HARDWARE_FAILURE + * \retval #PSA_ERROR_CORRUPTION_DETECTED + * \retval #PSA_ERROR_STORAGE_FAILURE + * \retval #PSA_ERROR_BAD_STATE + * The library has not been previously initialized by psa_crypto_init(). + * It is implementation-dependent whether a failure to initialize + * results in this error code. + */ +psa_status_t mbedtls_psa_aead_decrypt_setup(psa_aead_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg); + +/** Generate a random nonce for an authenticated encryption operation. + * + * \note The signature of this function is that of a PSA driver + * aead_generate_nonce entry point. This function behaves as an + * aead_generate_nonce entry point as defined in the PSA driver interface + * specification for transparent drivers. + * + * This function generates a random nonce for the authenticated encryption + * operation with an appropriate size for the chosen algorithm, key type + * and key size. + * + * The application must call mbedtls_psa_aead_encrypt_setup() before + * calling this function. + * + * If this function returns an error status, the operation enters an error + * state and must be aborted by calling mbedtls_psa_aead_abort(). + * + * \param[in,out] operation Active AEAD operation. + * \param[out] nonce Buffer where the generated nonce is to be + * written. + * \param nonce_size Size of the \p nonce buffer in bytes. + * \param[out] nonce_length On success, the number of bytes of the + * generated nonce. + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_BAD_STATE + * The operation state is not valid (it must be an active aead encrypt + * operation, with no nonce set). + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * The size of the \p nonce buffer is too small. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY + * \retval #PSA_ERROR_COMMUNICATION_FAILURE + * \retval #PSA_ERROR_HARDWARE_FAILURE + * \retval #PSA_ERROR_CORRUPTION_DETECTED + * \retval #PSA_ERROR_STORAGE_FAILURE + * \retval #PSA_ERROR_BAD_STATE + * The library has not been previously initialized by psa_crypto_init(). + * It is implementation-dependent whether a failure to initialize + * results in this error code. + */ +psa_status_t mbedtls_psa_aead_generate_nonce(psa_aead_operation_t *operation, + uint8_t *nonce, + size_t nonce_size, + size_t *nonce_length); + +/** Set the nonce for an authenticated encryption or decryption operation. + * + * \note The signature of this function is that of a PSA driver + * psa_aead_set_nonce entry point. This function behaves as an + * psa_aead_set_nonce entry point as defined in the PSA driver interface + * specification for transparent drivers. + * + * This function sets the nonce for the authenticated + * encryption or decryption operation. + * + * The application must call mbedtls_psa_aead_encrypt_setup() or + * mbedtls_psa_aead_decrypt_setup() before calling this function. + * + * If this function returns an error status, the operation enters an error + * state and must be aborted by calling mbedtls_psa_aead_abort(). + * + * \note When encrypting, applications should use mbedtls_psa_aead_generate_nonce() + * instead of this function, unless implementing a protocol that requires + * a non-random IV. + * + * \param[in,out] operation Active AEAD operation. + * \param[in] nonce Buffer containing the nonce to use. + * \param nonce_length Size of the nonce in bytes. + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_BAD_STATE + * The operation state is not valid (it must be active, with no nonce + * set). + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The size of \p nonce is not acceptable for the chosen algorithm. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY + * \retval #PSA_ERROR_COMMUNICATION_FAILURE + * \retval #PSA_ERROR_HARDWARE_FAILURE + * \retval #PSA_ERROR_CORRUPTION_DETECTED + * \retval #PSA_ERROR_STORAGE_FAILURE + * \retval #PSA_ERROR_BAD_STATE + * The library has not been previously initialized by psa_crypto_init(). + * It is implementation-dependent whether a failure to initialize + * results in this error code. + */ +psa_status_t mbedtls_psa_aead_set_nonce(psa_aead_operation_t *operation, + const uint8_t *nonce, + size_t nonce_length); + +/** Declare the lengths of the message and additional data for AEAD. + * + * \note The signature of this function is that of a PSA driver + * psa_aead_set_lengths entry point. This function behaves as an + * psa_aead_set_lengths entry point as defined in the PSA driver interface + * specification for transparent drivers. + * + * The application must call this function before calling + * mbedtls_psa_aead_update_ad() or mbedtls_psa_aead_update() if the algorithm for + * the operation requires it. If the algorithm does not require it, + * calling this function is optional, but if this function is called + * then the implementation must enforce the lengths. + * + * You may call this function before or after setting the nonce with + * mbedtls_psa_aead_set_nonce() or mbedtls_psa_aead_generate_nonce(). + * + * - For #PSA_ALG_CCM, calling this function is required. + * - For the other AEAD algorithms defined in this specification, calling + * this function is not required. + * - For vendor-defined algorithm, refer to the vendor documentation. + * + * If this function returns an error status, the operation enters an error + * state and must be aborted by calling mbedtls_psa_aead_abort(). + * + * \param[in,out] operation Active AEAD operation. + * \param ad_length Size of the non-encrypted additional + * authenticated data in bytes. + * \param plaintext_length Size of the plaintext to encrypt in bytes. + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_BAD_STATE + * The operation state is not valid (it must be active, and + * mbedtls_psa_aead_update_ad() and mbedtls_psa_aead_update() must not have been + * called yet). + * \retval #PSA_ERROR_INVALID_ARGUMENT + * At least one of the lengths is not acceptable for the chosen + * algorithm. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY + * \retval #PSA_ERROR_COMMUNICATION_FAILURE + * \retval #PSA_ERROR_HARDWARE_FAILURE + * \retval #PSA_ERROR_CORRUPTION_DETECTED + * \retval #PSA_ERROR_BAD_STATE + * The library has not been previously initialized by psa_crypto_init(). + * It is implementation-dependent whether a failure to initialize + * results in this error code. + */ +psa_status_t mbedtls_psa_aead_set_lengths(psa_aead_operation_t *operation, + size_t ad_length, + size_t plaintext_length); + +/** Pass additional data to an active AEAD operation. + * + * \note The signature of this function is that of a PSA driver + * aead_update_ad entry point. This function behaves as an aead_update_ad + * entry point as defined in the PSA driver interface specification for + * transparent drivers. + * + * Additional data is authenticated, but not encrypted. + * + * You may call this function multiple times to pass successive fragments + * of the additional data. You may not call this function after passing + * data to encrypt or decrypt with mbedtls_psa_aead_update(). + * + * Before calling this function, you must: + * 1. Call either mbedtls_psa_aead_encrypt_setup() or mbedtls_psa_aead_decrypt_setup(). + * 2. Set the nonce with mbedtls_psa_aead_generate_nonce() or + * mbedtls_psa_aead_set_nonce(). + * + * If this function returns an error status, the operation enters an error + * state and must be aborted by calling mbedtls_psa_aead_abort(). + * + * \warning When decrypting, until mbedtls_psa_aead_verify() has returned #PSA_SUCCESS, + * there is no guarantee that the input is valid. Therefore, until + * you have called mbedtls_psa_aead_verify() and it has returned #PSA_SUCCESS, + * treat the input as untrusted and prepare to undo any action that + * depends on the input if mbedtls_psa_aead_verify() returns an error status. + * + * \note For the time being #PSA_ALG_CCM and #PSA_ALG_GCM require the entire + * additional data to be passed in in one go, i.e. only call + * mbedtls_mbedtls_psa_aead_update_ad() once. + * + * \param[in,out] operation Active AEAD operation. + * \param[in] input Buffer containing the fragment of + * additional data. + * \param input_length Size of the \p input buffer in bytes. + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_BAD_STATE + * The operation state is not valid (it must be active, have a nonce + * set, have lengths set if required by the algorithm, and + * mbedtls_psa_aead_update() must not have been called yet). + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The total input length overflows the additional data length that + * was previously specified with mbedtls_psa_aead_set_lengths(). + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY + * \retval #PSA_ERROR_COMMUNICATION_FAILURE + * \retval #PSA_ERROR_HARDWARE_FAILURE + * \retval #PSA_ERROR_CORRUPTION_DETECTED + * \retval #PSA_ERROR_STORAGE_FAILURE + * \retval #PSA_ERROR_BAD_STATE + * The library has not been previously initialized by psa_crypto_init(). + * It is implementation-dependent whether a failure to initialize + * results in this error code. + */ +psa_status_t mbedtls_psa_aead_update_ad(psa_aead_operation_t *operation, + const uint8_t *input, + size_t input_length); + +/** Encrypt or decrypt a message fragment in an active AEAD operation. + * + * \note The signature of this function is that of a PSA driver + * aead_update entry point. This function behaves as an aead_update entry + * point as defined in the PSA driver interface specification for + * transparent drivers. + * + * Before calling this function, you must: + * 1. Call either mbedtls_psa_aead_encrypt_setup() or mbedtls_psa_aead_decrypt_setup(). + * The choice of setup function determines whether this function + * encrypts or decrypts its input. + * 2. Set the nonce with mbedtls_psa_aead_generate_nonce() or mbedtls_psa_aead_set_nonce(). + * 3. Call mbedtls_psa_aead_update_ad() to pass all the additional data. + * + * If this function returns an error status, the operation enters an error + * state and must be aborted by calling mbedtls_psa_aead_abort(). + * + * \warning When decrypting, until mbedtls_psa_aead_verify() has returned + * #PSA_SUCCESS, there is no guarantee that the input is valid. + * Therefore, until you have called mbedtls_psa_aead_verify() and it + * has returned #PSA_SUCCESS: + * - Do not use the output in any way other than storing it in a + * confidential location. If you take any action that depends + * on the tentative decrypted data, this action will need to be + * undone if the input turns out not to be valid. Furthermore, + * if an adversary can observe that this action took place + * (for example through timing), they may be able to use this + * fact as an oracle to decrypt any message encrypted with the + * same key. + * - In particular, do not copy the output anywhere but to a + * memory or storage space that you have exclusive access to. + * + * This function does not require the input to be aligned to any + * particular block boundary. If the implementation can only process + * a whole block at a time, it must consume all the input provided, but + * it may delay the end of the corresponding output until a subsequent + * call to mbedtls_psa_aead_update(), mbedtls_psa_aead_finish() or + * mbedtls_psa_aead_verify() provides sufficient input. The amount of data that + * can be delayed in this way is bounded by #PSA_AEAD_UPDATE_OUTPUT_SIZE. + * + * \note For the time being #PSA_ALG_CCM and #PSA_ALG_GCM require the entire + * data to be passed in in one go, i.e. only call + * mbedtls_mbedtls_psa_aead_update() once. + * + * \param[in,out] operation Active AEAD operation. + * \param[in] input Buffer containing the message fragment to + * encrypt or decrypt. + * \param input_length Size of the \p input buffer in bytes. + * \param[out] output Buffer where the output is to be written. + * \param output_size Size of the \p output buffer in bytes. + * This must be at least + * #PSA_AEAD_UPDATE_OUTPUT_SIZE(\c alg, + * \p input_length) where \c alg is the + * algorithm that is being calculated. + * \param[out] output_length On success, the number of bytes + * that make up the returned output. + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_BAD_STATE + * The operation state is not valid (it must be active, have a nonce + * set, and have lengths set if required by the algorithm). + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * The size of the \p output buffer is too small. + * You can determine a sufficient buffer size by calling + * #PSA_AEAD_UPDATE_OUTPUT_SIZE(\c alg, \p input_length) + * where \c alg is the algorithm that is being calculated. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The total length of input to mbedtls_psa_aead_update_ad() so far is + * less than the additional data length that was previously + * specified with mbedtls_psa_aead_set_lengths(). + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The total input length overflows the plaintext length that + * was previously specified with mbedtls_psa_aead_set_lengths(). + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY + * \retval #PSA_ERROR_COMMUNICATION_FAILURE + * \retval #PSA_ERROR_HARDWARE_FAILURE + * \retval #PSA_ERROR_CORRUPTION_DETECTED + * \retval #PSA_ERROR_STORAGE_FAILURE + * \retval #PSA_ERROR_BAD_STATE + * The library has not been previously initialized by psa_crypto_init(). + * It is implementation-dependent whether a failure to initialize + * results in this error code. + */ +psa_status_t mbedtls_psa_aead_update(psa_aead_operation_t *operation, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length); + +/** Finish encrypting a message in an AEAD operation. + * + * \note The signature of this function is that of a PSA driver + * aead_finish entry point. This function behaves as an aead_finish entry + * point as defined in the PSA driver interface specification for + * transparent drivers. + * + * The operation must have been set up with mbedtls_psa_aead_encrypt_setup(). + * + * This function finishes the authentication of the additional data + * formed by concatenating the inputs passed to preceding calls to + * mbedtls_psa_aead_update_ad() with the plaintext formed by concatenating the + * inputs passed to preceding calls to mbedtls_psa_aead_update(). + * + * This function has two output buffers: + * - \p ciphertext contains trailing ciphertext that was buffered from + * preceding calls to mbedtls_psa_aead_update(). + * - \p tag contains the authentication tag. Its length is always + * #PSA_AEAD_TAG_LENGTH(\c alg) where \c alg is the AEAD algorithm + * that the operation performs. + * + * When this function returns successfuly, the operation becomes inactive. + * If this function returns an error status, the operation enters an error + * state and must be aborted by calling mbedtls_psa_aead_abort(). + * + * \param[in,out] operation Active AEAD operation. + * \param[out] ciphertext Buffer where the last part of the ciphertext + * is to be written. + * \param ciphertext_size Size of the \p ciphertext buffer in bytes. + * This must be at least + * #PSA_AEAD_FINISH_OUTPUT_SIZE(\c alg) where + * \c alg is the algorithm that is being + * calculated. + * \param[out] ciphertext_length On success, the number of bytes of + * returned ciphertext. + * \param[out] tag Buffer where the authentication tag is + * to be written. + * \param tag_size Size of the \p tag buffer in bytes. + * This must be at least + * #PSA_AEAD_TAG_LENGTH(\c alg) where \c alg is + * the algorithm that is being calculated. + * \param[out] tag_length On success, the number of bytes + * that make up the returned tag. + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_BAD_STATE + * The operation state is not valid (it must be an active encryption + * operation with a nonce set). + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * The size of the \p ciphertext or \p tag buffer is too small. + * You can determine a sufficient buffer size for \p ciphertext by + * calling #PSA_AEAD_FINISH_OUTPUT_SIZE(\c alg) + * where \c alg is the algorithm that is being calculated. + * You can determine a sufficient buffer size for \p tag by + * calling #PSA_AEAD_TAG_LENGTH(\c alg). + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The total length of input to psa_aead_update_ad() so far is + * less than the additional data length that was previously + * specified with psa_aead_set_lengths(). + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The total length of input to mbedtls_psa_aead_update() so far is + * less than the plaintext length that was previously + * specified with mbedtls_psa_aead_set_lengths(). + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY + * \retval #PSA_ERROR_COMMUNICATION_FAILURE + * \retval #PSA_ERROR_HARDWARE_FAILURE + * \retval #PSA_ERROR_CORRUPTION_DETECTED + * \retval #PSA_ERROR_STORAGE_FAILURE + * \retval #PSA_ERROR_BAD_STATE + * The library has not been previously initialized by psa_crypto_init(). + * It is implementation-dependent whether a failure to initialize + * results in this error code. + */ +psa_status_t mbedtls_psa_aead_finish(psa_aead_operation_t *operation, + uint8_t *ciphertext, + size_t ciphertext_size, + size_t *ciphertext_length, + uint8_t *tag, + size_t tag_size, + size_t *tag_length); + +/** Finish authenticating and decrypting a message in an AEAD operation. + * + * \note The signature of this function is that of a PSA driver + * aead_verify entry point. This function behaves as an aead_verify entry + * point as defined in the PSA driver interface specification for + * transparent drivers. + * + * The operation must have been set up with mbedtls_psa_aead_decrypt_setup(). + * + * This function finishes the authenticated decryption of the message + * components: + * + * - The additional data consisting of the concatenation of the inputs + * passed to preceding calls to mbedtls_psa_aead_update_ad(). + * - The ciphertext consisting of the concatenation of the inputs passed to + * preceding calls to mbedtls_psa_aead_update(). + * - The tag passed to this function call. + * + * If the authentication tag is correct, this function outputs any remaining + * plaintext and reports success. If the authentication tag is not correct, + * this function returns #PSA_ERROR_INVALID_SIGNATURE. + * + * When this function returns successfuly, the operation becomes inactive. + * If this function returns an error status, the operation enters an error + * state and must be aborted by calling mbedtls_psa_aead_abort(). + * + * \note Implementations shall make the best effort to ensure that the + * comparison between the actual tag and the expected tag is performed + * in constant time. + * + * \param[in,out] operation Active AEAD operation. + * \param[out] plaintext Buffer where the last part of the plaintext + * is to be written. This is the remaining data + * from previous calls to mbedtls_psa_aead_update() + * that could not be processed until the end + * of the input. + * \param plaintext_size Size of the \p plaintext buffer in bytes. + * This must be at least + * #PSA_AEAD_VERIFY_OUTPUT_SIZE(\c alg) where + * \c alg is the algorithm that is being + * calculated. + * \param[out] plaintext_length On success, the number of bytes of + * returned plaintext. + * \param[in] tag Buffer containing the authentication tag. + * \param tag_length Size of the \p tag buffer in bytes. + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_INVALID_SIGNATURE + * The calculations were successful, but the authentication tag is + * not correct. + * \retval #PSA_ERROR_BAD_STATE + * The operation state is not valid (it must be an active decryption + * operation with a nonce set). + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * The size of the \p plaintext buffer is too small. + * You can determine a sufficient buffer size for \p plaintext by + * calling #PSA_AEAD_VERIFY_OUTPUT_SIZE(\c alg) + * where \c alg is the algorithm that is being calculated. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The total length of input to mbedtls_psa_aead_update_ad() so far is + * less than the additional data length that was previously + * specified with mbedtls_psa_aead_set_lengths(). + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The total length of input to mbedtls_psa_aead_update() so far is + * less than the plaintext length that was previously + * specified with psa_aead_set_lengths(). + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY + * \retval #PSA_ERROR_COMMUNICATION_FAILURE + * \retval #PSA_ERROR_HARDWARE_FAILURE + * \retval #PSA_ERROR_CORRUPTION_DETECTED + * \retval #PSA_ERROR_STORAGE_FAILURE + * \retval #PSA_ERROR_BAD_STATE + * The library has not been previously initialized by psa_crypto_init(). + * It is implementation-dependent whether a failure to initialize + * results in this error code. + */ +psa_status_t mbedtls_psa_aead_verify(psa_aead_operation_t *operation, + uint8_t *plaintext, + size_t plaintext_size, + size_t *plaintext_length, + const uint8_t *tag, + size_t tag_length); + +/** Abort an AEAD operation. + * + * \note The signature of this function is that of a PSA driver + * aead_abort entry point. This function behaves as an aead_abort entry + * point as defined in the PSA driver interface specification for + * transparent drivers. + * + * Aborting an operation frees all associated resources except for the + * \p operation structure itself. Once aborted, the operation object + * can be reused for another operation by calling + * mbedtls_psa_aead_encrypt_setup() or mbedtls_psa_aead_decrypt_setup() again. + * + * You may call this function any time after the operation object has + * been initialized as described in #psa_aead_operation_t. + * + * In particular, calling mbedtls_psa_aead_abort() after the operation has been + * terminated by a call to mbedtls_psa_aead_abort(), mbedtls_psa_aead_finish() or + * mbedtls_psa_aead_verify() is safe and has no effect. + * + * \param[in,out] operation Initialized AEAD operation. + * + * \retval #PSA_SUCCESS + * \retval #PSA_ERROR_COMMUNICATION_FAILURE + * \retval #PSA_ERROR_HARDWARE_FAILURE + * \retval #PSA_ERROR_CORRUPTION_DETECTED + * \retval #PSA_ERROR_BAD_STATE + * The library has not been previously initialized by psa_crypto_init(). + * It is implementation-dependent whether a failure to initialize + * results in this error code. + */ +psa_status_t mbedtls_psa_aead_abort(psa_aead_operation_t *operation); + + #endif /* PSA_CRYPTO_AEAD */