diff --git a/include/polarssl/cipher.h b/include/polarssl/cipher.h index dc5a41ca3..b7d449210 100644 --- a/include/polarssl/cipher.h +++ b/include/polarssl/cipher.h @@ -30,6 +30,12 @@ #ifndef POLARSSL_CIPHER_H #define POLARSSL_CIPHER_H +#include "config.h" + +#if defined(POLARSSL_GCM_C) +#define POLARSSL_CIPHER_MODE_AEAD +#endif + #include #if defined(_MSC_VER) && !defined(inline) @@ -457,15 +463,13 @@ int cipher_set_iv( cipher_context_t *ctx, * \brief Finish preparation of the given context * * \param ctx generic cipher context - * \param ad Additional data for AEAD ciphers, or discarded. - * May be NULL only if ad_len is 0. - * \param ad_len Length of ad for AEAD ciphers, or discarded. * * \returns 0 on success, POLARSSL_ERR_CIPHER_BAD_INPUT_DATA * if parameter verification fails. */ int cipher_reset( cipher_context_t *ctx ); +#if defined(POLARSSL_CIPHER_MODE_AEAD) /** * \brief Add additional data (for AEAD ciphers). * This function has no effect for non-AEAD ciphers. @@ -483,6 +487,7 @@ int cipher_reset( cipher_context_t *ctx ); */ int cipher_update_ad( cipher_context_t *ctx, const unsigned char *ad, size_t ad_len ); +#endif /* POLARSSL_CIPHER_MODE_AEAD */ /** * \brief Generic cipher update function. Encrypts/decrypts @@ -530,6 +535,7 @@ int cipher_update( cipher_context_t *ctx, const unsigned char *input, size_t ile int cipher_finish( cipher_context_t *ctx, unsigned char *output, size_t *olen ); +#if defined(POLARSSL_CIPHER_MODE_AEAD) /** * \brief Write tag for AEAD ciphers. * No effect for other ciphers. @@ -556,6 +562,7 @@ int cipher_write_tag( cipher_context_t *ctx, */ int cipher_check_tag( cipher_context_t *ctx, const unsigned char *tag, size_t tag_len ); +#endif /* POLARSSL_CIPHER_MODE_AEAD */ /** * \brief Checkup routine diff --git a/library/cipher.c b/library/cipher.c index a90e2dcd9..160f4bcad 100644 --- a/library/cipher.c +++ b/library/cipher.c @@ -425,6 +425,7 @@ int cipher_reset( cipher_context_t *ctx ) return 0; } +#if defined(POLARSSL_CIPHER_MODE_AEAD) int cipher_update_ad( cipher_context_t *ctx, const unsigned char *ad, size_t ad_len ) { @@ -444,13 +445,11 @@ int cipher_update_ad( cipher_context_t *ctx, return gcm_starts( ctx->cipher_ctx, ctx->operation, ctx->iv, ctx->iv_size, ad, ad_len ); } -#else - ((void) ad); - ((void) ad_len); #endif return 0; } +#endif /* POLARSSL_CIPHER_MODE_AEAD */ int cipher_update( cipher_context_t *ctx, const unsigned char *input, size_t ilen, unsigned char *output, size_t *olen ) @@ -904,50 +903,62 @@ int cipher_set_padding_mode( cipher_context_t *ctx, cipher_padding_t mode ) return 0; } +#if defined(POLARSSL_CIPHER_MODE_AEAD) int cipher_write_tag( cipher_context_t *ctx, unsigned char *tag, size_t tag_len ) { if( NULL == ctx || NULL == ctx->cipher_info || NULL == tag ) return POLARSSL_ERR_CIPHER_BAD_INPUT_DATA; - if( POLARSSL_MODE_GCM != ctx->cipher_info->mode ) - return( 0 ); - if( POLARSSL_ENCRYPT != ctx->operation ) return POLARSSL_ERR_CIPHER_BAD_INPUT_DATA; - return gcm_finish( ctx->cipher_ctx, tag, tag_len ); +#if defined(POLARSSL_GCM_C) + if( POLARSSL_MODE_GCM == ctx->cipher_info->mode ) + return gcm_finish( ctx->cipher_ctx, tag, tag_len ); +#endif + + return 0; } int cipher_check_tag( cipher_context_t *ctx, const unsigned char *tag, size_t tag_len ) { int ret; - unsigned char check_tag[16]; - size_t i; - int diff; - if( NULL == ctx || NULL == ctx->cipher_info ) + if( NULL == ctx || NULL == ctx->cipher_info || + POLARSSL_DECRYPT != ctx->operation ) + { return POLARSSL_ERR_CIPHER_BAD_INPUT_DATA; + } + +#if defined(POLARSSL_GCM_C) + if( POLARSSL_MODE_GCM == ctx->cipher_info->mode ) + { + unsigned char check_tag[16]; + size_t i; + int diff; + + if( tag_len > sizeof( check_tag ) ) + return POLARSSL_ERR_CIPHER_BAD_INPUT_DATA; + + if( 0 != ( ret = gcm_finish( ctx->cipher_ctx, check_tag, tag_len ) ) ) + return( ret ); + + /* Check the tag in "constant-time" */ + for( diff = 0, i = 0; i < tag_len; i++ ) + diff |= tag[i] ^ check_tag[i]; + + if( diff != 0 ) + return( POLARSSL_ERR_GCM_AUTH_FAILED ); - if( POLARSSL_MODE_GCM != ctx->cipher_info->mode ) return( 0 ); - - if( POLARSSL_DECRYPT != ctx->operation || tag_len > sizeof( check_tag ) ) - return POLARSSL_ERR_CIPHER_BAD_INPUT_DATA; - - if( 0 != ( ret = gcm_finish( ctx->cipher_ctx, check_tag, tag_len ) ) ) - return( ret ); - - /* On decryption, check the tag (in "constant-time") */ - for( diff = 0, i = 0; i < tag_len; i++ ) - diff |= tag[i] ^ check_tag[i]; - - if( diff != 0 ) - return( POLARSSL_ERR_GCM_AUTH_FAILED ); + } +#endif return( 0 ); } +#endif /* POLARSSL_CIPHER_MODE_AEAD */ #if defined(POLARSSL_SELF_TEST) diff --git a/tests/suites/test_suite_cipher.function b/tests/suites/test_suite_cipher.function index 5d32bc3d1..63de2db4d 100644 --- a/tests/suites/test_suite_cipher.function +++ b/tests/suites/test_suite_cipher.function @@ -64,8 +64,10 @@ void enc_dec_buf( int cipher_id, char *cipher_string, int key_len, TEST_ASSERT( 0 == cipher_reset( &ctx_dec ) ); TEST_ASSERT( 0 == cipher_reset( &ctx_enc ) ); +#if defined(POLARSSL_CIPHER_MODE_AEAD) TEST_ASSERT( 0 == cipher_update_ad( &ctx_dec, ad, 13 ) ); TEST_ASSERT( 0 == cipher_update_ad( &ctx_enc, ad, 13 ) ); +#endif /* POLARSSL_CIPHER_MODE_AEAD */ /* encode length number of bytes from inbuf */ TEST_ASSERT( 0 == cipher_update( &ctx_enc, inbuf, length, encbuf, &outlen ) ); @@ -79,7 +81,9 @@ void enc_dec_buf( int cipher_id, char *cipher_string, int key_len, TEST_ASSERT( 0 == cipher_finish( &ctx_enc, encbuf + outlen, &outlen ) ); total_len += outlen; +#if defined(POLARSSL_CIPHER_MODE_AEAD) TEST_ASSERT( 0 == cipher_write_tag( &ctx_enc, tag, 16 ) ); +#endif /* POLARSSL_CIPHER_MODE_AEAD */ TEST_ASSERT( total_len == length || ( total_len % cipher_get_block_size( &ctx_enc ) == 0 && @@ -98,7 +102,9 @@ void enc_dec_buf( int cipher_id, char *cipher_string, int key_len, TEST_ASSERT( 0 == cipher_finish( &ctx_dec, decbuf + outlen, &outlen ) ); total_len += outlen; +#if defined(POLARSSL_CIPHER_MODE_AEAD) TEST_ASSERT( 0 == cipher_check_tag( &ctx_dec, tag, 16 ) ); +#endif /* POLARSSL_CIPHER_MODE_AEAD */ TEST_ASSERT( total_len == length ); @@ -143,7 +149,9 @@ void enc_fail( int cipher_id, int pad_mode, int key_len, TEST_ASSERT( 0 == cipher_set_padding_mode( &ctx, pad_mode ) ); TEST_ASSERT( 0 == cipher_set_iv( &ctx, iv, 16 ) ); TEST_ASSERT( 0 == cipher_reset( &ctx ) ); +#if defined(POLARSSL_CIPHER_MODE_AEAD) TEST_ASSERT( 0 == cipher_update_ad( &ctx, NULL, 0 ) ); +#endif /* POLARSSL_CIPHER_MODE_AEAD */ /* encode length number of bytes from inbuf */ TEST_ASSERT( 0 == cipher_update( &ctx, inbuf, length, encbuf, &outlen ) ); @@ -188,7 +196,9 @@ void dec_empty_buf() TEST_ASSERT( 0 == cipher_reset( &ctx_dec ) ); +#if defined(POLARSSL_CIPHER_MODE_AEAD) TEST_ASSERT( 0 == cipher_update_ad( &ctx_dec, NULL, 0 ) ); +#endif /* POLARSSL_CIPHER_MODE_AEAD */ /* decode 0-byte string */ TEST_ASSERT( 0 == cipher_update( &ctx_dec, encbuf, 0, decbuf, &outlen ) ); @@ -248,8 +258,10 @@ void enc_dec_buf_multipart( int cipher_id, int key_len, int first_length_val, TEST_ASSERT( 0 == cipher_reset( &ctx_dec ) ); TEST_ASSERT( 0 == cipher_reset( &ctx_enc ) ); +#if defined(POLARSSL_CIPHER_MODE_AEAD) TEST_ASSERT( 0 == cipher_update_ad( &ctx_dec, NULL, 0 ) ); TEST_ASSERT( 0 == cipher_update_ad( &ctx_enc, NULL, 0 ) ); +#endif /* POLARSSL_CIPHER_MODE_AEAD */ /* encode length number of bytes from inbuf */ TEST_ASSERT( 0 == cipher_update( &ctx_enc, inbuf, first_length, encbuf, &outlen ) );