From 37e230c0226f435f4029f0aa5702c164326a07f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Wed, 28 Aug 2013 13:50:42 +0200 Subject: [PATCH 1/5] Add arc4 support in the cipher layer --- include/polarssl/cipher.h | 4 + library/cipher.c | 29 ++++++ library/cipher_wrap.c | 35 ++++++-- tests/CMakeLists.txt | 1 + tests/Makefile | 9 ++ tests/suites/test_suite_cipher.arc4.data | 110 +++++++++++++++++++++++ 6 files changed, 183 insertions(+), 5 deletions(-) create mode 100644 tests/suites/test_suite_cipher.arc4.data diff --git a/include/polarssl/cipher.h b/include/polarssl/cipher.h index 0ab2b563b..3164a9a63 100644 --- a/include/polarssl/cipher.h +++ b/include/polarssl/cipher.h @@ -151,6 +151,10 @@ typedef struct { int (*ctr_func)( void *ctx, size_t length, size_t *nc_off, unsigned char *nonce_counter, unsigned char *stream_block, const unsigned char *input, unsigned char *output ); + /** Encrypt using STREAM */ + int (*stream_func)( void *ctx, size_t length, + const unsigned char *input, unsigned char *output ); + /** Set key for encryption purposes */ int (*setkey_enc_func)( void *ctx, const unsigned char *key, unsigned int key_length); diff --git a/library/cipher.c b/library/cipher.c index 826d8fcd2..5a260a0bc 100644 --- a/library/cipher.c +++ b/library/cipher.c @@ -36,6 +36,10 @@ #include +#if defined(POLARSSL_ARC4_C) +#define POLARSSL_CIPHER_MODE_STREAM +#endif + #if defined _MSC_VER && !defined strcasecmp #define strcasecmp _stricmp #endif @@ -61,6 +65,10 @@ static const int supported_ciphers[] = { #endif /* defined(POLARSSL_AES_C) */ +#if defined(POLARSSL_ARC4_C) + POLARSSL_CIPHER_ARC4_128, +#endif + #if defined(POLARSSL_CAMELLIA_C) POLARSSL_CIPHER_CAMELLIA_128_CBC, POLARSSL_CIPHER_CAMELLIA_192_CBC, @@ -279,6 +287,11 @@ const cipher_info_t *cipher_info_from_string( const char *cipher_name ) #endif /* defined(POLARSSL_CIPHER_MODE_CTR) */ #endif +#if defined(POLARSSL_ARC4_C) + if( !strcasecmp( "ARC4-128", cipher_name ) ) + return( cipher_info_from_type( POLARSSL_CIPHER_ARC4_128 ) ); +#endif + #if defined(POLARSSL_DES_C) if( !strcasecmp( "DES-CBC", cipher_name ) ) return cipher_info_from_type( POLARSSL_CIPHER_DES_CBC ); @@ -527,6 +540,21 @@ int cipher_update( cipher_context_t *ctx, const unsigned char *input, size_t ile } #endif +#if defined(POLARSSL_CIPHER_MODE_STREAM) + if( ctx->cipher_info->mode == POLARSSL_MODE_STREAM ) + { + if( 0 != ( ret = ctx->cipher_info->base->stream_func( ctx->cipher_ctx, + ilen, input, output ) ) ) + { + return ret; + } + + *olen = ilen; + + return 0; + } +#endif + return POLARSSL_ERR_CIPHER_FEATURE_UNAVAILABLE; } @@ -697,6 +725,7 @@ int cipher_finish( cipher_context_t *ctx, unsigned char *output, size_t *olen) if( POLARSSL_MODE_CFB == ctx->cipher_info->mode || POLARSSL_MODE_CTR == ctx->cipher_info->mode || + POLARSSL_MODE_STREAM == ctx->cipher_info->mode || POLARSSL_MODE_NULL == ctx->cipher_info->mode ) { return 0; diff --git a/library/cipher_wrap.c b/library/cipher_wrap.c index baff2aac3..7a4ff753b 100644 --- a/library/cipher_wrap.c +++ b/library/cipher_wrap.c @@ -37,6 +37,10 @@ #include "polarssl/aes.h" #endif +#if defined(POLARSSL_ARC4_C) +#include "polarssl/arc4.h" +#endif + #if defined(POLARSSL_CAMELLIA_C) #include "polarssl/camellia.h" #endif @@ -129,6 +133,7 @@ const cipher_base_t aes_info = { aes_crypt_cbc_wrap, aes_crypt_cfb128_wrap, aes_crypt_ctr_wrap, + NULL, aes_setkey_enc_wrap, aes_setkey_dec_wrap, aes_ctx_alloc, @@ -324,6 +329,7 @@ const cipher_base_t camellia_info = { camellia_crypt_cbc_wrap, camellia_crypt_cfb128_wrap, camellia_crypt_ctr_wrap, + NULL, camellia_setkey_enc_wrap, camellia_setkey_dec_wrap, camellia_ctx_alloc, @@ -531,6 +537,7 @@ const cipher_base_t des_info = { des_crypt_cbc_wrap, des_crypt_cfb128_wrap, des_crypt_ctr_wrap, + NULL, des_setkey_enc_wrap, des_setkey_dec_wrap, des_ctx_alloc, @@ -552,6 +559,7 @@ const cipher_base_t des_ede_info = { des3_crypt_cbc_wrap, des_crypt_cfb128_wrap, des_crypt_ctr_wrap, + NULL, des3_set2key_enc_wrap, des3_set2key_dec_wrap, des3_ctx_alloc, @@ -573,6 +581,7 @@ const cipher_base_t des_ede3_info = { des3_crypt_cbc_wrap, des_crypt_cfb128_wrap, des_crypt_ctr_wrap, + NULL, des3_set3key_enc_wrap, des3_set3key_dec_wrap, des3_ctx_alloc, @@ -661,6 +670,7 @@ const cipher_base_t blowfish_info = { blowfish_crypt_cbc_wrap, blowfish_crypt_cfb64_wrap, blowfish_crypt_ctr_wrap, + NULL, blowfish_setkey_enc_wrap, blowfish_setkey_dec_wrap, blowfish_ctx_alloc, @@ -703,15 +713,28 @@ const cipher_info_t blowfish_ctr_info = { #endif /* POLARSSL_BLOWFISH_C */ #if defined(POLARSSL_ARC4_C) -static void * arc4_ctx_alloc( void ) +static int arc4_crypt_stream_wrap( void *ctx, size_t length, + const unsigned char *input, + unsigned char *output ) { - return (void *) 1; + return( arc4_crypt( (arc4_context *) ctx, length, input, output ) ); } +static int arc4_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_length ) +{ + arc4_setup( (arc4_context *) ctx, key, key_length ); + return( 0 ); +} + +static void * arc4_ctx_alloc( void ) +{ + return polarssl_malloc( sizeof( arc4_context ) ); +} static void arc4_ctx_free( void *ctx ) { - ((void) ctx); + polarssl_free( ctx ); } const cipher_base_t arc4_base_info = { @@ -719,8 +742,9 @@ const cipher_base_t arc4_base_info = { NULL, NULL, NULL, - NULL, - NULL, + arc4_crypt_stream_wrap, + arc4_setkey_wrap, + arc4_setkey_wrap, arc4_ctx_alloc, arc4_ctx_free }; @@ -755,6 +779,7 @@ const cipher_base_t null_base_info = { NULL, NULL, NULL, + NULL, null_ctx_alloc, null_ctx_free }; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2bd41c0af..cac80a4c9 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -40,6 +40,7 @@ add_test_suite(base64) add_test_suite(blowfish) add_test_suite(camellia) add_test_suite(cipher cipher.aes) +add_test_suite(cipher cipher.arc4) add_test_suite(cipher cipher.blowfish) add_test_suite(cipher cipher.camellia) add_test_suite(cipher cipher.des) diff --git a/tests/Makefile b/tests/Makefile index 4d70858e8..ad678ea76 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -27,6 +27,7 @@ APPS = test_suite_aes.ecb test_suite_aes.cbc \ test_suite_arc4 \ test_suite_base64 test_suite_blowfish \ test_suite_camellia test_suite_cipher.aes \ + test_suite_cipher.arc4 \ test_suite_cipher.blowfish \ test_suite_cipher.camellia \ test_suite_cipher.des test_suite_cipher.null \ @@ -74,6 +75,10 @@ test_suite_cipher.aes.c : suites/test_suite_cipher.function suites/test_suite_ci echo " Generate $@" scripts/generate_code.pl suites test_suite_cipher test_suite_cipher.aes +test_suite_cipher.arc4.c : suites/test_suite_cipher.function suites/test_suite_cipher.arc4.data scripts/generate_code.pl suites/helpers.function suites/main_test.function + echo " Generate $@" + scripts/generate_code.pl suites test_suite_cipher test_suite_cipher.arc4 + test_suite_cipher.blowfish.c : suites/test_suite_cipher.function suites/test_suite_cipher.blowfish.data scripts/generate_code.pl suites/helpers.function suites/main_test.function echo " Generate $@" scripts/generate_code.pl suites test_suite_cipher test_suite_cipher.blowfish @@ -158,6 +163,10 @@ test_suite_cipher.aes: test_suite_cipher.aes.c ../library/libpolarssl.a echo " CC $@.c" $(CC) $(CFLAGS) $(OFLAGS) $@.c $(LDFLAGS) -o $@ +test_suite_cipher.arc4: test_suite_cipher.arc4.c ../library/libpolarssl.a + echo " CC $@.c" + $(CC) $(CFLAGS) $(OFLAGS) $@.c $(LDFLAGS) -o $@ + test_suite_cipher.blowfish: test_suite_cipher.blowfish.c ../library/libpolarssl.a echo " CC $@.c" $(CC) $(CFLAGS) $(OFLAGS) $@.c $(LDFLAGS) -o $@ diff --git a/tests/suites/test_suite_cipher.arc4.data b/tests/suites/test_suite_cipher.arc4.data new file mode 100644 index 000000000..93d35b35d --- /dev/null +++ b/tests/suites/test_suite_cipher.arc4.data @@ -0,0 +1,110 @@ +Cipher Selftest +depends_on:POLARSSL_SELF_TEST +cipher_selftest: + +Decrypt empty buffer +dec_empty_buf: + +ARC4 Encrypt and decrypt 0 bytes +depends_on:POLARSSL_ARC4_C +enc_dec_buf:POLARSSL_CIPHER_ARC4_128:"ARC4-128":128:0:-1 + +ARC4 Encrypt and decrypt 1 byte +depends_on:POLARSSL_ARC4_C +enc_dec_buf:POLARSSL_CIPHER_ARC4_128:"ARC4-128":128:1:-1 + +ARC4 Encrypt and decrypt 2 bytes +depends_on:POLARSSL_ARC4_C +enc_dec_buf:POLARSSL_CIPHER_ARC4_128:"ARC4-128":128:2:-1 + +ARC4 Encrypt and decrypt 7 bytes +depends_on:POLARSSL_ARC4_C +enc_dec_buf:POLARSSL_CIPHER_ARC4_128:"ARC4-128":128:7:-1 + +ARC4 Encrypt and decrypt 8 bytes +depends_on:POLARSSL_ARC4_C +enc_dec_buf:POLARSSL_CIPHER_ARC4_128:"ARC4-128":128:8:-1 + +ARC4 Encrypt and decrypt 9 bytes +depends_on:POLARSSL_ARC4_C +enc_dec_buf:POLARSSL_CIPHER_ARC4_128:"ARC4-128":128:9:-1 + +ARC4 Encrypt and decrypt 15 bytes +depends_on:POLARSSL_ARC4_C +enc_dec_buf:POLARSSL_CIPHER_ARC4_128:"ARC4-128":128:15:-1 + +ARC4 Encrypt and decrypt 16 bytes +depends_on:POLARSSL_ARC4_C +enc_dec_buf:POLARSSL_CIPHER_ARC4_128:"ARC4-128":128:16:-1 + +ARC4 Encrypt and decrypt 17 bytes +depends_on:POLARSSL_ARC4_C +enc_dec_buf:POLARSSL_CIPHER_ARC4_128:"ARC4-128":128:17:-1 + +ARC4 Encrypt and decrypt 31 bytes +depends_on:POLARSSL_ARC4_C +enc_dec_buf:POLARSSL_CIPHER_ARC4_128:"ARC4-128":128:31:-1 + +ARC4 Encrypt and decrypt 32 bytes +depends_on:POLARSSL_ARC4_C +enc_dec_buf:POLARSSL_CIPHER_ARC4_128:"ARC4-128":128:32:-1 + +ARC4 Encrypt and decrypt 32 bytes +depends_on:POLARSSL_ARC4_C +enc_dec_buf:POLARSSL_CIPHER_ARC4_128:"ARC4-128":128:33:-1 + +ARC4 Encrypt and decrypt 47 bytes +depends_on:POLARSSL_ARC4_C +enc_dec_buf:POLARSSL_CIPHER_ARC4_128:"ARC4-128":128:47:-1 + +ARC4 Encrypt and decrypt 48 bytes +depends_on:POLARSSL_ARC4_C +enc_dec_buf:POLARSSL_CIPHER_ARC4_128:"ARC4-128":128:48:-1 + +ARC4 Encrypt and decrypt 49 bytes +depends_on:POLARSSL_ARC4_C +enc_dec_buf:POLARSSL_CIPHER_ARC4_128:"ARC4-128":128:49:-1 + +ARC4 Encrypt and decrypt 0 bytes in multiple parts +depends_on:POLARSSL_ARC4_C +enc_dec_buf_multipart:POLARSSL_CIPHER_ARC4_128:128:0:0: + +ARC4 Encrypt and decrypt 1 bytes in multiple parts 1 +depends_on:POLARSSL_ARC4_C +enc_dec_buf_multipart:POLARSSL_CIPHER_ARC4_128:128:1:0: + +ARC4 Encrypt and decrypt 1 bytes in multiple parts 2 +depends_on:POLARSSL_ARC4_C +enc_dec_buf_multipart:POLARSSL_CIPHER_ARC4_128:128:0:1: + +ARC4 Encrypt and decrypt 16 bytes in multiple parts 1 +depends_on:POLARSSL_ARC4_C +enc_dec_buf_multipart:POLARSSL_CIPHER_ARC4_128:128:16:0: + +ARC4 Encrypt and decrypt 16 bytes in multiple parts 2 +depends_on:POLARSSL_ARC4_C +enc_dec_buf_multipart:POLARSSL_CIPHER_ARC4_128:128:0:16: + +ARC4 Encrypt and decrypt 16 bytes in multiple parts 3 +depends_on:POLARSSL_ARC4_C +enc_dec_buf_multipart:POLARSSL_CIPHER_ARC4_128:128:1:15: + +ARC4 Encrypt and decrypt 16 bytes in multiple parts 4 +depends_on:POLARSSL_ARC4_C +enc_dec_buf_multipart:POLARSSL_CIPHER_ARC4_128:128:15:1: + +ARC4 Encrypt and decrypt 22 bytes in multiple parts 1 +depends_on:POLARSSL_ARC4_C +enc_dec_buf_multipart:POLARSSL_CIPHER_ARC4_128:128:15:7: + +ARC4 Encrypt and decrypt 22 bytes in multiple parts 1 +depends_on:POLARSSL_ARC4_C +enc_dec_buf_multipart:POLARSSL_CIPHER_ARC4_128:128:16:6: + +ARC4 Encrypt and decrypt 22 bytes in multiple parts 1 +depends_on:POLARSSL_ARC4_C +enc_dec_buf_multipart:POLARSSL_CIPHER_ARC4_128:128:17:6: + +ARC4 Encrypt and decrypt 32 bytes in multiple parts 1 +depends_on:POLARSSL_ARC4_C +enc_dec_buf_multipart:POLARSSL_CIPHER_ARC4_128:128:16:16: From b5e85885de37f8368f293db0d343a8fca0410487 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Wed, 28 Aug 2013 16:36:14 +0200 Subject: [PATCH 2/5] Handle NULL as a stream cipher for more uniformity --- include/polarssl/cipher.h | 1 - library/cipher.c | 23 ++------------ library/cipher_wrap.c | 39 ++++++++++++++++-------- tests/suites/test_suite_cipher.null.data | 28 ++++++++--------- 4 files changed, 42 insertions(+), 49 deletions(-) diff --git a/include/polarssl/cipher.h b/include/polarssl/cipher.h index 3164a9a63..67ca28ccf 100644 --- a/include/polarssl/cipher.h +++ b/include/polarssl/cipher.h @@ -95,7 +95,6 @@ typedef enum { typedef enum { POLARSSL_MODE_NONE = 0, - POLARSSL_MODE_NULL, POLARSSL_MODE_CBC, POLARSSL_MODE_CFB, POLARSSL_MODE_OFB, diff --git a/library/cipher.c b/library/cipher.c index 5a260a0bc..60e1d911e 100644 --- a/library/cipher.c +++ b/library/cipher.c @@ -36,7 +36,7 @@ #include -#if defined(POLARSSL_ARC4_C) +#if defined(POLARSSL_ARC4_C) || defined(POLARSSL_CIPHER_NULL_CIPHER) #define POLARSSL_CIPHER_MODE_STREAM #endif @@ -367,11 +367,6 @@ int cipher_setkey( cipher_context_t *ctx, const unsigned char *key, ctx->key_length = key_length; ctx->operation = operation; -#if defined(POLARSSL_CIPHER_NULL_CIPHER) - if( ctx->cipher_info->mode == POLARSSL_MODE_NULL ) - return 0; -#endif /* defined(POLARSSL_CIPHER_NULL_CIPHER) */ - /* * For CFB and CTR mode always use the encryption key schedule */ @@ -421,19 +416,6 @@ int cipher_update( cipher_context_t *ctx, const unsigned char *input, size_t ile return POLARSSL_ERR_CIPHER_BAD_INPUT_DATA; } -#if defined(POLARSSL_CIPHER_NULL_CIPHER) - if( ctx->cipher_info->mode == POLARSSL_MODE_NULL ) - { - *olen = ilen; - - if( output == input ) - return( 0 ); - - memcpy( output, input, ilen ); - return 0; - } -#endif /* defined(POLARSSL_CIPHER_NULL_CIPHER) */ - if( ctx->cipher_info->mode == POLARSSL_MODE_CBC ) { /* @@ -725,8 +707,7 @@ int cipher_finish( cipher_context_t *ctx, unsigned char *output, size_t *olen) if( POLARSSL_MODE_CFB == ctx->cipher_info->mode || POLARSSL_MODE_CTR == ctx->cipher_info->mode || - POLARSSL_MODE_STREAM == ctx->cipher_info->mode || - POLARSSL_MODE_NULL == ctx->cipher_info->mode ) + POLARSSL_MODE_STREAM == ctx->cipher_info->mode ) { return 0; } diff --git a/library/cipher_wrap.c b/library/cipher_wrap.c index 7a4ff753b..562f8b34b 100644 --- a/library/cipher_wrap.c +++ b/library/cipher_wrap.c @@ -645,12 +645,7 @@ static int blowfish_crypt_ctr_wrap( void *ctx, size_t length, #endif } -static int blowfish_setkey_dec_wrap( void *ctx, const unsigned char *key, unsigned int key_length ) -{ - return blowfish_setkey( (blowfish_context *) ctx, key, key_length ); -} - -static int blowfish_setkey_enc_wrap( void *ctx, const unsigned char *key, unsigned int key_length ) +static int blowfish_setkey_wrap( void *ctx, const unsigned char *key, unsigned int key_length ) { return blowfish_setkey( (blowfish_context *) ctx, key, key_length ); } @@ -671,8 +666,8 @@ const cipher_base_t blowfish_info = { blowfish_crypt_cfb64_wrap, blowfish_crypt_ctr_wrap, NULL, - blowfish_setkey_enc_wrap, - blowfish_setkey_dec_wrap, + blowfish_setkey_wrap, + blowfish_setkey_wrap, blowfish_ctx_alloc, blowfish_ctx_free }; @@ -761,12 +756,30 @@ const cipher_info_t arc4_128_info = { #endif /* POLARSSL_ARC4_C */ #if defined(POLARSSL_CIPHER_NULL_CIPHER) +static int null_crypt_stream( void *ctx, size_t length, + const unsigned char *input, + unsigned char *output ) +{ + ((void) ctx); + memmove( output, input, length ); + return( 0 ); +} + +static int null_setkey( void *ctx, const unsigned char *key, + unsigned int key_length ) +{ + ((void) ctx); + ((void) key); + ((void) key_length); + + return( 0 ); +} + static void * null_ctx_alloc( void ) { return (void *) 1; } - static void null_ctx_free( void *ctx ) { ((void) ctx); @@ -777,16 +790,16 @@ const cipher_base_t null_base_info = { NULL, NULL, NULL, - NULL, - NULL, - NULL, + null_crypt_stream, + null_setkey, + null_setkey, null_ctx_alloc, null_ctx_free }; const cipher_info_t null_cipher_info = { POLARSSL_CIPHER_NULL, - POLARSSL_MODE_NULL, + POLARSSL_MODE_STREAM, 0, "NULL", 0, diff --git a/tests/suites/test_suite_cipher.null.data b/tests/suites/test_suite_cipher.null.data index 96aa36a9d..dd6827715 100644 --- a/tests/suites/test_suite_cipher.null.data +++ b/tests/suites/test_suite_cipher.null.data @@ -7,59 +7,59 @@ dec_empty_buf: NULL Encrypt and decrypt 0 bytes depends_on:POLARSSL_CIPHER_NULL_CIPHER -enc_dec_buf:POLARSSL_CIPHER_NULL:NULL:0:0 +enc_dec_buf:POLARSSL_CIPHER_NULL:"NULL":0:0:-1 NULL Encrypt and decrypt 1 bytes depends_on:POLARSSL_CIPHER_NULL_CIPHER -enc_dec_buf:POLARSSL_CIPHER_NULL:NULL:0:1 +enc_dec_buf:POLARSSL_CIPHER_NULL:"NULL":0:1:-1 NULL Encrypt and decrypt 2 bytes depends_on:POLARSSL_CIPHER_NULL_CIPHER -enc_dec_buf:POLARSSL_CIPHER_NULL:NULL:0:2 +enc_dec_buf:POLARSSL_CIPHER_NULL:"NULL":0:2:-1 NULL Encrypt and decrypt 7 bytes depends_on:POLARSSL_CIPHER_NULL_CIPHER -enc_dec_buf:POLARSSL_CIPHER_NULL:NULL:0:7 +enc_dec_buf:POLARSSL_CIPHER_NULL:"NULL":0:7:-1 NULL Encrypt and decrypt 8 bytes depends_on:POLARSSL_CIPHER_NULL_CIPHER -enc_dec_buf:POLARSSL_CIPHER_NULL:NULL:0:8 +enc_dec_buf:POLARSSL_CIPHER_NULL:"NULL":0:8:-1 NULL Encrypt and decrypt 9 bytes depends_on:POLARSSL_CIPHER_NULL_CIPHER -enc_dec_buf:POLARSSL_CIPHER_NULL:NULL:0:9 +enc_dec_buf:POLARSSL_CIPHER_NULL:"NULL":0:9:-1 NULL Encrypt and decrypt 15 bytes depends_on:POLARSSL_CIPHER_NULL_CIPHER -enc_dec_buf:POLARSSL_CIPHER_NULL:NULL:0:15 +enc_dec_buf:POLARSSL_CIPHER_NULL:"NULL":0:15:-1 NULL Encrypt and decrypt 16 bytes depends_on:POLARSSL_CIPHER_NULL_CIPHER -enc_dec_buf:POLARSSL_CIPHER_NULL:NULL:0:16 +enc_dec_buf:POLARSSL_CIPHER_NULL:"NULL":0:16:-1 NULL Encrypt and decrypt 31 bytes depends_on:POLARSSL_CIPHER_NULL_CIPHER -enc_dec_buf:POLARSSL_CIPHER_NULL:NULL:0:31 +enc_dec_buf:POLARSSL_CIPHER_NULL:"NULL":0:31:-1 NULL Encrypt and decrypt 32 bytes depends_on:POLARSSL_CIPHER_NULL_CIPHER -enc_dec_buf:POLARSSL_CIPHER_NULL:NULL:0:32 +enc_dec_buf:POLARSSL_CIPHER_NULL:"NULL":0:32:-1 NULL Encrypt and decrypt 33 bytes depends_on:POLARSSL_CIPHER_NULL_CIPHER -enc_dec_buf:POLARSSL_CIPHER_NULL:NULL:0:33 +enc_dec_buf:POLARSSL_CIPHER_NULL:"NULL":0:33:-1 NULL Encrypt and decrypt 47 bytes depends_on:POLARSSL_CIPHER_NULL_CIPHER -enc_dec_buf:POLARSSL_CIPHER_NULL:NULL:0:47 +enc_dec_buf:POLARSSL_CIPHER_NULL:"NULL":0:47:-1 NULL Encrypt and decrypt 48 bytes depends_on:POLARSSL_CIPHER_NULL_CIPHER -enc_dec_buf:POLARSSL_CIPHER_NULL:NULL:0:48 +enc_dec_buf:POLARSSL_CIPHER_NULL:"NULL":0:48:-1 NULL Encrypt and decrypt 49 bytes depends_on:POLARSSL_CIPHER_NULL_CIPHER -enc_dec_buf:POLARSSL_CIPHER_NULL:NULL:0:49 +enc_dec_buf:POLARSSL_CIPHER_NULL:"NULL":0:49:-1 NULL Encrypt and decrypt 1 bytes in multiple parts 1 depends_on:POLARSSL_CIPHER_NULL_CIPHER From 07f8fa5a69f09bf2bba24a0c93fc3333e4d42a3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Fri, 30 Aug 2013 18:34:08 +0200 Subject: [PATCH 3/5] GCM in the cipher layer, step 1 - no support for additional data - no support for tag --- library/cipher.c | 70 ++++++++++++++- library/cipher_wrap.c | 35 +++++++- library/gcm.c | 4 +- tests/CMakeLists.txt | 1 + tests/Makefile | 10 ++- tests/suites/test_suite_cipher.function | 2 +- tests/suites/test_suite_cipher.gcm.data | 110 ++++++++++++++++++++++++ 7 files changed, 225 insertions(+), 7 deletions(-) create mode 100644 tests/suites/test_suite_cipher.gcm.data diff --git a/library/cipher.c b/library/cipher.c index 60e1d911e..733f6e5f9 100644 --- a/library/cipher.c +++ b/library/cipher.c @@ -34,6 +34,10 @@ #include "polarssl/cipher.h" #include "polarssl/cipher_wrap.h" +#if defined(POLARSSL_GCM_C) +#include "polarssl/gcm.h" +#endif + #include #if defined(POLARSSL_ARC4_C) || defined(POLARSSL_CIPHER_NULL_CIPHER) @@ -285,7 +289,14 @@ const cipher_info_t *cipher_info_from_string( const char *cipher_name ) if( !strcasecmp( "AES-256-CTR", cipher_name ) ) return cipher_info_from_type( POLARSSL_CIPHER_AES_256_CTR ); #endif /* defined(POLARSSL_CIPHER_MODE_CTR) */ + +#if defined(POLARSSL_GCM_C) + if( !strcasecmp( "AES-128-GCM", cipher_name ) ) + return cipher_info_from_type( POLARSSL_CIPHER_AES_128_GCM ); + if( !strcasecmp( "AES-256-GCM", cipher_name ) ) + return cipher_info_from_type( POLARSSL_CIPHER_AES_256_GCM ); #endif +#endif /* POLARSSL_AES_C */ #if defined(POLARSSL_ARC4_C) if( !strcasecmp( "ARC4-128", cipher_name ) ) @@ -392,6 +403,16 @@ int cipher_reset( cipher_context_t *ctx, const unsigned char *iv ) ctx->unprocessed_len = 0; +#if defined(POLARSSL_GCM_C) + if( POLARSSL_MODE_GCM == ctx->cipher_info->mode ) + { + // TODO: allow other IV length + // TODO: allow additional data + return gcm_starts( ctx->cipher_ctx, ctx->operation, + iv, 12, (unsigned char *) "", 0 ); + } +#endif + memcpy( ctx->iv, iv, cipher_get_iv_size( ctx ) ); return 0; @@ -416,7 +437,8 @@ int cipher_update( cipher_context_t *ctx, const unsigned char *input, size_t ile return POLARSSL_ERR_CIPHER_BAD_INPUT_DATA; } - if( ctx->cipher_info->mode == POLARSSL_MODE_CBC ) + if( ctx->cipher_info->mode == POLARSSL_MODE_CBC || + ctx->cipher_info->mode == POLARSSL_MODE_GCM ) { /* * If there is not enough data for a full block, cache it. @@ -443,6 +465,18 @@ int cipher_update( cipher_context_t *ctx, const unsigned char *input, size_t ile memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ), input, copy_len ); +#if defined(POLARSSL_GCM_C) + if( ctx->cipher_info->mode == POLARSSL_MODE_GCM ) + { + if( 0 != ( ret = gcm_update( ctx->cipher_ctx, + cipher_get_block_size( ctx ), + ctx->unprocessed_data, output ) ) ) + { + return ret; + } + } + else +#endif if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx, ctx->operation, cipher_get_block_size( ctx ), ctx->iv, ctx->unprocessed_data, output ) ) ) @@ -479,11 +513,23 @@ int cipher_update( cipher_context_t *ctx, const unsigned char *input, size_t ile */ if( ilen ) { +#if defined(POLARSSL_GCM_C) + if( ctx->cipher_info->mode == POLARSSL_MODE_GCM ) + { + if( 0 != ( ret = gcm_update( ctx->cipher_ctx, + ilen, input, output ) ) ) + { + return ret; + } + } + else +#endif if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx, ctx->operation, ilen, ctx->iv, input, output ) ) ) { return ret; } + *olen += ilen; } @@ -712,6 +758,28 @@ int cipher_finish( cipher_context_t *ctx, unsigned char *output, size_t *olen) return 0; } +#if defined(POLARSSL_GCM_C) + if( POLARSSL_MODE_GCM == ctx->cipher_info->mode ) + { + size_t tag_len = 0; // TODO + unsigned char tag[16]; + + if( 0 != ( ret = gcm_update( ctx->cipher_ctx, + ctx->unprocessed_len, ctx->unprocessed_data, + output ) ) ) + { + return( ret ); + } + + *olen += ctx->unprocessed_len; + + if( 0 != ( ret = gcm_finish( ctx->cipher_ctx, tag, tag_len ) ) ) + return( ret ); + + return( 0 ); + } +#endif + if( POLARSSL_MODE_CBC == ctx->cipher_info->mode ) { if( POLARSSL_ENCRYPT == ctx->operation ) diff --git a/library/cipher_wrap.c b/library/cipher_wrap.c index 562f8b34b..c8eee5432 100644 --- a/library/cipher_wrap.c +++ b/library/cipher_wrap.c @@ -53,6 +53,10 @@ #include "polarssl/blowfish.h" #endif +#if defined(POLARSSL_GCM_C) +#include "polarssl/gcm.h" +#endif + #if defined(POLARSSL_MEMORY_C) #include "polarssl/memory.h" #else @@ -235,6 +239,33 @@ const cipher_info_t aes_256_ctr_info = { #endif /* POLARSSL_CIPHER_MODE_CTR */ #if defined(POLARSSL_GCM_C) +static void *gcm_ctx_alloc( void ) +{ + return polarssl_malloc( sizeof( gcm_context ) ); +} + +static void gcm_ctx_free( void *ctx ) +{ + polarssl_free( ctx ); +} + +static int gcm_setkey_wrap( void *ctx, const unsigned char *key, unsigned int key_length ) +{ + return gcm_init( (gcm_context *) ctx, key, key_length ); +} + +const cipher_base_t gcm_aes_info = { + POLARSSL_CIPHER_ID_AES, + NULL, + NULL, + NULL, + NULL, + gcm_setkey_wrap, + gcm_setkey_wrap, + gcm_ctx_alloc, + gcm_ctx_free, +}; + const cipher_info_t aes_128_gcm_info = { POLARSSL_CIPHER_AES_128_GCM, POLARSSL_MODE_GCM, @@ -242,7 +273,7 @@ const cipher_info_t aes_128_gcm_info = { "AES-128-GCM", 16, 16, - &aes_info + &gcm_aes_info }; const cipher_info_t aes_256_gcm_info = { @@ -252,7 +283,7 @@ const cipher_info_t aes_256_gcm_info = { "AES-256-GCM", 16, 16, - &aes_info + &gcm_aes_info }; #endif /* POLARSSL_GCM_C */ diff --git a/library/gcm.c b/library/gcm.c index 3e9969d3b..9c079bddd 100644 --- a/library/gcm.c +++ b/library/gcm.c @@ -293,11 +293,11 @@ int gcm_finish( gcm_context *ctx, uint64_t orig_len = ctx->len * 8; uint64_t orig_add_len = ctx->add_len * 8; - memcpy( tag, ctx->base_ectr, tag_len ); - if( tag_len > 16 ) return( POLARSSL_ERR_GCM_BAD_INPUT ); + memcpy( tag, ctx->base_ectr, tag_len ); + if( orig_len || orig_add_len ) { memset( work_buf, 0x00, 16 ); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index cac80a4c9..20f3c8d94 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -44,6 +44,7 @@ add_test_suite(cipher cipher.arc4) add_test_suite(cipher cipher.blowfish) add_test_suite(cipher cipher.camellia) add_test_suite(cipher cipher.des) +add_test_suite(cipher cipher.gcm) add_test_suite(cipher cipher.null) add_test_suite(cipher cipher.padding) add_test_suite(ctr_drbg) diff --git a/tests/Makefile b/tests/Makefile index ad678ea76..4d2bcba61 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -27,7 +27,7 @@ APPS = test_suite_aes.ecb test_suite_aes.cbc \ test_suite_arc4 \ test_suite_base64 test_suite_blowfish \ test_suite_camellia test_suite_cipher.aes \ - test_suite_cipher.arc4 \ + test_suite_cipher.arc4 test_suite_cipher.gcm \ test_suite_cipher.blowfish \ test_suite_cipher.camellia \ test_suite_cipher.des test_suite_cipher.null \ @@ -79,6 +79,10 @@ test_suite_cipher.arc4.c : suites/test_suite_cipher.function suites/test_suite_c echo " Generate $@" scripts/generate_code.pl suites test_suite_cipher test_suite_cipher.arc4 +test_suite_cipher.gcm.c : suites/test_suite_cipher.function suites/test_suite_cipher.gcm.data scripts/generate_code.pl suites/helpers.function suites/main_test.function + echo " Generate $@" + scripts/generate_code.pl suites test_suite_cipher test_suite_cipher.gcm + test_suite_cipher.blowfish.c : suites/test_suite_cipher.function suites/test_suite_cipher.blowfish.data scripts/generate_code.pl suites/helpers.function suites/main_test.function echo " Generate $@" scripts/generate_code.pl suites test_suite_cipher test_suite_cipher.blowfish @@ -167,6 +171,10 @@ test_suite_cipher.arc4: test_suite_cipher.arc4.c ../library/libpolarssl.a echo " CC $@.c" $(CC) $(CFLAGS) $(OFLAGS) $@.c $(LDFLAGS) -o $@ +test_suite_cipher.gcm: test_suite_cipher.gcm.c ../library/libpolarssl.a + echo " CC $@.c" + $(CC) $(CFLAGS) $(OFLAGS) $@.c $(LDFLAGS) -o $@ + test_suite_cipher.blowfish: test_suite_cipher.blowfish.c ../library/libpolarssl.a echo " CC $@.c" $(CC) $(CFLAGS) $(OFLAGS) $@.c $(LDFLAGS) -o $@ diff --git a/tests/suites/test_suite_cipher.function b/tests/suites/test_suite_cipher.function index 1f7943a44..537720872 100644 --- a/tests/suites/test_suite_cipher.function +++ b/tests/suites/test_suite_cipher.function @@ -248,7 +248,7 @@ void enc_dec_buf_multipart( int cipher_id, int key_len, int first_length_val, TEST_ASSERT( totaloutlen == length || ( totaloutlen % cipher_get_block_size( &ctx_dec ) == 0 && totaloutlen < length && - totaloutlen + cipher_get_block_size( &ctx_dec ) > length ) ); + totaloutlen + cipher_get_block_size( &ctx_dec ) >= length ) ); TEST_ASSERT( 0 == cipher_finish( &ctx_dec, decbuf + outlen, &outlen ) ); totaloutlen += outlen; diff --git a/tests/suites/test_suite_cipher.gcm.data b/tests/suites/test_suite_cipher.gcm.data new file mode 100644 index 000000000..aacdca8eb --- /dev/null +++ b/tests/suites/test_suite_cipher.gcm.data @@ -0,0 +1,110 @@ +Cipher Selftest +depends_on:POLARSSL_SELF_TEST +cipher_selftest: + +Decrypt empty buffer +dec_empty_buf: + +AES-GCM Encrypt and decrypt 0 bytes +depends_on:POLARSSL_AES_C:POLARSSL_GCM_C +enc_dec_buf:POLARSSL_CIPHER_AES_128_GCM:"AES-128-GCM":128:0:-1 + +AES 128 GCM Encrypt and decrypt 1 byte +depends_on:POLARSSL_AES_C:POLARSSL_GCM_C +enc_dec_buf:POLARSSL_CIPHER_AES_128_GCM:"AES-128-GCM":128:1:-1 + +AES 128 GCM Encrypt and decrypt 2 bytes +depends_on:POLARSSL_AES_C:POLARSSL_GCM_C +enc_dec_buf:POLARSSL_CIPHER_AES_128_GCM:"AES-128-GCM":128:2:-1 + +AES 128 GCM Encrypt and decrypt 7 bytes +depends_on:POLARSSL_AES_C:POLARSSL_GCM_C +enc_dec_buf:POLARSSL_CIPHER_AES_128_GCM:"AES-128-GCM":128:7:-1 + +AES 128 GCM Encrypt and decrypt 8 bytes +depends_on:POLARSSL_AES_C:POLARSSL_GCM_C +enc_dec_buf:POLARSSL_CIPHER_AES_128_GCM:"AES-128-GCM":128:8:-1 + +AES 128 GCM Encrypt and decrypt 9 bytes +depends_on:POLARSSL_AES_C:POLARSSL_GCM_C +enc_dec_buf:POLARSSL_CIPHER_AES_128_GCM:"AES-128-GCM":128:9:-1 + +AES 128 GCM Encrypt and decrypt 15 bytes +depends_on:POLARSSL_AES_C:POLARSSL_GCM_C +enc_dec_buf:POLARSSL_CIPHER_AES_128_GCM:"AES-128-GCM":128:15:-1 + +AES 128 GCM Encrypt and decrypt 16 bytes +depends_on:POLARSSL_AES_C:POLARSSL_GCM_C +enc_dec_buf:POLARSSL_CIPHER_AES_128_GCM:"AES-128-GCM":128:16:-1 + +AES 128 GCM Encrypt and decrypt 17 bytes +depends_on:POLARSSL_AES_C:POLARSSL_GCM_C +enc_dec_buf:POLARSSL_CIPHER_AES_128_GCM:"AES-128-GCM":128:17:-1 + +AES 128 GCM Encrypt and decrypt 31 bytes +depends_on:POLARSSL_AES_C:POLARSSL_GCM_C +enc_dec_buf:POLARSSL_CIPHER_AES_128_GCM:"AES-128-GCM":128:31:-1 + +AES 128 GCM Encrypt and decrypt 32 bytes +depends_on:POLARSSL_AES_C:POLARSSL_GCM_C +enc_dec_buf:POLARSSL_CIPHER_AES_128_GCM:"AES-128-GCM":128:32:-1 + +AES 128 GCM Encrypt and decrypt 32 bytes +depends_on:POLARSSL_AES_C:POLARSSL_GCM_C +enc_dec_buf:POLARSSL_CIPHER_AES_128_GCM:"AES-128-GCM":128:33:-1 + +AES 128 GCM Encrypt and decrypt 47 bytes +depends_on:POLARSSL_AES_C:POLARSSL_GCM_C +enc_dec_buf:POLARSSL_CIPHER_AES_128_GCM:"AES-128-GCM":128:47:-1 + +AES 128 GCM Encrypt and decrypt 48 bytes +depends_on:POLARSSL_AES_C:POLARSSL_GCM_C +enc_dec_buf:POLARSSL_CIPHER_AES_128_GCM:"AES-128-GCM":128:48:-1 + +AES 128 GCM Encrypt and decrypt 49 bytes +depends_on:POLARSSL_AES_C:POLARSSL_GCM_C +enc_dec_buf:POLARSSL_CIPHER_AES_128_GCM:"AES-128-GCM":128:49:-1 + +AES 128 GCM Encrypt and decrypt 0 bytes in multiple parts +depends_on:POLARSSL_AES_C:POLARSSL_GCM_C +enc_dec_buf_multipart:POLARSSL_CIPHER_AES_128_GCM:128:0:0 + +AES 128 GCM Encrypt and decrypt 1 bytes in multiple parts 1 +depends_on:POLARSSL_AES_C:POLARSSL_GCM_C +enc_dec_buf_multipart:POLARSSL_CIPHER_AES_128_GCM:128:1:0 + +AES 128 GCM Encrypt and decrypt 1 bytes in multiple parts 2 +depends_on:POLARSSL_AES_C:POLARSSL_GCM_C +enc_dec_buf_multipart:POLARSSL_CIPHER_AES_128_GCM:128:0:1 + +AES 128 GCM Encrypt and decrypt 16 bytes in multiple parts 1 +depends_on:POLARSSL_AES_C:POLARSSL_GCM_C +enc_dec_buf_multipart:POLARSSL_CIPHER_AES_128_GCM:128:16:0 + +AES 128 GCM Encrypt and decrypt 16 bytes in multiple parts 2 +depends_on:POLARSSL_AES_C:POLARSSL_GCM_C +enc_dec_buf_multipart:POLARSSL_CIPHER_AES_128_GCM:128:0:16 + +AES 128 GCM Encrypt and decrypt 16 bytes in multiple parts 3 +depends_on:POLARSSL_AES_C:POLARSSL_GCM_C +enc_dec_buf_multipart:POLARSSL_CIPHER_AES_128_GCM:128:1:15 + +AES 128 GCM Encrypt and decrypt 16 bytes in multiple parts 4 +depends_on:POLARSSL_AES_C:POLARSSL_GCM_C +enc_dec_buf_multipart:POLARSSL_CIPHER_AES_128_GCM:128:15:1 + +AES 128 GCM Encrypt and decrypt 22 bytes in multiple parts 1 +depends_on:POLARSSL_AES_C:POLARSSL_GCM_C +enc_dec_buf_multipart:POLARSSL_CIPHER_AES_128_GCM:128:15:7 + +AES 128 GCM Encrypt and decrypt 22 bytes in multiple parts 1 +depends_on:POLARSSL_AES_C:POLARSSL_GCM_C +enc_dec_buf_multipart:POLARSSL_CIPHER_AES_128_GCM:128:16:6 + +AES 128 GCM Encrypt and decrypt 22 bytes in multiple parts 1 +depends_on:POLARSSL_AES_C:POLARSSL_GCM_C +enc_dec_buf_multipart:POLARSSL_CIPHER_AES_128_GCM:128:17:6 + +AES 128 GCM Encrypt and decrypt 32 bytes in multiple parts 1 +depends_on:POLARSSL_AES_C:POLARSSL_GCM_C +enc_dec_buf_multipart:POLARSSL_CIPHER_AES_128_GCM:128:16:16 From 20d6a17af99ad538db902dbebf16879c0b3de687 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Sat, 31 Aug 2013 16:37:46 +0200 Subject: [PATCH 4/5] Make GCM tag check "constant-time" --- library/gcm.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/library/gcm.c b/library/gcm.c index 9c079bddd..104fda3a4 100644 --- a/library/gcm.c +++ b/library/gcm.c @@ -357,15 +357,22 @@ int gcm_auth_decrypt( gcm_context *ctx, unsigned char *output ) { unsigned char check_tag[16]; + size_t i; + int diff; gcm_crypt_and_tag( ctx, GCM_DECRYPT, length, iv, iv_len, add, add_len, input, output, tag_len, check_tag ); - if( memcmp( check_tag, tag, tag_len ) == 0 ) - return( 0 ); + /* Check tag in "constant-time" */ + for( diff = 0, i = 0; i < tag_len; i++ ) + diff |= tag[i] ^ check_tag[i]; - memset( output, 0, length ); + if( diff != 0 ) + { + memset( output, 0, length ); + return( POLARSSL_ERR_GCM_AUTH_FAILED ); + } - return( POLARSSL_ERR_GCM_AUTH_FAILED ); + return( 0 ); } #if defined(POLARSSL_SELF_TEST) From 9241be7ac56cf5bf76487e77f710961eaddc762b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Sat, 31 Aug 2013 17:31:03 +0200 Subject: [PATCH 5/5] Change cipher prototypes for GCM --- include/polarssl/cipher.h | 22 ++++++++++--- include/polarssl/gcm.h | 8 ++--- library/cipher.c | 41 ++++++++++++++++++++----- library/cipher_wrap.c | 4 +-- library/gcm.c | 3 +- library/pkcs12.c | 7 +++-- library/pkcs5.c | 7 +++-- programs/aes/crypt_and_hash.c | 8 ++--- tests/suites/test_suite_cipher.function | 33 ++++++++++++-------- 9 files changed, 94 insertions(+), 39 deletions(-) diff --git a/include/polarssl/cipher.h b/include/polarssl/cipher.h index 67ca28ccf..ef037be5d 100644 --- a/include/polarssl/cipher.h +++ b/include/polarssl/cipher.h @@ -320,7 +320,7 @@ static inline cipher_mode_t cipher_get_cipher_mode( const cipher_context_t *ctx * \param ctx cipher's context. Must have been initialised. * * \return size of the cipher's IV, or 0 if ctx has not been - * initialised. + * initialised or accepts IV of various sizes. */ static inline int cipher_get_iv_size( const cipher_context_t *ctx ) { @@ -432,11 +432,18 @@ int cipher_set_padding_mode( cipher_context_t *ctx, cipher_padding_t mode ); * * \param ctx generic cipher context * \param iv IV to use or NONCE_COUNTER in the case of a CTR-mode cipher + * \param iv_len IV length for ciphers with variable-size IV, + * Discared by ciphers with fixed-size IV. + * \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, const unsigned char *iv ); +int cipher_reset( cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len, + const unsigned char *ad, size_t ad_len ); /** * \brief Generic cipher update function. Encrypts/decrypts @@ -471,8 +478,13 @@ int cipher_update( cipher_context_t *ctx, const unsigned char *input, size_t ile * the last block, and written to the output buffer. * * \param ctx Generic cipher context - * \param output buffer to write data to. Needs block_size data available. + * \param output buffer to write data to. Needs block_size available. * \param olen length of the data written to the output buffer. + * \param tag Ignore by non-AEAD ciphers. For AEAD ciphers: + * - on encryption: buffer to write the tag; + * - on decryption: tag to verify. + * May be NULL if tag_len is zero. + * \param tag_len Length of the tag to write/check for AEAD ciphers. * * \returns 0 on success, POLARSSL_ERR_CIPHER_BAD_INPUT_DATA if * parameter verification fails, @@ -481,7 +493,9 @@ int cipher_update( cipher_context_t *ctx, const unsigned char *input, size_t ile * POLARSSL_ERR_CIPHER_INVALID_PADDING on invalid padding * while decrypting or a cipher specific error code. */ -int cipher_finish( cipher_context_t *ctx, unsigned char *output, size_t *olen); +int cipher_finish( cipher_context_t *ctx, + unsigned char *output, size_t *olen, + unsigned char *tag, size_t tag_len ); /** * \brief Checkup routine diff --git a/include/polarssl/gcm.h b/include/polarssl/gcm.h index 2bed34288..dc058dcd7 100644 --- a/include/polarssl/gcm.h +++ b/include/polarssl/gcm.h @@ -146,7 +146,7 @@ int gcm_auth_decrypt( gcm_context *ctx, * \param mode GCM_ENCRYPT or GCM_DECRYPT * \param iv initialization vector * \param iv_len length of IV - * \param add additional data + * \param add additional data (or NULL if length is 0) * \param add_len length of additional data * * \return 0 if successful @@ -182,14 +182,14 @@ int gcm_update( gcm_context *ctx, /** * \brief Generic GCM finalisation function. Wraps up the GCM stream - * and generated the tag. The tag can have a maximum length of + * and generates the tag. The tag can have a maximum length of * 16 bytes. * * \param ctx GCM context - * \param tag buffer for holding the tag + * \param tag buffer for holding the tag (may be NULL if tag_len is 0) * \param tag_len length of the tag to generate * - * \return 0 if successful or POLARSSL_ERR_GCM_BAD_INPUT + * \return 0 if successful or POLARSSL_ERR_GCM_BAD_INPUT */ int gcm_finish( gcm_context *ctx, unsigned char *tag, diff --git a/library/cipher.c b/library/cipher.c index 733f6e5f9..d7cac05f0 100644 --- a/library/cipher.c +++ b/library/cipher.c @@ -396,7 +396,9 @@ int cipher_setkey( cipher_context_t *ctx, const unsigned char *key, return POLARSSL_ERR_CIPHER_BAD_INPUT_DATA; } -int cipher_reset( cipher_context_t *ctx, const unsigned char *iv ) +int cipher_reset( cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len, + const unsigned char *ad, size_t ad_len ) { if( NULL == ctx || NULL == ctx->cipher_info || NULL == iv ) return POLARSSL_ERR_CIPHER_BAD_INPUT_DATA; @@ -406,11 +408,13 @@ int cipher_reset( cipher_context_t *ctx, const unsigned char *iv ) #if defined(POLARSSL_GCM_C) if( POLARSSL_MODE_GCM == ctx->cipher_info->mode ) { - // TODO: allow other IV length - // TODO: allow additional data return gcm_starts( ctx->cipher_ctx, ctx->operation, - iv, 12, (unsigned char *) "", 0 ); + iv, iv_len, ad, ad_len ); } +#else + ((void) ad); + ((void) ad_len); + ((void) iv_len); #endif memcpy( ctx->iv, iv, cipher_get_iv_size( ctx ) ); @@ -742,7 +746,9 @@ static int get_no_padding( unsigned char *input, size_t input_len, return 0; } -int cipher_finish( cipher_context_t *ctx, unsigned char *output, size_t *olen) +int cipher_finish( cipher_context_t *ctx, + unsigned char *output, size_t *olen, + unsigned char *tag, size_t tag_len ) { int ret = 0; @@ -761,8 +767,9 @@ int cipher_finish( cipher_context_t *ctx, unsigned char *output, size_t *olen) #if defined(POLARSSL_GCM_C) if( POLARSSL_MODE_GCM == ctx->cipher_info->mode ) { - size_t tag_len = 0; // TODO - unsigned char tag[16]; + unsigned char check_tag[16]; + size_t i; + int diff; if( 0 != ( ret = gcm_update( ctx->cipher_ctx, ctx->unprocessed_len, ctx->unprocessed_data, @@ -773,11 +780,29 @@ int cipher_finish( cipher_context_t *ctx, unsigned char *output, size_t *olen) *olen += ctx->unprocessed_len; - if( 0 != ( ret = gcm_finish( ctx->cipher_ctx, tag, tag_len ) ) ) + if( 0 != ( ret = gcm_finish( ctx->cipher_ctx, check_tag, tag_len ) ) ) return( ret ); + /* On encryption, write the tag */ + if( POLARSSL_ENCRYPT == ctx->operation ) + { + if( tag_len != 0 ) + memcpy( tag, check_tag, tag_len ); + return( 0 ); + } + + /* 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 ); + return( 0 ); } +#else + ((void) tag); + ((void) tag_len); #endif if( POLARSSL_MODE_CBC == ctx->cipher_info->mode ) diff --git a/library/cipher_wrap.c b/library/cipher_wrap.c index c8eee5432..5c9810056 100644 --- a/library/cipher_wrap.c +++ b/library/cipher_wrap.c @@ -271,7 +271,7 @@ const cipher_info_t aes_128_gcm_info = { POLARSSL_MODE_GCM, 128, "AES-128-GCM", - 16, + 0, 16, &gcm_aes_info }; @@ -281,7 +281,7 @@ const cipher_info_t aes_256_gcm_info = { POLARSSL_MODE_GCM, 256, "AES-256-GCM", - 16, + 0, 16, &gcm_aes_info }; diff --git a/library/gcm.c b/library/gcm.c index 104fda3a4..99036a05c 100644 --- a/library/gcm.c +++ b/library/gcm.c @@ -296,7 +296,8 @@ int gcm_finish( gcm_context *ctx, if( tag_len > 16 ) return( POLARSSL_ERR_GCM_BAD_INPUT ); - memcpy( tag, ctx->base_ectr, tag_len ); + if( tag_len != 0 ) + memcpy( tag, ctx->base_ectr, tag_len ); if( orig_len || orig_add_len ) { diff --git a/library/pkcs12.c b/library/pkcs12.c index e0d7207ce..9ccb60ab7 100644 --- a/library/pkcs12.c +++ b/library/pkcs12.c @@ -184,7 +184,7 @@ int pkcs12_pbe( asn1_buf *pbe_params, int mode, if( ( ret = cipher_setkey( &cipher_ctx, key, keylen, mode ) ) != 0 ) goto exit; - if( ( ret = cipher_reset( &cipher_ctx, iv ) ) != 0 ) + if( ( ret = cipher_reset( &cipher_ctx, iv, 0, NULL, 0 ) ) != 0 ) goto exit; if( ( ret = cipher_update( &cipher_ctx, data, len, @@ -193,8 +193,11 @@ int pkcs12_pbe( asn1_buf *pbe_params, int mode, goto exit; } - if( ( ret = cipher_finish( &cipher_ctx, output + olen, &olen ) ) != 0 ) + if( ( ret = cipher_finish( &cipher_ctx, output + olen, &olen, NULL, 0 ) ) + != 0 ) + { ret = POLARSSL_ERR_PKCS12_PASSWORD_MISMATCH; + } exit: cipher_free_ctx( &cipher_ctx ); diff --git a/library/pkcs5.c b/library/pkcs5.c index 9e3ce9332..2b6a75a92 100644 --- a/library/pkcs5.c +++ b/library/pkcs5.c @@ -187,7 +187,7 @@ int pkcs5_pbes2( asn1_buf *pbe_params, int mode, if( ( ret = cipher_setkey( &cipher_ctx, key, keylen, mode ) ) != 0 ) goto exit; - if( ( ret = cipher_reset( &cipher_ctx, iv ) ) != 0 ) + if( ( ret = cipher_reset( &cipher_ctx, iv, 0, NULL, 0 ) ) != 0 ) goto exit; if( ( ret = cipher_update( &cipher_ctx, data, datalen, @@ -196,8 +196,11 @@ int pkcs5_pbes2( asn1_buf *pbe_params, int mode, goto exit; } - if( ( ret = cipher_finish( &cipher_ctx, output + olen, &olen ) ) != 0 ) + if( ( ret = cipher_finish( &cipher_ctx, output + olen, &olen, NULL, 0 ) ) + != 0 ) + { ret = POLARSSL_ERR_PKCS5_PASSWORD_MISMATCH; + } exit: md_free_ctx( &md_ctx ); diff --git a/programs/aes/crypt_and_hash.c b/programs/aes/crypt_and_hash.c index 47b17d523..a9b862e7a 100644 --- a/programs/aes/crypt_and_hash.c +++ b/programs/aes/crypt_and_hash.c @@ -306,7 +306,7 @@ int main( int argc, char *argv[] ) fprintf( stderr, "cipher_setkey() returned error\n"); goto exit; } - if( cipher_reset( &cipher_ctx, IV ) != 0 ) + if( cipher_reset( &cipher_ctx, IV, 16, NULL, 0 ) != 0 ) { fprintf( stderr, "cipher_reset() returned error\n"); goto exit; @@ -338,7 +338,7 @@ int main( int argc, char *argv[] ) } } - if( cipher_finish( &cipher_ctx, output, &olen ) != 0 ) + if( cipher_finish( &cipher_ctx, output, &olen, NULL, 0 ) != 0 ) { fprintf( stderr, "cipher_finish() returned error\n" ); goto exit; @@ -424,7 +424,7 @@ int main( int argc, char *argv[] ) cipher_setkey( &cipher_ctx, digest, cipher_info->key_length, POLARSSL_DECRYPT ); - cipher_reset( &cipher_ctx, IV); + cipher_reset( &cipher_ctx, IV, 16, NULL, 0 ); md_hmac_starts( &md_ctx, digest, 32 ); @@ -455,7 +455,7 @@ int main( int argc, char *argv[] ) /* * Write the final block of data */ - cipher_finish( &cipher_ctx, output, &olen ); + cipher_finish( &cipher_ctx, output, &olen, NULL, 0 ); if( fwrite( output, 1, olen, fout ) != olen ) { diff --git a/tests/suites/test_suite_cipher.function b/tests/suites/test_suite_cipher.function index 537720872..b1814fab0 100644 --- a/tests/suites/test_suite_cipher.function +++ b/tests/suites/test_suite_cipher.function @@ -14,6 +14,8 @@ void enc_dec_buf( int cipher_id, char *cipher_string, int key_len, size_t length = length_val; unsigned char key[32]; unsigned char iv[16]; + unsigned char ad[13]; + unsigned char tag[16]; const cipher_info_t *cipher_info; cipher_context_t ctx_dec; @@ -35,6 +37,8 @@ void enc_dec_buf( int cipher_id, char *cipher_string, int key_len, memset( inbuf, 5, 64 ); memset( encbuf, 0, 64 ); memset( decbuf, 0, 64 ); + memset( tag, 0, 16 ); + memset( ad, 0x2a, 13 ); /* Check and get info structures */ cipher_info = cipher_info_from_type( cipher_id ); @@ -54,8 +58,8 @@ void enc_dec_buf( int cipher_id, char *cipher_string, int key_len, TEST_ASSERT( 0 == cipher_set_padding_mode( &ctx_enc, pad_mode ) ); } - TEST_ASSERT( 0 == cipher_reset( &ctx_dec, iv ) ); - TEST_ASSERT( 0 == cipher_reset( &ctx_enc, iv ) ); + TEST_ASSERT( 0 == cipher_reset( &ctx_dec, iv, 16, ad, 13 ) ); + TEST_ASSERT( 0 == cipher_reset( &ctx_enc, iv, 16, ad, 13 ) ); /* encode length number of bytes from inbuf */ TEST_ASSERT( 0 == cipher_update( &ctx_enc, inbuf, length, encbuf, &outlen ) ); @@ -66,7 +70,8 @@ void enc_dec_buf( int cipher_id, char *cipher_string, int key_len, total_len < length && total_len + cipher_get_block_size( &ctx_enc ) > length ) ); - TEST_ASSERT( 0 == cipher_finish( &ctx_enc, encbuf + outlen, &outlen ) ); + TEST_ASSERT( 0 == cipher_finish( &ctx_enc, encbuf + outlen, &outlen, + tag, 16 ) ); total_len += outlen; TEST_ASSERT( total_len == length || @@ -83,7 +88,8 @@ void enc_dec_buf( int cipher_id, char *cipher_string, int key_len, total_len < length && total_len + cipher_get_block_size( &ctx_dec ) >= length ) ); - TEST_ASSERT( 0 == cipher_finish( &ctx_dec, decbuf + outlen, &outlen ) ); + TEST_ASSERT( 0 == cipher_finish( &ctx_dec, decbuf + outlen, &outlen, + tag, 16 ) ); total_len += outlen; TEST_ASSERT( total_len == length ); @@ -127,11 +133,11 @@ void enc_fail( int cipher_id, int pad_mode, int key_len, TEST_ASSERT( 0 == cipher_init_ctx( &ctx, cipher_info ) ); TEST_ASSERT( 0 == cipher_setkey( &ctx, key, key_len, POLARSSL_ENCRYPT ) ); TEST_ASSERT( 0 == cipher_set_padding_mode( &ctx, pad_mode ) ); - TEST_ASSERT( 0 == cipher_reset( &ctx, iv ) ); + TEST_ASSERT( 0 == cipher_reset( &ctx, iv, 16, NULL, 0 ) ); /* encode length number of bytes from inbuf */ TEST_ASSERT( 0 == cipher_update( &ctx, inbuf, length, encbuf, &outlen ) ); - TEST_ASSERT( ret == cipher_finish( &ctx, encbuf + outlen, &outlen ) ); + TEST_ASSERT( ret == cipher_finish( &ctx, encbuf + outlen, &outlen, NULL, 0 ) ); /* done */ TEST_ASSERT( 0 == cipher_free_ctx( &ctx ) ); @@ -168,12 +174,13 @@ void dec_empty_buf() TEST_ASSERT( 0 == cipher_setkey( &ctx_dec, key, 128, POLARSSL_DECRYPT ) ); - TEST_ASSERT( 0 == cipher_reset( &ctx_dec, iv ) ); + TEST_ASSERT( 0 == cipher_reset( &ctx_dec, iv, 16, NULL, 0 ) ); /* decode 0-byte string */ TEST_ASSERT( 0 == cipher_update( &ctx_dec, encbuf, 0, decbuf, &outlen ) ); TEST_ASSERT( 0 == outlen ); - TEST_ASSERT( POLARSSL_ERR_CIPHER_FULL_BLOCK_EXPECTED == cipher_finish( &ctx_dec, decbuf + outlen, &outlen ) ); + TEST_ASSERT( POLARSSL_ERR_CIPHER_FULL_BLOCK_EXPECTED == cipher_finish( + &ctx_dec, decbuf + outlen, &outlen, NULL, 0 ) ); TEST_ASSERT( 0 == outlen ); TEST_ASSERT( 0 == cipher_free_ctx( &ctx_dec ) ); @@ -221,8 +228,8 @@ void enc_dec_buf_multipart( int cipher_id, int key_len, int first_length_val, TEST_ASSERT( 0 == cipher_setkey( &ctx_dec, key, key_len, POLARSSL_DECRYPT ) ); TEST_ASSERT( 0 == cipher_setkey( &ctx_enc, key, key_len, POLARSSL_ENCRYPT ) ); - TEST_ASSERT( 0 == cipher_reset( &ctx_dec, iv ) ); - TEST_ASSERT( 0 == cipher_reset( &ctx_enc, iv ) ); + TEST_ASSERT( 0 == cipher_reset( &ctx_dec, iv, 16, NULL, 0 ) ); + TEST_ASSERT( 0 == cipher_reset( &ctx_enc, iv, 16, NULL, 0 ) ); /* encode length number of bytes from inbuf */ TEST_ASSERT( 0 == cipher_update( &ctx_enc, inbuf, first_length, encbuf, &outlen ) ); @@ -234,7 +241,8 @@ void enc_dec_buf_multipart( int cipher_id, int key_len, int first_length_val, totaloutlen < length && totaloutlen + cipher_get_block_size( &ctx_enc ) > length ) ); - TEST_ASSERT( 0 == cipher_finish( &ctx_enc, encbuf + totaloutlen, &outlen ) ); + TEST_ASSERT( 0 == cipher_finish( &ctx_enc, encbuf + totaloutlen, &outlen, + NULL, 0 ) ); totaloutlen += outlen; TEST_ASSERT( totaloutlen == length || ( totaloutlen % cipher_get_block_size( &ctx_enc ) == 0 && @@ -250,7 +258,8 @@ void enc_dec_buf_multipart( int cipher_id, int key_len, int first_length_val, totaloutlen < length && totaloutlen + cipher_get_block_size( &ctx_dec ) >= length ) ); - TEST_ASSERT( 0 == cipher_finish( &ctx_dec, decbuf + outlen, &outlen ) ); + TEST_ASSERT( 0 == cipher_finish( &ctx_dec, decbuf + outlen, &outlen, + NULL, 0 ) ); totaloutlen += outlen; TEST_ASSERT( totaloutlen == length );