Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CCM mode #169

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 98 additions & 6 deletions aes.c
Original file line number Diff line number Diff line change
Expand Up @@ -479,12 +479,7 @@ void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf)

#endif // #if defined(ECB) && (ECB == 1)





#if defined(CBC) && (CBC == 1)

#if (defined(CBC) && (CBC == 1)) || (defined(CCM) && (CCM == 1))

static void XorWithIv(uint8_t* buf, const uint8_t* Iv)
{
Expand All @@ -495,6 +490,12 @@ static void XorWithIv(uint8_t* buf, const uint8_t* Iv)
}
}

#endif // #if (defined(CBC) && (CBC == 1)) || (defined(CCM) && (CCM == 1))



#if defined(CBC) && (CBC == 1)

void AES_CBC_encrypt_buffer(struct AES_ctx *ctx, uint8_t* buf, uint32_t length)
{
uintptr_t i;
Expand Down Expand Up @@ -567,3 +568,94 @@ void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length)

#endif // #if defined(CTR) && (CTR == 1)

#if defined(CCM) && (CCM == 1)

static void IncCounter(uint8_t* counter_block)
{
for (int_fast8_t i = ((int8_t)AES_BLOCKLEN - 1); i >= 0; --i) {
if (counter_block[i] == 0xFFu) {
counter_block[i] = 0;
} else {
counter_block[i]++;
break;
}
}
}

static void CCM_Xcrypt(AES_CCM_ctx* ctx, uint8_t buf[], uint32_t len, int enc)
{
for (uintptr_t i = 0u; i < len; ++i) {
if (ctx->byte_pos >= AES_BLOCKLEN) {
ctx->byte_pos = 0u;
Cipher((state_t*)ctx->cbc_buf, ctx->round_key);
memcpy(ctx->ctr_buf, ctx->counter, AES_BLOCKLEN);
Cipher((state_t*)ctx->ctr_buf, ctx->round_key);
IncCounter(ctx->counter);
}
if (enc){
ctx->cbc_buf[ctx->byte_pos] ^= buf[i];
buf[i] ^= ctx->ctr_buf[ctx->byte_pos];
} else {
buf[i] ^= ctx->ctr_buf[ctx->byte_pos];
ctx->cbc_buf[ctx->byte_pos] ^= buf[i];
}
ctx->byte_pos++;
}
}

void AES_CCM_init(AES_CCM_ctx* ctx, const uint8_t key[AES_KEYLEN],
const uint8_t nonce[], uint8_t nonce_len,
uint32_t data_len, uint8_t tag_len)
{
KeyExpansion(ctx->round_key, key);
ctx->ctr_len = (uint8_t)((AES_BLOCKLEN - (uint8_t)1u) - nonce_len);
uint8_t tag_bits_L = ctx->ctr_len - (uint8_t)1u;
uint8_t tag_bits_M = (uint8_t)(8u * (tag_len - 2u) / 2u);
ctx->cbc_buf[0u] = tag_bits_M + tag_bits_L;
ctx->counter[0u] = tag_bits_L;
for (uint_fast8_t i = 0u; i < nonce_len; ++i) {
ctx->cbc_buf[i + 1u] = nonce[i];
ctx->counter[i + 1u] = nonce[i];
}
uint32_t tmp = data_len;
for (uint_fast8_t i = 0u; i < ctx->ctr_len; ++i) {
uint_fast8_t pos = (AES_BLOCKLEN - 1u) - i;
ctx->cbc_buf[pos] = (uint8_t)tmp;
tmp = tmp >> 8u;
ctx->counter[pos] = 0u;
}
IncCounter(ctx->counter);
ctx->byte_pos = AES_BLOCKLEN;
}

void AES_CCM_encrypt(AES_CCM_ctx* ctx, uint8_t buf[], uint32_t len)
{
CCM_Xcrypt(ctx, buf, len, 1);
}

void AES_CCM_decrypt(AES_CCM_ctx* ctx, uint8_t buf[], uint32_t len)
{
CCM_Xcrypt(ctx, buf, len, 0);
}

