ext: tinycrypt: update ctr mode to stream

Add an offset parameter to mode ctr so it can be properly used as a
streaming cipher, like required by the flash encryption algorithm.

Signed-off-by: Fabio Utzig <fabio.utzig@nordicsemi.no>
diff --git a/boot/bootutil/include/bootutil/crypto/aes_ctr.h b/boot/bootutil/include/bootutil/crypto/aes_ctr.h
index b2ba7a4..8422f45 100644
--- a/boot/bootutil/include/bootutil/crypto/aes_ctr.h
+++ b/boot/bootutil/include/bootutil/crypto/aes_ctr.h
@@ -96,31 +96,9 @@
 
 static int _bootutil_aes_ctr_crypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, const uint8_t *in, uint32_t inlen, uint32_t blk_off, uint8_t *out)
 {
-    uint8_t buf[16];
-    uint32_t buflen;
     int rc;
-    if (blk_off == 0) {
-        rc = tc_ctr_mode(out, inlen, in, inlen, counter, ctx);
-        if (rc != TC_CRYPTO_SUCCESS) {
-            return -1;
-        }
-    } else if (blk_off < 16) {
-        buflen = ((inlen + blk_off <= 16) ? inlen : (16 - blk_off));
-        inlen -= buflen;
-        memcpy(&buf[blk_off], &in[0], buflen);
-        rc = tc_ctr_mode(buf, 16, buf, 16, counter, ctx);
-        if (rc != TC_CRYPTO_SUCCESS) {
-            return -1;
-        }
-        memcpy(&out[0], &buf[blk_off], buflen);
-        memset(&buf[0], 0, 16);
-        if (inlen > 0) {
-            rc = tc_ctr_mode(&out[buflen], inlen, &in[buflen], inlen, counter, ctx);
-        }
-        if (rc != TC_CRYPTO_SUCCESS) {
-            return -1;
-        }
-    } else {
+    rc = tc_ctr_mode(out, inlen, in, inlen, counter, &blk_off, ctx);
+    if (rc != TC_CRYPTO_SUCCESS) {
         return -1;
     }
     return 0;
diff --git a/ext/tinycrypt/lib/include/tinycrypt/ctr_mode.h b/ext/tinycrypt/lib/include/tinycrypt/ctr_mode.h
index dc221f9..9936c92 100644
--- a/ext/tinycrypt/lib/include/tinycrypt/ctr_mode.h
+++ b/ext/tinycrypt/lib/include/tinycrypt/ctr_mode.h
@@ -96,10 +96,12 @@
  * @param in IN -- data to encrypt (or decrypt)
  * @param inlen IN -- length of input data in bytes
  * @param ctr IN/OUT -- the current counter value
+ * @param blk_off IN/OUT -- the offset in the block
  * @param sched IN -- an initialized AES key schedule
  */
 int tc_ctr_mode(uint8_t *out, unsigned int outlen, const uint8_t *in,
-		unsigned int inlen, uint8_t *ctr, const TCAesKeySched_t sched);
+		unsigned int inlen, uint8_t *ctr, uint32_t *blk_off,
+		const TCAesKeySched_t sched);
 
 #ifdef __cplusplus
 }
