/*  cmac_mode.h -- interface to a CMAC implementation */

/*
    Copyright (C) 2017 by Intel Corporation, All Rights Reserved

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:

      - Redistributions of source code must retain the above copyright notice,
       this list of conditions and the following disclaimer.

      - Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.

      - Neither the name of Intel Corporation nor the names of its contributors
      may be used to endorse or promote products derived from this software
      without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGE.
*/

/**
    @file
    @brief Interface to a CMAC implementation.

    Overview: CMAC is defined NIST in SP 800-38B, and is the standard algorithm
              for computing a MAC using a block cipher. It can compute the MAC
              for a byte string of any length. It is distinguished from CBC-MAC
              in the processing of the final message block; CMAC uses a
              different technique to compute the final message block is full
              size or only partial, while CBC-MAC uses the same technique for
              both. This difference permits CMAC to be applied to variable
              length messages, while all messages authenticated by CBC-MAC must
              be the same length.

    Security: AES128-CMAC mode of operation offers 64 bits of security against
              collision attacks. Note however that an external attacker cannot
              generate the tags him/herself without knowing the MAC key. In this
              sense, to attack the collision property of AES128-CMAC, an
              external attacker would need the cooperation of the legal user to
              produce an exponentially high number of tags (e.g. 2^64) to
              finally be able to look for collisions and benefit from them. As
              an extra precaution, the current implementation allows to at most
              2^48 calls to the tc_cmac_update function before re-calling
              tc_cmac_setup (allowing a new key to be set), as suggested in
              Appendix B of SP 800-38B.

    Requires: AES-128

    Usage:   This implementation provides a "scatter-gather" interface, so that
             the CMAC value can be computed incrementally over a message
             scattered in different segments throughout memory. Experience shows
             this style of interface tends to minimize the burden of programming
             correctly. Like all symmetric key operations, it is session
             oriented.

             To begin a CMAC session, use tc_cmac_setup to initialize a struct
             tc_cmac_struct with encryption key and buffer. Our implementation
             always assume that the AES key to be the same size as the block
             cipher block size. Once setup, this data structure can be used for
             many CMAC computations.

             Once the state has been setup with a key, computing the CMAC of
             some data requires three steps:

             (1) first use tc_cmac_init to initialize a new CMAC computation.
             (2) next mix all of the data into the CMAC computation state using
                 tc_cmac_update. If all of the data resides in a single data
                 segment then only one tc_cmac_update call is needed; if data
                 is scattered throughout memory in n data segments, then n calls
                 will be needed. CMAC IS ORDER SENSITIVE, to be able to detect
                 attacks that swap bytes, so the order in which data is mixed
                 into the state is critical!
             (3) Once all of the data for a message has been mixed, use
                 tc_cmac_final to compute the CMAC tag value.

             Steps (1)-(3) can be repeated as many times as you want to CMAC
             multiple messages. A practical limit is 2^48 1K messages before you
             have to change the key.

             Once you are done computing CMAC with a key, it is a good idea to
             destroy the state so an attacker cannot recover the key; use
             tc_cmac_erase to accomplish this.
*/

#ifndef __TC_CMAC_MODE_H__
#define __TC_CMAC_MODE_H__

#include <tinycrypt/aes.h>

#include <stddef.h>

#ifdef __cplusplus
extern "C" {
#endif

/* padding for last message block */
#define TC_CMAC_PADDING 0x80

/* struct tc_cmac_struct represents the state of a CMAC computation */
typedef struct tc_cmac_struct
{
    /* initialization vector */
    uint8_t iv[TC_AES_BLOCK_SIZE];
    /* used if message length is a multiple of block_size bytes */
    uint8_t K1[TC_AES_BLOCK_SIZE];
    /* used if message length isn't a multiple block_size bytes */
    uint8_t K2[TC_AES_BLOCK_SIZE];
    /* where to put bytes that didn't fill a block */
    uint8_t leftover[TC_AES_BLOCK_SIZE];
    /* identifies the encryption key */
    unsigned int keyid;
    /* next available leftover location */
    unsigned int leftover_offset;
    /* AES key schedule */
    TCAesKeySched_t sched;
    /* calls to tc_cmac_update left before re-key */
    uint64_t countdown;
}* TCCmacState_t;

/**
    @brief Configures the CMAC state to use the given AES key
    @return returns TC_CRYPTO_SUCCESS (1) after having configured the CMAC state
           returns TC_CRYPTO_FAIL (0) if:
                s == NULL or
                key == NULL

    @param s IN/OUT -- the state to set up
    @param key IN -- the key to use
    @param sched IN -- AES key schedule
*/
int tc_cmac_setup(TCCmacState_t s, const uint8_t* key,
                  TCAesKeySched_t sched);

/**
    @brief Erases the CMAC state
    @return returns TC_CRYPTO_SUCCESS (1) after having configured the CMAC state
           returns TC_CRYPTO_FAIL (0) if:
                s == NULL

    @param s IN/OUT -- the state to erase
*/
int tc_cmac_erase(TCCmacState_t s);

/**
    @brief Initializes a new CMAC computation
    @return returns TC_CRYPTO_SUCCESS (1) after having initialized the CMAC state
           returns TC_CRYPTO_FAIL (0) if:
                s == NULL

    @param s IN/OUT -- the state to initialize
*/
int tc_cmac_init(TCCmacState_t s);

/**
    @brief Incrementally computes CMAC over the next data segment
    @return returns TC_CRYPTO_SUCCESS (1) after successfully updating the CMAC state
           returns TC_CRYPTO_FAIL (0) if:
                s == NULL or
                if data == NULL when dlen > 0

    @param s IN/OUT -- the CMAC state
    @param data IN -- the next data segment to MAC
    @param dlen IN -- the length of data in bytes
*/
int tc_cmac_update(TCCmacState_t s, const uint8_t* data, size_t dlen);

/**
    @brief Generates the tag from the CMAC state
    @return returns TC_CRYPTO_SUCCESS (1) after successfully generating the tag
           returns TC_CRYPTO_FAIL (0) if:
                tag == NULL or
                s == NULL

    @param tag OUT -- the CMAC tag
    @param s IN -- CMAC state
*/
int tc_cmac_final(uint8_t* tag, TCCmacState_t s);

#ifdef __cplusplus
}
#endif

#endif /* __TC_CMAC_MODE_H__ */
