Split ccm_auth function.
Move logic to ccm_starts, ccm_set_lengths, ccm_update_ad,
ccm_update and ccm_finish
Use separate variable to track context state.
Encode first block only if both mbedtls_ccm_starts() and
mbedtls_ccm_set_lengths() were called.
Signed-off-by: Mateusz Starzyk <mateusz.starzyk@mobica.com>
diff --git a/include/mbedtls/ccm.h b/include/mbedtls/ccm.h
index 2b9909e..f9f8000 100644
--- a/include/mbedtls/ccm.h
+++ b/include/mbedtls/ccm.h
@@ -87,6 +87,9 @@
#MBEDTLS_CCM_DECRYPT or
#MBEDTLS_CCM_STAR_ENCRYPT or
#MBEDTLS_CCM_STAR_DECRYPT. */
+ int MBEDTLS_PRIVATE(state); /*!< Working value holding context's
+ state. Used for chunked data
+ input */
}
mbedtls_ccm_context;
diff --git a/library/ccm.c b/library/ccm.c
index 686eda5..a2ca986 100644
--- a/library/ccm.c
+++ b/library/ccm.c
@@ -142,22 +142,105 @@
(dst)[i] = (src)[i] ^ ctx->b[i]; \
} while( 0 )
-/*
- * Authenticated encryption or decryption
- */
-static int ccm_auth_crypt( mbedtls_ccm_context *ctx, int mode, size_t length,
- const unsigned char *iv, size_t iv_len,
- const unsigned char *add, size_t add_len,
- const unsigned char *input, unsigned char *output,
- unsigned char *tag, size_t tag_len )
+#define CCM_STATE__CLEAR 0
+#define CCM_STATE__STARTED 0x0001
+#define CCM_STATE__LENGHTS_SET 0x0002
+
+static void mbedtls_ccm_clear_state(mbedtls_ccm_context *ctx) {
+ ctx->state = CCM_STATE__CLEAR;
+ memset( ctx->b, 0, 16);
+ memset( ctx->y, 0, 16);
+ memset( ctx->ctr, 0, 16);
+}
+
+static int mbedtls_ccm_calculate_first_block(mbedtls_ccm_context *ctx)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
unsigned char i;
size_t len_left, olen;
- const unsigned char *src;
- unsigned char *dst;
+
+ /* length calulcation can be done only after both
+ * mbedtls_ccm_starts() and mbedtls_ccm_set_lengths() have been executed
+ */
+ if( !(ctx->state & CCM_STATE__STARTED) || !(ctx->state & CCM_STATE__LENGHTS_SET) )
+ return 0;
+
+ /*
+ * First block B_0:
+ * 0 .. 0 flags - set by: mbedtls_ccm_starts() and mbedtls_ccm_set_lenghts()
+ * 1 .. iv_len nonce (aka iv) - set by: mbedtls_ccm_starts()
+ * iv_len+1 .. 15 length - set by: mbedtls_ccm_calculate_first_block()
+ */
+ for( i = 0, len_left = ctx->plaintext_len; i < ctx->q; i++, len_left >>= 8 )
+ ctx->b[15-i] = (unsigned char)( len_left & 0xFF );
+
+ if( len_left > 0 )
+ return( MBEDTLS_ERR_CCM_BAD_INPUT );
+
+ /* Start CBC-MAC with first block*/
+ UPDATE_CBC_MAC;
+
+ return (0);
+}
+
+int mbedtls_ccm_starts( mbedtls_ccm_context *ctx,
+ int mode,
+ const unsigned char *iv,
+ size_t iv_len )
+{
+ int ret;
+
+ /* Also implies q is within bounds */
+ if( iv_len < 7 || iv_len > 13 )
+ return( MBEDTLS_ERR_CCM_BAD_INPUT );
ctx->mode = mode;
+ ctx->q = 16 - 1 - (unsigned char) iv_len;
+
+ /*
+ * Prepare counter block for encryption:
+ * 0 .. 0 flags
+ * 1 .. iv_len nonce (aka iv)
+ * iv_len+1 .. 15 counter (initially 1)
+ *
+ * With flags as (bits):
+ * 7 .. 3 0
+ * 2 .. 0 q - 1
+ */
+ memset( ctx->ctr, 0, 16);
+ ctx->ctr[0] = ctx->q - 1;
+ memcpy( ctx->ctr + 1, iv, iv_len );
+ memset( ctx->ctr + 1 + iv_len, 0, ctx->q );
+ ctx->ctr[15] = 1;
+
+ /*
+ * First block B_0:
+ * 0 .. 0 flags - set by: mbedtls_ccm_starts() and mbedtls_ccm_set_lenghts()
+ * 1 .. iv_len nonce (aka iv) - set by: mbedtls_ccm_starts()
+ * iv_len+1 .. 15 length - set by: mbedtls_ccm_calculate_first_block()
+ *
+ * With flags as (bits):
+ * 7 0
+ * 6 add present? - set by: mbedtls_ccm_set_lengths()
+ * 5 .. 3 (t - 2) / 2 - set by: mbedtls_ccm_set_lengths()
+ * 2 .. 0 q - 1 - set by: mbedtls_ccm_starts()
+ */
+ ctx->b[0] |= ctx->q - 1;
+
+ memcpy( ctx->b + 1, iv, iv_len );
+
+ ctx->state |= CCM_STATE__STARTED;
+ ret = mbedtls_ccm_calculate_first_block(ctx);
+
+ return ret;
+}
+
+int mbedtls_ccm_set_lengths( mbedtls_ccm_context *ctx,
+ size_t total_ad_len,
+ size_t plaintext_len,
+ size_t tag_len )
+{
+ int ret;
/*
* Check length requirements: SP800-38C A.1
@@ -169,44 +252,40 @@
if( tag_len == 2 || tag_len > 16 || tag_len % 2 != 0 )
return( MBEDTLS_ERR_CCM_BAD_INPUT );
- /* Also implies q is within bounds */
- if( iv_len < 7 || iv_len > 13 )
+ if( total_ad_len >= 0xFF00 )
return( MBEDTLS_ERR_CCM_BAD_INPUT );
- if( add_len >= 0xFF00 )
- return( MBEDTLS_ERR_CCM_BAD_INPUT );
-
- ctx->q = 16 - 1 - (unsigned char) iv_len;
-
/*
* First block B_0:
- * 0 .. 0 flags
- * 1 .. iv_len nonce (aka iv)
- * iv_len+1 .. 15 length
+ * 0 .. 0 flags - set by: mbedtls_ccm_starts() and mbedtls_ccm_set_lenghts()
+ * 1 .. iv_len nonce (aka iv) - set by: mbedtls_ccm_starts()
+ * iv_len+1 .. 15 length - set by: mbedtls_ccm_calculate_first_block()
*
* With flags as (bits):
* 7 0
- * 6 add present?
- * 5 .. 3 (t - 2) / 2
- * 2 .. 0 q - 1
+ * 6 add present? - set by: mbedtls_ccm_set_lengths()
+ * 5 .. 3 (t - 2) / 2 - set by: mbedtls_ccm_set_lengths()
+ * 2 .. 0 q - 1 - set by: mbedtls_ccm_starts()
*/
- ctx->b[0] = 0;
- ctx->b[0] |= ( add_len > 0 ) << 6;
+ ctx->b[0] |= ( total_ad_len > 0 ) << 6;
ctx->b[0] |= ( ( tag_len - 2 ) / 2 ) << 3;
- ctx->b[0] |= ctx->q - 1;
- memcpy( ctx->b + 1, iv, iv_len );
+ ctx->plaintext_len = plaintext_len;
- for( i = 0, len_left = length; i < ctx->q; i++, len_left >>= 8 )
- ctx->b[15-i] = (unsigned char)( len_left & 0xFF );
+ ctx->state |= CCM_STATE__LENGHTS_SET;
+ ret = mbedtls_ccm_calculate_first_block(ctx);
- if( len_left > 0 )
- return( MBEDTLS_ERR_CCM_BAD_INPUT );
+ return ret;
+}
-
- /* Start CBC-MAC with first block */
- memset( ctx->y, 0, 16 );
- UPDATE_CBC_MAC;
+int mbedtls_ccm_update_ad( mbedtls_ccm_context *ctx,
+ const unsigned char *add,
+ size_t add_len )
+{
+ int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+ unsigned char i;
+ size_t len_left, olen;
+ const unsigned char *src;
/*
* If there is additional data, update CBC-MAC with
@@ -242,20 +321,24 @@
}
}
- /*
- * Prepare counter block for encryption:
- * 0 .. 0 flags
- * 1 .. iv_len nonce (aka iv)
- * iv_len+1 .. 15 counter (initially 1)
- *
- * With flags as (bits):
- * 7 .. 3 0
- * 2 .. 0 q - 1
- */
- ctx->ctr[0] = ctx->q - 1;
- memcpy( ctx->ctr + 1, iv, iv_len );
- memset( ctx->ctr + 1 + iv_len, 0, ctx->q );
- ctx->ctr[15] = 1;
+ return (0);
+}
+
+int mbedtls_ccm_update( mbedtls_ccm_context *ctx,
+ const unsigned char *input, size_t input_len,
+ unsigned char *output, size_t output_size,
+ size_t *output_len )
+{
+ int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+ unsigned char i;
+ size_t len_left, olen;
+ const unsigned char *src;
+ unsigned char *dst;
+
+ if( output_size < input_len )
+ return( MBEDTLS_ERR_CCM_BAD_INPUT );
+ CCM_VALIDATE_RET( output_length != NULL );
+ *output_len = input_len;
/*
* Authenticate and {en,de}crypt the message.
@@ -263,7 +346,7 @@
* The only difference between encryption and decryption is
* the respective order of authentication and {en,de}cryption.
*/
- len_left = length;
+ len_left = input_len;
src = input;
dst = output;
@@ -300,6 +383,16 @@
break;
}
+ return (0);
+}
+
+int mbedtls_ccm_finish( mbedtls_ccm_context *ctx,
+ unsigned char *tag, size_t tag_len )
+{
+ int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+ unsigned char i;
+ size_t olen;
+
/*
* Authentication: reset counter and crypt/mask internal tag
*/
@@ -308,6 +401,38 @@
CTR_CRYPT( ctx->y, ctx->y, 16 );
memcpy( tag, ctx->y, tag_len );
+ mbedtls_ccm_clear_state(ctx);
+
+ return( 0 );
+}
+
+/*
+ * Authenticated encryption or decryption
+ */
+static int ccm_auth_crypt( mbedtls_ccm_context *ctx, int mode, size_t length,
+ const unsigned char *iv, size_t iv_len,
+ const unsigned char *add, size_t add_len,
+ const unsigned char *input, unsigned char *output,
+ unsigned char *tag, size_t tag_len )
+{
+ int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+ size_t olen;
+
+ if( ( ret = mbedtls_ccm_starts( ctx, mode, iv, iv_len ) ) != 0 )
+ return( ret );
+
+ if( ( ret = mbedtls_ccm_set_lengths( ctx, add_len, length, tag_len ) ) != 0 )
+ return( ret );
+
+ if( ( ret = mbedtls_ccm_update_ad( ctx, add, add_len ) ) != 0 )
+ return( ret );
+
+ if( ( ret = mbedtls_ccm_update( ctx, input, length,
+ output, length, &olen ) ) != 0 )
+ return( ret );
+
+ if( ( ret = mbedtls_ccm_finish( ctx, tag, tag_len ) ) != 0 )
+ return( ret );
return( 0 );
}