1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Unified Cipher API and Block cipher operation modes

This commit is contained in:
Nico von Geyso 2015-04-02 08:56:18 +02:00 committed by Lucas Jenss
parent 5813db3249
commit 4a4235c622
37 changed files with 2128 additions and 404 deletions

View File

@ -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

View File

@ -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;

View File

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

50
sys/crypto/ciphers.c Normal file
View File

@ -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;
}

View File

@ -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.
*/

35
sys/crypto/helper.c Normal file
View File

@ -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;
}

View File

@ -0,0 +1,2 @@
MODULE = cipher_modes
include $(RIOTBASE)/Makefile.base

88
sys/crypto/modes/cbc.c Normal file
View File

@ -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;
}

257
sys/crypto/modes/ccm.c Normal file
View File

@ -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;
}

58
sys/crypto/modes/ctr.c Normal file
View File

@ -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);
}

66
sys/crypto/modes/ecb.c Normal file
View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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
}

View File

@ -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

View File

@ -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
/**
* Context sizes needed for the different ciphers.
* Always order by number of bytes descending!!! <br><br>
*
* threedes needs 24 bytes <br>
* aes needs CIPHERS_MAX_KEY_SIZE bytes <br>
* twofish needs CIPHERS_MAX_KEY_SIZE bytes <br>
* skipjack needs 20 bytes
*/
#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
* always order by number of bytes descending!!! <br>
* rc5 needs 104 bytes <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>
*/
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 */
#endif
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
*/
typedef struct CipherModeContext {
cipher_context_t cc; /**< CipherContext for the cipher-operations */
uint8_t context[24]; /**< context for the block-cipher-modes' */
} CipherModeContext;
/**
* @brief struct for an archive of all available ciphers
* @brief basic struct for using block ciphers
* contains the cipher interface and the context
*/
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;
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 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
*/
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
}

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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_*/

View File

@ -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_*/

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -1 +1,3 @@
USEMODULE += crypto
USEMODULE += cipher_modes
CFLAGS += -DCRYPTO_THREEDES

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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());
}

View File

@ -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