Browse Source

Unified Cipher API and Block cipher operation modes

dev/timer
Nico von Geyso 8 years ago committed by Lucas Jenss
parent
commit
4a4235c622
  1. 3
      sys/Makefile
  2. 38
      sys/crypto/3des.c
  3. 46
      sys/crypto/aes.c
  4. 50
      sys/crypto/ciphers.c
  5. 40
      sys/crypto/doc.txt
  6. 35
      sys/crypto/helper.c
  7. 2
      sys/crypto/modes/Makefile
  8. 88
      sys/crypto/modes/cbc.c
  9. 257
      sys/crypto/modes/ccm.c
  10. 58
      sys/crypto/modes/ctr.c
  11. 66
      sys/crypto/modes/ecb.c
  12. 50
      sys/crypto/rc5.c
  13. 87
      sys/crypto/skipjack.c
  14. 56
      sys/crypto/twofish.c
  15. 38
      sys/include/crypto/3des.h
  16. 36
      sys/include/crypto/aes.h
  17. 168
      sys/include/crypto/ciphers.h
  18. 55
      sys/include/crypto/helper.h
  19. 62
      sys/include/crypto/modes/cbc.h
  20. 89
      sys/include/crypto/modes/ccm.h
  21. 74
      sys/include/crypto/modes/ctr.h
  22. 63
      sys/include/crypto/modes/ecb.h
  23. 42
      sys/include/crypto/rc5.h
  24. 49
      sys/include/crypto/skipjack.h
  25. 39
      sys/include/crypto/twofish.h
  26. 3
      tests/unittests/Makefile
  27. 2
      tests/unittests/tests-crypto/Makefile.include
  28. 92
      tests/unittests/tests-crypto/tests-crypto-3des.c
  29. 96
      tests/unittests/tests-crypto/tests-crypto-aes.c
  30. 72
      tests/unittests/tests-crypto/tests-crypto-cipher.c
  31. 127
      tests/unittests/tests-crypto/tests-crypto-modes-cbc.c
  32. 161
      tests/unittests/tests-crypto/tests-crypto-modes-ccm.c
  33. 133
      tests/unittests/tests-crypto/tests-crypto-modes-ctr.c
  34. 122
      tests/unittests/tests-crypto/tests-crypto-modes-ecb.c
  35. 96
      tests/unittests/tests-crypto/tests-crypto-twofish.c
  36. 9
      tests/unittests/tests-crypto/tests-crypto.c
  37. 22
      tests/unittests/tests-crypto/tests-crypto.h

3
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

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

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

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

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

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

2
sys/crypto/modes/Makefile

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

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

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

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

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

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

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

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

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