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 optional CTR_SEEK mode functions #218

Open
wants to merge 1 commit 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
77 changes: 77 additions & 0 deletions aes.c
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,42 @@ static void InvCipher(state_t* state, const uint8_t* RoundKey)
}
#endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)

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

// Adds two AES_BLOCKLEN sized numbers together
static void AddCounterBlock(const uint8_t* blkLeft, const uint8_t* blkRight, uint8_t* blkOut)
{
uint16_t carry;
int i;

carry = 0;
for (i = AES_BLOCKLEN - 1; i >= 0; --i)
{
uint16_t sum = carry + blkLeft[i] + blkRight[i];
blkOut[i] = sum & 0xFF;
carry = (sum >> 8) & 0xFF;
}
}

// Encodes a size_t into a buffer as little-endian
static void EncodeAsCounterBlock(size_t counter, uint8_t* block)
{
#define NUM_COUNTER_BYTES (sizeof(size_t) < AES_BLOCKLEN ? sizeof(size_t) : sizeof(size_t))
memset(block, 0, AES_BLOCKLEN);

for (int i = 0; i < NUM_COUNTER_BYTES; ++i)
{
int arrayIdx = (AES_BLOCKLEN - 1) - i;
int byteShift = i * 8;
size_t byteMask = (size_t)0xFF << byteShift;

block[arrayIdx] = ((counter & byteMask) >> byteShift) & 0xFF;
}
#undef NUM_COUNTER_BYTES
}

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

/*****************************************************************************/
/* Public functions: */
/*****************************************************************************/
Expand Down Expand Up @@ -570,3 +606,44 @@ void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length)

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



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

// Applies the same encryption process as AES_CTR_xcrypt_buffer but to a single block from a
// specific position in the stream.
void AES_CTR_xcrypt_block_at_position(const struct AES_ctx* ctx, uint8_t* blkBuf, size_t blkIndex)
{
uint8_t buffer[AES_BLOCKLEN]; // holds block index, Iv at given index then the xor block
int i;

EncodeAsCounterBlock(blkIndex, buffer);
AddCounterBlock(buffer, ctx->Iv, buffer); // add index to Iv

Cipher((state_t*)buffer, ctx->RoundKey); // create xor'able block

for (i = 0; i < AES_BLOCKLEN; ++i)
{
blkBuf[i] = (blkBuf[i] ^ buffer[i]);
}
}

// Because AES_CTR_xcrypt_block_at_position uses size_t for the block index, this function is provided for
// indexing the full size of the stream using an array of bytes representing a little-endian integer which is the index.
void AES_CTR_xcrypt_block_at_position_extended(const struct AES_ctx* ctx, uint8_t* blkBuf, const uint8_t* blkIndexBuf)
{
uint8_t buffer[AES_BLOCKLEN]; // Iv at given index then the xor block
int i;

AddCounterBlock(blkIndexBuf, ctx->Iv, buffer); // add index to Iv

Cipher((state_t*)buffer, ctx->RoundKey); // create xor'able block

for (i = 0; i < AES_BLOCKLEN; ++i)
{
blkBuf[i] = (blkBuf[i] ^ buffer[i]);
}
}

#endif

30 changes: 30 additions & 0 deletions aes.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
//
// CBC enables AES encryption in CBC-mode of operation.
// CTR enables encryption in counter-mode.
// CTR_SEEK enables out of order encryption in counter-mode
// ECB enables the basic ECB 16-byte block algorithm. All can be enabled simultaneously.

// The #ifndef-guard allows it to be configured before #include'ing or at compile time.
Expand All @@ -23,6 +24,9 @@
#define CTR 1
#endif

#ifndef CTR_SEEK
#define CTR_SEEK 1
#endif

#define AES128 1
//#define AES192 1
Expand Down Expand Up @@ -88,4 +92,30 @@ void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length);
#endif // #if defined(CTR) && (CTR == 1)


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

// Same function for encrypting as for decrypting.
// Similar to AES_CTR_xcrypt_buffer however can be used to encrypt/decrypt specific blocks without
// encrypt/decrypt the previous blocks beforehand.
// 'blkBuf' specifies which block should be encrypted/decrypted
// 'blkIndex' specifies the block to be encrypted/decrypted MUST be of size AES_BLOCKLEN
// Suggesting https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme
// NOTES: you need to set IV in ctx with AES_init_ctx_iv() or AES_ctx_set_iv().
// no IV should ever be reused with the same key.
// blkIndex allows for counters up to maximum size of size_t, for bigger indices use
// AES_CTR_xcrypt_block_at_position_extended().
void AES_CTR_xcrypt_block_at_position(const struct AES_ctx* ctx, uint8_t* blkBuf, size_t blkIndex);

// Same function for encrypting as for decrypting.
// Functions the same as AES_CTR_xcrypt_block_at_position however can be used with streams bigger than size_t
// 'blkIndexBuf' specifies the index of which block to be encrypted/decrypted MUST be of size AES_BLOCKLEN
// and encoded as little-endian.
// Suggesting https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme
// NOTES: you need to set IV in ctx with AES_init_ctx_iv() or AES_ctx_set_iv()
// no IV should ever be reused with the same key
void AES_CTR_xcrypt_block_at_position_extended(const struct AES_ctx* ctx, uint8_t* blkBuf, const uint8_t* blkIndexBuf);

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