void CCM_generate_tag(AES_CCM_ctx* ctx)
{
memset(ctx->counter + AES_BLOCKLEN - ctx->ctr_len, 0, ctx->ctr_len);
memcpy(ctx->ctr_buf, ctx->counter, AES_BLOCKLEN);
Cipher((state_t*)ctx->ctr_buf, ctx->round_key);
Cipher((state_t*)ctx->cbc_buf, ctx->round_key);
XorWithIv(ctx->cbc_buf, ctx->ctr_buf);
}

void AES_CCM_generate_tag(AES_CCM_ctx* ctx, uint8_t tag[AES_BLOCKLEN], uint8_t tag_len)
{
CCM_generate_tag(ctx);
memcpy(tag, ctx->cbc_buf, tag_len);
}

bool AES_CCM_verify_tag(AES_CCM_ctx* ctx, uint8_t tag[], uint8_t tag_len)
{
return memcmp(tag, ctx->cbc_buf, tag_len) == 0;
}

#endif // #if defined(CTR) && (CTR == 1)
31 changes: 31 additions & 0 deletions aes.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define _AES_H_

#include <stdint.h>
#include <stdbool.h>

// #define the macros below to 1/0 to enable/disable the mode of operation.
//
Expand All @@ -22,6 +23,10 @@
#define CTR 1
#endif

#ifndef CCM
#define CCM 1
#endif


#define AES128 1
//#define AES192 1
Expand Down Expand Up @@ -86,5 +91,31 @@ void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length);

#endif // #if defined(CTR) && (CTR == 1)

#if defined(CCM) && (CCM == 1)

typedef struct {
uint8_t round_key[AES_keyExpSize];
uint8_t cbc_buf[AES_BLOCKLEN];
uint8_t counter[AES_BLOCKLEN];
uint8_t ctr_buf[AES_BLOCKLEN];
uint8_t byte_pos;
uint8_t ctr_len;
} AES_CCM_ctx;
// nonce_len should be between 7..13 bytes.
// Adata is not supported yet.
// AES_CCM_Encrypt and AES_CCM_Decrypt could be called multiple times.
// The sum of len MUST be data_len given in AES_CCM_Init.
// The tag_len in AES_CCM_Init and AES_CCM_GenerateTag MUST be the same.
// After calling AES_CCM_GenerateTag or AES_CCM_verify_tag, ctx MUST be initialized before reused.
void AES_CCM_init(AES_CCM_ctx* ctx, const uint8_t key[AES_KEYLEN],
const uint8_t nonce[], uint8_t nonce_len,
uint32_t data_len, uint8_t tag_len);
void AES_CCM_encrypt(AES_CCM_ctx* ctx, uint8_t buf[], uint32_t len);
void AES_CCM_decrypt(AES_CCM_ctx* ctx, uint8_t buf[], uint32_t len);
void AES_CCM_generate_tag(AES_CCM_ctx* ctx, uint8_t tag[], uint8_t tag_len);
bool AES_CCM_verify_tag(AES_CCM_ctx* ctx, uint8_t tag[], uint8_t tag_len);

#endif // #if defined(CTR) && (CTR == 1)


#endif // _AES_H_
112 changes: 110 additions & 2 deletions test.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ static int test_encrypt_ctr(void);
static int test_decrypt_ctr(void);
static int test_encrypt_ecb(void);
static int test_decrypt_ecb(void);
static int test_encrypt_ccm(void);
static int test_decrypt_ccm(void);
static void test_encrypt_ecb_verbose(void);


Expand All @@ -37,8 +39,9 @@ int main(void)
#endif

exit = test_encrypt_cbc() + test_decrypt_cbc() +
test_encrypt_ctr() + test_decrypt_ctr() +
test_decrypt_ecb() + test_encrypt_ecb();
test_encrypt_ctr() + test_decrypt_ctr() +
test_decrypt_ecb() + test_encrypt_ecb() +
test_encrypt_ccm() + test_decrypt_ccm();
test_encrypt_ecb_verbose();

return exit;
Expand Down Expand Up @@ -313,4 +316,109 @@ static int test_decrypt_ecb(void)
}
}

