| /* 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__ */ |