#endif // _AES_H_
8 changes: 6 additions & 2 deletions conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ class TinyAesCConan(ConanFile):

# enable encryption in counter-mode
"CTR": [True, False],

# enable encryption in counter-mode with seekable counter
"CTR_SEEK": [True, False],
}

options = _options_dict
Expand All @@ -43,12 +46,13 @@ class TinyAesCConan(ConanFile):
"AES256": False,
"CBC": True,
"ECB": True,
"CTR": True
"CTR": True,
"CTR_SEEK": True
}

def configure(self):
if not self.options.CBC and not self.options.ECB and not self.options.CTR:
raise ConanException("Need to at least specify one of CBC, ECB or CTR modes")
raise ConanException("Need to at least specify one of CBC, ECB, CTR, CTR-SEEK modes")

if not self.options.AES128 and not self.options.AES192 and not self.options.AES256:
raise ConanException("Need to at least specify one of AES{128, 192, 256} modes")
Expand Down
65 changes: 63 additions & 2 deletions test.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
#include <stdint.h>

// Enable ECB, CTR and CBC mode. Note this can be done before including aes.h or at compile-time.
// E.g. with GCC by using the -D flag: gcc -c aes.c -DCBC=0 -DCTR=1 -DECB=1
// E.g. with GCC by using the -D flag: gcc -c aes.c -DCBC=0 -DCTR=1 -DECB=1 -DCTR_SEEK=1
#define CBC 1
#define CTR 1
#define ECB 1
#define CTR_SEEK 1

#include "aes.h"

Expand All @@ -19,6 +20,8 @@ static int test_decrypt_ctr(void);
static int test_encrypt_ecb(void);
static int test_decrypt_ecb(void);
static void test_encrypt_ecb_verbose(void);
static int test_encrypt_ctr_at_position(void);
static int test_decrypt_ctr_at_position(void);


int main(void)
Expand All @@ -38,7 +41,8 @@ int main(void)

exit = test_encrypt_cbc() + test_decrypt_cbc() +
test_encrypt_ctr() + test_decrypt_ctr() +
test_decrypt_ecb() + test_encrypt_ecb();
test_decrypt_ecb() + test_encrypt_ecb() +
test_encrypt_ctr_at_position() + test_decrypt_ctr_at_position();
test_encrypt_ecb_verbose();

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

static int test_xcrypt_ctr_at_position(const char* xcrypt)
{
#if defined(AES256)
uint8_t key[32] = { 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4 };
uint8_t in[64] = { 0x60, 0x1e, 0xc3, 0x13, 0x77, 0x57, 0x89, 0xa5, 0xb7, 0xa7, 0xf5, 0x04, 0xbb, 0xf3, 0xd2, 0x28,
0xf4, 0x43, 0xe3, 0xca, 0x4d, 0x62, 0xb5, 0x9a, 0xca, 0x84, 0xe9, 0x90, 0xca, 0xca, 0xf5, 0xc5,
0x2b, 0x09, 0x30, 0xda, 0xa2, 0x3d, 0xe9, 0x4c, 0xe8, 0x70, 0x17, 0xba, 0x2d, 0x84, 0x98, 0x8d,
0xdf, 0xc9, 0xc5, 0x8d, 0xb6, 0x7a, 0xad, 0xa6, 0x13, 0xc2, 0xdd, 0x08, 0x45, 0x79, 0x41, 0xa6 };
#elif defined(AES192)
uint8_t key[24] = { 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5,
0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b };
uint8_t in[64] = { 0x1a, 0xbc, 0x93, 0x24, 0x17, 0x52, 0x1c, 0xa2, 0x4f, 0x2b, 0x04, 0x59, 0xfe, 0x7e, 0x6e, 0x0b,
0x09, 0x03, 0x39, 0xec, 0x0a, 0xa6, 0xfa, 0xef, 0xd5, 0xcc, 0xc2, 0xc6, 0xf4, 0xce, 0x8e, 0x94,
0x1e, 0x36, 0xb2, 0x6b, 0xd1, 0xeb, 0xc6, 0x70, 0xd1, 0xbd, 0x1d, 0x66, 0x56, 0x20, 0xab, 0xf7,
0x4f, 0x78, 0xa7, 0xf6, 0xd2, 0x98, 0x09, 0x58, 0x5a, 0x97, 0xda, 0xec, 0x58, 0xc6, 0xb0, 0x50 };
#elif defined(AES128)
uint8_t key[16] = { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c };
uint8_t in[64] = { 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 };
#endif
uint8_t iv[16] = { 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff };
uint8_t out[64] = { 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 };
struct AES_ctx ctx;

AES_init_ctx_iv(&ctx, key, iv);

// input can be processed out of order
AES_CTR_xcrypt_block_at_position(&ctx, in + AES_BLOCKLEN * 3, 3);
AES_CTR_xcrypt_block_at_position(&ctx, in, 0);
AES_CTR_xcrypt_block_at_position(&ctx, in + AES_BLOCKLEN * 2, 2);
AES_CTR_xcrypt_block_at_position(&ctx, in + AES_BLOCKLEN, 1);

printf("CTR-SEEK %s: ", xcrypt);

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

static int test_encrypt_ctr_at_position(void)
{
return test_xcrypt_ctr_at_position("encrypt");
}

static int test_decrypt_ctr_at_position(void)
{
return test_xcrypt_ctr_at_position("decrypt");
}