static int test_encrypt_ccm(void)
{
#if defined(AES256)
uint8_t key[32] = {0xfa, 0x0f, 0xf0, 0x16, 0x9d, 0xc9, 0x57, 0x56, 0x74, 0x06, 0x66, 0x76, 0xcf, 0xb0, 0xb4, 0xeb,
0x89, 0x02, 0xc4, 0x42, 0x69, 0xda, 0x1c, 0xf6, 0xba, 0x66, 0xd3, 0xf8, 0xb6, 0xd4, 0xb1, 0x00};
uint8_t out[64] = {0xc6, 0xbf, 0x09, 0xfb, 0x30, 0x1c, 0xcc, 0xec, 0xba, 0x48, 0x5a, 0x47, 0x43, 0x63, 0xc1, 0x80,
0xf5, 0x3c, 0x00, 0x55, 0x86, 0xb0, 0xcd, 0xd9, 0x2d, 0x1b, 0xda, 0xee, 0x7a, 0x7a, 0xc1, 0x2f,
0xf9, 0x83, 0xf2, 0x1d, 0x37, 0xf0, 0x67, 0x98, 0x8f, 0x2c, 0xdf, 0xbb, 0xea, 0x7b, 0x63, 0xf7,
0x4e, 0xdb, 0x87, 0x08, 0x90, 0xd6, 0x3b, 0xde, 0x61, 0x37, 0xad, 0x66, 0x21, 0x9c, 0xd1, 0x17};
uint8_t tag[16] = {0xe1, 0x01, 0x06, 0xae, 0xbe, 0x26, 0x0c, 0xc5, 0xb9, 0x51, 0x45, 0x39, 0x2a, 0xce, 0x02, 0x37};
#elif defined(AES192)
uint8_t key[24] = {0xa9, 0xea, 0x0e, 0x75, 0x5a, 0x5c, 0x2e, 0x82, 0x10, 0x24, 0x2a, 0x08, 0xe7, 0x07, 0x8f, 0x7f,
0x89, 0x38, 0x5e, 0xb0, 0x94, 0x23, 0x55, 0x51};
uint8_t out[64] = {0xf6, 0x5e, 0xe8, 0xe4, 0x45, 0xfe, 0x27, 0x84, 0x0d, 0x66, 0xff, 0x45, 0x30, 0x2f, 0x27, 0xf0,
0xb5, 0xfb, 0xf6, 0xd0, 0xb0, 0x57, 0xb7, 0xea, 0xd3, 0xbb, 0x09, 0x62, 0x0b, 0x35, 0xf6, 0x51,
0xae, 0x86, 0x49, 0xb3, 0x51, 0x31, 0x77, 0xe4, 0xff, 0x07, 0x3f, 0x1d, 0x35, 0xb0, 0x14, 0x5c,
0x50, 0x74, 0x84, 0x30, 0xbe, 0x67, 0x4b, 0x64, 0x94, 0x0d, 0xa5, 0xda, 0x07, 0x14, 0x96, 0xcc};
uint8_t tag[16] = {0x3a, 0xf9, 0xa6, 0x56, 0x7c, 0x17, 0x32, 0x1d, 0x7e, 0x91, 0xb2, 0xc7, 0xde, 0xcc, 0x15, 0x5f};
#elif defined(AES128)
uint8_t key[16] = {0x82, 0x56, 0x8b, 0x96, 0xe8, 0xa4, 0xfe, 0xf2, 0x3a, 0x0c, 0x9f, 0xc5, 0xaf, 0xd7, 0x60, 0x84};
uint8_t out[64] = {0xab, 0x77, 0x29, 0x3a, 0xf7, 0x8a, 0x1f, 0x03, 0x6d, 0x19, 0xc2, 0x76, 0x76, 0xb1, 0xb7, 0xa3,
0x7c, 0xa5, 0xe9, 0x90, 0x75, 0x47, 0xcd, 0x6a, 0x5a, 0x51, 0xf5, 0x7a, 0xb9, 0xa2, 0x2a, 0x23,
0x39, 0x90, 0x9b, 0x7f, 0xe0, 0xa4, 0xd5, 0x7c, 0x65, 0x23, 0xf1, 0x03, 0x12, 0xbc, 0x90, 0x10,
0xab, 0xc5, 0x2d, 0x7b, 0xf2, 0xa7, 0x4b, 0x66, 0x9c, 0x80, 0x36, 0x8a, 0x40, 0xf9, 0xcb, 0x51};
uint8_t tag[16] = {0x25, 0x95, 0x7a, 0x23, 0xff, 0xf0, 0x34, 0x1a, 0x78, 0xa5, 0xec, 0xf4, 0x65, 0x08, 0x8f, 0xbc};
#endif
uint8_t in[64] = {0x44, 0x20, 0x82, 0x3c, 0xfd, 0xe6, 0xf1, 0xc2, 0x6b, 0x30, 0xf9, 0x0e, 0xc7, 0xdd, 0x01, 0xe4,
0x88, 0x75, 0x34, 0xa2, 0x0f, 0x0b, 0x0d, 0x04, 0xc3, 0x6e, 0xd8, 0x0e, 0x71, 0xe0, 0xfd, 0x77,
0xb0, 0x76, 0x70, 0xeb, 0x94, 0x0b, 0xd5, 0x33, 0x5f, 0x97, 0x3d, 0xaa, 0xd8, 0x61, 0x9b, 0x91,
0xff, 0xc9, 0x11, 0xf5, 0x7c, 0xce, 0xd4, 0x58, 0xbb, 0xbf, 0x2c, 0xe0, 0x37, 0x53, 0xc9, 0xbd};
uint8_t nonce[11] = {0x37, 0x81, 0x6b, 0xdd, 0x0a, 0x73, 0x09, 0xcb, 0x4a, 0x12, 0x52};
uint8_t tag_out[16];
AES_CCM_ctx ctx;

AES_CCM_init(&ctx, key, nonce, sizeof(nonce), sizeof(in), sizeof(tag));
AES_CCM_encrypt(&ctx, in, sizeof(in));
AES_CCM_generate_tag(&ctx, tag_out, 16);

printf("CCM encrypt: ");

if ((0 == memcmp((char *)out, (char *)in, sizeof(out)))
&& (0 == memcmp((char *)tag, (char *)tag_out, sizeof(tag))))
{
printf("SUCCESS!\n");
return (0);
}
else
{
printf("FAILURE!\n");
return (1);
}
}

