Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 121 additions & 28 deletions sys/crypto/modes/ccm.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
* @{
*
* @file
* @brief Crypto mode - counter with CBC-MAC
* @brief Crypto mode - counter with CBC-MAC (CCM) and CCM*
*
* @author Nico von Geyso <nico.geyso@fu-berlin.de>
*
Expand Down Expand Up @@ -43,6 +43,12 @@ static int ccm_compute_cbc_mac(cipher_t *cipher, const uint8_t iv[16],
block_size = cipher_get_block_size(cipher);
memmove(mac, iv, 16);
offset = 0;

/* no input message */
if(length == 0) {
return 0;
}

do {
uint8_t block_size_input = (length - offset > block_size) ?
block_size : length - offset;
Expand Down Expand Up @@ -77,6 +83,7 @@ static int ccm_create_mac_iv(cipher_t *cipher, uint8_t auth_data_len, uint8_t M,
7 6 5..3 2..0
Reserved Adata M_ L_ */
M_ = (M - 2) / 2;

L_ = L - 1;
X1[0] = 64 * (auth_data_len > 0) + 8 * M_ + L_;

Expand Down Expand Up @@ -167,8 +174,20 @@ static inline int _fits_in_nbytes(size_t value, uint8_t num_bytes)
return (value >> shift) <= 1;
}

/* Valid mac_length are 4, 6, 8 ... 16 octets */
static bool _valid_mac_length_ccm(uint8_t mac_length)
{
return (mac_length % 2 == 0 && mac_length >= 4 && mac_length <= 16);
}

/* Valid mac_length are 0, 4, 6, 8 ... 16 octets */
static bool _valid_mac_length_ccms(uint8_t mac_length)
{
return (mac_length == 0) || \
(mac_length % 2 == 0 && mac_length >=4 && mac_length <= 16);
}

int cipher_encrypt_ccm(cipher_t *cipher,
int _cipher_encrypt_ccm(cipher_t *cipher,
const uint8_t *auth_data, uint32_t auth_data_len,
uint8_t mac_length, uint8_t length_encoding,
const uint8_t *nonce, size_t nonce_len,
Expand All @@ -179,10 +198,6 @@ int cipher_encrypt_ccm(cipher_t *cipher,
uint8_t nonce_counter[16] = { 0 }, mac_iv[16] = { 0 }, mac[16] = { 0 },
stream_block[16] = { 0 }, zero_block[16] = { 0 }, block_size;

if (mac_length % 2 != 0 || mac_length < 4 || mac_length > 16) {
return CCM_ERR_INVALID_MAC_LENGTH;
}

if (length_encoding < 2 || length_encoding > 8 ||
!_fits_in_nbytes(input_len, length_encoding)) {
return CCM_ERR_INVALID_LENGTH_ENCODING;
Expand All @@ -191,15 +206,22 @@ int cipher_encrypt_ccm(cipher_t *cipher,
/* Create B0, encrypt it (X1) and use it as mac_iv */
block_size = cipher_get_block_size(cipher);
assert(block_size == CCM_BLOCK_SIZE);
if (ccm_create_mac_iv(cipher, auth_data_len, mac_length, length_encoding,
nonce, nonce_len, input_len, mac_iv) < 0) {
return CCM_ERR_INVALID_DATA_LENGTH;
}

/* MAC calculation (T) with additional data and plaintext */
len = ccm_compute_adata_mac(cipher, auth_data, auth_data_len, mac_iv);
if (len < 0) {
return len;
/* The value M = 0 (mac_length = 0) corresponds to disabling authenticity,
since then the authentication field is the empty string, this is only
possible in ccms, in ccm mac_lenth !=0 would have been checked by
_valid_mac_length_ccm() */
if (mac_length != 0) {
if (ccm_create_mac_iv(cipher, auth_data_len, mac_length, length_encoding,
nonce, nonce_len, input_len, mac_iv) < 0) {
return CCM_ERR_INVALID_DATA_LENGTH;
}

/* MAC calculation (T) with additional data and plaintext */
len = ccm_compute_adata_mac(cipher, auth_data, auth_data_len, mac_iv);
if (len < 0) {
return len;
}
}

len = ccm_compute_cbc_mac(cipher, mac_iv, input, input_len, mac);
Expand Down Expand Up @@ -234,7 +256,7 @@ int cipher_encrypt_ccm(cipher_t *cipher,
}


int cipher_decrypt_ccm(cipher_t *cipher,
int _cipher_decrypt_ccm(cipher_t *cipher,
const uint8_t *auth_data, uint32_t auth_data_len,
uint8_t mac_length, uint8_t length_encoding,
const uint8_t *nonce, size_t nonce_len,
Expand All @@ -248,10 +270,6 @@ int cipher_decrypt_ccm(cipher_t *cipher,
block_size;
size_t plain_len;

if (mac_length % 2 != 0 || mac_length < 4 || mac_length > 16) {
return CCM_ERR_INVALID_MAC_LENGTH;
}

if (length_encoding < 2 || length_encoding > 8 ||
!_fits_in_nbytes(input_len, length_encoding)) {
return CCM_ERR_INVALID_LENGTH_ENCODING;
Expand All @@ -278,17 +296,24 @@ int cipher_decrypt_ccm(cipher_t *cipher,
return len;
}

/* Create B0, encrypt it (X1) and use it as mac_iv */
if (ccm_create_mac_iv(cipher, auth_data_len, mac_length, length_encoding,
nonce, nonce_len, plain_len, mac_iv) < 0) {
return CCM_ERR_INVALID_DATA_LENGTH;
}
/* The value M = 0 (mac_length = 0) corresponds to disabling authenticity,
since then the authentication field is the empty string, this is only
possible in ccms, in ccm mac_lenth !=0 would have been checked by
_valid_mac_length_ccm() */
if (mac_length != 0) {
/* Create B0, encrypt it (X1) and use it as mac_iv */
if (ccm_create_mac_iv(cipher, auth_data_len, mac_length, length_encoding,
nonce, nonce_len, plain_len, mac_iv) < 0) {
return CCM_ERR_INVALID_DATA_LENGTH;
}

/* MAC calculation (T) with additional data and plaintext */
len = ccm_compute_adata_mac(cipher, auth_data, auth_data_len, mac_iv);
if (len < 0) {
return len;
/* MAC calculation (T) with additional data and plaintext */
len = ccm_compute_adata_mac(cipher, auth_data, auth_data_len, mac_iv);
if (len < 0) {
return len;
}
}

len = ccm_compute_cbc_mac(cipher, mac_iv, plain, plain_len, mac);
if (len < 0) {
return len;
Expand All @@ -305,3 +330,71 @@ int cipher_decrypt_ccm(cipher_t *cipher,

return plain_len;
}

int cipher_decrypt_ccm(cipher_t *cipher,
const uint8_t *auth_data, uint32_t auth_data_len,
uint8_t mac_length, uint8_t length_encoding,
const uint8_t *nonce, size_t nonce_len,
const uint8_t *input, size_t input_len,
uint8_t *plain)
{
if(_valid_mac_length_ccm(mac_length)){
return _cipher_decrypt_ccm(cipher, auth_data, auth_data_len, mac_length,
length_encoding, nonce, nonce_len, input,
input_len, plain);
}
else {
return CCM_ERR_INVALID_MAC_LENGTH;
}
}

int cipher_decrypt_ccms(cipher_t *cipher,
const uint8_t *auth_data, uint32_t auth_data_len,
uint8_t mac_length, uint8_t length_encoding,
const uint8_t *nonce, size_t nonce_len,
const uint8_t *input, size_t input_len,
uint8_t *plain)
{
if(_valid_mac_length_ccms(mac_length)){
return _cipher_decrypt_ccm(cipher, auth_data, auth_data_len, mac_length,
length_encoding, nonce, nonce_len, input,
input_len, plain);
}
else {
return CCM_ERR_INVALID_MAC_LENGTH;
}
}

int cipher_encrypt_ccm(cipher_t *cipher,
const uint8_t *auth_data, uint32_t auth_data_len,
uint8_t mac_length, uint8_t length_encoding,
const uint8_t *nonce, size_t nonce_len,
const uint8_t *input, size_t input_len,
uint8_t *output)
{
if(_valid_mac_length_ccm(mac_length)) {
return _cipher_encrypt_ccm(cipher, auth_data, auth_data_len, mac_length,
length_encoding, nonce, nonce_len, input,
input_len, output);
}
else {
return CCM_ERR_INVALID_MAC_LENGTH;
}
}

int cipher_encrypt_ccms(cipher_t *cipher,
const uint8_t *auth_data, uint32_t auth_data_len,
uint8_t mac_length, uint8_t length_encoding,
const uint8_t *nonce, size_t nonce_len,
const uint8_t *input, size_t input_len,
uint8_t *output)
{
if(_valid_mac_length_ccms(mac_length)) {
return _cipher_encrypt_ccm(cipher, auth_data, auth_data_len, mac_length,
length_encoding, nonce, nonce_len, input,
input_len, output);
}
else {
return CCM_ERR_INVALID_MAC_LENGTH;
}
}
30 changes: 8 additions & 22 deletions sys/include/crypto/modes/ccm.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,29 +20,12 @@
#ifndef CRYPTO_MODES_CCM_H
#define CRYPTO_MODES_CCM_H

#include "crypto/ciphers.h"
#include "ccm_common.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
* @name CCM error codes
* @{
*/
#define CCM_ERR_INVALID_NONCE_LENGTH (-2)
#define CCM_ERR_INVALID_CBC_MAC (-3)
#define CCM_ERR_INVALID_DATA_LENGTH (-3)
#define CCM_ERR_INVALID_LENGTH_ENCODING (-4)
#define CCM_ERR_INVALID_MAC_LENGTH (-5)
/** @} */

/**
* @brief Block size required for the cipher. CCM is only defined for 128 bit ciphers.
*/
#define CCM_BLOCK_SIZE 16


/**
* @brief Encrypt and authenticate data of arbitrary length in ccm mode.
*
Expand All @@ -57,10 +40,12 @@ extern "C" {
* @param nonce_len Length of the nonce in octets
* (maximum: 15-length_encoding)
* @param input pointer to input data to encrypt
* @param input_len length of the input data, max 2^32
* @param input_len length of the input data, [0, 2^32]
* @param output pointer to allocated memory for encrypted data. It
* has to be of size data_len + mac_length.
* @return Length of encrypted data on a successful encryption
*
* @return Length of encrypted data on a successful encryption,
* can be 0 if input_len=0 (no plaintext)
* @return A negative error code if something went wrong
*/
int cipher_encrypt_ccm(cipher_t *cipher,
Expand All @@ -85,11 +70,12 @@ int cipher_encrypt_ccm(cipher_t *cipher,
* @param nonce_len Length of the nonce in octets
* (maximum: 15-length_encoding)
* @param input pointer to input data to decrypt
* @param input_len length of the input data, max 2^32
* @param input_len length of the input data, [0, 2^32]
* @param output pointer to allocated memory for decrypted data. It
* has to be of size data_len - mac_length.
*
* @return Length of the decrypted data on a successful decryption
* @return Length of the decrypted data on a successful decryption,
* can be 0 if only auth_data and MAC is present.
* @return A negative error code if something went wrong
*/
int cipher_decrypt_ccm(cipher_t *cipher,
Expand Down
50 changes: 50 additions & 0 deletions sys/include/crypto/modes/ccm_common.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright (C) 2015 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/

/**
* @ingroup sys_crypto
* @{
*
* @file ccm.h
* @brief Common header definitions for CBC-MAC (CCM) and CCM* (CCMS)
*
* @author Freie Universitaet Berlin, Computer Systems & Telematics
* @author Nico von Geyso <nico.geyso@fu-berlin.de>
*/

#ifndef CRYPTO_MODES_CCM_COMMON_H
#define CRYPTO_MODES_CCM_COMMON_H

#include "crypto/ciphers.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
* @name CCM error codes
* @{
*/
#define CCM_ERR_INVALID_NONCE_LENGTH (-2)
#define CCM_ERR_INVALID_CBC_MAC (-3)
#define CCM_ERR_INVALID_DATA_LENGTH (-3)
#define CCM_ERR_INVALID_LENGTH_ENCODING (-4)
#define CCM_ERR_INVALID_MAC_LENGTH (-5)
/** @} */

/**
* @brief Block size required for the cipher. CCM is only defined for 128 bit ciphers.
*/
#define CCM_BLOCK_SIZE 16

#ifdef __cplusplus
}
#endif

#endif /* CRYPTO_MODES_CCM_H */
/** @} */
Loading