Skip to content

Commit

Permalink
Merge #14: Implement constant time AES CBC
Browse files Browse the repository at this point in the history
8835446 Implement constant time AES CBC (Kristaps Kaupe)

Pull request description:

  Tried to not change anything in existing code, except for making `AES_encrypt()` and `AES_decrypt()` public.

  Related to #11.

ACKs for top commit:
  sipa:
    ACK 8835446
  gmaxwell:
    ACK 8835446

Tree-SHA512: aab1b44989610a86458dfa782f99803051ce000ff843c4ac13f3ef9f9e4ec0b3d6cfa72fef12c079af9c9f70167def39b4bc66f3b8d37a1ff14a84562616032a
  • Loading branch information
sipa committed Aug 18, 2020
2 parents 3d61b58 + 8835446 commit a1caf29
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 1 deletion.
76 changes: 76 additions & 0 deletions ctaes.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

#include "ctaes.h"

#include <string.h>

/* Slice variable slice_i contains the i'th bit of the 16 state variables in this order:
* 0 1 2 3
* 4 5 6 7
Expand Down Expand Up @@ -554,3 +556,77 @@ void AES256_decrypt(const AES256_ctx* ctx, size_t blocks, unsigned char* plain16
plain16 += 16;
}
}

static void Xor128(uint8_t* buf1, const uint8_t* buf2) {
size_t i;
for (i = 0; i < 16; i++) {
buf1[i] ^= buf2[i];
}
}

static void AESCBC_encrypt(const AES_state* rounds, uint8_t* iv, int nk, size_t blocks, unsigned char* encrypted, const unsigned char* plain) {
size_t i;
unsigned char buf[16];

for (i = 0; i < blocks; i++) {
memcpy(buf, plain, 16);
Xor128(buf, iv);
AES_encrypt(rounds, nk, encrypted, buf);
memcpy(iv, encrypted, 16);
plain += 16;
encrypted += 16;
}
}

static void AESCBC_decrypt(const AES_state* rounds, uint8_t* iv, int nk, size_t blocks, unsigned char* plain, const unsigned char* encrypted) {
size_t i;
uint8_t next_iv[16];

for (i = 0; i < blocks; i++) {
memcpy(next_iv, encrypted, 16);
AES_decrypt(rounds, nk, plain, encrypted);
Xor128(plain, iv);
memcpy(iv, next_iv, 16);
plain += 16;
encrypted += 16;
}
}

void AES128_CBC_init(AES128_CBC_ctx* ctx, const unsigned char* key16, const uint8_t* iv) {
AES128_init(&(ctx->ctx), key16);
memcpy(ctx->iv, iv, 16);
}

void AES192_CBC_init(AES192_CBC_ctx* ctx, const unsigned char* key16, const uint8_t* iv) {
AES192_init(&(ctx->ctx), key16);
memcpy(ctx->iv, iv, 16);
}

void AES256_CBC_init(AES256_CBC_ctx* ctx, const unsigned char* key16, const uint8_t* iv) {
AES256_init(&(ctx->ctx), key16);
memcpy(ctx->iv, iv, 16);
}

void AES128_CBC_encrypt(AES128_CBC_ctx* ctx, size_t blocks, unsigned char* encrypted, const unsigned char* plain) {
AESCBC_encrypt(ctx->ctx.rk, ctx->iv, 10, blocks, encrypted, plain);
}

void AES128_CBC_decrypt(AES128_CBC_ctx* ctx, size_t blocks, unsigned char* plain, const unsigned char *encrypted) {
AESCBC_decrypt(ctx->ctx.rk, ctx->iv, 10, blocks, plain, encrypted);
}

void AES192_CBC_encrypt(AES192_CBC_ctx* ctx, size_t blocks, unsigned char* encrypted, const unsigned char* plain) {
AESCBC_encrypt(ctx->ctx.rk, ctx->iv, 12, blocks, encrypted, plain);
}

void AES192_CBC_decrypt(AES192_CBC_ctx* ctx, size_t blocks, unsigned char* plain, const unsigned char *encrypted) {
AESCBC_decrypt(ctx->ctx.rk, ctx->iv, 12, blocks, plain, encrypted);
}

void AES256_CBC_encrypt(AES256_CBC_ctx* ctx, size_t blocks, unsigned char* encrypted, const unsigned char* plain) {
AESCBC_encrypt(ctx->ctx.rk, ctx->iv, 14, blocks, encrypted, plain);
}

void AES256_CBC_decrypt(AES256_CBC_ctx* ctx, size_t blocks, unsigned char* plain, const unsigned char *encrypted) {
AESCBC_decrypt(ctx->ctx.rk, ctx->iv, 14, blocks, plain, encrypted);
}
29 changes: 28 additions & 1 deletion ctaes.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,21 @@ typedef struct {
AES_state rk[15];
} AES256_ctx;

typedef struct {
AES128_ctx ctx;
uint8_t iv[16]; /* iv is updated after each use */
} AES128_CBC_ctx;

