Signed-off-by: Dmitry Eremin-Solenikov <[email protected]>
---
cmac.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++-
cmac.h | 69 +++++++++++++++++++++++++++
nettle-types.h | 7 +++
3 files changed, 200 insertions(+), 1 deletion(-)
diff --git a/cmac.c b/cmac.c
index c5a59b18e572..e93e26947b19 100644
--- a/cmac.c
+++ b/cmac.c
@@ -1,9 +1,10 @@
/*
- AES-CMAC-128 (rfc 4493)
+ AES-CMAC-128 (rfc 4493) / CMAC-64
Copyright (C) Stefan Metzmacher 2012
Copyright (C) Jeremy Allison 2012
Copyright (C) Michael Adam 2012
Copyright (C) 2017, Red Hat Inc.
+ Copyright (C) 2019, Dmitry Eremin-Solenikov
This file is part of GNU Nettle.
@@ -56,6 +57,15 @@ block_mulx(union nettle_block16 *dst,
dst->u64[0] = (src->u64[0] << 1) | (src->u64[1] >> 63);
dst->u64[1] = (src->u64[1] << 1) ^ (0x87 & -carry);
}
+
+static void
+block_mulx8(union nettle_block8 *dst,
+ const union nettle_block8 *src)
+{
+ uint64_t carry = src->u64 >> 63;
+
+ dst->u64 = (src->u64 << 1) ^ (0x1b & -carry);
+}
#else /* !WORDS_BIGENDIAN */
#define LE_SHIFT(x) ((((x) & 0x7f7f7f7f7f7f7f7f) << 1) | \
(((x) & 0x8080808080808080) >> 15))
@@ -67,6 +77,15 @@ block_mulx(union nettle_block16 *dst,
dst->u64[0] = LE_SHIFT(src->u64[0]) | ((src->u64[1] & 0x80) << 49);
dst->u64[1] = LE_SHIFT(src->u64[1]) ^ (0x8700000000000000 & -carry);
}
+
+static void
+block_mulx8(union nettle_block8 *dst,
+ const union nettle_block8 *src)
+{
+ uint64_t carry = (src->u64 & 0x80) >> 7;
+
+ dst->u64 = LE_SHIFT(src->u64) ^ (0x1b00000000000000 & -carry);
+}
#endif /* !WORDS_BIGENDIAN */
void
@@ -173,3 +192,107 @@ cmac128_digest(struct cmac128_ctx *ctx, const struct
cmac128_key *key,
/* reset state for re-use */
cmac128_init(ctx);
}
+
+void
+cmac64_set_key(struct cmac64_key *key, const void *cipher,
+ nettle_cipher_func *encrypt)
+{
+ static const union nettle_block8 zero_block;
+ union nettle_block8 L;
+
+ /* step 1 - generate subkeys k1 and k2 */
+ encrypt(cipher, 8, L.b, zero_block.b);
+
+ block_mulx8(&key->K1, &L);
+ block_mulx8(&key->K2, &key->K1);
+}
+
+void
+cmac64_init(struct cmac64_ctx *ctx)
+{
+ memset(&ctx->X, 0, sizeof(ctx->X));
+ ctx->index = 0;
+}
+
+void
+cmac64_update(struct cmac64_ctx *ctx, const void *cipher,
+ nettle_cipher_func *encrypt,
+ size_t msg_len, const uint8_t *msg)
+{
+ union nettle_block16 Y;
+ /*
+ * check if we expand the block
+ */
+ if (ctx->index < 8)
+ {
+ size_t len = MIN(8 - ctx->index, msg_len);
+ memcpy(&ctx->block.b[ctx->index], msg, len);
+ msg += len;
+ msg_len -= len;
+ ctx->index += len;
+ }
+
+ if (msg_len == 0) {
+ /* if it is still the last block, we are done */
+ return;
+ }
+
+ /*
+ * now checksum everything but the last block
+ */
+ memxor3(Y.b, ctx->X.b, ctx->block.b, 8);
+ encrypt(cipher, 8, ctx->X.b, Y.b);
+
+ while (msg_len > 8)
+ {
+ memxor3(Y.b, ctx->X.b, msg, 8);
+ encrypt(cipher, 8, ctx->X.b, Y.b);
+ msg += 8;
+ msg_len -= 8;
+ }
+
+ /*
+ * copy the last block, it will be processed in
+ * cmac64_digest().
+ */
+ memcpy(ctx->block.b, msg, msg_len);
+ ctx->index = msg_len;
+}
+
+void
+cmac64_digest(struct cmac64_ctx *ctx, const struct cmac64_key *key,
+ const void *cipher, nettle_cipher_func *encrypt,
+ unsigned length, uint8_t *dst)
+{
+ union nettle_block8 Y;
+
+ memset(ctx->block.b+ctx->index, 0, sizeof(ctx->block.b)-ctx->index);
+
+ /* re-use ctx->block for memxor output */
+ if (ctx->index < 8)
+ {
+ ctx->block.b[ctx->index] = 0x80;
+ memxor(ctx->block.b, key->K2.b, 8);
+ }
+ else
+ {
+ memxor(ctx->block.b, key->K1.b, 8);
+ }
+
+ memxor3(Y.b, ctx->block.b, ctx->X.b, 8);
+
+ assert(length <= 8);
+ if (length == 8)
+ {
+ encrypt(cipher, 8, dst, Y.b);
+ }
+ else
+ {
+ encrypt(cipher, 8, ctx->block.b, Y.b);
+ memcpy(dst, ctx->block.b, length);
+ }
+
+ /* reset state for re-use */
+ memset(&ctx->X, 0, sizeof(ctx->X));
+ ctx->index = 0;
+}
diff --git a/cmac.h b/cmac.h
index 3c5b7bea3e55..0cf9462d2120 100644
--- a/cmac.h
+++ b/cmac.h
@@ -44,6 +44,7 @@ extern "C" {
#endif
#define CMAC128_DIGEST_SIZE 16
+#define CMAC64_DIGEST_SIZE 8
#define cmac128_set_key nettle_cmac128_set_key
#define cmac128_init nettle_cmac128_init
@@ -56,6 +57,11 @@ extern "C" {
#define cmac_aes256_update nettle_cmac_aes256_update
#define cmac_aes256_digest nettle_cmac_aes256_digest
+#define cmac64_set_key nettle_cmac64_set_key
+#define cmac64_init nettle_cmac64_init
+#define cmac64_update nettle_cmac64_update
+#define cmac64_digest nettle_cmac64_digest
+
struct cmac128_key
{
union nettle_block16 K1;
@@ -72,6 +78,22 @@ struct cmac128_ctx
size_t index;
};
+struct cmac64_key
+{
+ union nettle_block8 K1;
+ union nettle_block8 K2;
+};
+
+struct cmac64_ctx
+{
+ /* MAC state */
+ union nettle_block8 X;
+
+ /* Block buffer */
+ union nettle_block8 block;
+ size_t index;
+};
+
void
cmac128_set_key(struct cmac128_key *key, const void *cipher,
nettle_cipher_func *encrypt);
@@ -118,6 +140,53 @@ cmac128_digest(struct cmac128_ctx *ctx, const struct
cmac128_key *key,
(nettle_cipher_func *) (encrypt), \
(length), (digest)))
+void
+cmac64_set_key(struct cmac64_key *key, const void *cipher,
+ nettle_cipher_func *encrypt);
+
+void
+cmac64_init(struct cmac64_ctx *ctx);
+
+void
+cmac64_update(struct cmac64_ctx *ctx, const void *cipher,
+ nettle_cipher_func *encrypt,
+ size_t msg_len, const uint8_t *msg);
+
+void
+cmac64_digest(struct cmac64_ctx *ctx, const struct cmac64_key *key,
+ const void *cipher, nettle_cipher_func *encrypt,
+ unsigned length, uint8_t *digest);
+
+
+#define CMAC64_CTX(type) \
+ { struct cmac64_key key; struct cmac64_ctx ctx; type cipher; }
+
+/* NOTE: Avoid using NULL, as we don't include anything defining it. */
+#define CMAC64_SET_KEY(self, set_key, encrypt, cmac_key) \
+ do { \
+ (set_key)(&(self)->cipher, (cmac_key)); \
+ if (0) (encrypt)(&(self)->cipher, ~(size_t) 0, \
+ (uint8_t *) 0, (const uint8_t *) 0); \
+ cmac64_set_key(&(self)->key, &(self)->cipher, \
+ (nettle_cipher_func *) (encrypt)); \
+ cmac64_init(&(self)->ctx); \
+ } while (0)
+
+#define CMAC64_UPDATE(self, encrypt, length, src) \
+ (0 ? (encrypt)(&(self)->cipher, ~(size_t) 0, \
+ (uint8_t *) 0, (const uint8_t *) 0) \
+ : cmac64_update(&(self)->ctx, &(self)->cipher, \
+ (nettle_cipher_func *)encrypt, \
+ (length), (src)))
+
+#define CMAC64_DIGEST(self, encrypt, length, digest) \
+ (0 ? (encrypt)(&(self)->cipher, ~(size_t) 0, \
+ (uint8_t *) 0, (const uint8_t *) 0) \
+ : cmac64_digest(&(self)->ctx, &(self)->key, \
+ &(self)->cipher, \
+ (nettle_cipher_func *) (encrypt), \
+ (length), (digest)))
+
struct cmac_aes128_ctx CMAC128_CTX(struct aes128_ctx);
void
diff --git a/nettle-types.h b/nettle-types.h
index 87292ac69730..e06c85c48f8c 100644
--- a/nettle-types.h
+++ b/nettle-types.h
@@ -65,6 +65,13 @@ union nettle_block16
uint64_t u64[2];
};
+union nettle_block8
+{
+ uint8_t b[8];
+ unsigned long w[8 / sizeof(unsigned long)];
+ uint64_t u64;
+};
+
/* Randomness. Used by key generation and dsa signature creation. */
typedef void nettle_random_func(void *ctx,
size_t length, uint8_t *dst);
--
2.20.1
_______________________________________________
nettle-bugs mailing list
[email protected]
http://lists.lysator.liu.se/mailman/listinfo/nettle-bugs