+/* increment counter (64-bit int) by 1 */
+static void ctr64_inc(unsigned char *counter)
+{
+ int n = 8;
+ unsigned char c;
+
+ do {
+ --n;
+ c = counter[n];
+ ++c;
+ counter[n] = c;
+ if (c > 0)
+ return;
+ } while (n > 0);
+}
+
+static int getivgen(PROV_GCM_CTX *ctx, unsigned char *out, size_t olen)
+{
+ if (!ctx->iv_gen
+ || !ctx->key_set
+ || !ctx->hw->setiv(ctx, ctx->iv, ctx->ivlen))
+ return 0;
+ if (olen == 0 || olen > ctx->ivlen)
+ olen = ctx->ivlen;
+ memcpy(out, ctx->iv + ctx->ivlen - olen, olen);
+ /*
+ * Invocation field will be at least 8 bytes in size and so no need
+ * to check wrap around or increment more than last 8 bytes.
+ */
+ ctr64_inc(ctx->iv + ctx->ivlen - 8);
+ ctx->iv_state = IV_STATE_COPIED;
+ return 1;
+}
+
+static int setivinv(PROV_GCM_CTX *ctx, unsigned char *in, size_t inl)
+{
+ if (!ctx->iv_gen
+ || !ctx->key_set
+ || ctx->enc)
+ return 0;
+
+ memcpy(ctx->iv + ctx->ivlen - inl, in, inl);
+ if (!ctx->hw->setiv(ctx, ctx->iv, ctx->ivlen))
+ return 0;
+ ctx->iv_state = IV_STATE_COPIED;
+ return 1;
+}
+