/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Support for AES-CMAC, AES-XCBC-MAC, and AES-CBC-MAC
 *
 * Copyright 2026 Google LLC
 */
#ifndef _CRYPTO_AES_CBC_MACS_H
#define _CRYPTO_AES_CBC_MACS_H

#include <crypto/aes.h>
#include <linux/string.h>

/**
 * struct aes_cmac_key - Prepared key for AES-CMAC or AES-XCBC-MAC
 * @aes: The AES key for cipher block chaining
 * @k_final: Finalization subkeys for the final block.
 *	     k_final[0] (CMAC K1, XCBC-MAC K2) is used if it's a full block.
 *	     k_final[1] (CMAC K2, XCBC-MAC K3) is used if it's a partial block.
 */
struct aes_cmac_key {
	struct aes_enckey aes;
	union {
		u8 b[AES_BLOCK_SIZE];
		__be64 w[2];
	} k_final[2];
};

/**
 * aes_cmac_zeroize_key() - Zeroize an aes_cmac_key structure
 * @key: The location of the key structure that should be zeroized
 *
 * Explicitly fills the aes_cmac_key with zeroes. This should be done once
 * the key is not required anymore to avoid that its contents are leaked
 * on the stack or heap (if not using kfree_sensitive()).
 */
static inline void aes_cmac_zeroize_key(struct aes_cmac_key *key)
{
	memzero_explicit(key, sizeof(*key));
}

/**
 * struct aes_cmac_ctx - Context for computing an AES-CMAC or AES-XCBC-MAC value
 * @key: Pointer to the key struct.  A pointer is used rather than a copy of the
 *	 struct, since the key struct size may be large.  It is assumed that the
 *	 key lives at least as long as the context.
 * @partial_len: Number of bytes that have been XOR'ed into @h since the last
 *		 AES encryption.  This is 0 if no data has been processed yet,
 *		 or between 1 and AES_BLOCK_SIZE inclusive otherwise.
 * @h: The current chaining value
 */
struct aes_cmac_ctx {
	const struct aes_cmac_key *key;
	size_t partial_len;
	u8 h[AES_BLOCK_SIZE];
};

/**
 * aes_cmac_zeroize_ctx() - Zeroize an aes_cmac_ctx structure
 * @ctx: The location of the context that should be zeroized
 *
 * Explicitly fills the aes_cmac_ctx with zeroes. This should be done once
 * the context is not required anymore to avoid that its contents are
 * leaked on the stack or heap. Only required if not using aes_cmac_final().
 */
static inline void aes_cmac_zeroize_ctx(struct aes_cmac_ctx *ctx)
{
	memzero_explicit(ctx, sizeof(*ctx));
}

/**
 * aes_cmac_preparekey() - Prepare a key for AES-CMAC
 * @key: (output) The key struct to initialize
 * @in_key: The raw AES key
 * @key_len: Length of the raw key in bytes.  The supported values are
 *	     AES_KEYSIZE_128, AES_KEYSIZE_192, and AES_KEYSIZE_256.
 *
 * On success, the caller should ensure that the prepared key is zeroized
 * at the end of its lifetime, e.g. by calling aes_cmac_zeroize_key() or
 * kfree_sensitive().
 *
 * Context: Any context.
 * Return: 0 on success or -EINVAL if the given key length is invalid.  No other
 *	   errors are possible, so callers that always pass a valid key length
 *	   don't need to check for errors.
 */
int aes_cmac_preparekey(struct aes_cmac_key *key, const u8 *in_key,
			size_t key_len);

/**
 * aes_xcbcmac_preparekey() - Prepare a key for AES-XCBC-MAC
 * @key: (output) The key struct to initialize
 * @in_key: The raw key.  As per the AES-XCBC-MAC specification (RFC 3566), this
 *	    is 128 bits, matching the internal use of AES-128.
 *
 * AES-XCBC-MAC and AES-CMAC are the same except for the key preparation.  After
 * that step, AES-XCBC-MAC is supported via the aes_cmac_* functions.
 *
 * New users should use AES-CMAC instead of AES-XCBC-MAC.
 *
 * Context: Any context.
 */
