diff --git a/sys/Makefile b/sys/Makefile index 970754859092b1166ce4710e4f494924f4129dd5..de4647c6bc47134a9f2617ef1f6474ca4a353d67 100644 --- a/sys/Makefile +++ b/sys/Makefile @@ -110,6 +110,9 @@ endif ifneq (,$(filter ng_nomac,$(USEMODULE))) DIRS += net/link_layer/ng_nomac endif +ifneq (,$(filter cipher_modes,$(USEMODULE))) + DIRS += crypto/modes +endif ifneq (,$(filter ng_pktbuf,$(USEMODULE))) DIRS += net/crosslayer/ng_pktbuf endif diff --git a/sys/crypto/3des.c b/sys/crypto/3des.c index dfc7db2f17da293294ba57e5da26fd638db13d76..f23c22193bf0181d063b44fe9e78d30738e6be6f 100644 --- a/sys/crypto/3des.c +++ b/sys/crypto/3des.c @@ -44,14 +44,15 @@ /** * @brief Interface to the 3DES cipher */ -block_cipher_interface_t tripledes_interface = { - "3DES", +static const cipher_interface_t tripledes_interface = { + THREEDES_BLOCK_SIZE, + THREEDES_MAX_KEY_SIZE, tripledes_init, tripledes_encrypt, - tripledes_decrypt, - tripledes_setup_key, - tripledes_get_preferred_block_size + tripledes_decrypt }; +const cipher_id_t CIPHER_3DES = &tripledes_interface; + /** * @brief struct for the 3DES key expansion @@ -247,15 +248,14 @@ static const uint32_t SP8[64] = { }; -int tripledes_init(cipher_context_t *context, uint8_t blockSize, uint8_t keySize, - uint8_t *key) +int tripledes_init(cipher_context_t *context, const uint8_t *key, + uint8_t keySize) { uint8_t i; - //printf("%-40s: Entry\r\n", __FUNCTION__); - // 16 byte blocks only - if (blockSize != THREEDES_BLOCK_SIZE) { - printf("%-40s: blockSize != 3DES_BLOCK_SIZE...\r\n", __FUNCTION__); + // Make sure that context is large enough. If this is not the case, + // you should build with -DTHREEDES + if(CIPHER_MAX_CONTEXT_SIZE < THREEDES_MAX_KEY_SIZE) { return 0; } @@ -275,14 +275,7 @@ int tripledes_init(cipher_context_t *context, uint8_t blockSize, uint8_t keySize return 1; } -int tripledes_setup_key(cipher_context_t *context, uint8_t *key, - uint8_t keysize) //To change !!! -{ - return tripledes_init(context, tripledes_get_preferred_block_size(), - keysize, key); -} - -int tripledes_encrypt(cipher_context_t *context, uint8_t *plain, uint8_t *crypt) +int tripledes_encrypt(const cipher_context_t *context, const uint8_t *plain, uint8_t *crypt) { int res; struct des3_key_s *key = malloc(sizeof(des3_key_s)); @@ -317,7 +310,7 @@ int tripledes_encrypt(cipher_context_t *context, uint8_t *plain, uint8_t *crypt) } -int tripledes_decrypt(cipher_context_t *context, uint8_t *crypt, uint8_t *plain) +int tripledes_decrypt(const cipher_context_t *context, const uint8_t *crypt, uint8_t *plain) { int res; struct des3_key_s *key = malloc(sizeof(des3_key_s)); @@ -351,11 +344,6 @@ int tripledes_decrypt(cipher_context_t *context, uint8_t *crypt, uint8_t *plain) return 1; } -uint8_t tripledes_get_preferred_block_size(void) -{ - return THREEDES_BLOCK_SIZE; -} - static void cookey(const uint32_t *raw1, uint32_t *keyout) { uint32_t *cook; diff --git a/sys/crypto/aes.c b/sys/crypto/aes.c index f837a9884da91d3fde3032af67a002c377a3eb00..e2601eada90378064eaf70226adca28ddae83fd6 100644 --- a/sys/crypto/aes.c +++ b/sys/crypto/aes.c @@ -40,14 +40,14 @@ /** * Interface to the aes cipher */ -block_cipher_interface_t aes_interface = { - "AES", +static const cipher_interface_t aes_interface = { + AES_BLOCK_SIZE, + AES_KEY_SIZE, aes_init, aes_encrypt, - aes_decrypt, - aes_setup_key, - aes_get_preferred_block_size + aes_decrypt }; +const cipher_id_t CIPHER_AES_128 = &aes_interface; static const u32 Te0[256] = { 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, @@ -720,27 +720,25 @@ static const u32 rcon[] = { }; -int aes_init(cipher_context_t *context, uint8_t blockSize, uint8_t keySize, - uint8_t *key) +int aes_init(cipher_context_t *context, const uint8_t *key, uint8_t keySize) { - //printf("%-40s: Entry\r\n", __FUNCTION__); - // 16 byte blocks only - if (blockSize != AES_BLOCK_SIZE) { - printf("%-40s: blockSize != AES_BLOCK_SIZE...\r\n", __FUNCTION__); + uint8_t i; + + // Make sure that context is large enough. If this is not the case, + // you should build with -DAES + if(CIPHER_MAX_CONTEXT_SIZE < AES_KEY_SIZE) { return 0; } - uint8_t i; - - //key must be at least CIPHERS_KEYSIZE Bytes long - if (keySize < CIPHERS_KEYSIZE) { + //key must be at least CIPHERS_MAX_KEY_SIZE Bytes long + if (keySize < CIPHERS_MAX_KEY_SIZE) { //fill up by concatenating key to as long as needed - for (i = 0; i < CIPHERS_KEYSIZE; i++) { + for (i = 0; i < CIPHERS_MAX_KEY_SIZE; i++) { context->context[i] = key[(i % keySize)]; } } else { - for (i = 0; i < CIPHERS_KEYSIZE; i++) { + for (i = 0; i < CIPHERS_MAX_KEY_SIZE; i++) { context->context[i] = key[i]; } } @@ -748,11 +746,6 @@ int aes_init(cipher_context_t *context, uint8_t blockSize, uint8_t keySize, return 1; } -int aes_setup_key(cipher_context_t *context, uint8_t *key, uint8_t keysize) -{ - return aes_init(context, aes_get_preferred_block_size(), keysize, key); -} - /** * Expand the cipher key into the encryption key schedule. */ @@ -943,7 +936,7 @@ static int aes_set_decrypt_key(const unsigned char *userKey, const int bits, * Encrypt a single block * in and out can overlap */ -int aes_encrypt(cipher_context_t *context, uint8_t *plainBlock, +int aes_encrypt(const cipher_context_t *context, const uint8_t *plainBlock, uint8_t *cipherBlock) { //setup AES_KEY @@ -1202,7 +1195,7 @@ int aes_encrypt(cipher_context_t *context, uint8_t *plainBlock, * Decrypt a single block * in and out can overlap */ -int aes_decrypt(cipher_context_t *context, uint8_t *cipherBlock, +int aes_decrypt(const cipher_context_t *context, const uint8_t *cipherBlock, uint8_t *plainBlock) { //setup AES_KEY @@ -1458,9 +1451,4 @@ int aes_decrypt(cipher_context_t *context, uint8_t *cipherBlock, return 1; } -uint8_t aes_get_preferred_block_size(void) -{ - return AES_BLOCK_SIZE; -} - #endif /* AES_ASM */ diff --git a/sys/crypto/ciphers.c b/sys/crypto/ciphers.c new file mode 100644 index 0000000000000000000000000000000000000000..2a6a07884caeba010102a7fca9946c20b8a5ac29 --- /dev/null +++ b/sys/crypto/ciphers.c @@ -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 ciphers.c + * @author Nico von Geyso <nico.geyso@fu-berlin.de> + * @} + */ + +#include <string.h> +#include <stdio.h> +#include "crypto/ciphers.h" + + +int cipher_init(cipher_t* cipher, cipher_id_t cipher_id, const uint8_t* key, + uint8_t key_size) +{ + if (key_size > cipher_id->max_key_size) { + return CIPHER_ERR_INVALID_KEY_SIZE; + } + + cipher->interface = cipher_id; + return cipher->interface->init(&cipher->context, key, key_size); + +} + + +int cipher_encrypt(const cipher_t* cipher, const uint8_t* input, uint8_t* output) +{ + return cipher->interface->encrypt(&cipher->context, input, output); +} + + +int cipher_decrypt(const cipher_t* cipher, const uint8_t* input, uint8_t* output) +{ + return cipher->interface->decrypt(&cipher->context, input, output); +} + + +int cipher_get_block_size(const cipher_t* cipher) +{ + return cipher->interface->block_size; +} diff --git a/sys/crypto/doc.txt b/sys/crypto/doc.txt index d9374a16e476cc8e009a16790ff1d7cc5b343c1e..261dea442adb325e80c76ab4356eb54a592e135c 100644 --- a/sys/crypto/doc.txt +++ b/sys/crypto/doc.txt @@ -8,6 +8,42 @@ /** * @defgroup sys_crypto Crypto - * @ingroup sys - * @brief The crypto module is a lose collection of different crypto and hash algorithms + * @brief RIOT provides a collection of block cipher ciphers, different + operation modes and cryptographic hash algorithms. + * + * \section ciphers Ciphers + * + * Riot supports the following block ciphers: + * * AES-128 + * * 3DES + * * Twofish + * * Skipjack + * * NULL + * + * You can use them directly by adding "crypto" to your USEMODULE-List. + * While you can use the ciphers functions directly, you should resort to + * the generic API for block ciphers whenever possible. + * + * Example: + * \code + * #include "crypto/ciphers.h" + * + * ciphter_t cipher; + * uint8_t key[16] = {0}, plain_text[16] = {0}, cipher_text[16] = {0}; + * + * if (cipher_init(&cipher, CIPHER_AES_128, key, key_len) < 0) + * printf("Cipher init failed!\n"); + * + * if (cipher_encrypt(&cipher, plain_text, cipher_text) < 0) + * printf("Cipher encryption!\n"); + * \endcode + * + * If you need to encrypt data of arbitrary size take a look at the different + * operation modes like: CBC, CTR or CCM. + * + * Additional examples can be found in the test suite. + * + * \section hashes Hashes + * + * RIOT currently supports sha256 as a cryptographic hash implementation. */ diff --git a/sys/crypto/helper.c b/sys/crypto/helper.c new file mode 100644 index 0000000000000000000000000000000000000000..9ddbfc47f892ca0ec556ce70e7b1541ff9dd5229 --- /dev/null +++ b/sys/crypto/helper.c @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2015 Nico von Geyso <nico.geyso@fu-berlin.de> + * Copyright (C) 2015 René Kijewski <rene.kijewski@fu-berlin.de> + * + * 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. + */ + +#include "crypto/helper.h" + +void crypto_block_inc_ctr(uint8_t block[16], int L) +{ + uint8_t *b = &block[15]; + for (int i = 0; i < L; ++i, --b) { + if (++*b != 0) { + break; + } + } +} + +int crypto_equals(uint8_t *a, uint8_t *b, size_t len) +{ + uint8_t diff = 0; + for (size_t i = 0; i < len; ++i, ++a, ++b) { + diff |= (*a ^ *b); + } + + diff |= (diff >> 1) | (diff << 7); + diff |= (diff >> 2) | (diff << 6); + diff |= (diff >> 4) | (diff << 4); + ++diff; + + return diff; +} diff --git a/sys/crypto/modes/Makefile b/sys/crypto/modes/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f06baf4be3819ebf9136a3d24d8afd38d9021b45 --- /dev/null +++ b/sys/crypto/modes/Makefile @@ -0,0 +1,2 @@ +MODULE = cipher_modes +include $(RIOTBASE)/Makefile.base diff --git a/sys/crypto/modes/cbc.c b/sys/crypto/modes/cbc.c new file mode 100644 index 0000000000000000000000000000000000000000..ab36a10f0dd1459d074ffbc52316100c313c860f --- /dev/null +++ b/sys/crypto/modes/cbc.c @@ -0,0 +1,88 @@ +/* + * 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_modes + * @{ + * + * @file + * @brief Crypto mode - cipher block chaining + * + * @author Nico von Geyso <nico.geyso@fu-berlin.de> + * + * @} + */ + + +#include <string.h> +#include "crypto/modes/cbc.h" + +int cipher_encrypt_cbc(cipher_t* cipher, uint8_t iv[16], + uint8_t* input, size_t length, uint8_t* output) +{ + size_t offset = 0; + uint8_t block_size, input_block[CIPHER_MAX_BLOCK_SIZE] = {0}, + *output_block_last; + + block_size = cipher_get_block_size(cipher); + if (length % block_size != 0) { + return CIPHER_ERR_INVALID_LENGTH; + } + + output_block_last = iv; + do { + /* CBC-Mode: XOR plaintext with ciphertext of (n-1)-th block */ + memcpy(input_block, input + offset, block_size); + for (int i = 0; i < block_size; ++i) { + input_block[i] ^= output_block_last[i]; + } + + if (cipher_encrypt(cipher, input_block, output + offset) != 1) { + return CIPHER_ERR_ENC_FAILED; + } + + output_block_last = output + offset; + offset += block_size; + } while (offset < length); + + return offset; +} + + +int cipher_decrypt_cbc(cipher_t* cipher, uint8_t iv[16], + uint8_t* input, size_t length, uint8_t* output) +{ + size_t offset = 0; + uint8_t* input_block, *output_block, *input_block_last, block_size; + + + block_size = cipher_get_block_size(cipher); + if (length % block_size != 0) { + return CIPHER_ERR_INVALID_LENGTH; + } + + input_block_last = iv; + do { + input_block = input + offset; + output_block = output + offset; + + if (cipher_decrypt(cipher, input_block, output_block) != 1) { + return CIPHER_ERR_DEC_FAILED; + } + + /* CBC-Mode: XOR plaintext with ciphertext of (n-1)-th block */ + for (uint8_t i = 0; i < block_size; ++i) { + output_block[i] ^= input_block_last[i]; + } + + input_block_last = input_block; + offset += block_size; + } while (offset < length); + + return offset; +} diff --git a/sys/crypto/modes/ccm.c b/sys/crypto/modes/ccm.c new file mode 100644 index 0000000000000000000000000000000000000000..8c0a9093925dc8d734b49d81f9c4233e9afa6829 --- /dev/null +++ b/sys/crypto/modes/ccm.c @@ -0,0 +1,257 @@ +/* + * 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_modes + * @{ + * + * @file + * @brief Crypto mode - counter with CBC-MAC + * + * @author Nico von Geyso <nico.geyso@fu-berlin.de> + * + * @} + */ + +#include <string.h> +#include "debug.h" +#include "crypto/helper.h" +#include "crypto/modes/ctr.h" +#include "crypto/modes/ccm.h" + +static inline int min(int a, int b) +{ + if (a < b) { + return a; + } + else { + return b; + } +} + +int ccm_compute_cbc_mac(cipher_t* cipher, uint8_t iv[16], + uint8_t* input, size_t length, uint8_t* mac) +{ + uint8_t offset, block_size, mac_enc[16] = {0}; + + block_size = cipher_get_block_size(cipher); + memcpy(mac, iv, 16); + offset = 0; + do { + uint8_t block_size_input = (length - offset > block_size) ? + block_size : length - offset; + + /* CBC-Mode: XOR plaintext with ciphertext of (n-1)-th block */ + for (int i = 0; i < block_size_input; ++i) { + mac[i] ^= input[offset + i]; + } + + if (cipher_encrypt(cipher, mac, mac_enc) != 1) { + return CIPHER_ERR_ENC_FAILED; + } + + memcpy(mac, mac_enc, block_size); + offset += block_size_input; + } while (offset < length); + + return offset; +} + + +int ccm_create_mac_iv(cipher_t* cipher, uint8_t auth_data_len, uint8_t M, + uint8_t L, uint8_t* nonce, uint8_t nonce_len, + size_t plaintext_len, uint8_t X1[16]) +{ + uint8_t M_, L_; + + /* ensure everything is set to zero */ + memset(X1, 0, 16); + + /* set flags in B[0] - bit format: + 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_; + + /* copy nonce to B[1..15-L] */ + memcpy(&X1[1], nonce, min(nonce_len, 15 - L)); + + /* write plaintext_len to B[15..16-L] */ + for (uint8_t i = 15; i > 16 - L; --i) { + X1[i] = plaintext_len & 0xff; + plaintext_len >>= 8; + } + + /* if there is still data, plaintext_len was too big */ + if (plaintext_len > 0) { + return CIPHER_ERR_INVALID_LENGTH; + } + + if (cipher_encrypt(cipher, X1, X1) != 1) { + return CIPHER_ERR_ENC_FAILED; + } + return 0; +} + +int ccm_compute_adata_mac(cipher_t* cipher, uint8_t* auth_data, + uint32_t auth_data_len, uint8_t X1[16]) +{ + if (auth_data_len > 0) { + int len; + + /* 16 octet block size + max. 10 len encoding */ + uint8_t auth_data_encoded[26], len_encoding = 0; + + if ( auth_data_len < (((uint32_t) 2) << 16)) { /* length (0x0001 ... 0xFEFF) */ + len_encoding = 2; + + auth_data_encoded[1] = auth_data_len & 0xFF; + auth_data_encoded[0] = (auth_data_len >> 8) & 0xFF; + } else { + DEBUG("UNSUPPORTED Adata length"); + return -1; + } + + memcpy(auth_data_encoded + len_encoding, auth_data, auth_data_len); + len = ccm_compute_cbc_mac(cipher, X1, auth_data_encoded, auth_data_len + len_encoding, X1); + if (len < 0) { + return -1; + } + } + + return 0; +} + + +int cipher_encrypt_ccm(cipher_t* cipher, uint8_t* auth_data, uint32_t auth_data_len, + uint8_t mac_length, uint8_t length_encoding, + uint8_t* nonce, size_t nonce_len, + uint8_t* input, size_t input_len, + uint8_t* output) +{ + int len = -1; + uint32_t length_max; + 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; + } + + length_max = 2 << (8 * length_encoding); + if (length_encoding < 2 || length_encoding > 8 || + input_len - auth_data_len > length_max) { + return CCM_ERR_INVALID_LENGTH_ENCODING; + } + + /* Create B0, encrypt it (X1) and use it as mac_iv */ + block_size = cipher_get_block_size(cipher); + 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 calulation (T) with additional data and plaintext */ + ccm_compute_adata_mac(cipher, auth_data, auth_data_len, mac_iv); + len = ccm_compute_cbc_mac(cipher, mac_iv, input, input_len, mac); + if (len < 0) { + return len; + } + + /* Compute first stream block */ + nonce_counter[0] = length_encoding - 1; + memcpy(&nonce_counter[1], nonce, + min(nonce_len, (size_t) 15 - length_encoding)); + len = cipher_encrypt_ctr(cipher, nonce_counter, block_size, + zero_block, block_size, stream_block); + if (len < 0) { + return len; + } + + /* Encrypt message in counter mode */ + crypto_block_inc_ctr(nonce_counter, block_size - nonce_len); + len = cipher_encrypt_ctr(cipher, nonce_counter, nonce_len, input, + input_len, output); + if (len < 0) { + return len; + } + + /* auth value: mac ^ first stream block */ + for (uint8_t i = 0; i < mac_length; ++i) { + output[len + i] = mac[i] ^ stream_block[i]; + } + + return len + mac_length; +} + + +int cipher_decrypt_ccm(cipher_t* cipher, uint8_t* auth_data, + uint32_t auth_data_len, uint8_t mac_length, + uint8_t length_encoding, uint8_t* nonce, size_t nonce_len, + uint8_t* input, size_t input_len, uint8_t* plain) +{ + int len = -1; + uint32_t length_max; + uint8_t nonce_counter[16] = {0}, mac_iv[16] = {0}, mac[16] = {0}, + mac_recv[16] = {0}, stream_block[16] = {0}, zero_block[16] = {0}, + plain_len, block_size; + + if (mac_length % 2 != 0 || mac_length < 4 || mac_length > 16) { + return CCM_ERR_INVALID_MAC_LENGTH; + } + + length_max = 2 << (8 * length_encoding); + if (length_encoding < 2 || length_encoding > 8 || + input_len - auth_data_len > length_max) { + return CCM_ERR_INVALID_LENGTH_ENCODING; + } + + /* Compute first stream block */ + nonce_counter[0] = length_encoding - 1; + block_size = cipher_get_block_size(cipher); + memcpy(&nonce_counter[1], nonce, min(nonce_len, (size_t) 15 - length_encoding)); + len = cipher_encrypt_ctr(cipher, nonce_counter, block_size, zero_block, + block_size, stream_block); + if (len < 0) { + return len; + } + + /* Decrypt message in counter mode */ + plain_len = input_len - mac_length; + crypto_block_inc_ctr(nonce_counter, block_size - nonce_len); + len = cipher_encrypt_ctr(cipher, nonce_counter, nonce_len, input, + plain_len, plain); + if (len < 0) { + 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; + } + + /* MAC calulation (T) with additional data and plaintext */ + ccm_compute_adata_mac(cipher, auth_data, auth_data_len, mac_iv); + len = ccm_compute_cbc_mac(cipher, mac_iv, plain, plain_len, mac); + if (len < 0) { + return len; + } + + /* mac = input[plain_len...plain_len+mac_length] ^ first stream block */ + for (uint8_t i = 0; i < mac_length; ++i) { + mac_recv[i] = input[len + i] ^ stream_block[i]; + } + + if (!crypto_equals(mac_recv, mac, mac_length)) { + return CCM_ERR_INVALID_CBC_MAC; + } + + return plain_len; +} diff --git a/sys/crypto/modes/ctr.c b/sys/crypto/modes/ctr.c new file mode 100644 index 0000000000000000000000000000000000000000..8ede351094c51dc39fcdaec3e082ca457287c957 --- /dev/null +++ b/sys/crypto/modes/ctr.c @@ -0,0 +1,58 @@ +/* + * 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_modes +* @{ +* +* @file +* @brief Crypto mode - Counter +* +* @author Nico von Geyso <nico.geyso@fu-berlin.de> +* +* @} +*/ + +#include "crypto/helper.h" +#include "crypto/modes/ctr.h" + +int cipher_encrypt_ctr(cipher_t* cipher, uint8_t nonce_counter[16], + uint8_t nonce_len, uint8_t* input, size_t length, + uint8_t* output) +{ + size_t offset = 0; + uint8_t stream_block[16] = {0}, block_size; + + block_size = cipher_get_block_size(cipher); + do { + uint8_t block_size_input; + + if (cipher_encrypt(cipher, nonce_counter, stream_block) != 1) { + return CIPHER_ERR_ENC_FAILED; + } + + block_size_input = (length - offset > block_size) ? + block_size : length - offset; + for (uint8_t i = 0; i < block_size_input; ++i) { + output[offset + i] = stream_block[i] ^ input[offset + i]; + } + + offset += block_size_input; + crypto_block_inc_ctr(nonce_counter, block_size - nonce_len); + } while (offset < length); + + return offset; +} + +int cipher_decrypt_ctr(cipher_t* cipher, uint8_t nonce_counter[16], + uint8_t nonce_len, uint8_t* input, size_t length, + uint8_t* output) +{ + return cipher_encrypt_ctr(cipher, nonce_counter, nonce_len, input, + length, output); +} diff --git a/sys/crypto/modes/ecb.c b/sys/crypto/modes/ecb.c new file mode 100644 index 0000000000000000000000000000000000000000..627d9ae72b404d595fa09d9b24928e7d96134325 --- /dev/null +++ b/sys/crypto/modes/ecb.c @@ -0,0 +1,66 @@ +/* + * 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_modes +* @{ +* +* @file +* @brief Crypto mode - electronic code book +* +* @author Nico von Geyso <nico.geyso@fu-berlin.de> +* +* @} +*/ + +#include "crypto/modes/ecb.h" + +int cipher_encrypt_ecb(cipher_t* cipher, uint8_t* input, + size_t length, uint8_t* output) +{ + size_t offset; + uint8_t block_size; + + block_size = cipher_get_block_size(cipher); + if (length % block_size != 0) { + return CIPHER_ERR_INVALID_LENGTH; + } + + offset = 0; + do { + if (cipher_encrypt(cipher, input + offset, output + offset) != 1) { + return CIPHER_ERR_ENC_FAILED; + } + + offset += block_size; + } while (offset < length); + + return offset; +} + +int cipher_decrypt_ecb(cipher_t* cipher, uint8_t* input, + size_t length, uint8_t* output) +{ + size_t offset = 0; + uint8_t block_size; + + block_size = cipher_get_block_size(cipher); + if (length % block_size != 0) { + return CIPHER_ERR_INVALID_LENGTH; + } + + do { + if (cipher_decrypt(cipher, input + offset, output + offset) != 1) { + return CIPHER_ERR_DEC_FAILED; + } + + offset += block_size; + } while (offset < length); + + return offset; +} diff --git a/sys/crypto/rc5.c b/sys/crypto/rc5.c index 99c8a6a0061d3c5ca6064aca24c223a7b3ed1fd1..9a32cf01be72af00b762b3eb29b240d60df8fd53 100644 --- a/sys/crypto/rc5.c +++ b/sys/crypto/rc5.c @@ -36,29 +36,17 @@ /** * @brief Interface to the rc5 cipher */ -block_cipher_interface_t rc5_interface = { - "RC5", +static const cipher_interface_t rc5_interface = { + BLOCK_SIZE, + CIPHERS_MAX_KEY_SIZE, rc5_init, rc5_encrypt, - rc5_decrypt, - rc5_setup_key, - rc5_get_preferred_block_size + rc5_decrypt }; +const cipher_id_t CIPHER_RC5 = &rc5_interface; -int rc5_init(cipher_context_t *context, uint8_t blockSize, uint8_t keySize, uint8_t *key) -{ - (void)keySize; - // 8 byte blocks only - if (blockSize != BLOCK_SIZE) { - return 0; - } - - return rc5_setup_key(context, key, 0); -} - - -int rc5_encrypt(cipher_context_t *context, uint8_t *block, +int rc5_encrypt(const cipher_context_t *context, const uint8_t *block, uint8_t *cipherBlock) { register uint32_t l; @@ -91,7 +79,7 @@ int rc5_encrypt(cipher_context_t *context, uint8_t *block, return 1; } -int rc5_decrypt(cipher_context_t *context, uint8_t *cipherBlock, +int rc5_decrypt(const cipher_context_t *context, const uint8_t *cipherBlock, uint8_t *plainBlock) { register uint32_t l; @@ -125,13 +113,20 @@ int rc5_decrypt(cipher_context_t *context, uint8_t *cipherBlock, return 1; } -int rc5_setup_key(cipher_context_t *context, uint8_t *key, uint8_t keysize) +int rc5_init(cipher_context_t *context, const uint8_t *key, uint8_t keySize) { - (void)keysize; + (void) keySize; uint32_t *L, l, A, B, *S; uint8_t ii, jj; int8_t i; uint8_t tmp[8]; + + // Make sure that context is large enough. If this is not the case, + // you should build with -DRC5. + if(CIPHER_MAX_CONTEXT_SIZE < RC5_CONTEXT_SIZE) { + return 0; + } + rc5_context_t *rc5_context = (rc5_context_t *) context->context; S = rc5_context->skey; @@ -179,16 +174,3 @@ int rc5_setup_key(cipher_context_t *context, uint8_t *key, uint8_t keysize) return 1; } - -/** - * Returns the preferred block size that this cipher operates with. It is - * always safe to call this function before the init() call has been made. - * - * @return the preferred block size for this cipher. In the case where the - * cipher operates with multiple block sizes, this will pick one - * particular size (deterministically). - */ -uint8_t rc5_get_preferred_block_size(void) -{ - return BLOCK_SIZE; -} diff --git a/sys/crypto/skipjack.c b/sys/crypto/skipjack.c index 53390804a196b69ea5253354ee4cfe15ba191670..83df59cada0333f1ed7bd039dffb8ff7e8dbea05 100644 --- a/sys/crypto/skipjack.c +++ b/sys/crypto/skipjack.c @@ -53,14 +53,14 @@ /** * @brief Interface to the skipjack cipher */ -block_cipher_interface_t skipjack_interface = { - "SkipJack", +static const cipher_interface_t skipjack_interface = { + BLOCK_SIZE, + CIPHERS_MAX_KEY_SIZE, skipjack_init, skipjack_encrypt, - skipjack_decrypt, - skipjack_setup_key, - skipjack_get_preferred_block_size + skipjack_decrypt }; +const cipher_id_t CIPHER_SKIPJACK = &skipjack_interface; // F-BOX // It can live in either RAM (faster access) or program memory (save ram, @@ -94,17 +94,6 @@ static const uint8_t SJ_F[] /*__attribute__((C))*/ = { }; -int skipjack_init(cipher_context_t *context, uint8_t blockSize, uint8_t keySize, - uint8_t *key) -{ - // 8 byte blocks only - if (blockSize != BLOCK_SIZE) { - return 0; - } - - return skipjack_setup_key(context, key, keySize); -} - /** * @brief convert 2x uint8_t to uint16_t * @@ -112,7 +101,7 @@ int skipjack_init(cipher_context_t *context, uint8_t blockSize, uint8_t keySize, * @param s pointer to the resulting uint16_t * */ -static void c2sM(uint8_t *c, uint16_t *s) +static void c2sM(const uint8_t *c, uint16_t *s) { memcpy(s, c, sizeof(uint16_t)); return; @@ -124,21 +113,22 @@ static void c2sM(uint8_t *c, uint16_t *s) * @param s pointer to the uint16_t input * @param c pointer to the first resulting uint8_ts */ -static void s2cM(uint16_t s, uint8_t *c) +static void s2cM(const uint16_t s, uint8_t *c) { memcpy(c, &s, sizeof(uint16_t)); return; } -int skipjack_encrypt(cipher_context_t *context, uint8_t *plainBlock, +int skipjack_encrypt(const cipher_context_t *context, const uint8_t *plainBlock, uint8_t *cipherBlock) { // prologue 10 pushs = 20 cycles /*register*/ uint8_t counter = 1; - skipjack_context_t *skipjack_context = (skipjack_context_t *)context->context; - /*register*/ uint8_t *skey = skipjack_context->skey; + cipher_context_t *skipjack_context = (cipher_context_t *)context->context; + /*register*/ uint8_t *skey = skipjack_context->context; + /*register*/ uint16_t w1, w2, w3, w4, tmp; /*register*/ uint8_t bLeft, bRight; @@ -173,7 +163,7 @@ int skipjack_encrypt(cipher_context_t *context, uint8_t *plainBlock, RULE_A(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); } - skey = skipjack_context->skey; + skey = skipjack_context->context; while (counter < 9) { // 3x RULE_A(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); @@ -183,13 +173,13 @@ int skipjack_encrypt(cipher_context_t *context, uint8_t *plainBlock, RULE_B(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); } - skey = skipjack_context->skey; + skey = skipjack_context->context; while (counter < 16) { // 5x RULE_B(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); } - skey = skipjack_context->skey; + skey = skipjack_context->context; // 1x RULE_B(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); @@ -197,7 +187,7 @@ int skipjack_encrypt(cipher_context_t *context, uint8_t *plainBlock, RULE_A(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); } - skey = skipjack_context->skey; + skey = skipjack_context->context; while (counter < 25) { // 4x RULE_A(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); @@ -205,13 +195,13 @@ int skipjack_encrypt(cipher_context_t *context, uint8_t *plainBlock, // 1x RULE_B(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); - skey = skipjack_context->skey; + skey = skipjack_context->context; while (counter < 31) { // 5x RULE_B(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); } - skey = skipjack_context->skey; + skey = skipjack_context->context; while (counter < 33) { // 2x RULE_B(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); @@ -232,12 +222,12 @@ int skipjack_encrypt(cipher_context_t *context, uint8_t *plainBlock, } -int skipjack_decrypt(cipher_context_t *context, uint8_t *cipherBlock, +int skipjack_decrypt(const cipher_context_t *context, const uint8_t *cipherBlock, uint8_t *plainBlock) { /*register*/ uint8_t counter = 32; - skipjack_context_t *skipjack_context = (skipjack_context_t *)context->context; - /*register*/ uint8_t *skey = skipjack_context->skey + 4; + cipher_context_t *skipjack_context = (cipher_context_t *)context->context; + /*register*/ uint8_t *skey = skipjack_context->context + 4; /*register*/ uint16_t w1, w2, w3, w4, tmp; /*register*/ uint8_t bLeft, bRight; @@ -271,13 +261,13 @@ int skipjack_decrypt(cipher_context_t *context, uint8_t *cipherBlock, RULE_B_INV(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); } - skey = skipjack_context->skey + 16; + skey = skipjack_context->context + 16; while (counter > 25) { //5x RULE_B_INV(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); } - skey = skipjack_context->skey + 16; + skey = skipjack_context->context + 16; //1x RULE_B_INV(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); @@ -285,7 +275,7 @@ int skipjack_decrypt(cipher_context_t *context, uint8_t *cipherBlock, RULE_A_INV(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); } - skey = skipjack_context->skey + 16; + skey = skipjack_context->context + 16; while (counter > 16) { //4x RULE_A_INV(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); @@ -293,13 +283,13 @@ int skipjack_decrypt(cipher_context_t *context, uint8_t *cipherBlock, //1x RULE_B_INV(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); - skey = skipjack_context->skey + 16; + skey = skipjack_context->context + 16; while (counter > 10) { //5x RULE_B_INV(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); } - skey = skipjack_context->skey + 16; + skey = skipjack_context->context + 16; while (counter > 8) { // 2x RULE_B_INV(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); @@ -309,7 +299,7 @@ int skipjack_decrypt(cipher_context_t *context, uint8_t *cipherBlock, RULE_A_INV(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); } - skey = skipjack_context->skey + 16; + skey = skipjack_context->context + 16; while (counter > 0) { // 5x RULE_A_INV(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); @@ -327,31 +317,32 @@ int skipjack_decrypt(cipher_context_t *context, uint8_t *cipherBlock, } -int skipjack_setup_key(cipher_context_t *context, uint8_t *key, uint8_t keysize) +int skipjack_init(cipher_context_t *context, const uint8_t *key, uint8_t keysize) { int i = 0; - skipjack_context_t *skipjack_context = (skipjack_context_t *)context->context; - uint8_t *skey = skipjack_context->skey; + + // Make sure that context is large enough. If this is not the case, + // you should build with -DSKIPJACK. + if(CIPHER_MAX_CONTEXT_SIZE < SKIPJACK_CONTEXT_SIZE) { + return 0; + } + + cipher_context_t *skipjack_context = (cipher_context_t *)context->context; + uint8_t *skey = skipjack_context->context; // for keys which are smaller than 160 bits, concatenate until they reach // 160 bits in size. Note that key expansion is just concatenation. - if (keysize < CIPHERS_KEYSIZE) { + if (keysize < CIPHERS_MAX_KEY_SIZE) { //fill up by concatenating key to as long as needed - for (i = 0; i < CIPHERS_KEYSIZE; i++) { + for (i = 0; i < CIPHERS_MAX_KEY_SIZE; i++) { skey[i] = key[(i % keysize)]; } } else { - for (i = 0; i < CIPHERS_KEYSIZE; i++) { + for (i = 0; i < CIPHERS_MAX_KEY_SIZE; i++) { skey[i] = key[i]; } } return 1; } - - -uint8_t skipjack_get_preferred_block_size(void) -{ - return BLOCK_SIZE; -} diff --git a/sys/crypto/twofish.c b/sys/crypto/twofish.c index 42045be36b10c41a57c9c3652068bd46ccf5615b..049c1a41f0fe27fe0467e570181d5bffa34e1f07 100644 --- a/sys/crypto/twofish.c +++ b/sys/crypto/twofish.c @@ -32,17 +32,17 @@ //prototype -static int twofish_set_key(twofish_context_t *ctx, uint8_t *key, uint8_t keylen); +static int twofish_setup_key(twofish_context_t *ctx, const uint8_t *key, uint8_t keylen); // twofish interface -block_cipher_interface_t twofish_interface = { - "TWOFISH", +static const cipher_interface_t twofish_interface = { + TWOFISH_BLOCK_SIZE, + TWOFISH_KEY_SIZE, twofish_init, twofish_encrypt, - twofish_decrypt, - twofish_setup_key, - twofish_get_preferred_block_size + twofish_decrypt }; +const cipher_id_t CIPHER_TWOFISH = &twofish_interface; /* These two tables are the q0 and q1 permutations, exactly as described in * the Twofish paper. */ @@ -473,27 +473,26 @@ static uint8_t calc_sb_tbl[512] = { -int twofish_init(cipher_context_t *context, uint8_t blockSize, uint8_t keySize, - uint8_t *key) +int twofish_init(cipher_context_t *context, const uint8_t *key, + uint8_t keySize) { - //printf("%-40s: Entry\r\n", __FUNCTION__); - // 16 byte blocks only - if (blockSize != TWOFISH_BLOCK_SIZE) { - printf("%-40s: blockSize != TWOFISH_BLOCK_SIZE...\r\n", __FUNCTION__); + uint8_t i; + + // Make sure that context is large enough. If this is not the case, + // you should build with -DTWOFISH. + if(CIPHER_MAX_CONTEXT_SIZE < TWOFISH_CONTEXT_SIZE) { return 0; } - uint8_t i; - - //key must be at least CIPHERS_KEYSIZE Bytes long - if (keySize < CIPHERS_KEYSIZE) { + //key must be at least CIPHERS_MAX_KEY_SIZE Bytes long + if (keySize < CIPHERS_MAX_KEY_SIZE) { //fill up by concatenating key to as long as needed - for (i = 0; i < CIPHERS_KEYSIZE; i++) { + for (i = 0; i < CIPHERS_MAX_KEY_SIZE; i++) { context->context[i] = key[(i % keySize)]; } } else { - for (i = 0; i < CIPHERS_KEYSIZE; i++) { + for (i = 0; i < CIPHERS_MAX_KEY_SIZE; i++) { context->context[i] = key[i]; } } @@ -501,12 +500,6 @@ int twofish_init(cipher_context_t *context, uint8_t blockSize, uint8_t keySize, return 1; } -int twofish_setup_key(cipher_context_t *context, uint8_t *key, uint8_t keysize) -{ - return twofish_init(context, twofish_get_preferred_block_size(), - keysize, key); -} - /** * @brief Perform the key setup. * Note that this works only with 128- and 256-bit keys, despite the @@ -518,7 +511,7 @@ int twofish_setup_key(cipher_context_t *context, uint8_t *key, uint8_t keysize) * * @return -1 if invalid key-length, 0 otherwise */ -static int twofish_set_key(twofish_context_t *ctx, uint8_t *key, uint8_t keylen) +static int twofish_setup_key(twofish_context_t *ctx, const uint8_t *key, uint8_t keylen) { int i, j, k; @@ -658,7 +651,7 @@ static int twofish_set_key(twofish_context_t *ctx, uint8_t *key, uint8_t keylen) /* Encrypt one block. in and out may be the same. */ -int twofish_encrypt(cipher_context_t *context, uint8_t *in, uint8_t *out) +int twofish_encrypt(const cipher_context_t *context, const uint8_t *in, uint8_t *out) { int res; //setup the twofish-specific context @@ -670,7 +663,7 @@ int twofish_encrypt(cipher_context_t *context, uint8_t *in, uint8_t *out) return -1; } - res = twofish_set_key(ctx, context->context, TWOFISH_KEY_SIZE); + res = twofish_setup_key(ctx, context->context, TWOFISH_KEY_SIZE); if (res < 0) { printf("%-40s: [ERROR] twofish_setKey failed with Code %i\r\n", @@ -716,7 +709,7 @@ int twofish_encrypt(cipher_context_t *context, uint8_t *in, uint8_t *out) } /* Decrypt one block. in and out may be the same. */ -int twofish_decrypt(cipher_context_t *context, uint8_t *in, uint8_t *out) +int twofish_decrypt(const cipher_context_t *context, const uint8_t *in, uint8_t *out) { int res; twofish_context_t *ctx = malloc(sizeof(twofish_context_t)); @@ -727,7 +720,7 @@ int twofish_decrypt(cipher_context_t *context, uint8_t *in, uint8_t *out) return -1; } - res = twofish_set_key(ctx, context->context, TWOFISH_KEY_SIZE); + res = twofish_setup_key(ctx, context->context, TWOFISH_KEY_SIZE); if (res < 0) { printf("%-40s: [ERROR] twofish_setKey failed with Code %i\r\n", @@ -771,8 +764,3 @@ int twofish_decrypt(cipher_context_t *context, uint8_t *in, uint8_t *out) free(ctx); return 1; } - -uint8_t twofish_get_preferred_block_size(void) -{ - return TWOFISH_BLOCK_SIZE; -} diff --git a/sys/include/crypto/3des.h b/sys/include/crypto/3des.h index 8f335118fedee65e94626cc58d5c3b70351652e6..fecac32a23f2913942aee89f5536c916ee69838d 100644 --- a/sys/include/crypto/3des.h +++ b/sys/include/crypto/3des.h @@ -34,7 +34,7 @@ extern "C" { #endif #define THREEDES_BLOCK_SIZE 8 -#define THREEDES_KEY_SIZE PARSEC_KEYSIZE +#define THREEDES_MAX_KEY_SIZE 24 #define ROLc(x, y) \ ((((unsigned long) (x) << (unsigned long) ((y) & 31)) | \ @@ -81,27 +81,14 @@ static const uint32_t bigbyte[24] = { * * @param context the cipher_context_t-struct to save the * initialization of the cipher in - * @param blockSize the used blocksize - this must match - * the cipher-blocksize - * @param keySize the size of the key * @param key a pointer to the key - * - * @return 0 if blocksize doesn't match else 1 - */ -int tripledes_init(cipher_context_t *context, uint8_t blockSize, uint8_t keySize, - uint8_t *key); + * @param keySize the size of the key -/** - * @brief updates the used key for this context after initialization has - * already been done - * - * @param context the cipher_context_t-struct to save the updated key in - * @param key a pointer to the key - * @param keysize the length of the key * - * @return 0 if initialized blocksize is wrong, 1 else + * @return Whether initialization was successful. The command may be + * unsuccessful if the key size is not valid. */ -int tripledes_setup_key(cipher_context_t *context, uint8_t *key, uint8_t keysize); +int tripledes_init(cipher_context_t *context, const uint8_t* key, uint8_t keySize); /** * @brief encrypts one plain-block and saves the result in crypt. @@ -120,7 +107,7 @@ int tripledes_setup_key(cipher_context_t *context, uint8_t *key, uint8_t keysize * -2 if the key could not be setup correctly * 1 if encryption was successful */ -int tripledes_encrypt(cipher_context_t *context, uint8_t *plain, uint8_t *crypt); +int tripledes_encrypt(const cipher_context_t *context, const uint8_t *plain, uint8_t *crypt); /** * @brief decrypts one cipher-block and saves the plain-block in plain. @@ -139,18 +126,7 @@ int tripledes_encrypt(cipher_context_t *context, uint8_t *plain, uint8_t *crypt) * -2 if the key could not be setup correctly * 1 if decryption was successful */ -int tripledes_decrypt(cipher_context_t *context, uint8_t *crypt, uint8_t *plain); - -/** - * @brief returns the blocksize of the 3DES algorithm - */ -uint8_t tripledes_get_preferred_block_size(void); - -/** - * Interface to access the functions - * - */ -extern block_cipher_interface_t tripledes_interface; +int tripledes_decrypt(const cipher_context_t *context, const uint8_t *crypt, uint8_t *plain); #ifdef __cplusplus } diff --git a/sys/include/crypto/aes.h b/sys/include/crypto/aes.h index c410c8ea9b8b65beee453a0805aadc492d3e7d5f..f38132332ddea1d1532074fc142e31f9d6c26b76 100644 --- a/sys/include/crypto/aes.h +++ b/sys/include/crypto/aes.h @@ -77,28 +77,13 @@ typedef struct { * * @param context the cipher_context_t-struct to save the initialization * of the cipher in - * @param blockSize the used blocksize - this must match the - * cipher-blocksize * @param keySize the size of the key * @param key a pointer to the key * - * @return 0 if blocksize doesn't match else 1 + * @return Whether initialization was successful. The command may be + * unsuccessful if the key size is not valid. */ -int aes_init(cipher_context_t *context, uint8_t blockSize, uint8_t keySize, - uint8_t *key); - -/** - * @brief updates the used key for this context after initialization has - * already been done - * - * @param context the cipher_context_t-struct to save the updated key - * in - * @param key a pointer to the key - * @param keysize the length of the key - * - * @return 0 if initialized blocksize is wrong, 1 else - */ -int aes_setup_key(cipher_context_t *context, uint8_t *key, uint8_t keysize); +int aes_init(cipher_context_t *context, const uint8_t *key, uint8_t keySize); /** * @brief encrypts one plainBlock-block and saves the result in cipherblock. @@ -115,7 +100,7 @@ int aes_setup_key(cipher_context_t *context, uint8_t *key, uint8_t keysize); * * @return 1 or result of aes_set_encrypt_key if it failed */ -int aes_encrypt(cipher_context_t *context, uint8_t *plain_block, +int aes_encrypt(const cipher_context_t *context, const uint8_t *plain_block, uint8_t *cipher_block); /** @@ -134,20 +119,9 @@ int aes_encrypt(cipher_context_t *context, uint8_t *plain_block, * @return 1 or negative value if cipher key cannot be expanded into * decryption key schedule */ -int aes_decrypt(cipher_context_t *context, uint8_t *cipher_block, +int aes_decrypt(const cipher_context_t *context, const uint8_t *cipher_block, uint8_t *plain_block); -/** - * @brief returns the blocksize of the AES algorithm - */ -uint8_t aes_get_preferred_block_size(void); - -/** - * Interface to access the functions - * - */ -extern block_cipher_interface_t aes_inerface; - #ifdef __cplusplus } #endif diff --git a/sys/include/crypto/ciphers.h b/sys/include/crypto/ciphers.h index da8511ebaef881bc8cee50e5ad3c7acaeeb02fa4..e8581ea7d20b0eb651504c531d7fa2c9bf34701c 100644 --- a/sys/include/crypto/ciphers.h +++ b/sys/include/crypto/ciphers.h @@ -22,6 +22,8 @@ #ifndef __CIPHERS_H_ #define __CIPHERS_H_ +#include <stdint.h> + #ifdef __cplusplus extern "C" { #endif @@ -30,84 +32,142 @@ extern "C" { /* Set the algorithms that should be compiled in here. When these defines * are set, then packets will be compiled 5 times. - * - * */ -#define AES -// #define RC5 -// #define THREEDES -// #define AES -// #define TWOFISH -// #define SKIPJACK + */ +// #define CRYPTO_THREEDES +// #define CRYPTO_AES +// #define CRYPTO_TWOFISH +// #define CRYPTO_SKIPJACK /** @brief the length of keys in bytes */ -#define PARSEC_MAX_BLOCK_CIPHERS 5 -#define CIPHERS_KEYSIZE 20 +#define CIPHERS_MAX_KEY_SIZE 20 +#define CIPHER_MAX_BLOCK_SIZE 16 + /** - * @brief the context for cipher-operations - * always order by number of bytes descending!!! <br> - * rc5 needs 104 bytes <br> + * Context sizes needed for the different ciphers. + * Always order by number of bytes descending!!! <br><br> + * * threedes needs 24 bytes <br> - * aes needs PARSEC_KEYSIZE bytes <br> - * twofish needs PARSEC_KEYSIZE bytes <br> - * skipjack needs 20 bytes <br> - * identity needs 1 byte <br> + * aes needs CIPHERS_MAX_KEY_SIZE bytes <br> + * twofish needs CIPHERS_MAX_KEY_SIZE bytes <br> + * skipjack needs 20 bytes */ -typedef struct { -#if defined(RC5) - uint8_t context[104]; /**< supports RC5 and lower */ -#elif defined(THREEDES) - uint8_t context[24]; /**< supports ThreeDES and lower */ -#elif defined(AES) - uint8_t context[CIPHERS_KEYSIZE]; /**< supports AES and lower */ -#elif defined(TWOFISH) - uint8_t context[CIPHERS_KEYSIZE]; /**< supports TwoFish and lower */ -#elif defined(SKIPJACK) - uint8_t context[20]; /**< supports SkipJack and lower */ +#if defined(CRYPTO_THREEDES) + #define CIPHER_MAX_CONTEXT_SIZE 24 +#elif defined(CRYPTO_AES) + #define CIPHER_MAX_CONTEXT_SIZE CIPHERS_MAX_KEY_SIZE +#elif defined(CRYPTO_TWOFISH) + #define CIPHER_MAX_CONTEXT_SIZE CIPHERS_MAX_KEY_SIZE +#elif defined(CRYPTO_SKIPJACK) + #define CIPHER_MAX_CONTEXT_SIZE 20 +#else + // 0 is not a possibility because 0-sized arrays are not allowed in ISO C + #define CIPHER_MAX_CONTEXT_SIZE 1 #endif + +/** + * error codes + */ +#define CIPHER_ERR_INVALID_KEY_SIZE -3 +#define CIPHER_ERR_INVALID_LENGTH -4 +#define CIPHER_ERR_ENC_FAILED -5 +#define CIPHER_ERR_DEC_FAILED -6 + +/** + * @brief the context for cipher-operations + */ +typedef struct { + uint8_t context[CIPHER_MAX_CONTEXT_SIZE]; /**< buffer for cipher operations */ } cipher_context_t; /** * @brief BlockCipher-Interface for the Cipher-Algorithms */ -typedef struct { - /** the name of the cipher algorithm as a string */ - char name[10]; +typedef struct cipher_interface_st { + /** Blocksize of this cipher */ + uint8_t block_size; + + /** Maximum key size for this cipher */ + uint8_t max_key_size; + /** the init function */ - int (*BlockCipher_init)(cipher_context_t *context, uint8_t blockSize, - uint8_t keySize, uint8_t *key); + int (*init)(cipher_context_t* ctx, const uint8_t* key, uint8_t key_size); + /** the encrypt function */ - int (*BlockCipher_encrypt)(cipher_context_t *context, uint8_t *plainBlock, - uint8_t *cipherBlock); + int (*encrypt)(const cipher_context_t* ctx, const uint8_t* plain_block, + uint8_t* cipher_block); + /** the decrypt function */ - int (*BlockCipher_decrypt)(cipher_context_t *context, uint8_t *cipherBlock, - uint8_t *plainBlock); - /** the setupKey function */ - int (*setupKey)(cipher_context_t *context, uint8_t *key, uint8_t keysize); - /** read the BlockSize of this Cipher */ - uint8_t (*BlockCipherInfo_getPreferredBlockSize)(void); -} block_cipher_interface_t; + int (*decrypt)(const cipher_context_t* ctx, const uint8_t* cipher_block, + uint8_t* plain_block); +} cipher_interface_t; + + +typedef const cipher_interface_t *cipher_id_t; + +extern const cipher_id_t CIPHER_3DES; +extern const cipher_id_t CIPHER_AES_128; +extern const cipher_id_t CIPHER_TWOFISH; +extern const cipher_id_t CIPHER_SKIPJACK; /** - * @brief The cipher mode context + * @brief basic struct for using block ciphers + * contains the cipher interface and the context */ -typedef struct CipherModeContext { - cipher_context_t cc; /**< CipherContext for the cipher-operations */ - uint8_t context[24]; /**< context for the block-cipher-modes' */ -} CipherModeContext; +typedef struct { + const cipher_interface_t* interface; /**< BlockCipher-Interface for the + Cipher-Algorithms */ + cipher_context_t context; /**< The encryption context (buffer) + for the algorithm */ +} cipher_t; /** - * @brief struct for an archive of all available ciphers + * @brief Initialize new cipher state + * + * @param cipher cipher struct to init (already allocated memory) + * @param cipher_id cipher algorithm id + * @param key encryption key to use + * @param key_size length of the encryption key */ -typedef struct { - /** the number of available ciphers */ - uint8_t NoCiphers; - /** the ciphers in form or BlockCipherInterface_ts */ - block_cipher_interface_t ciphers[PARSEC_MAX_BLOCK_CIPHERS]; -} block_cipher_archive_t; +int cipher_init(cipher_t* cipher, cipher_id_t cipher_id, const uint8_t* key, + uint8_t key_size); + + +/** + * @brief Encrypt data of BLOCK_SIZE length + * * + * + * @param cipher Already initialized cipher struct + * @param input pointer to input data to encrypt + * @param output pointer to allocated memory for encrypted data. It has to + * be of size BLOCK_SIZE + */ +int cipher_encrypt(const cipher_t* cipher, const uint8_t* input, uint8_t* output); + + +/** + * @brief Decrypt data of BLOCK_SIZE length + * * + * + * @param cipher Already initialized cipher struct + * @param input pointer to input data (of size BLOCKS_SIZE) to decrypt + * @param output pointer to allocated memory for decrypted data. It has to + * be of size BLOCK_SIZE + */ +int cipher_decrypt(const cipher_t* cipher, const uint8_t* input, uint8_t* output); + + +/** + * @brief Get block size of cipher + * * + * + * @param cipher Already initialized cipher struct + */ +int cipher_get_block_size(const cipher_t* cipher); + #ifdef __cplusplus } diff --git a/sys/include/crypto/helper.h b/sys/include/crypto/helper.h new file mode 100644 index 0000000000000000000000000000000000000000..9b1efa8c8965c0fbb6d917ea8c88a89b2ad83d45 --- /dev/null +++ b/sys/include/crypto/helper.h @@ -0,0 +1,55 @@ +/* + * 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 helper.h + * @brief helper functions for sys_crypto_modes + * + * @author Freie Universitaet Berlin, Computer Systems & Telematics + * @author Nico von Geyso <nico.geyso@fu-berlin.de> + */ + +#ifndef __CRYPTO_MODES_HELPER_H_ +#define __CRYPTO_MODES_HELPER_H_ + +#include "kernel.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Increment a counter encoded in an 16 octet block. The counter is + * encoded from the least significant bit in the following form: + * block[15-L..15]) + * + * @param block encoded block + * @param L length of counter + */ +void crypto_block_inc_ctr(uint8_t block[16], int L); + + +/** + * @brief Compares two blocks of same size in deterministic time. + * + * @param a block a + * @param b block b + * @param len size of both blocks + * + * @returns 0 iff the blocks are non-equal. + */ +int crypto_equals(uint8_t *a, uint8_t *b, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* __CRYPTO_MODES_HELPER_H_ */ diff --git a/sys/include/crypto/modes/cbc.h b/sys/include/crypto/modes/cbc.h new file mode 100644 index 0000000000000000000000000000000000000000..edb21f53790f382eca88aa7e6377caa36e646701 --- /dev/null +++ b/sys/include/crypto/modes/cbc.h @@ -0,0 +1,62 @@ +/* + * 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 cbc.h + * @brief Cipher block chaining mode of operation for block ciphers + * + * @author Freie Universitaet Berlin, Computer Systems & Telematics + * @author Nico von Geyso <nico.geyso@fu-berlin.de> + */ + +#ifndef __CRYPTO_MODES_CBC_H_ +#define __CRYPTO_MODES_CBC_H_ + +#include "kernel.h" +#include "crypto/ciphers.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Encrypt data of arbitrary length in cipher block chaining mode. + * + * @param cipher Already initialized cipher struct + * @param iv 16 octet initialization vector. Must never be used more + * than once for a given key. + * @param input pointer to input data to encrypt + * @param input_len length of the input data + * @param output pointer to allocated memory for encrypted data. It has to + * be of size data_len + BLOCK_SIZE - data_len % BLOCK_SIZE. + */ +int cipher_encrypt_cbc(cipher_t* cipher, uint8_t iv[16], uint8_t* input, + size_t input_len, uint8_t* output); + + +/** + * @brief Decrypt encrypted data in cipher block chaining mode. + * + * @param cipher Already initialized cipher struct + * @param iv 16 octet initialization vector. + * @param input pointer to input data to decrypt + * @param input_len length of the input data + * @param output pointer to allocated memory for plaintext data. It has to + * be of size input_len. + */ +int cipher_decrypt_cbc(cipher_t* cipher, uint8_t iv[16], uint8_t* input, + size_t input_len, uint8_t* output); + +#ifdef __cplusplus +} +#endif + +#endif /* __CRYPTO_MODES_CBC_H_ */ diff --git a/sys/include/crypto/modes/ccm.h b/sys/include/crypto/modes/ccm.h new file mode 100644 index 0000000000000000000000000000000000000000..b5a65d2e5240a95c1ebc9dd5efaa9374582c11cd --- /dev/null +++ b/sys/include/crypto/modes/ccm.h @@ -0,0 +1,89 @@ +/* + * 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 Counter with CBC-MAC mode of operation for block ciphers + * + * @author Freie Universitaet Berlin, Computer Systems & Telematics + * @author Nico von Geyso <nico.geyso@fu-berlin.de> + */ + +#ifndef __CRYPTO_MODES_CCM_H_ +#define __CRYPTO_MODES_CCM_H_ + +#include "kernel.h" +#include "crypto/ciphers.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#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 Encrypt and authenticate data of arbitrary length in ccm mode. + * + * @param cipher Already initialized cipher struct + * @param auth_data Additional data to authenticate in MAC + * @param auth_data_len Length of additional data + * @param mac_length length of the appended MAC (between 4 and 16 - only + * even values) + * @param length_encoding maximal supported length of plaintext + * (2^(8*length_enc)). + * @param nonce Nounce for ctr mode encryption + * @param nonce_len Length of the nonce in octets + * (maximum: 16-length_encoding) + * @param input pointer to input data to encrypt + * @param input_len length of the input data + * @param output pointer to allocated memory for encrypted data. It + * has to be of size data_len + mac_length. + * @return length of encrypted data or error code + */ +int cipher_encrypt_ccm(cipher_t* cipher, uint8_t* auth_data, + uint32_t auth_data_len, uint8_t mac_length, + uint8_t length_encoding, uint8_t* nonce, size_t nonce_len, + uint8_t* input, size_t input_len, uint8_t* output); + + +/** + * @brief Decrypt data of arbitrary length in ccm mode. + * + * @param cipher Already initialized cipher struct + * @param auth_data Additional data to authenticate in MAC + * @param auth_data_len Length of additional data + * @param mac_length length of the appended MAC (between 4 and 16 - only + * even values) + * @param length_encoding maximal supported length of plaintext + * (2^(8*length_enc)). + * @param nonce Nounce for ctr mode encryption + * @param nonce_len Length of the nonce in octets + * (maximum: 16-length_encoding) + * @param input pointer to input data to decrypt + * @param input_len length of the input data + * @param output pointer to allocated memory for decrypted data. It + * has to be of size data_len - mac_length. + * @return length of encrypted data or error code + */ +int cipher_decrypt_ccm(cipher_t* cipher, uint8_t* auth_data, + uint32_t auth_data_len, uint8_t mac_length, + uint8_t length_encoding, uint8_t* nonce, size_t nonce_len, + uint8_t* input, size_t input_len, uint8_t* output); + +#ifdef __cplusplus +} +#endif + +#endif /* __CRYPTO_MODES_CCM_H_ */ diff --git a/sys/include/crypto/modes/ctr.h b/sys/include/crypto/modes/ctr.h new file mode 100644 index 0000000000000000000000000000000000000000..2599aae8da61b17dcfb2d9ed288e903af837df30 --- /dev/null +++ b/sys/include/crypto/modes/ctr.h @@ -0,0 +1,74 @@ +/* + * 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 ctr.h + * @brief Counter mode of operation for block ciphers + * + * @author Freie Universitaet Berlin, Computer Systems & Telematics + * @author Nico von Geyso <nico.geyso@fu-berlin.de> + */ + +#ifndef __CRYPTO_MODES_CTR_H_ +#define __CRYPTO_MODES_CTR_H_ + +#include "kernel.h" +#include "crypto/ciphers.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Encrypt data of arbitrary length in counter mode. + * + * @param cipher Already initialized cipher struct + * @param nonce_counter A nounce and a counter encoded in 16 octets. The counter + * will be modified in each block encryption. + * @param nonce_len Length of the nonce in octets. As nounce and counter + * have to fit in one aligned 16 octet block, maximum + * length of nonce is limited by input_len: + * 16 - log_2(input_len) + * @param input pointer to input data to encrypt + * @param length length of the input data + * @param output pointer to allocated memory for encrypted data. It has + * to be of size data_len. + */ +int cipher_encrypt_ctr(cipher_t* cipher, uint8_t nonce_counter[16], + uint8_t nonce_len, uint8_t* input, size_t length, + uint8_t* output); + + +/** + * @brief Decrypt data of arbitrary length in counter mode. Encryption and + * decryption in ctr mode are basically the same. + * + * @param cipher Already initialized cipher struct + * @param nonce_counter A nounce and a counter encoded in 16 octets. The counter + * will be modified in each block encryption. + * @param nonce_len Length of the nonce in octets. As nounce and counter + * have to fit in one aligned 16 octet block, maximum + * length of nonce is limited by input_len: + * 16 - log_2(input_len) + * @param input pointer to input data to encrypt + * @param length length of the input data + * @param output pointer to allocated memory for encrypted data. It has + * to be of size data_len. + */ +int cipher_decrypt_ctr(cipher_t* cipher, uint8_t nonce_counter[16], + uint8_t nonce_len, uint8_t* input, size_t length, + uint8_t* output); + +#ifdef __cplusplus +} +#endif + +#endif /* __CRYPTO_MODES_CTR_H_*/ diff --git a/sys/include/crypto/modes/ecb.h b/sys/include/crypto/modes/ecb.h new file mode 100644 index 0000000000000000000000000000000000000000..59d6783f7ebebbd77d2ee868a738159dd046a7c3 --- /dev/null +++ b/sys/include/crypto/modes/ecb.h @@ -0,0 +1,63 @@ +/* + * 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 ecb.h + * @brief Electronic code book mode of operation for block ciphers + * + * @author Freie Universitaet Berlin, Computer Systems & Telematics + * @author Nico von Geyso <nico.geyso@fu-berlin.de> + */ + +#ifndef __CRYPTO_MODES_ECB_H_ +#define __CRYPTO_MODES_ECB_H_ + +#include "kernel.h" +#include "crypto/ciphers.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Encrypt data of arbitrary length in ecb mode. Caution each identical + * block results in an identical encrypted block. Normally you do not + * want to use ECB. + * + * + * @param cipher Already initialized cipher struct + * @param input pointer to input data to encrypt + * @param length length of the input data + * @param output pointer to allocated memory for encrypted data. It has to + * be of size data_len + BLOCK_SIZE - data_len % BLOCK_SIZE. + */ +int cipher_encrypt_ecb(cipher_t* cipher, uint8_t* input, size_t length, + uint8_t* output); + + +/** + * @brief Decrypts data of arbitrary length in ecb mode. + * + * + * @param cipher Already initialized cipher struct + * @param input pointer to input data to decrypt + * @param length length of the input data + * @param output pointer to allocated memory for plaintext data. It has to + * be of size `lengh`. + */ +int cipher_decrypt_ecb(cipher_t* cipher, uint8_t* input, size_t length, + uint8_t* output); + +#ifdef __cplusplus +} +#endif + +#endif /* __CRYPTO_MODES_ECB_H_*/ diff --git a/sys/include/crypto/rc5.h b/sys/include/crypto/rc5.h index 7cba2df77f22f6ae44c3045931eae457d53ca75a..ebb1dfffbfc6e3a4632bac0ad0f6e1ea594deebd 100644 --- a/sys/include/crypto/rc5.h +++ b/sys/include/crypto/rc5.h @@ -56,12 +56,14 @@ extern "C" { // 2 * (ROUNDS +1) * 4 // 2 * 13 * 4 = 104 bytes +#define RC5_CONTEXT_SIZE (2 * (RC5_ROUNDS + 1)) + /** * @brief the cipher_context_t adapted for RC5 */ typedef struct { /** @cond INTERNAL */ - uint32_t skey [2 * (RC5_ROUNDS + 1)]; + uint32_t skey [RC5_CONTEXT_SIZE]; /** @endcond */ } rc5_context_t; @@ -70,17 +72,14 @@ typedef struct { * * @param context the cipher_context_t-struct to save the initialization * of the cipher in -* @param blockSize the used blocksize - this must match the -* cipher-blocksize * @param keySize the size of the key * @param key a pointer to the key * * @return Whether initialization was successful. The command may be -* unsuccessful if the key size or blockSize are not valid for the +* unsuccessful if the key size is not valid for the * given cipher implementation. */ -int rc5_init(cipher_context_t *context, uint8_t blockSize, uint8_t keySize, - uint8_t *key); +int rc5_init(cipher_context_t *context, const uint8_t *key, uint8_t keySize); /** * @brief Encrypts a single block (of blockSize) using the passed context. @@ -99,7 +98,7 @@ int rc5_init(cipher_context_t *context, uint8_t blockSize, uint8_t keySize, * @return Whether the encryption was successful. Possible failure reasons * include not calling init(). */ -int rc5_encrypt(cipher_context_t *context, uint8_t *plain_block, uint8_t *cipher_block); +int rc5_encrypt(const cipher_context_t *context, const uint8_t *plain_block, uint8_t *cipher_block); /** * @brief Decrypts a single block (of blockSize) using the key and the @@ -112,36 +111,9 @@ int rc5_encrypt(cipher_context_t *context, uint8_t *plain_block, uint8_t *cipher * @return Whether the decryption was successful. Possible failure reasons * include not calling init() or an unimplimented decrypt function. */ -int rc5_decrypt(cipher_context_t *context, uint8_t *cipherBlock, +int rc5_decrypt(const cipher_context_t *context, const uint8_t *cipherBlock, uint8_t *plainBlock); -/** - * @brief Sets up the key for usage with RC5 - * Performs the key expansion on the real secret. - * - * @param context the cipher_context_t-struct to save the updated key in - * @param key a pointer to the secret key - * @param keysize the length of the secret key - * - * @return SUCCESS - */ -int rc5_setup_key(cipher_context_t *context, uint8_t *key, uint8_t keysize); - -/** - * @brief Returns the preferred block size that this cipher operates with. - * It is always safe to call this function before the init() call has - * been made. - * - * @return the preferred block size for this cipher. - */ -uint8_t rc5_get_preferred_block_size(void); - -/** - * Interface to access the functions - * - */ -extern block_cipher_interface_t rc5_interface; - #ifdef __cplusplus } #endif diff --git a/sys/include/crypto/skipjack.h b/sys/include/crypto/skipjack.h index 04ea50227c09a8be2f22acff2c640fc32c2883bb..1ad9d05b118334be283f88e8a37e7eeed7eaa0aa 100644 --- a/sys/include/crypto/skipjack.h +++ b/sys/include/crypto/skipjack.h @@ -87,13 +87,8 @@ extern "C" { counter--; \ skey -= 4; } -/** - * @brief The cipher_context_t adapted for SkipJack - */ -typedef struct { - /** 2 times keysize. makes unrolling keystream easier / efficient */ - uint8_t skey [ 20 ]; -} skipjack_context_t; +/** 2 times keysize. makes unrolling keystream easier / efficient */ +#define SKIPJACK_CONTEXT_SIZE 20 /** * @brief Initialize the SkipJack-BlockCipher context. @@ -102,15 +97,13 @@ typedef struct { * initialization call. It should be passed to future * invocations of this module which use this particular * key. - * @param blockSize size of the block in bytes. * @param keySize key size in bytes * @param key pointer to the key * * @return Whether initialization was successful. The command may be - * unsuccessful if the key size or blockSize are not valid. + * unsuccessful if the key size is not valid. */ -int skipjack_init(cipher_context_t *context, uint8_t blockSize, uint8_t keySize, - uint8_t *key); +int skipjack_init(cipher_context_t *context, const uint8_t *key, uint8_t keySize); /** * @brief Encrypts a single block (of blockSize) using the passed context. @@ -123,7 +116,7 @@ int skipjack_init(cipher_context_t *context, uint8_t blockSize, uint8_t keySize, * @return Whether the encryption was successful. Possible failure reasons * include not calling init(). */ -int skipjack_encrypt(cipher_context_t *context, uint8_t *plainBlock, +int skipjack_encrypt(const cipher_context_t *context, const uint8_t *plainBlock, uint8_t *cipherBlock); /** @@ -137,39 +130,9 @@ int skipjack_encrypt(cipher_context_t *context, uint8_t *plainBlock, * @return Whether the decryption was successful. Possible failure reasons * include not calling init() */ -int skipjack_decrypt(cipher_context_t *context, uint8_t *cipherBlock, +int skipjack_decrypt(const cipher_context_t *context, const uint8_t *cipherBlock, uint8_t *plainBlock); -/** - * @brief Sets up the context to use the passed key for usage with SkipJack - * Performs the key expansion on the real secret. - * - * @param context the cipher_context_t-struct to save the updated key in - * @param key a pointer to the secret key - * @param keysize the length of the secret key - * - * @return SUCCESS - */ -int skipjack_setup_key(cipher_context_t *context, uint8_t *key, uint8_t keysize); - -/** - * @brief Returns the preferred block size that this cipher operates with. - * It is always safe to call this function before the init() call has - * been made. - * - * @return the preferred block size for this cipher. In the case where the - * cipher operates with multiple block sizes, this will pick one - * particular size (deterministically). - */ -uint8_t skipjack_get_preferred_block_size(void); - - -/** - * Interface to access the functions - * - */ -extern block_cipher_interface_t skipjack_interface; - #ifdef __cplusplus } #endif diff --git a/sys/include/crypto/twofish.h b/sys/include/crypto/twofish.h index c0ded1392e3cda6461351992b7ef094003baa5d3..0ad6976ce6389950102585a07b0212234d762649 100644 --- a/sys/include/crypto/twofish.h +++ b/sys/include/crypto/twofish.h @@ -34,6 +34,7 @@ extern "C" { #define TWOFISH_BLOCK_SIZE 16 #define TWOFISH_KEY_SIZE 16 //only alternative is 32! +#define TWOFISH_CONTEXT_SIZE 20 /** * Macro to perform one column of the RS matrix multiplication. The @@ -218,26 +219,13 @@ typedef struct { * call. It should be passed to future invocations of * this module * which use this particular key. - * @param block_size size of the block in bytes. * @param key_size key size in bytes * @param key pointer to the key * * @return Whether initialization was successful. The command may be - * unsuccessful if the key size or blockSize are not valid. + * unsuccessful if the key size is not valid. */ -int twofish_init(cipher_context_t *context, uint8_t block_size, uint8_t key_size, uint8_t *key); - -/** - * @brief Sets up the context to use the passed key for usage with TwoFish - * Performs the key expansion on the real secret. - * - * @param context the CipherContext-struct to save the updated key in - * @param key a pointer to the secret key - * @param key_size the length of the secret key - * - * @return SUCCESS - */ -int twofish_setup_key(cipher_context_t *context, uint8_t *key, uint8_t key_size); +int twofish_init(cipher_context_t *context, const uint8_t *key, uint8_t key_size); /** * @brief Encrypts a single block (of blockSize) using the passed context. @@ -250,7 +238,7 @@ int twofish_setup_key(cipher_context_t *context, uint8_t *key, uint8_t key_size) * @return Whether the encryption was successful. Possible failure reasons * include not calling init(). */ -int twofish_encrypt(cipher_context_t *context, uint8_t *in, uint8_t *out); +int twofish_encrypt(const cipher_context_t *context, const uint8_t *in, uint8_t *out); /** * @brief Decrypts a single block (of blockSize) using the passed context. @@ -263,24 +251,7 @@ int twofish_encrypt(cipher_context_t *context, uint8_t *in, uint8_t *out); * @return Whether the decryption was successful. Possible failure reasons * include not calling init() */ -int twofish_decrypt(cipher_context_t *context, uint8_t *in, uint8_t *out); - -/** - * @brief Returns the preferred block size that this cipher operates with. - * It is always safe to call this function before the init() call has - * been made. - * - * @return the preferred block size for this cipher. In the case where the - * cipher operates with multiple block sizes, this will pick one - * particular size (deterministically). - */ -uint8_t twofish_get_preferred_block_size(void); - -/** - * Interface to access the functions - * - */ -extern block_cipher_interface_t twofish_interface; +int twofish_decrypt(const cipher_context_t *context, const uint8_t *in, uint8_t *out); #ifdef __cplusplus } diff --git a/tests/unittests/Makefile b/tests/unittests/Makefile index 49d7578d115bf70d044278d62928223f9b92933c..3e5ce104707b0d9387a2d3e76660bd254d918457 100644 --- a/tests/unittests/Makefile +++ b/tests/unittests/Makefile @@ -4,7 +4,8 @@ include ../Makefile.tests_common BOARD_INSUFFICIENT_RAM := airfy-beacon chronos msb-430 msb-430h pca10000 \ pca10005 redbee-econotag spark-core stm32f0discovery \ telosb wsn430-v1_3b wsn430-v1_4 z1 nucleo-f334 \ - yunjia-nrf51822 samr21-xpro arduino-mega2560 + yunjia-nrf51822 samr21-xpro arduino-mega2560 \ + airfy-beacon USEMODULE += embunit diff --git a/tests/unittests/tests-crypto/Makefile.include b/tests/unittests/tests-crypto/Makefile.include index b1cd537fb7b9cfd3ac6f9ee19081353fc3983e56..7918c930f0ed9a1ea736f2f19fee7666fe5dc214 100644 --- a/tests/unittests/tests-crypto/Makefile.include +++ b/tests/unittests/tests-crypto/Makefile.include @@ -1 +1,3 @@ USEMODULE += crypto +USEMODULE += cipher_modes +CFLAGS += -DCRYPTO_THREEDES diff --git a/tests/unittests/tests-crypto/tests-crypto-3des.c b/tests/unittests/tests-crypto/tests-crypto-3des.c new file mode 100644 index 0000000000000000000000000000000000000000..b5d5733f0b6816bb9976a4dfc0e09b24dcf253dd --- /dev/null +++ b/tests/unittests/tests-crypto/tests-crypto-3des.c @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2015 Nico von Geyso + * + * 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. + */ + +#include <limits.h> + +#include "embUnit.h" +#include "crypto/3des.h" +#include "tests-crypto.h" + +static uint8_t TEST_0_KEY[] = { + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF +}; + +static uint8_t TEST_0_INP[] = { + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 +}; +static uint8_t TEST_0_ENC[] = { + 0xDF, 0x0B, 0x6C, 0x9C, 0x31, 0xCD, 0x0C, 0xE4 +}; + +static uint8_t TEST_1_KEY[] = { + 0x23, 0xA0, 0x18, 0x53, 0xFA, 0xB3, 0x89, 0x23, + 0x65, 0x89, 0x2A, 0xBC, 0x43, 0x99, 0xCC, 0x00 +}; + +static uint8_t TEST_1_INP[] = { + 0x11, 0x53, 0x81, 0xE2, 0x5F, 0x33, 0xE7, 0x41 +}; +static uint8_t TEST_1_ENC[] = { + 0x6C, 0x71, 0x5C, 0xC2, 0x58, 0x13, 0xEC, 0x6E +}; + +static void test_crypto_tripledes_encrypt(void) +{ + cipher_context_t ctx; + int err; + uint8_t data[THREEDES_BLOCK_SIZE]; + + err = tripledes_init(&ctx, TEST_0_KEY, 16); + TEST_ASSERT_EQUAL_INT(1, err); + + err = tripledes_encrypt(&ctx, TEST_0_INP, data); + TEST_ASSERT_EQUAL_INT(1, err); + TEST_ASSERT_MESSAGE(1 == compare(TEST_0_ENC, data, THREEDES_BLOCK_SIZE), "wrong ciphertext"); + + err = tripledes_init(&ctx, TEST_1_KEY, 16); + TEST_ASSERT_EQUAL_INT(1, err); + + err = tripledes_encrypt(&ctx, TEST_1_INP, data); + TEST_ASSERT_EQUAL_INT(1, err); + TEST_ASSERT_MESSAGE(1 == compare(TEST_1_ENC, data, THREEDES_BLOCK_SIZE), "wrong ciphertext"); +} + +static void test_crypto_tripledes_decrypt(void) +{ + + cipher_context_t ctx; + int err; + uint8_t data[THREEDES_BLOCK_SIZE]; + + err = tripledes_init(&ctx, TEST_0_KEY, 16); + TEST_ASSERT_EQUAL_INT(1, err); + + err = tripledes_decrypt(&ctx, TEST_0_ENC, data); + TEST_ASSERT_EQUAL_INT(1, err); + TEST_ASSERT_MESSAGE(1 == compare(TEST_0_INP, data, THREEDES_BLOCK_SIZE), "wrong plaintext"); + + err = tripledes_init(&ctx, TEST_1_KEY, 16); + TEST_ASSERT_EQUAL_INT(1, err); + + err = tripledes_decrypt(&ctx, TEST_1_ENC, data); + TEST_ASSERT_EQUAL_INT(1, err); + TEST_ASSERT_MESSAGE(1 == compare(TEST_1_INP, data, THREEDES_BLOCK_SIZE), "wrong plaintext"); +} + +Test* tests_crypto_3des_tests(void) +{ + EMB_UNIT_TESTFIXTURES(fixtures) { + new_TestFixture(test_crypto_tripledes_encrypt), + new_TestFixture(test_crypto_tripledes_decrypt), + }; + + EMB_UNIT_TESTCALLER(crypto_tripledes_tests, NULL, NULL, fixtures); + + return (Test*)&crypto_tripledes_tests; +} diff --git a/tests/unittests/tests-crypto/tests-crypto-aes.c b/tests/unittests/tests-crypto/tests-crypto-aes.c new file mode 100644 index 0000000000000000000000000000000000000000..9f458e7ccb2061900edd3d35a4c3682fb7a5adb2 --- /dev/null +++ b/tests/unittests/tests-crypto/tests-crypto-aes.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2015 Nico von Geyso + * + * 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. + */ + +#include <limits.h> + +#include "embUnit.h" +#include "crypto/aes.h" +#include "tests-crypto.h" + +static uint8_t TEST_0_KEY[] = { + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF +}; + +static uint8_t TEST_0_INP[] = { + 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, +}; +static uint8_t TEST_0_ENC[] = { + 0x37, 0x29, 0xa3, 0x6c, 0xaf, 0xe9, 0x84, 0xff, + 0x46, 0x22, 0x70, 0x42, 0xee, 0x24, 0x83, 0xf6 +}; + +static uint8_t TEST_1_KEY[] = { + 0x23, 0xA0, 0x18, 0x53, 0xFA, 0xB3, 0x89, 0x23, + 0x65, 0x89, 0x2A, 0xBC, 0x43, 0x99, 0xCC, 0x00 +}; + +static uint8_t TEST_1_INP[] = { + 0x11, 0x53, 0x81, 0xE2, 0x5F, 0x33, 0xE7, 0x41, + 0xBB, 0x12, 0x67, 0x38, 0xE9, 0x12, 0x54, 0x23 +}; +static uint8_t TEST_1_ENC[] = { + 0xD7, 0x9A, 0x54, 0x0E, 0x61, 0x33, 0x03, 0x72, + 0x59, 0x0f, 0x87, 0x91, 0xEF, 0xB0, 0xF8, 0x16 +}; + +static void test_crypto_aes_encrypt(void) +{ + cipher_context_t ctx; + int err; + uint8_t data[AES_BLOCK_SIZE]; + + err = aes_init(&ctx, TEST_0_KEY, AES_KEY_SIZE); + TEST_ASSERT_EQUAL_INT(1, err); + + err = aes_encrypt(&ctx, TEST_0_INP, data); + TEST_ASSERT_EQUAL_INT(1, err); + TEST_ASSERT_MESSAGE(1 == compare(TEST_0_ENC, data, AES_BLOCK_SIZE), "wrong ciphertext"); + + err = aes_init(&ctx, TEST_1_KEY, AES_KEY_SIZE); + TEST_ASSERT_EQUAL_INT(1, err); + + err = aes_encrypt(&ctx, TEST_1_INP, data); + TEST_ASSERT_EQUAL_INT(1, err); + TEST_ASSERT_MESSAGE(1 == compare(TEST_1_ENC, data, AES_BLOCK_SIZE), "wrong ciphertext"); +} + +static void test_crypto_aes_decrypt(void) +{ + + cipher_context_t ctx; + int err; + uint8_t data[AES_BLOCK_SIZE]; + + err = aes_init(&ctx, TEST_0_KEY, AES_KEY_SIZE); + TEST_ASSERT_EQUAL_INT(1, err); + + err = aes_decrypt(&ctx, TEST_0_ENC, data); + TEST_ASSERT_EQUAL_INT(1, err); + TEST_ASSERT_MESSAGE(1 == compare(TEST_0_INP, data, AES_BLOCK_SIZE), "wrong plaintext"); + + err = aes_init(&ctx, TEST_1_KEY, AES_KEY_SIZE); + TEST_ASSERT_EQUAL_INT(1, err); + + err = aes_decrypt(&ctx, TEST_1_ENC, data); + TEST_ASSERT_EQUAL_INT(1, err); + TEST_ASSERT_MESSAGE(1 == compare(TEST_1_INP, data, AES_BLOCK_SIZE), "wrong plaintext"); +} + +Test* tests_crypto_aes_tests(void) +{ + EMB_UNIT_TESTFIXTURES(fixtures) { + new_TestFixture(test_crypto_aes_encrypt), + new_TestFixture(test_crypto_aes_decrypt), + }; + + EMB_UNIT_TESTCALLER(crypto_aes_tests, NULL, NULL, fixtures); + + return (Test*)&crypto_aes_tests; +} diff --git a/tests/unittests/tests-crypto/tests-crypto-cipher.c b/tests/unittests/tests-crypto/tests-crypto-cipher.c new file mode 100644 index 0000000000000000000000000000000000000000..f535d8ecf463116a6c98313233508c1da4edc6e0 --- /dev/null +++ b/tests/unittests/tests-crypto/tests-crypto-cipher.c @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2015 Nico von Geyso + * + * 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. + */ + +#include <limits.h> + +#include "embUnit.h" +#include "crypto/ciphers.h" +#include "tests-crypto.h" + +static uint8_t TEST_KEY[] = { + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF +}; + +static uint8_t TEST_INP[] = { + 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 +}; + +static uint8_t TEST_ENC_AES[] = { + 0x37, 0x29, 0xa3, 0x6c, 0xaf, 0xe9, 0x84, 0xff, + 0x46, 0x22, 0x70, 0x42, 0xee, 0x24, 0x83, 0xf6 +}; + +static void test_crypto_cipher_aes_encrypt(void) +{ + cipher_t cipher; + int err, cmp; + uint8_t data[16] = {0}; + + err = cipher_init(&cipher, CIPHER_AES_128, TEST_KEY, 16); + TEST_ASSERT_EQUAL_INT(1, err); + + err = cipher_encrypt(&cipher, TEST_INP, data); + TEST_ASSERT_EQUAL_INT(1, err); + + cmp = compare(TEST_ENC_AES, data, 16); + TEST_ASSERT_MESSAGE(1 == cmp , "wrong ciphertext"); +} + +static void test_crypto_cipher_aes_decrypt(void) +{ + cipher_t cipher; + int err, cmp; + uint8_t data[16]; + + err = cipher_init(&cipher, CIPHER_AES_128, TEST_KEY, 16); + TEST_ASSERT_EQUAL_INT(1, err); + + err = cipher_decrypt(&cipher, TEST_ENC_AES, data); + TEST_ASSERT_EQUAL_INT(1, err); + + cmp = compare(TEST_INP, data, 16); + TEST_ASSERT_MESSAGE(1 == cmp , "wrong plaintext"); +} + +Test* tests_crypto_cipher_tests(void) +{ + EMB_UNIT_TESTFIXTURES(fixtures) { + new_TestFixture(test_crypto_cipher_aes_encrypt), + new_TestFixture(test_crypto_cipher_aes_decrypt) + }; + + EMB_UNIT_TESTCALLER(crypto_cipher_tests, NULL, NULL, fixtures); + + return (Test*)&crypto_cipher_tests; +} diff --git a/tests/unittests/tests-crypto/tests-crypto-modes-cbc.c b/tests/unittests/tests-crypto/tests-crypto-modes-cbc.c new file mode 100644 index 0000000000000000000000000000000000000000..e746e394eae4ba1bc37a1e8d0606c8c58b9943ff --- /dev/null +++ b/tests/unittests/tests-crypto/tests-crypto-modes-cbc.c @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2015 Nico von Geyso + * + * 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. + */ + +#include <limits.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "embUnit.h" +#include "crypto/ciphers.h" +#include "crypto/modes/cbc.h" +#include "tests-crypto.h" + +/* + * all test vectors are from "Recommendation for Block Cipher Modes of + * Operation - Methods and Techniques" by Morris Dworkin / NIST + * + * http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf + */ + + +/* PACKET VECTOR #1 (Page 27) */ +static uint8_t TEST_1_KEY[] = { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c +}; +static uint8_t TEST_1_KEY_LEN = 16; + +static uint8_t TEST_1_IV[16] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f +}; + +static uint8_t TEST_1_PLAIN[] = { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 +}; +static uint8_t TEST_1_PLAIN_LEN = 64; + +static uint8_t TEST_1_CIPHER[] = { + 0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46, + 0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d, + 0x50, 0x86, 0xcb, 0x9b, 0x50, 0x72, 0x19, 0xee, + 0x95, 0xdb, 0x11, 0x3a, 0x91, 0x76, 0x78, 0xb2, + 0x73, 0xbe, 0xd6, 0xb8, 0xe3, 0xc1, 0x74, 0x3b, + 0x71, 0x16, 0xe6, 0x9e, 0x22, 0x22, 0x95, 0x16, + 0x3f, 0xf1, 0xca, 0xa1, 0x68, 0x1f, 0xac, 0x09, + 0x12, 0x0e, 0xca, 0x30, 0x75, 0x86, 0xe1, 0xa7 +}; +static uint8_t TEST_1_CIPHER_LEN = 64; + +static void test_encrypt_op(uint8_t* key, uint8_t key_len, uint8_t iv[16], + uint8_t* input, uint8_t input_len, uint8_t* output, + uint8_t output_len) +{ + cipher_t cipher; + int len, err, cmp; + uint8_t data[64]; + + err = cipher_init(&cipher, CIPHER_AES_128, key, key_len); + TEST_ASSERT_EQUAL_INT(1, err); + + len = cipher_encrypt_cbc(&cipher, iv, input, input_len, data); + TEST_ASSERT_MESSAGE(len > 0, "Encryption failed"); + + TEST_ASSERT_EQUAL_INT(output_len, len); + cmp = compare(output, data, len); + TEST_ASSERT_MESSAGE(1 == cmp , "wrong ciphertext"); + +} + +static void test_decrypt_op(uint8_t* key, uint8_t key_len, uint8_t iv[16], + uint8_t* input, uint8_t input_len, uint8_t* output, + uint8_t output_len) +{ + cipher_t cipher; + int len, err, cmp; + uint8_t data[64]; + + err = cipher_init(&cipher, CIPHER_AES_128, key, key_len); + TEST_ASSERT_EQUAL_INT(1, err); + + len = cipher_decrypt_cbc(&cipher, iv, input, input_len, data); + TEST_ASSERT_MESSAGE(len > 0, "Encryption failed"); + + TEST_ASSERT_EQUAL_INT(output_len, len); + cmp = compare(output, data, len); + TEST_ASSERT_MESSAGE(1 == cmp , "wrong ciphertext"); + +} + +static void test_crypto_modes_cbc_encrypt(void) +{ + test_encrypt_op(TEST_1_KEY, TEST_1_KEY_LEN, TEST_1_IV, TEST_1_PLAIN, + TEST_1_PLAIN_LEN, TEST_1_CIPHER, TEST_1_CIPHER_LEN); +} + +static void test_crypto_modes_cbc_decrypt(void) +{ + test_decrypt_op(TEST_1_KEY, TEST_1_KEY_LEN, TEST_1_IV, TEST_1_CIPHER, + TEST_1_CIPHER_LEN, TEST_1_PLAIN, TEST_1_PLAIN_LEN); +} + + +Test* tests_crypto_modes_cbc_tests(void) +{ + EMB_UNIT_TESTFIXTURES(fixtures) { + new_TestFixture(test_crypto_modes_cbc_encrypt), + new_TestFixture(test_crypto_modes_cbc_decrypt) + }; + + EMB_UNIT_TESTCALLER(crypto_modes_cbc_tests, NULL, NULL, fixtures); + + return (Test*)&crypto_modes_cbc_tests; +} diff --git a/tests/unittests/tests-crypto/tests-crypto-modes-ccm.c b/tests/unittests/tests-crypto/tests-crypto-modes-ccm.c new file mode 100644 index 0000000000000000000000000000000000000000..822d21cf6debeddac7ab7afaaa0d0d0887f1db61 --- /dev/null +++ b/tests/unittests/tests-crypto/tests-crypto-modes-ccm.c @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2015 Nico von Geyso + * + * 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. + */ + +#include <limits.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "embUnit.h" +#include "crypto/ciphers.h" +#include "crypto/modes/ccm.h" +#include "tests-crypto.h" + +/* PACKET VECTOR #1 (RFC 3610 - Page 10) */ +static uint8_t TEST_1_KEY[] = { + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF +}; +static uint8_t TEST_1_KEY_LEN = 16; + +static uint8_t TEST_1_NONCE[] = { + 0x00, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0xA0, + 0xA1, 0xA2, 0xA3, 0xA4, 0xA5 +}; +static uint8_t TEST_1_NONCE_LEN = 13; + +static uint8_t TEST_1_INPUT[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* additional auth data */ + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* input */ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* input */ + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E /* input */ +}; +static uint8_t TEST_1_INPUT_LEN = 23; +static uint8_t TEST_1_ADATA_LEN = 8; + +static uint8_t TEST_1_EXPECTED[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x58, 0x8C, 0x97, 0x9A, 0x61, 0xC6, 0x63, 0xD2, + 0xF0, 0x66, 0xD0, 0xC2, 0xC0, 0xF9, 0x89, 0x80, + 0x6D, 0x5F, 0x6B, 0x61, 0xDA, 0xC3, 0x84, 0x17, + 0xE8, 0xD1, 0x2C, 0xFD, 0xF9, 0x26, 0xE0 +}; +static uint8_t TEST_1_EXPECTED_LEN = 39; + +/* PACKET VECTOR #2 (RFC 3610 - Page 10) */ +static uint8_t TEST_2_KEY[] = { + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF +}; +static uint8_t TEST_2_KEY_LEN = 16; + +static uint8_t TEST_2_NONCE[] = { + 0x00, 0x00, 0x00, 0x04, 0x03, 0x02, 0x01, 0xA0, + 0xA1, 0xA2, 0xA3, 0xA4, 0xA5 +}; +static uint8_t TEST_2_NONCE_LEN = 13; + +static uint8_t TEST_2_INPUT[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F +}; +static uint8_t TEST_2_INPUT_LEN = 24; +static uint8_t TEST_2_ADATA_LEN = 8; + +static uint8_t TEST_2_EXPECTED[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x72, 0xC9, 0x1A, 0x36, 0xE1, 0x35, 0xF8, 0xCF, + 0x29, 0x1C, 0xA8, 0x94, 0x08, 0x5C, 0x87, 0xE3, + 0xCC, 0x15, 0xC4, 0x39, 0xC9, 0xE4, 0x3A, 0x3B, + 0xA0, 0x91, 0xD5, 0x6E, 0x10, 0x40, 0x09, 0x16 +}; +static uint8_t TEST_2_EXPECTED_LEN = 40; + +static void test_encrypt_op(uint8_t* key, uint8_t key_len, uint8_t* adata, + uint8_t adata_len, uint8_t* nonce, uint8_t nonce_len, uint8_t* plain, + uint8_t plain_len, uint8_t* output_expected, uint8_t output_expected_len) +{ + cipher_t cipher; + int len, err, cmp; + uint8_t data[60]; + + err = cipher_init(&cipher, CIPHER_AES_128, key, key_len); + TEST_ASSERT_EQUAL_INT(1, err); + + len = cipher_encrypt_ccm(&cipher, adata, adata_len, 8, 2, nonce, + nonce_len, plain, plain_len, data); + TEST_ASSERT_MESSAGE(len > 0, "Encryption failed"); + + TEST_ASSERT_EQUAL_INT(output_expected_len, len); + cmp = compare(output_expected, data, len); + TEST_ASSERT_MESSAGE(1 == cmp , "wrong ciphertext"); + +} + +static void test_decrypt_op(uint8_t* key, uint8_t key_len, uint8_t* adata, + uint8_t adata_len, uint8_t* nonce, uint8_t nonce_len, uint8_t* encrypted, + uint8_t encrypted_len, uint8_t* output_expected, uint8_t output_expected_len) +{ + cipher_t cipher; + int len, err, cmp; + uint8_t data[60]; + + err = cipher_init(&cipher, CIPHER_AES_128, key, key_len); + TEST_ASSERT_EQUAL_INT(1, err); + + len = cipher_decrypt_ccm(&cipher, adata, adata_len, 8, 2, nonce, + nonce_len, encrypted, encrypted_len, data); + TEST_ASSERT_MESSAGE(len > 0, "Decryption failed"); + + TEST_ASSERT_EQUAL_INT(output_expected_len, len); + cmp = compare(output_expected, data, len); + TEST_ASSERT_MESSAGE(1 == cmp , "wrong ciphertext"); + +} + +static void test_crypto_modes_ccm_encrypt(void) +{ + test_encrypt_op(TEST_1_KEY, TEST_1_KEY_LEN, TEST_1_INPUT, TEST_1_ADATA_LEN, + TEST_1_NONCE, TEST_1_NONCE_LEN, TEST_1_INPUT + TEST_1_ADATA_LEN, + TEST_1_INPUT_LEN, TEST_1_EXPECTED + TEST_1_ADATA_LEN, + TEST_1_EXPECTED_LEN - TEST_1_ADATA_LEN); + + test_encrypt_op(TEST_2_KEY, TEST_2_KEY_LEN, TEST_2_INPUT, TEST_2_ADATA_LEN, + TEST_2_NONCE, TEST_2_NONCE_LEN, TEST_2_INPUT + TEST_2_ADATA_LEN, + TEST_2_INPUT_LEN, TEST_2_EXPECTED + TEST_2_ADATA_LEN, + TEST_2_EXPECTED_LEN - TEST_2_ADATA_LEN); +} + +static void test_crypto_modes_ccm_decrypt(void) +{ + test_decrypt_op(TEST_1_KEY, TEST_1_KEY_LEN, TEST_1_INPUT, TEST_1_ADATA_LEN, + TEST_1_NONCE, TEST_1_NONCE_LEN, TEST_1_EXPECTED + TEST_1_ADATA_LEN, + TEST_1_EXPECTED_LEN - TEST_1_ADATA_LEN, TEST_1_INPUT + TEST_1_ADATA_LEN, + TEST_1_INPUT_LEN); + + test_decrypt_op(TEST_2_KEY, TEST_2_KEY_LEN, TEST_2_INPUT, TEST_2_ADATA_LEN, + TEST_2_NONCE, TEST_2_NONCE_LEN, TEST_2_EXPECTED + TEST_2_ADATA_LEN, + TEST_2_EXPECTED_LEN - TEST_2_ADATA_LEN, TEST_2_INPUT + TEST_2_ADATA_LEN, + TEST_2_INPUT_LEN); +} + + +Test* tests_crypto_modes_ccm_tests(void) +{ + EMB_UNIT_TESTFIXTURES(fixtures) { + new_TestFixture(test_crypto_modes_ccm_encrypt), + new_TestFixture(test_crypto_modes_ccm_decrypt) + }; + + EMB_UNIT_TESTCALLER(crypto_modes_ccm_tests, NULL, NULL, fixtures); + + return (Test*)&crypto_modes_ccm_tests; +} diff --git a/tests/unittests/tests-crypto/tests-crypto-modes-ctr.c b/tests/unittests/tests-crypto/tests-crypto-modes-ctr.c new file mode 100644 index 0000000000000000000000000000000000000000..757b2d530fd92d846372307825179b27431afcf2 --- /dev/null +++ b/tests/unittests/tests-crypto/tests-crypto-modes-ctr.c @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2015 Nico von Geyso + * + * 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. + */ + +#include <limits.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "embUnit.h" +#include "crypto/ciphers.h" +#include "crypto/modes/ctr.h" +#include "tests-crypto.h" + +/* + * all test vectors are from "Recommendation for Block Cipher Modes of + * Operation - Methods and Techniques" by Morris Dworkin / NIST + * + * http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf + */ + + +/* PACKET VECTOR #1 (Page 55) */ +static uint8_t TEST_1_KEY[] = { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c +}; +static uint8_t TEST_1_KEY_LEN = 16; + +static uint8_t TEST_1_COUNTER[16] = { + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + +static uint8_t TEST_1_PLAIN[] = { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 +}; +static uint8_t TEST_1_PLAIN_LEN = 64; + +static uint8_t TEST_1_CIPHER[] = { + 0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26, + 0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce, + 0x98, 0x06, 0xf6, 0x6b, 0x79, 0x70, 0xfd, 0xff, + 0x86, 0x17, 0x18, 0x7b, 0xb9, 0xff, 0xfd, 0xff, + 0x5a, 0xe4, 0xdf, 0x3e, 0xdb, 0xd5, 0xd3, 0x5e, + 0x5b, 0x4f, 0x09, 0x02, 0x0d, 0xb0, 0x3e, 0xab, + 0x1e, 0x03, 0x1d, 0xda, 0x2f, 0xbe, 0x03, 0xd1, + 0x79, 0x21, 0x70, 0xa0, 0xf3, 0x00, 0x9c, 0xee +}; +static uint8_t TEST_1_CIPHER_LEN = 64; + +static void test_encrypt_op(uint8_t* key, uint8_t key_len, uint8_t ctr[16], + uint8_t* input, uint8_t input_len, uint8_t* output, + uint8_t output_len) +{ + cipher_t cipher; + int len, err, cmp; + uint8_t data[64]; + + err = cipher_init(&cipher, CIPHER_AES_128, key, key_len); + TEST_ASSERT_EQUAL_INT(1, err); + + len = cipher_encrypt_ctr(&cipher, ctr, 0, input, input_len, data); + TEST_ASSERT_MESSAGE(len > 0, "Encryption failed"); + + TEST_ASSERT_EQUAL_INT(output_len, len); + cmp = compare(output, data, len); + TEST_ASSERT_MESSAGE(1 == cmp , "wrong ciphertext"); + +} + +static void test_decrypt_op(uint8_t* key, uint8_t key_len, uint8_t ctr[16], + uint8_t* input, uint8_t input_len, uint8_t* output, + uint8_t output_len) +{ + cipher_t cipher; + int len, err, cmp; + uint8_t data[64]; + + err = cipher_init(&cipher, CIPHER_AES_128, key, key_len); + TEST_ASSERT_EQUAL_INT(1, err); + + len = cipher_decrypt_ctr(&cipher, ctr, 0, input, input_len, data); + TEST_ASSERT_MESSAGE(len > 0, "Encryption failed"); + + TEST_ASSERT_EQUAL_INT(output_len, len); + cmp = compare(output, data, len); + TEST_ASSERT_MESSAGE(1 == cmp , "wrong ciphertext"); + +} + +static void test_crypto_modes_ctr_encrypt(void) +{ + uint8_t ctr[16]; + + memcpy(ctr, TEST_1_COUNTER, 16); + test_encrypt_op(TEST_1_KEY, TEST_1_KEY_LEN, ctr, TEST_1_PLAIN, + TEST_1_PLAIN_LEN, TEST_1_CIPHER, TEST_1_CIPHER_LEN); +} + +static void test_crypto_modes_ctr_decrypt(void) +{ + uint8_t ctr[16]; + + memcpy(ctr, TEST_1_COUNTER, 16); + test_decrypt_op(TEST_1_KEY, TEST_1_KEY_LEN, ctr, TEST_1_CIPHER, + TEST_1_CIPHER_LEN, TEST_1_PLAIN, TEST_1_PLAIN_LEN); +} + + +Test* tests_crypto_modes_ctr_tests(void) +{ + EMB_UNIT_TESTFIXTURES(fixtures) { + new_TestFixture(test_crypto_modes_ctr_encrypt), + new_TestFixture(test_crypto_modes_ctr_decrypt) + }; + + EMB_UNIT_TESTCALLER(crypto_modes_ctr_tests, NULL, NULL, fixtures); + + return (Test*)&crypto_modes_ctr_tests; +} diff --git a/tests/unittests/tests-crypto/tests-crypto-modes-ecb.c b/tests/unittests/tests-crypto/tests-crypto-modes-ecb.c new file mode 100644 index 0000000000000000000000000000000000000000..c25985015817662523e50b873891af0286195621 --- /dev/null +++ b/tests/unittests/tests-crypto/tests-crypto-modes-ecb.c @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2015 Nico von Geyso + * + * 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. + */ + +#include <limits.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "embUnit.h" +#include "crypto/ciphers.h" +#include "crypto/modes/ecb.h" +#include "tests-crypto.h" + +/* + * all test vectors are from "Recommendation for Block Cipher Modes of + * Operation - Methods and Techniques" by Morris Dworkin / NIST + * + * http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf + */ + + +/* PACKET VECTOR #1 (Page 24) */ +static uint8_t TEST_1_KEY[] = { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c +}; +static uint8_t TEST_1_KEY_LEN = 16; + +static uint8_t TEST_1_PLAIN[] = { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 +}; +static uint8_t TEST_1_PLAIN_LEN = 64; + +static uint8_t TEST_1_CIPHER[] = { + 0x3a, 0xd7, 0x7b, 0xb4, 0x0d, 0x7a, 0x36, 0x60, + 0xa8, 0x9e, 0xca, 0xf3, 0x24, 0x66, 0xef, 0x97, + 0xf5, 0xd3, 0xd5, 0x85, 0x03, 0xb9, 0x69, 0x9d, + 0xe7, 0x85, 0x89, 0x5a, 0x96, 0xfd, 0xba, 0xaf, + 0x43, 0xb1, 0xcd, 0x7f, 0x59, 0x8e, 0xce, 0x23, + 0x88, 0x1b, 0x00, 0xe3, 0xed, 0x03, 0x06, 0x88, + 0x7b, 0x0c, 0x78, 0x5e, 0x27, 0xe8, 0xad, 0x3f, + 0x82, 0x23, 0x20, 0x71, 0x04, 0x72, 0x5d, 0xd4 +}; +static uint8_t TEST_1_CIPHER_LEN = 64; + +static void test_encrypt_op(uint8_t* key, uint8_t key_len, uint8_t* input, + uint8_t input_len, uint8_t* output, + uint8_t output_len) +{ + cipher_t cipher; + int len, err, cmp; + uint8_t data[64]; + + err = cipher_init(&cipher, CIPHER_AES_128, key, key_len); + TEST_ASSERT_EQUAL_INT(1, err); + + len = cipher_encrypt_ecb(&cipher, input, input_len, data); + TEST_ASSERT_MESSAGE(len > 0, "Encryption failed"); + + TEST_ASSERT_EQUAL_INT(output_len, len); + cmp = compare(output, data, len); + TEST_ASSERT_MESSAGE(1 == cmp , "wrong ciphertext"); + +} + +static void test_decrypt_op(uint8_t* key, uint8_t key_len, uint8_t* input, + uint8_t input_len, uint8_t* output, + uint8_t output_len) +{ + cipher_t cipher; + int len, err, cmp; + uint8_t data[64]; + + err = cipher_init(&cipher, CIPHER_AES_128, key, key_len); + TEST_ASSERT_EQUAL_INT(1, err); + + len = cipher_decrypt_ecb(&cipher, input, input_len, data); + TEST_ASSERT_MESSAGE(len > 0, "Encryption failed"); + + TEST_ASSERT_EQUAL_INT(output_len, len); + cmp = compare(output, data, len); + TEST_ASSERT_MESSAGE(1 == cmp , "wrong ciphertext"); + +} + +static void test_crypto_modes_ecb_encrypt(void) +{ + test_encrypt_op(TEST_1_KEY, TEST_1_KEY_LEN, TEST_1_PLAIN, TEST_1_PLAIN_LEN, + TEST_1_CIPHER, TEST_1_CIPHER_LEN); +} + +static void test_crypto_modes_ecb_decrypt(void) +{ + test_decrypt_op(TEST_1_KEY, TEST_1_KEY_LEN, TEST_1_CIPHER, TEST_1_CIPHER_LEN, + TEST_1_PLAIN, TEST_1_PLAIN_LEN); +} + + +Test* tests_crypto_modes_ecb_tests(void) +{ + EMB_UNIT_TESTFIXTURES(fixtures) { + new_TestFixture(test_crypto_modes_ecb_encrypt), + new_TestFixture(test_crypto_modes_ecb_decrypt) + }; + + EMB_UNIT_TESTCALLER(crypto_modes_ecb_tests, NULL, NULL, fixtures); + + return (Test*)&crypto_modes_ecb_tests; +} diff --git a/tests/unittests/tests-crypto/tests-crypto-twofish.c b/tests/unittests/tests-crypto/tests-crypto-twofish.c new file mode 100644 index 0000000000000000000000000000000000000000..ccda631d8f61ba440c016028fd2f8731f9ab0ef1 --- /dev/null +++ b/tests/unittests/tests-crypto/tests-crypto-twofish.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2015 Nico von Geyso + * + * 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. + */ + +#include <limits.h> + +#include "embUnit.h" +#include "crypto/twofish.h" +#include "tests-crypto.h" + +static uint8_t TEST_0_KEY[] = { + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF +}; + +static uint8_t TEST_0_INP[] = { + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF +}; +static uint8_t TEST_0_ENC[] = { + 0x9F, 0xB6, 0x33, 0x37, 0x15, 0x1B, 0xE9, 0xC7, + 0x13, 0x06, 0xD1, 0x59, 0xEA, 0x7A, 0xFA, 0xA4 +}; + +static uint8_t TEST_1_KEY[] = { + 0x23, 0xA0, 0x18, 0x53, 0xFA, 0xB3, 0x89, 0x23, + 0x65, 0x89, 0x2A, 0xBC, 0x43, 0x99, 0xCC, 0x00 +}; + +static uint8_t TEST_1_INP[] = { + 0x11, 0x53, 0x81, 0xE2, 0x5F, 0x33, 0xE7, 0x41, + 0xBB, 0x12, 0x67, 0x38, 0xE9, 0x12, 0x54, 0x23 +}; +static uint8_t TEST_1_ENC[] = { + 0xEA, 0x27, 0x44, 0xBB, 0x15, 0x56, 0xDB, 0xF3, + 0x33, 0xD4, 0x90, 0x09, 0x44, 0x7B, 0x83, 0x57 +}; + +static void test_crypto_twofish_encrypt(void) +{ + cipher_context_t ctx; + int err; + uint8_t data[TWOFISH_BLOCK_SIZE]; + + err = twofish_init(&ctx, TEST_0_KEY, TWOFISH_KEY_SIZE); + TEST_ASSERT_EQUAL_INT(1, err); + + err = twofish_encrypt(&ctx, TEST_0_INP, data); + TEST_ASSERT_EQUAL_INT(1, err); + TEST_ASSERT_MESSAGE(1 == compare(TEST_0_ENC, data, TWOFISH_BLOCK_SIZE), "wrong ciphertext"); + + err = twofish_init(&ctx, TEST_1_KEY, TWOFISH_KEY_SIZE); + TEST_ASSERT_EQUAL_INT(1, err); + + err = twofish_encrypt(&ctx, TEST_1_INP, data); + TEST_ASSERT_EQUAL_INT(1, err); + TEST_ASSERT_MESSAGE(1 == compare(TEST_1_ENC, data, TWOFISH_BLOCK_SIZE), "wrong ciphertext"); +} + +static void test_crypto_twofish_decrypt(void) +{ + + cipher_context_t ctx; + int err; + uint8_t data[TWOFISH_BLOCK_SIZE]; + + err = twofish_init(&ctx, TEST_0_KEY, TWOFISH_KEY_SIZE); + TEST_ASSERT_EQUAL_INT(1, err); + + err = twofish_decrypt(&ctx, TEST_0_ENC, data); + TEST_ASSERT_EQUAL_INT(1, err); + TEST_ASSERT_MESSAGE(1 == compare(TEST_0_INP, data, TWOFISH_BLOCK_SIZE), "wrong plaintext"); + + err = twofish_init(&ctx, TEST_1_KEY, TWOFISH_KEY_SIZE); + TEST_ASSERT_EQUAL_INT(1, err); + + err = twofish_decrypt(&ctx, TEST_1_ENC, data); + TEST_ASSERT_EQUAL_INT(1, err); + TEST_ASSERT_MESSAGE(1 == compare(TEST_1_INP, data, TWOFISH_BLOCK_SIZE), "wrong plaintext"); +} + +Test* tests_crypto_twofish_tests(void) +{ + EMB_UNIT_TESTFIXTURES(fixtures) { + new_TestFixture(test_crypto_twofish_encrypt), + new_TestFixture(test_crypto_twofish_decrypt), + }; + + EMB_UNIT_TESTCALLER(crypto_twofish_tests, NULL, NULL, fixtures); + + return (Test*)&crypto_twofish_tests; +} diff --git a/tests/unittests/tests-crypto/tests-crypto.c b/tests/unittests/tests-crypto/tests-crypto.c index 432b662ff9f9d6b5441159a94ea4b3872403e45d..1d2646bb7ed8346bf11759dad1d7207f92649831 100644 --- a/tests/unittests/tests-crypto/tests-crypto.c +++ b/tests/unittests/tests-crypto/tests-crypto.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2014 Philipp Rosenkranz + * Copyright (C) 2014 Nico von Geyso * * 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 @@ -12,4 +13,12 @@ void tests_crypto(void) { TESTS_RUN(tests_crypto_sha256_tests()); TESTS_RUN(tests_crypto_chacha_tests()); + TESTS_RUN(tests_crypto_aes_tests()); + TESTS_RUN(tests_crypto_3des_tests()); + TESTS_RUN(tests_crypto_twofish_tests()); + TESTS_RUN(tests_crypto_cipher_tests()); + TESTS_RUN(tests_crypto_modes_ccm_tests()); + TESTS_RUN(tests_crypto_modes_ecb_tests()); + TESTS_RUN(tests_crypto_modes_cbc_tests()); + TESTS_RUN(tests_crypto_modes_ctr_tests()); } diff --git a/tests/unittests/tests-crypto/tests-crypto.h b/tests/unittests/tests-crypto/tests-crypto.h index b390fe2ec441e01efae19d347edd3458aeba5852..d7f05e3824ce5e41c32ee306905aa7f7963cf71b 100644 --- a/tests/unittests/tests-crypto/tests-crypto.h +++ b/tests/unittests/tests-crypto/tests-crypto.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2014 Philipp Rosenkranz + * Copyright (C) 2014 Nico von Geyso * * 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 @@ -19,6 +20,7 @@ #define TESTS_CRYPTO_H_ #include "embUnit.h" +#include "kernel.h" #ifdef __cplusplus extern "C" { @@ -43,6 +45,26 @@ Test *tests_crypto_sha256_tests(void); */ Test *tests_crypto_chacha_tests(void); +static inline int compare(uint8_t a[16], uint8_t b[16], uint8_t len) +{ + int result = 1; + + for (uint8_t i = 0; i < len; ++i) { + result &= a[i] == b[i]; + } + + return result; +} + +Test* tests_crypto_aes_tests(void); +Test* tests_crypto_3des_tests(void); +Test* tests_crypto_twofish_tests(void); +Test* tests_crypto_cipher_tests(void); +Test* tests_crypto_modes_ccm_tests(void); +Test* tests_crypto_modes_ecb_tests(void); +Test* tests_crypto_modes_cbc_tests(void); +Test* tests_crypto_modes_ctr_tests(void); + #ifdef __cplusplus } #endif