typedef struct {
AES192_ctx ctx;
uint8_t iv[16]; /* iv is updated after each use */
} AES192_CBC_ctx;

typedef struct {
AES256_ctx ctx;
uint8_t iv[16]; /* iv is updated after each use */
} AES256_CBC_ctx;

void AES128_init(AES128_ctx* ctx, const unsigned char* key16);
void AES128_encrypt(const AES128_ctx* ctx, size_t blocks, unsigned char* cipher16, const unsigned char* plain16);
void AES128_decrypt(const AES128_ctx* ctx, size_t blocks, unsigned char* plain16, const unsigned char* cipher16);
Expand All @@ -38,4 +53,16 @@ void AES256_init(AES256_ctx* ctx, const unsigned char* key32);
void AES256_encrypt(const AES256_ctx* ctx, size_t blocks, unsigned char* cipher16, const unsigned char* plain16);
void AES256_decrypt(const AES256_ctx* ctx, size_t blocks, unsigned char* plain16, const unsigned char* cipher16);

#endif /* CTAES_H */
void AES128_CBC_init(AES128_CBC_ctx* ctx, const unsigned char* key16, const uint8_t* iv);
void AES128_CBC_encrypt(AES128_CBC_ctx* ctx, size_t blocks, unsigned char* encrypted, const unsigned char* plain);
void AES128_CBC_decrypt(AES128_CBC_ctx* ctx, size_t blocks, unsigned char* plain, const unsigned char *encrypted);

void AES192_CBC_init(AES192_CBC_ctx* ctx, const unsigned char* key16, const uint8_t* iv);
void AES192_CBC_encrypt(AES192_CBC_ctx* ctx, size_t blocks, unsigned char* encrypted, const unsigned char* plain);
void AES192_CBC_decrypt(AES192_CBC_ctx* ctx, size_t blocks, unsigned char* plain, const unsigned char *encrypted);

void AES256_CBC_init(AES256_CBC_ctx* ctx, const unsigned char* key16, const uint8_t* iv);
void AES256_CBC_encrypt(AES256_CBC_ctx* ctx, size_t blocks, unsigned char* encrypted, const unsigned char* plain);
void AES256_CBC_decrypt(AES256_CBC_ctx* ctx, size_t blocks, unsigned char* plain, const unsigned char *encrypted);

#endif
74 changes: 74 additions & 0 deletions test.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ typedef struct {
const char* cipher;
} ctaes_test;

typedef struct {
int keysize;
const char* key;
const char* iv;
int nblocks;
const char* plain;
const char* cipher;
} ctaes_cbc_test;