void aes_xcbcmac_preparekey(struct aes_cmac_key *key,
			    const u8 in_key[at_least AES_KEYSIZE_128]);

/**
 * aes_cmac_init() - Start computing an AES-CMAC or AES-XCBC-MAC value
 * @ctx: (output) The context to initialize
 * @key: The key to use.  Note that a pointer to the key is saved in the
 *	 context, so the key must live at least as long as the context.
 *
 * This supports both AES-CMAC and AES-XCBC-MAC.  Which one is done depends on
 * whether aes_cmac_preparekey() or aes_xcbcmac_preparekey() was called.
 *
 * The caller should ensure that the context is zeroized at the end of its
 * lifetime, e.g. by calling aes_cmac_final() or aes_cmac_zeroize_ctx().
 */
static inline void aes_cmac_init(struct aes_cmac_ctx *ctx,
				 const struct aes_cmac_key *key)
{
	*ctx = (struct aes_cmac_ctx){ .key = key };
}

/**
 * aes_cmac_update() - Update an AES-CMAC or AES-XCBC-MAC context with more data
 * @ctx: The context to update; must have been initialized
 * @data: The message data
 * @data_len: The data length in bytes.  Doesn't need to be block-aligned.
 *
 * This can be called any number of times.
 *
 * Context: Any context.
 */
void aes_cmac_update(struct aes_cmac_ctx *ctx, const u8 *data, size_t data_len);

/**
 * aes_cmac_final() - Finish computing an AES-CMAC or AES-XCBC-MAC value
 * @ctx: The context to finalize; must have been initialized
 * @out: (output) The resulting MAC
 *
 * After finishing, this zeroizes @ctx.  So the caller does not need to do it.
 *
 * Context: Any context.
 */
void aes_cmac_final(struct aes_cmac_ctx *ctx, u8 out[at_least AES_BLOCK_SIZE]);

/**
 * aes_cmac() - Compute AES-CMAC or AES-XCBC-MAC in one shot
 * @key: The key to use
 * @data: The message data
 * @data_len: The data length in bytes
 * @out: (output) The resulting AES-CMAC or AES-XCBC-MAC value
 *
 * This supports both AES-CMAC and AES-XCBC-MAC.  Which one is done depends on
 * whether aes_cmac_preparekey() or aes_xcbcmac_preparekey() was called.
 *
 * Context: Any context.
 */
static inline void aes_cmac(const struct aes_cmac_key *key, const u8 *data,
			    size_t data_len, u8 out[at_least AES_BLOCK_SIZE])
{
	struct aes_cmac_ctx ctx;

	aes_cmac_init(&ctx, key);
	aes_cmac_update(&ctx, data, data_len);
	aes_cmac_final(&ctx, out);
}

/*
 * AES-CBC-MAC support.  This is provided only for use by the implementation of
 * AES-CCM.  It should have no other users.  Warning: unlike AES-CMAC and
 * AES-XCBC-MAC, AES-CBC-MAC isn't a secure MAC for variable-length messages.
 */
struct aes_cbcmac_ctx {
	const struct aes_enckey *key;
	size_t partial_len;
	u8 h[AES_BLOCK_SIZE];
};
static inline void aes_cbcmac_init(struct aes_cbcmac_ctx *ctx,
				   const struct aes_enckey *key)
{
	*ctx = (struct aes_cbcmac_ctx){ .key = key };
}
void aes_cbcmac_update(struct aes_cbcmac_ctx *ctx, const u8 *data,
		       size_t data_len);
void aes_cbcmac_final(struct aes_cbcmac_ctx *ctx,
		      u8 out[at_least AES_BLOCK_SIZE]);

#endif /* _CRYPTO_AES_CBC_MACS_H */
