+int CRYPTO_ccm128_encrypt_ccm64(CCM128_CONTEXT *ctx,
+ const unsigned char *inp, unsigned char *out,
+ size_t len, ccm128_f stream)
+{
+ size_t n;
+ unsigned int i, L;
+ unsigned char flags0 = ctx->nonce.c[0];
+ block128_f block = ctx->block;
+ void *key = ctx->key;
+ union {
+ u64 u[2];
+ u8 c[16];
+ } scratch;
+
+ if (!(flags0 & 0x40))
+ (*block) (ctx->nonce.c, ctx->cmac.c, key), ctx->blocks++;
+
+ ctx->nonce.c[0] = L = flags0 & 7;
+ for (n = 0, i = 15 - L; i < 15; ++i) {
+ n |= ctx->nonce.c[i];
+ ctx->nonce.c[i] = 0;
+ n <<= 8;
+ }
+ n |= ctx->nonce.c[15]; /* reconstructed length */
+ ctx->nonce.c[15] = 1;
+
+ if (n != len)
+ return -1; /* length mismatch */
+
+ ctx->blocks += ((len + 15) >> 3) | 1;
+ if (ctx->blocks > (U64(1) << 61))
+ return -2; /* too much data */
+
+ if ((n = len / 16)) {
+ (*stream) (inp, out, n, key, ctx->nonce.c, ctx->cmac.c);
+ n *= 16;
+ inp += n;
+ out += n;
+ len -= n;
+ if (len)
+ ctr64_add(ctx->nonce.c, n / 16);
+ }
+
+ if (len) {
+ for (i = 0; i < len; ++i)
+ ctx->cmac.c[i] ^= inp[i];
+ (*block) (ctx->cmac.c, ctx->cmac.c, key);
+ (*block) (ctx->nonce.c, scratch.c, key);
+ for (i = 0; i < len; ++i)
+ out[i] = scratch.c[i] ^ inp[i];
+ }
+
+ for (i = 15 - L; i < 16; ++i)
+ ctx->nonce.c[i] = 0;
+
+ (*block) (ctx->nonce.c, scratch.c, key);
+ ctx->cmac.u[0] ^= scratch.u[0];
+ ctx->cmac.u[1] ^= scratch.u[1];
+
+ ctx->nonce.c[0] = flags0;
+
+ return 0;
+}
+
+int CRYPTO_ccm128_decrypt_ccm64(CCM128_CONTEXT *ctx,
+ const unsigned char *inp, unsigned char *out,
+ size_t len, ccm128_f stream)
+{
+ size_t n;
+ unsigned int i, L;
+ unsigned char flags0 = ctx->nonce.c[0];
+ block128_f block = ctx->block;
+ void *key = ctx->key;
+ union {
+ u64 u[2];
+ u8 c[16];
+ } scratch;
+
+ if (!(flags0 & 0x40))
+ (*block) (ctx->nonce.c, ctx->cmac.c, key);
+
+ ctx->nonce.c[0] = L = flags0 & 7;
+ for (n = 0, i = 15 - L; i < 15; ++i) {
+ n |= ctx->nonce.c[i];
+ ctx->nonce.c[i] = 0;
+ n <<= 8;
+ }
+ n |= ctx->nonce.c[15]; /* reconstructed length */
+ ctx->nonce.c[15] = 1;
+
+ if (n != len)
+ return -1;
+
+ if ((n = len / 16)) {
+ (*stream) (inp, out, n, key, ctx->nonce.c, ctx->cmac.c);
+ n *= 16;
+ inp += n;
+ out += n;
+ len -= n;
+ if (len)
+ ctr64_add(ctx->nonce.c, n / 16);
+ }
+
+ if (len) {
+ (*block) (ctx->nonce.c, scratch.c, key);
+ for (i = 0; i < len; ++i)
+ ctx->cmac.c[i] ^= (out[i] = scratch.c[i] ^ inp[i]);
+ (*block) (ctx->cmac.c, ctx->cmac.c, key);
+ }
+
+ for (i = 15 - L; i < 16; ++i)
+ ctx->nonce.c[i] = 0;
+
+ (*block) (ctx->nonce.c, scratch.c, key);
+ ctx->cmac.u[0] ^= scratch.u[0];
+ ctx->cmac.u[1] ^= scratch.u[1];
+
+ ctx->nonce.c[0] = flags0;
+
+ return 0;
+}
+
+size_t CRYPTO_ccm128_tag(CCM128_CONTEXT *ctx, unsigned char *tag, size_t len)
+{
+ unsigned int M = (ctx->nonce.c[0] >> 3) & 7; /* the M parameter */
+
+ M *= 2;
+ M += 2;
+ if (len < M)
+ return 0;
+ memcpy(tag, ctx->cmac.c, M);
+ return M;