static int test_decrypt_ccm(void)
{
#if defined(AES256)
uint8_t key[32] = {0xfa, 0x0f, 0xf0, 0x16, 0x9d, 0xc9, 0x57, 0x56, 0x74, 0x06, 0x66, 0x76, 0xcf, 0xb0, 0xb4, 0xeb,
0x89, 0x02, 0xc4, 0x42, 0x69, 0xda, 0x1c, 0xf6, 0xba, 0x66, 0xd3, 0xf8, 0xb6, 0xd4, 0xb1, 0x00};
uint8_t in[64] = {0xc6, 0xbf, 0x09, 0xfb, 0x30, 0x1c, 0xcc, 0xec, 0xba, 0x48, 0x5a, 0x47, 0x43, 0x63, 0xc1, 0x80,
0xf5, 0x3c, 0x00, 0x55, 0x86, 0xb0, 0xcd, 0xd9, 0x2d, 0x1b, 0xda, 0xee, 0x7a, 0x7a, 0xc1, 0x2f,
0xf9, 0x83, 0xf2, 0x1d, 0x37, 0xf0, 0x67, 0x98, 0x8f, 0x2c, 0xdf, 0xbb, 0xea, 0x7b, 0x63, 0xf7,
0x4e, 0xdb, 0x87, 0x08, 0x90, 0xd6, 0x3b, 0xde, 0x61, 0x37, 0xad, 0x66, 0x21, 0x9c, 0xd1, 0x17};
uint8_t tag[16] = {0xe1, 0x01, 0x06, 0xae, 0xbe, 0x26, 0x0c, 0xc5, 0xb9, 0x51, 0x45, 0x39, 0x2a, 0xce, 0x02, 0x37};
#elif defined(AES192)
uint8_t key[24] = {0xa9, 0xea, 0x0e, 0x75, 0x5a, 0x5c, 0x2e, 0x82, 0x10, 0x24, 0x2a, 0x08, 0xe7, 0x07, 0x8f, 0x7f,
0x89, 0x38, 0x5e, 0xb0, 0x94, 0x23, 0x55, 0x51};
uint8_t in[64] = {0xf6, 0x5e, 0xe8, 0xe4, 0x45, 0xfe, 0x27, 0x84, 0x0d, 0x66, 0xff, 0x45, 0x30, 0x2f, 0x27, 0xf0,
0xb5, 0xfb, 0xf6, 0xd0, 0xb0, 0x57, 0xb7, 0xea, 0xd3, 0xbb, 0x09, 0x62, 0x0b, 0x35, 0xf6, 0x51,
0xae, 0x86, 0x49, 0xb3, 0x51, 0x31, 0x77, 0xe4, 0xff, 0x07, 0x3f, 0x1d, 0x35, 0xb0, 0x14, 0x5c,
0x50, 0x74, 0x84, 0x30, 0xbe, 0x67, 0x4b, 0x64, 0x94, 0x0d, 0xa5, 0xda, 0x07, 0x14, 0x96, 0xcc};
uint8_t tag[16] = {0x3a, 0xf9, 0xa6, 0x56, 0x7c, 0x17, 0x32, 0x1d, 0x7e, 0x91, 0xb2, 0xc7, 0xde, 0xcc, 0x15, 0x5f};
#elif defined(AES128)
uint8_t key[16] = {0x82, 0x56, 0x8b, 0x96, 0xe8, 0xa4, 0xfe, 0xf2, 0x3a, 0x0c, 0x9f, 0xc5, 0xaf, 0xd7, 0x60, 0x84};
uint8_t in[64] = {0xab, 0x77, 0x29, 0x3a, 0xf7, 0x8a, 0x1f, 0x03, 0x6d, 0x19, 0xc2, 0x76, 0x76, 0xb1, 0xb7, 0xa3,
0x7c, 0xa5, 0xe9, 0x90, 0x75, 0x47, 0xcd, 0x6a, 0x5a, 0x51, 0xf5, 0x7a, 0xb9, 0xa2, 0x2a, 0x23,
0x39, 0x90, 0x9b, 0x7f, 0xe0, 0xa4, 0xd5, 0x7c, 0x65, 0x23, 0xf1, 0x03, 0x12, 0xbc, 0x90, 0x10,
0xab, 0xc5, 0x2d, 0x7b, 0xf2, 0xa7, 0x4b, 0x66, 0x9c, 0x80, 0x36, 0x8a, 0x40, 0xf9, 0xcb, 0x51};
uint8_t tag[16] = {0x25, 0x95, 0x7a, 0x23, 0xff, 0xf0, 0x34, 0x1a, 0x78, 0xa5, 0xec, 0xf4, 0x65, 0x08, 0x8f, 0xbc};
#endif
uint8_t out[64] = {0x44, 0x20, 0x82, 0x3c, 0xfd, 0xe6, 0xf1, 0xc2, 0x6b, 0x30, 0xf9, 0x0e, 0xc7, 0xdd, 0x01, 0xe4,
0x88, 0x75, 0x34, 0xa2, 0x0f, 0x0b, 0x0d, 0x04, 0xc3, 0x6e, 0xd8, 0x0e, 0x71, 0xe0, 0xfd, 0x77,
0xb0, 0x76, 0x70, 0xeb, 0x94, 0x0b, 0xd5, 0x33, 0x5f, 0x97, 0x3d, 0xaa, 0xd8, 0x61, 0x9b, 0x91,
0xff, 0xc9, 0x11, 0xf5, 0x7c, 0xce, 0xd4, 0x58, 0xbb, 0xbf, 0x2c, 0xe0, 0x37, 0x53, 0xc9, 0xbd};
uint8_t nonce[11] = {0x37, 0x81, 0x6b, 0xdd, 0x0a, 0x73, 0x09, 0xcb, 0x4a, 0x12, 0x52};

uint8_t tag_out[16];
AES_CCM_ctx ctx;

AES_CCM_init(&ctx, key, nonce, sizeof(nonce), sizeof(in), sizeof(tag));
AES_CCM_decrypt(&ctx, in, sizeof(in));
AES_CCM_generate_tag(&ctx, tag_out, 16);

printf("CCM decrypt: ");

if ((0 == memcmp((char *)out, (char *)in, sizeof(out)))
&& (AES_CCM_verify_tag(&ctx, tag, 16)))
{
printf("SUCCESS!\n");
return (0);
}
else
{
printf("FAILURE!\n");
return (1);
}
}