diff --git a/include/polarssl/cipher.h b/include/polarssl/cipher.h index ef037be5d..e540c925f 100644 --- a/include/polarssl/cipher.h +++ b/include/polarssl/cipher.h @@ -185,7 +185,8 @@ typedef struct { /** Name of the cipher */ const char * name; - /** IV size, in bytes */ + /** IV/NONCE size, in bytes, for ciphers with fixed-length IVs), or + * 0 for ciphers with variable-length IVs or not using IVs */ unsigned int iv_size; /** block size, in bytes */ @@ -222,6 +223,9 @@ typedef struct { /** Current IV or NONCE_COUNTER for CTR-mode */ unsigned char iv[POLARSSL_MAX_IV_LENGTH]; + /** IV size in bytes (for ciphers with variable-length IVs) */ + size_t iv_size; + /** Cipher-specific context */ void *cipher_ctx; } cipher_context_t; @@ -315,18 +319,22 @@ static inline cipher_mode_t cipher_get_cipher_mode( const cipher_context_t *ctx } /** - * \brief Returns the size of the cipher's IV. + * \brief Returns the size of the cipher's IV/NONCE in bytes. * * \param ctx cipher's context. Must have been initialised. * - * \return size of the cipher's IV, or 0 if ctx has not been - * initialised or accepts IV of various sizes. + * \return If IV has not been set yet: desired size for ciphers + * with fixed-size IVs, 0 for other ciphers. + * If IV has already been set: actual size. */ static inline int cipher_get_iv_size( const cipher_context_t *ctx ) { if( NULL == ctx || NULL == ctx->cipher_info ) return 0; + if( ctx->iv_size != 0 ) + return ctx->iv_size; + return ctx->cipher_info->iv_size; } @@ -427,13 +435,25 @@ int cipher_setkey( cipher_context_t *ctx, const unsigned char *key, int key_leng */ int cipher_set_padding_mode( cipher_context_t *ctx, cipher_padding_t mode ); +/** + * \brief Set the initialization vector (IV) or nonce + * + * \param iv IV to use (or NONCE_COUNTER for CTR-mode ciphers) + * \param iv_len IV length for ciphers with variable-size IV, + * Discarded by ciphers with fixed-size IV. + * + * \returns O on success, or POLARSSL_ERR_CIPHER_BAD_INPUT_DATA + * + * \note Some ciphers don't use IVs nor NONCE. For these + * ciphers, this function has no effect. + */ +int cipher_set_iv( cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len ); + /** * \brief Reset the given context, setting the IV to iv * * \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. @@ -442,7 +462,6 @@ int cipher_set_padding_mode( cipher_context_t *ctx, cipher_padding_t mode ); * if parameter verification fails. */ int cipher_reset( cipher_context_t *ctx, - const unsigned char *iv, size_t iv_len, const unsigned char *ad, size_t ad_len ); /** diff --git a/library/cipher.c b/library/cipher.c index d7cac05f0..d90abe1ab 100644 --- a/library/cipher.c +++ b/library/cipher.c @@ -396,29 +396,42 @@ 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, size_t iv_len, - const unsigned char *ad, size_t ad_len ) +int cipher_set_iv( cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len ) { + size_t fixed_iv_size; + if( NULL == ctx || NULL == ctx->cipher_info || NULL == iv ) return POLARSSL_ERR_CIPHER_BAD_INPUT_DATA; + fixed_iv_size = cipher_get_iv_size( ctx ); + + /* 0 means variable size (or no IV): use given len */ + if( fixed_iv_size == 0 ) + fixed_iv_size = iv_len; + + memcpy( ctx->iv, iv, fixed_iv_size ); + ctx->iv_size = fixed_iv_size; + + return 0; +} + +int cipher_reset( cipher_context_t *ctx, + const unsigned char *ad, size_t ad_len ) +{ ctx->unprocessed_len = 0; #if defined(POLARSSL_GCM_C) if( POLARSSL_MODE_GCM == ctx->cipher_info->mode ) { return gcm_starts( ctx->cipher_ctx, ctx->operation, - iv, iv_len, ad, ad_len ); + ctx->iv, ctx->iv_size, ad, ad_len ); } #else ((void) ad); ((void) ad_len); - ((void) iv_len); #endif - memcpy( ctx->iv, iv, cipher_get_iv_size( ctx ) ); - return 0; } diff --git a/library/pkcs12.c b/library/pkcs12.c index 9ccb60ab7..3634ce139 100644 --- a/library/pkcs12.c +++ b/library/pkcs12.c @@ -184,7 +184,10 @@ 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, NULL, 0 ) ) != 0 ) + if( ( ret = cipher_set_iv( &cipher_ctx, iv, 0 ) ) != 0 ) + goto exit; + + if( ( ret = cipher_reset( &cipher_ctx, iv, 0 ) ) != 0 ) goto exit; if( ( ret = cipher_update( &cipher_ctx, data, len, diff --git a/library/pkcs5.c b/library/pkcs5.c index 2b6a75a92..6582fd05f 100644 --- a/library/pkcs5.c +++ b/library/pkcs5.c @@ -187,7 +187,10 @@ 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, NULL, 0 ) ) != 0 ) + if( ( ret = cipher_set_iv( &cipher_ctx, iv, 0 ) ) != 0 ) + goto exit; + + if( ( ret = cipher_reset( &cipher_ctx, NULL, 0 ) ) != 0 ) goto exit; if( ( ret = cipher_update( &cipher_ctx, data, datalen, diff --git a/programs/aes/crypt_and_hash.c b/programs/aes/crypt_and_hash.c index a9b862e7a..8ffdb9f94 100644 --- a/programs/aes/crypt_and_hash.c +++ b/programs/aes/crypt_and_hash.c @@ -306,7 +306,12 @@ int main( int argc, char *argv[] ) fprintf( stderr, "cipher_setkey() returned error\n"); goto exit; } - if( cipher_reset( &cipher_ctx, IV, 16, NULL, 0 ) != 0 ) + if( cipher_set_iv( &cipher_ctx, IV, 16 ) != 0 ) + { + fprintf( stderr, "cipher_set_iv() returned error\n"); + goto exit; + } + if( cipher_reset( &cipher_ctx, NULL, 0 ) != 0 ) { fprintf( stderr, "cipher_reset() returned error\n"); goto exit; @@ -424,7 +429,8 @@ int main( int argc, char *argv[] ) cipher_setkey( &cipher_ctx, digest, cipher_info->key_length, POLARSSL_DECRYPT ); - cipher_reset( &cipher_ctx, IV, 16, NULL, 0 ); + cipher_set_iv( &cipher_ctx, IV, 16 ); + cipher_reset( &cipher_ctx, NULL, 0 ); md_hmac_starts( &md_ctx, digest, 32 ); diff --git a/tests/suites/test_suite_cipher.function b/tests/suites/test_suite_cipher.function index b1814fab0..d247bab2a 100644 --- a/tests/suites/test_suite_cipher.function +++ b/tests/suites/test_suite_cipher.function @@ -58,8 +58,11 @@ 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, 16, ad, 13 ) ); - TEST_ASSERT( 0 == cipher_reset( &ctx_enc, iv, 16, ad, 13 ) ); + TEST_ASSERT( 0 == cipher_set_iv( &ctx_dec, iv, 16 ) ); + TEST_ASSERT( 0 == cipher_set_iv( &ctx_enc, iv, 16 ) ); + + TEST_ASSERT( 0 == cipher_reset( &ctx_dec, ad, 13 ) ); + TEST_ASSERT( 0 == cipher_reset( &ctx_enc, ad, 13 ) ); /* encode length number of bytes from inbuf */ TEST_ASSERT( 0 == cipher_update( &ctx_enc, inbuf, length, encbuf, &outlen ) ); @@ -133,7 +136,8 @@ 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, 16, NULL, 0 ) ); + TEST_ASSERT( 0 == cipher_set_iv( &ctx, iv, 16 ) ); + TEST_ASSERT( 0 == cipher_reset( &ctx, NULL, 0 ) ); /* encode length number of bytes from inbuf */ TEST_ASSERT( 0 == cipher_update( &ctx, inbuf, length, encbuf, &outlen ) ); @@ -166,7 +170,7 @@ void dec_empty_buf() memset( encbuf, 0, 64 ); memset( decbuf, 0, 64 ); - /* Initialise enc and dec contexts */ + /* Initialise context */ cipher_info = cipher_info_from_type( POLARSSL_CIPHER_AES_128_CBC ); TEST_ASSERT( NULL != cipher_info); @@ -174,7 +178,9 @@ void dec_empty_buf() TEST_ASSERT( 0 == cipher_setkey( &ctx_dec, key, 128, POLARSSL_DECRYPT ) ); - TEST_ASSERT( 0 == cipher_reset( &ctx_dec, iv, 16, NULL, 0 ) ); + TEST_ASSERT( 0 == cipher_set_iv( &ctx_dec, iv, 16 ) ); + + TEST_ASSERT( 0 == cipher_reset( &ctx_dec, NULL, 0 ) ); /* decode 0-byte string */ TEST_ASSERT( 0 == cipher_update( &ctx_dec, encbuf, 0, decbuf, &outlen ) ); @@ -228,8 +234,11 @@ 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, 16, NULL, 0 ) ); - TEST_ASSERT( 0 == cipher_reset( &ctx_enc, iv, 16, NULL, 0 ) ); + TEST_ASSERT( 0 == cipher_set_iv( &ctx_dec, iv, 16 ) ); + TEST_ASSERT( 0 == cipher_set_iv( &ctx_enc, iv, 16 ) ); + + TEST_ASSERT( 0 == cipher_reset( &ctx_dec, NULL, 0 ) ); + TEST_ASSERT( 0 == cipher_reset( &ctx_enc, NULL, 0 ) ); /* encode length number of bytes from inbuf */ TEST_ASSERT( 0 == cipher_update( &ctx_enc, inbuf, first_length, encbuf, &outlen ) );