static const ctaes_test ctaes_tests[] = {
/* AES test vectors from FIPS 197. */
{128, "000102030405060708090a0b0c0d0e0f", "00112233445566778899aabbccddeeff", "69c4e0d86a7b0430d8cdb78070b4c55a"},
Expand All @@ -38,6 +47,25 @@ static const ctaes_test ctaes_tests[] = {
{256, "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", "f69f2445df4f9b17ad2b417be66c3710", "23304b7a39f9f3ff067d8d8f9e24ecc7"}
};

static const ctaes_cbc_test ctaes_cbc_tests[] = {
/* AES-CBC test vectors from NIST sp800-38a. */
{
128, "2b7e151628aed2a6abf7158809cf4f3c", "000102030405060708090a0b0c0d0e0f", 4,
"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
"7649abac8119b246cee98e9b12e9197d5086cb9b507219ee95db113a917678b273bed6b8e3c1743b7116e69e222295163ff1caa1681fac09120eca307586e1a7"
},
{
192, "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b", "000102030405060708090a0b0c0d0e0f", 4,
"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
"4f021db243bc633d7178183a9fa071e8b4d9ada9ad7dedf4e5e738763f69145a571b242012fb7ae07fa9baac3df102e008b0e27988598881d920a9e64f5615cd"
},
{
256, "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", "000102030405060708090a0b0c0d0e0f", 4,
"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
"f58c4c04d6e5f1ba779eabfb5f7bfbd69cfc4e967edb808d679f777bc6702c7d39f23369a9d9bacfa530e26304231461b2eb05e2c39be9fcda6c19078c6a9d1b"
}
};

static void from_hex(unsigned char* data, int len, const char* hex) {
int p;
for (p = 0; p < len; p++) {
Expand Down Expand Up @@ -101,6 +129,52 @@ int main(void) {
fail++;
}
}
for (i = 0; i < sizeof(ctaes_cbc_tests) / sizeof(ctaes_cbc_tests[0]); i++) {
const ctaes_cbc_test* test = &ctaes_cbc_tests[i];
unsigned char key[32], iv[16], plain[4 * 16], cipher[4 * 16], ciphered[4 * 16], deciphered[4 * 16];
assert(test->keysize == 128 || test->keysize == 192 || test->keysize == 256);
assert(test->nblocks == 4);
from_hex(iv, 16, test->iv);
from_hex(plain, test->nblocks * 16, test->plain);
from_hex(cipher, test->nblocks * 16, test->cipher);
switch (test->keysize) {
case 128: {
AES128_CBC_ctx ctx;
from_hex(key, 16, test->key);
AES128_CBC_init(&ctx, key, iv);
AES128_CBC_encrypt(&ctx, test->nblocks, ciphered, plain);
AES128_CBC_init(&ctx, key, iv);
AES128_CBC_decrypt(&ctx, test->nblocks, deciphered, cipher);
break;
}
case 192: {
AES192_CBC_ctx ctx;
from_hex(key, 24, test->key);
AES192_CBC_init(&ctx, key, iv);
AES192_CBC_encrypt(&ctx, test->nblocks, ciphered, plain);
AES192_CBC_init(&ctx, key, iv);
AES192_CBC_decrypt(&ctx, test->nblocks, deciphered, cipher);
break;
}
case 256: {
AES256_CBC_ctx ctx;
from_hex(key, 32, test->key);
AES256_CBC_init(&ctx, key, iv);
AES256_CBC_encrypt(&ctx, test->nblocks, ciphered, plain);
AES256_CBC_init(&ctx, key, iv);
AES256_CBC_decrypt(&ctx, test->nblocks, deciphered, cipher);
break;
}
}
if (memcmp(cipher, ciphered, test->nblocks * 16)) {
fprintf(stderr, "E(key=\"%s\", plain=\"%s\") != \"%s\"\n", test->key, test->plain, test->cipher);
fail++;
}
if (memcmp(plain, deciphered, test->nblocks * 16)) {
fprintf(stderr, "D(key=\"%s\", cipher=\"%s\") != \"%s\"\n", test->key, test->cipher, test->plain);
fail++;
}
}
if (fail == 0) {
fprintf(stderr, "All tests successful\n");
} else {
Expand Down

0 comments on commit a1caf29

Please sign in to comment.