diff --git a/ctaes.c b/ctaes.c index 83d65e4..a6360cb 100644 --- a/ctaes.c +++ b/ctaes.c @@ -14,6 +14,8 @@ #include "ctaes.h" +#include + /* 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 @@ -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); +} diff --git a/ctaes.h b/ctaes.h index 72a261d..2844f94 100644 --- a/ctaes.h +++ b/ctaes.h @@ -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); @@ -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 diff --git a/test.c b/test.c index d4a043f..e063afa 100644 --- a/test.c +++ b/test.c @@ -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"}, @@ -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++) { @@ -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 {