Add support for chunked plaintext/cyphertext input.

Signed-off-by: Mateusz Starzyk <mateusz.starzyk@mobica.com>
diff --git a/library/ccm.c b/library/ccm.c
index ae5fa34..4b1b499 100644
--- a/library/ccm.c
+++ b/library/ccm.c
@@ -333,59 +333,67 @@
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     unsigned char i;
-    size_t len_left, olen;
-    const unsigned char *src;
-    unsigned char *dst;
+    size_t use_len, offset, olen;
 
     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.
-     *
-     * The only difference between encryption and decryption is
-     * the respective order of authentication and {en,de}cryption.
-     */
-    len_left = input_len;
-    src = input;
-    dst = output;
-
-    while( len_left > 0 )
+    if( ctx->processed == 0 )
     {
-        size_t use_len = len_left > 16 ? 16 : len_left;
-
-        if( ctx->mode == CCM_ENCRYPT )
-        {
-            memset( ctx->b, 0, 16 );
-            memcpy( ctx->b, src, use_len );
-            UPDATE_CBC_MAC;
-        }
-
-        mbedtls_ccm_crypt( ctx, 0, use_len, src, dst );
-
-        if( ctx->mode == CCM_DECRYPT )
-        {
-            memset( ctx->b, 0, 16 );
-            memcpy( ctx->b, dst, use_len );
-            UPDATE_CBC_MAC;
-        }
-
-        dst += use_len;
-        src += use_len;
-        len_left -= use_len;
-
-        /*
-         * Increment counter.
-         * No need to check for overflow thanks to the length check above.
-         */
-        for( i = 0; i < ctx->q; i++ )
-            if( ++(ctx->ctr)[15-i] != 0 )
-                break;
+        memset( ctx->b, 0, 16 );
     }
 
-    return (0);
+    while ( input_len > 0 )
+    {
+        offset = ctx->processed % 16;
+
+        use_len = 16 - offset;
+
+        if( use_len > input_len )
+            use_len = input_len;
+
+        ctx->processed += use_len;
+        memcpy( ctx->b + offset, input, use_len );
+
+        if( use_len + offset == 16 || ctx->processed == ctx->plaintext_len )
+        {
+            if( ctx->mode == CCM_ENCRYPT )
+            {
+                UPDATE_CBC_MAC;
+                ret = mbedtls_ccm_crypt( ctx, 0, use_len, ctx->b, output );
+                if( ret != 0 )
+                    return ret;
+                memset( ctx->b, 0, 16 );
+            }
+
+            if( ctx->mode == CCM_DECRYPT )
+            {
+                ret = mbedtls_ccm_crypt( ctx, 0, use_len, ctx->b, output );
+                if( ret != 0 )
+                    return ret;
+                memset( ctx->b, 0, 16 );
+                memcpy( ctx->b, output, use_len );
+                UPDATE_CBC_MAC;
+                memset( ctx->b, 0, 16 );
+            }
+
+            input_len -= use_len;
+            input += use_len;
+            output += use_len;
+
+            /*
+            * Increment counter.
+            * No need to check for overflow thanks to the length check above.
+            */
+            for( i = 0; i < ctx->q; i++ )
+                if( ++(ctx->ctr)[15-i] != 0 )
+                    break;
+        }
+    }
+
+    return 0;
 }
 
 int mbedtls_ccm_finish( mbedtls_ccm_context *ctx,