/* ccm_mode.h - TinyCrypt interface to a CCM mode 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 CCM mode implementation.

    Overview: CCM (for "Counter with CBC-MAC") mode is a NIST approved mode of
              operation defined in SP 800-38C.

              TinyCrypt CCM implementation accepts:

              1) Both non-empty payload and associated data (it encrypts and
              authenticates the payload and also authenticates the associated
              data);
              2) Non-empty payload and empty associated data (it encrypts and
              authenticates the payload);
              3) Non-empty associated data and empty payload (it degenerates to
              an authentication mode on the associated data).

              TinyCrypt CCM implementation accepts associated data of any length
              between 0 and (2^16 - 2^8) bytes.

    Security: The mac length parameter is an important parameter to estimate the
              security against collision attacks (that aim at finding different
              messages that produce the same authentication tag). TinyCrypt CCM
              implementation accepts any even integer between 4 and 16, as
              suggested in SP 800-38C.

              RFC-3610, which also specifies CCM, presents a few relevant
              security suggestions, such as: it is recommended for most
              applications to use a mac length greater than 8. Besides, the
              usage of the same nonce for two different messages which are
              encrypted with the same key destroys the security of CCM mode.

    Requires: AES-128

    Usage:    1) call tc_ccm_config to configure.

              2) call tc_ccm_mode_encrypt to encrypt data and generate tag.

              3) call tc_ccm_mode_decrypt to decrypt data and verify tag.
*/

#ifndef __TC_CCM_MODE_H__
#define __TC_CCM_MODE_H__

#include <tinycrypt/aes.h>
#include <stddef.h>

#ifdef __cplusplus
extern "C" {
#endif

/* max additional authenticated size in bytes: 2^16 - 2^8 = 65280 */
#define TC_CCM_AAD_MAX_BYTES 0xff00

/* max message size in bytes: 2^(8L) = 2^16 = 65536 */
#define TC_CCM_PAYLOAD_MAX_BYTES 0x10000

/* struct tc_ccm_mode_struct represents the state of a CCM computation */
typedef struct tc_ccm_mode_struct
{
    TCAesKeySched_t sched; /* AES key schedule */
    uint8_t* nonce; /* nonce required by CCM */
    unsigned int mlen; /* mac length in bytes (parameter t in SP-800 38C) */
}* TCCcmMode_t;

/**
    @brief CCM configuration procedure
    @return returns TC_CRYPTO_SUCCESS (1)
            returns TC_CRYPTO_FAIL (0) if:
                  c == NULL or
                  sched == NULL or
                  nonce == NULL or
                  mlen != {4, 6, 8, 10, 12, 16}
    @param c -- CCM state
    @param sched IN -- AES key schedule
    @param nonce IN - nonce
    @param nlen -- nonce length in bytes
    @param mlen -- mac length in bytes (parameter t in SP-800 38C)
*/
int tc_ccm_config(TCCcmMode_t c, TCAesKeySched_t sched, uint8_t* nonce,
                  unsigned int nlen, unsigned int mlen);

/**
    @brief CCM tag generation and encryption procedure
    @return returns TC_CRYPTO_SUCCESS (1)
           returns TC_CRYPTO_FAIL (0) if:
                  out == NULL or
                  c == NULL or
                  ((plen > 0) and (payload == NULL)) or
                  ((alen > 0) and (associated_data == NULL)) or
                  (alen >= TC_CCM_AAD_MAX_BYTES) or
                  (plen >= TC_CCM_PAYLOAD_MAX_BYTES) or
                  (olen < plen + maclength)

    @param out OUT -- encrypted data
    @param olen IN -- output length in bytes
    @param associated_data IN -- associated data
    @param alen IN -- associated data length in bytes
    @param payload IN -- payload
    @param plen IN -- payload length in bytes
    @param c IN -- CCM state

    @note: out buffer should be at least (plen + c->mlen) bytes long.

    @note: The sequence b for encryption is formatted as follows:
          b = [FLAGS | nonce | counter ], where:
            FLAGS is 1 byte long
            nonce is 13 bytes long
            counter is 2 bytes long
          The byte FLAGS is composed by the following 8 bits:
            0-2 bits: used to represent the value of q-1
            3-7 btis: always 0's

    @note: The sequence b for authentication is formatted as follows:
          b = [FLAGS | nonce | length(mac length)], where:
            FLAGS is 1 byte long
            nonce is 13 bytes long
            length(mac length) is 2 bytes long
          The byte FLAGS is composed by the following 8 bits:
            0-2 bits: used to represent the value of q-1
            3-5 bits: mac length (encoded as: (mlen-2)/2)
            6: Adata (0 if alen == 0, and 1 otherwise)
            7: always 0
*/
int tc_ccm_generation_encryption(uint8_t* out, unsigned int olen,
                                 const uint8_t* associated_data,
                                 unsigned int alen, const uint8_t* payload,
                                 unsigned int plen, TCCcmMode_t c);

/**
    @brief CCM decryption and tag verification procedure
    @return returns TC_CRYPTO_SUCCESS (1)
           returns TC_CRYPTO_FAIL (0) if:
                  out == NULL or
                  c == NULL or
                  ((plen > 0) and (payload == NULL)) or
                  ((alen > 0) and (associated_data == NULL)) or
                  (alen >= TC_CCM_AAD_MAX_BYTES) or
                  (plen >= TC_CCM_PAYLOAD_MAX_BYTES) or
                  (olen < plen - c->mlen)

    @param out OUT -- decrypted data
    @param associated_data IN -- associated data
    @param alen IN -- associated data length in bytes
    @param payload IN -- payload
    @param plen IN -- payload length in bytes
    @param c IN -- CCM state

    @note: out buffer should be at least (plen - c->mlen) bytes long.

    @note: The sequence b for encryption is formatted as follows:
          b = [FLAGS | nonce | counter ], where:
            FLAGS is 1 byte long
            nonce is 13 bytes long
            counter is 2 bytes long
          The byte FLAGS is composed by the following 8 bits:
            0-2 bits: used to represent the value of q-1
            3-7 btis: always 0's

    @note: The sequence b for authentication is formatted as follows:
          b = [FLAGS | nonce | length(mac length)], where:
            FLAGS is 1 byte long
            nonce is 13 bytes long
            length(mac length) is 2 bytes long
          The byte FLAGS is composed by the following 8 bits:
            0-2 bits: used to represent the value of q-1
            3-5 bits: mac length (encoded as: (mlen-2)/2)
            6: Adata (0 if alen == 0, and 1 otherwise)
            7: always 0
*/
int tc_ccm_decryption_verification(uint8_t* out, unsigned int olen,
                                   const uint8_t* associated_data,
                                   unsigned int alen, const uint8_t* payload, unsigned int plen,
                                   TCCcmMode_t c);

#ifdef __cplusplus
}
#endif

#endif /* __TC_CCM_MODE_H__ */