diff --git a/ext/tinycrypt/lib/source/ctr_mode.c b/ext/tinycrypt/lib/source/ctr_mode.c
index 1dfb92d..ec8c394 100644
--- a/ext/tinycrypt/lib/source/ctr_mode.c
+++ b/ext/tinycrypt/lib/source/ctr_mode.c
@@ -35,18 +35,21 @@
 #include <tinycrypt/utils.h>
 
 int tc_ctr_mode(uint8_t *out, unsigned int outlen, const uint8_t *in,
-		unsigned int inlen, uint8_t *ctr, const TCAesKeySched_t sched)
+		unsigned int inlen, uint8_t *ctr, uint32_t *blk_off,
+		const TCAesKeySched_t sched)
 {
 
 	uint8_t buffer[TC_AES_BLOCK_SIZE];
 	uint8_t nonce[TC_AES_BLOCK_SIZE];
 	unsigned int block_num;
 	unsigned int i;
+	uint32_t n;
 
 	/* input sanity check: */
 	if (out == (uint8_t *) 0 ||
 	    in == (uint8_t *) 0 ||
 	    ctr == (uint8_t *) 0 ||
+	    blk_off == (uint32_t *) 0 ||
 	    sched == (TCAesKeySched_t) 0 ||
 	    inlen == 0 ||
 	    outlen == 0 ||
@@ -60,8 +63,9 @@
 	/* select the last 4 bytes of the nonce to be incremented */
 	block_num = (nonce[12] << 24) | (nonce[13] << 16) |
 		    (nonce[14] << 8) | (nonce[15]);
+	n = *blk_off;
 	for (i = 0; i < inlen; ++i) {
-		if ((i % (TC_AES_BLOCK_SIZE)) == 0) {
+		if (n == 0) {
 			/* encrypt data using the current nonce */
 			if (tc_aes_encrypt(buffer, nonce, sched)) {
 				block_num++;
@@ -74,8 +78,10 @@
 			}
 		}
 		/* update the output */
-		*out++ = buffer[i%(TC_AES_BLOCK_SIZE)] ^ *in++;
+		*out++ = buffer[n] ^ *in++;
+		n = (n + 1) % TC_AES_BLOCK_SIZE;
 	}
+	*blk_off = n;
 
 	/* update the counter */
 	ctr[12] = nonce[12]; ctr[13] = nonce[13];
diff --git a/ext/tinycrypt/tests/test_ctr_mode.c b/ext/tinycrypt/tests/test_ctr_mode.c
index daf3787..f323856 100644
--- a/ext/tinycrypt/tests/test_ctr_mode.c
+++ b/ext/tinycrypt/tests/test_ctr_mode.c
@@ -81,30 +81,42 @@
         uint8_t out[80];
         uint8_t decrypted[64];
         unsigned int result = TC_PASS;
+        uint32_t off = 0;
 
         TC_PRINT("CTR test #1 (encryption SP 800-38a tests):\n");
         (void)tc_aes128_set_encrypt_key(&sched, key);
 
         (void)memcpy(out, ctr, sizeof(ctr));
         if (tc_ctr_mode(&out[TC_AES_BLOCK_SIZE], sizeof(plaintext), plaintext,
-			sizeof(plaintext), ctr, &sched) == 0) {
+			sizeof(plaintext), ctr, &off, &sched) == 0) {
                 TC_ERROR("CTR test #1 (encryption SP 800-38a tests) failed in %s.\n", __func__);
                 result = TC_FAIL;
                 goto exitTest1;
         }
 
+        if (off != 0) {
+            TC_ERROR("CTR test #1 invalid block offset (%u).\n", off);
+            result = TC_FAIL;
+            goto exitTest1;
+        }
         result = check_result(1, ciphertext, sizeof(out), out, sizeof(out));
         TC_END_RESULT(result);
 
         TC_PRINT("CTR test #2 (decryption SP 800-38a tests):\n");
         (void) memcpy(ctr, out, sizeof(ctr));
+        off = 0;
         if (tc_ctr_mode(decrypted, sizeof(decrypted), &out[TC_AES_BLOCK_SIZE],
-                        sizeof(decrypted), ctr, &sched) == 0) {
+                        sizeof(decrypted), ctr, &off, &sched) == 0) {
                 TC_ERROR("CTR test #2 (decryption SP 800-38a tests) failed in %s.\n", __func__);
                 result = TC_FAIL;
                 goto exitTest1;
         }
 
+        if (off != 0) {
+            TC_ERROR("CTR test #2 invalid block offset (%u).\n", off);
+            result = TC_FAIL;
+            goto exitTest1;
+        }
         result = check_result(2, plaintext, sizeof(plaintext),
 			      decrypted, sizeof(plaintext));
 
@@ -126,7 +138,7 @@
         TC_PRINT("Performing CTR tests:\n");
         result = test_1_and_2();
         if (result == TC_FAIL) { /* terminate test */
-                TC_ERROR("CBC test #1 failed.\n");
+                TC_ERROR("CTR test #1 failed.\n");
                 goto exitTest;
         }