195 lines
8.0 KiB
C
195 lines
8.0 KiB
C
/* 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 __BLE_MESH_TC_CMAC_MODE_H__
|
|
#define __BLE_MESH_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 /* __BLE_MESH_TC_CMAC_MODE_H__ */
|