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