diff options
author | toni <matzeton@googlemail.com> | 2016-06-27 03:17:02 +0200 |
---|---|---|
committer | toni <matzeton@googlemail.com> | 2016-06-27 03:17:02 +0200 |
commit | 37b0615e751e7653fc5572c8fa07d3887495cedb (patch) | |
tree | 236380193f17424bb33dd0464c1dc569f56b7d4d /aes.c | |
parent | 2a3d86fb553fd3d4c0967cb8b9b9f416fe14f4cc (diff) |
simple aes tool
Diffstat (limited to 'aes.c')
-rw-r--r-- | aes.c | 411 |
1 files changed, 411 insertions, 0 deletions
@@ -0,0 +1,411 @@ +// AES Implementation by X-N2O +// Started: 15:41:35 - 18 Nov 2009 +// Finished: 20:03:59 - 21 Nov 2009 +// Logarithm, S-Box, and RCON tables are not hardcoded +// Instead they are generated when the program starts +// All of the code below is based from the AES specification +// You can find it at http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf +// You may use this code as you wish, but do not remove this comment +// This is only a proof of concept, and should not be considered as the most efficient implementation + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#define AES_RPOL 0x011b // reduction polynomial (x^8 + x^4 + x^3 + x + 1) +#define AES_GEN 0x03 // gf(2^8) generator (x + 1) +#define AES_SBOX_CC 0x63 // S-Box C constant + +#define KEY_128 (128/8) +#define KEY_192 (192/8) +#define KEY_256 (256/8) + +#define aes_mul(a, b) ((a)&&(b)?g_aes_ilogt[(g_aes_logt[(a)]+g_aes_logt[(b)])%0xff]:0) +#define aes_inv(a) ((a)?g_aes_ilogt[0xff-g_aes_logt[(a)]]:0) + +unsigned char g_aes_logt[256], g_aes_ilogt[256]; +unsigned char g_aes_sbox[256], g_aes_isbox[256]; + +typedef struct { + unsigned char state[4][4]; + int kcol; + size_t rounds; + unsigned long keysched[0]; +} aes_ctx_t; + +void aes_init(); +aes_ctx_t *aes_alloc_ctx(unsigned char *key, size_t keyLen); +inline unsigned long aes_subword(unsigned long w); +inline unsigned long aes_rotword(unsigned long w); +void aes_keyexpansion(aes_ctx_t *ctx); + +inline unsigned char aes_mul_manual(unsigned char a, unsigned char b); // use aes_mul instead + +void aes_subbytes(aes_ctx_t *ctx); +void aes_shiftrows(aes_ctx_t *ctx); +void aes_mixcolumns(aes_ctx_t *ctx); +void aes_addroundkey(aes_ctx_t *ctx, int round); +void aes_encrypt(aes_ctx_t *ctx, unsigned char input[16], unsigned char output[16]); + +void aes_invsubbytes(aes_ctx_t *ctx); +void aes_invshiftrows(aes_ctx_t *ctx); +void aes_invmixcolumns(aes_ctx_t *ctx); +void aes_decrypt(aes_ctx_t *ctx, unsigned char input[16], unsigned char output[16]); + +void aes_free_ctx(aes_ctx_t *ctx); + +void init_aes() +{ + int i; + unsigned char gen; + + // build logarithm table and it's inverse + gen = 1; + for(i = 0; i < 0xff; i++) { + g_aes_logt[gen] = i; + g_aes_ilogt[i] = gen; + gen = aes_mul_manual(gen, AES_GEN); + } + + // build S-Box and it's inverse + for(i = 0; i <= 0xff; i++) { + char bi; + unsigned char inv = aes_inv(i); + + g_aes_sbox[i] = 0; + for(bi = 0; bi < 8; bi++) { + // based on transformation 5.1 + // could also be done with a loop based on the matrix + g_aes_sbox[i] |= ((inv & (1<<bi)?1:0) + ^ (inv & (1 << ((bi+4) & 7))?1:0) + ^ (inv & (1 << ((bi+5) & 7))?1:0) + ^ (inv & (1 << ((bi+6) & 7))?1:0) + ^ (inv & (1 << ((bi+7) & 7))?1:0) + ^ (AES_SBOX_CC & (1 << bi)?1:0) + ) << bi; + } + g_aes_isbox[g_aes_sbox[i]] = i; + } + // warning: quickhack + g_aes_sbox[1] = 0x7c; + g_aes_isbox[0x7c] = 1; + g_aes_isbox[0x63] = 0; +} + +aes_ctx_t *aes_alloc_ctx(unsigned char *key, size_t keyLen) +{ + aes_ctx_t *ctx; + size_t rounds; + size_t ks_size; + + switch(keyLen) { + case 16: // 128-bit key + rounds = 10; + break; + + case 24: // 192-bit key + rounds = 12; + break; + + case 32: // 256-bit key + rounds = 14; + break; + + default: + return NULL; + } + + ks_size = 4*(rounds+1)*sizeof(unsigned long); + ctx = malloc(sizeof(aes_ctx_t)+ks_size); + if(ctx) { + ctx->rounds = rounds; + ctx->kcol = keyLen/4; + memcpy(ctx->keysched, key, keyLen); + ctx->keysched[43] = 0; + aes_keyexpansion(ctx); + } + + return ctx; +} + +inline unsigned long aes_subword(unsigned long w) +{ + return g_aes_sbox[w & 0x000000ff] | + (g_aes_sbox[(w & 0x0000ff00) >> 8] << 8) | + (g_aes_sbox[(w & 0x00ff0000) >> 16] << 16) | + (g_aes_sbox[(w & 0xff000000) >> 24] << 24); +} + +inline unsigned long aes_rotword(unsigned long w) +{ + // May seem a bit different from the spec + // It was changed because unsigned long is represented with little-endian convention on x86 + // Should not depend on architecture, but this is only a POC + return ((w & 0x000000ff) << 24) | + ((w & 0x0000ff00) >> 8) | + ((w & 0x00ff0000) >> 8) | + ((w & 0xff000000) >> 8); +} + +void aes_keyexpansion(aes_ctx_t *ctx) +{ + unsigned long temp; + unsigned long rcon; + register int i; + + rcon = 0x00000001; + for(i = ctx->kcol; i < (4*(ctx->rounds+1)); i++) { + temp = ctx->keysched[i-1]; + if(!(i%ctx->kcol)) { + temp = aes_subword(aes_rotword(temp)) ^ rcon; + rcon = aes_mul(rcon, 2); + } else if(ctx->kcol > 6 && i%ctx->kcol == 4) + temp = aes_subword(temp); + ctx->keysched[i] = ctx->keysched[i-ctx->kcol] ^ temp; + } +} + +inline unsigned char aes_mul_manual(unsigned char a, unsigned char b) +{ + register unsigned short ac; + register unsigned char ret; + + ac = a; + ret = 0; + while(b) { + if(b & 0x01) + ret ^= ac; + ac <<= 1; + b >>= 1; + if(ac & 0x0100) + ac ^= AES_RPOL; + } + + return ret; +} + +void aes_subbytes(aes_ctx_t *ctx) +{ + int i; + + for(i = 0; i < 16; i++) { + int x, y; + + x = i & 0x03; + y = i >> 2; + ctx->state[x][y] = g_aes_sbox[ctx->state[x][y]]; + } +} + +void aes_shiftrows(aes_ctx_t *ctx) +{ + unsigned char nstate[4][4]; + int i; + + for(i = 0; i < 16; i++) { + int x, y; + + x = i & 0x03; + y = i >> 2; + nstate[x][y] = ctx->state[x][(y+x) & 0x03]; + } + + memcpy(ctx->state, nstate, sizeof(ctx->state)); +} + +void aes_mixcolumns(aes_ctx_t *ctx) +{ + unsigned char nstate[4][4]; + int i; + + for(i = 0; i < 4; i++) { + nstate[0][i] = aes_mul(0x02, ctx->state[0][i]) ^ + aes_mul(0x03, ctx->state[1][i]) ^ + ctx->state[2][i] ^ + ctx->state[3][i]; + nstate[1][i] = ctx->state[0][i] ^ + aes_mul(0x02, ctx->state[1][i]) ^ + aes_mul(0x03, ctx->state[2][i]) ^ + ctx->state[3][i]; + nstate[2][i] = ctx->state[0][i] ^ + ctx->state[1][i] ^ + aes_mul(0x02, ctx->state[2][i]) ^ + aes_mul(0x03, ctx->state[3][i]); + nstate[3][i] = aes_mul(0x03, ctx->state[0][i]) ^ + ctx->state[1][i] ^ + ctx->state[2][i] ^ + aes_mul(0x02, ctx->state[3][i]); + } + + memcpy(ctx->state, nstate, sizeof(ctx->state)); +} + +void aes_addroundkey(aes_ctx_t *ctx, int round) +{ + int i; + + for(i = 0; i < 16; i++) { + int x, y; + + x = i & 0x03; + y = i >> 2; + ctx->state[x][y] = ctx->state[x][y] ^ + ((ctx->keysched[round*4+y] & (0xff << (x*8))) >> (x*8)); + } +} + +void aes_encrypt(aes_ctx_t *ctx, unsigned char input[16], unsigned char output[16]) +{ + int i; + + // copy input to state + for(i = 0; i < 16; i++) + ctx->state[i & 0x03][i >> 2] = input[i]; + + aes_addroundkey(ctx, 0); + + for(i = 1; i < ctx->rounds; i++) { + aes_subbytes(ctx); + aes_shiftrows(ctx); + aes_mixcolumns(ctx); + aes_addroundkey(ctx, i); + } + + aes_subbytes(ctx); + aes_shiftrows(ctx); + aes_addroundkey(ctx, ctx->rounds); + + // copy state to output + for(i = 0; i < 16; i++) + output[i] = ctx->state[i & 0x03][i >> 2]; +} + +void aes_invshiftrows(aes_ctx_t *ctx) +{ + unsigned char nstate[4][4]; + int i; + + for(i = 0; i < 16; i++) { + int x, y; + + x = i & 0x03; + y = i >> 2; + nstate[x][(y+x) & 0x03] = ctx->state[x][y]; + } + + memcpy(ctx->state, nstate, sizeof(ctx->state)); +} + +void aes_invsubbytes(aes_ctx_t *ctx) +{ + int i; + + for(i = 0; i < 16; i++) { + int x, y; + + x = i & 0x03; + y = i >> 2; + ctx->state[x][y] = g_aes_isbox[ctx->state[x][y]]; + } +} + +void aes_invmixcolumns(aes_ctx_t *ctx) +{ + unsigned char nstate[4][4]; + int i; + + for(i = 0; i < 4; i++) { + nstate[0][i] = aes_mul(0x0e, ctx->state[0][i]) ^ + aes_mul(0x0b, ctx->state[1][i]) ^ + aes_mul(0x0d, ctx->state[2][i]) ^ + aes_mul(0x09, ctx->state[3][i]); + nstate[1][i] = aes_mul(0x09, ctx->state[0][i]) ^ + aes_mul(0x0e, ctx->state[1][i]) ^ + aes_mul(0x0b, ctx->state[2][i]) ^ + aes_mul(0x0d, ctx->state[3][i]); + nstate[2][i] = aes_mul(0x0d, ctx->state[0][i]) ^ + aes_mul(0x09, ctx->state[1][i]) ^ + aes_mul(0x0e, ctx->state[2][i]) ^ + aes_mul(0x0b, ctx->state[3][i]); + nstate[3][i] = aes_mul(0x0b, ctx->state[0][i]) ^ + aes_mul(0x0d, ctx->state[1][i]) ^ + aes_mul(0x09, ctx->state[2][i]) ^ + aes_mul(0x0e, ctx->state[3][i]); + } + + memcpy(ctx->state, nstate, sizeof(ctx->state)); +} + +void aes_decrypt(aes_ctx_t *ctx, unsigned char input[16], unsigned char output[16]) +{ + int i; + + // copy input to state + for(i = 0; i < 16; i++) + ctx->state[i & 0x03][i >> 2] = input[i]; + + aes_addroundkey(ctx, ctx->rounds); + for(i = ctx->rounds-1; i >= 1; i--) { + aes_invshiftrows(ctx); + aes_invsubbytes(ctx); + aes_addroundkey(ctx, i); + aes_invmixcolumns(ctx); + } + + aes_invshiftrows(ctx); + aes_invsubbytes(ctx); + aes_addroundkey(ctx, 0); + + // copy state to output + for(i = 0; i < 16; i++) + output[i] = ctx->state[i & 0x03][i >> 2]; +} + +void aes_free_ctx(aes_ctx_t *ctx) +{ + free(ctx); +} + +#define PRINT_BYTES(bPtr, siz, offset) { int _bPtr_idx; for (_bPtr_idx = offset; _bPtr_idx < offset+siz; _bPtr_idx++) { printf("%02X ", bPtr[_bPtr_idx]); } printf("\n"); } +int main(int argc, char *argv[]) +{ + if (argc != 3) { + fprintf(stderr, "usage: %s [KEY] [MSG]\n", argv[0]); + return 1; + } + + size_t klen = strlen(argv[1]); + unsigned char key[KEY_128]; + memcpy(key, argv[1], klen); + + size_t plen = strlen(argv[2]); + unsigned char ptext[plen+1]; + memcpy(ptext, argv[2], plen); + ptext[plen] = '\0'; + + unsigned char ctext[plen+1]; + memset(ctext, '\0', plen+1); + unsigned char decptext[plen+1]; + memset(decptext, '\0', plen+1); + + aes_ctx_t *ctx; + + init_aes(); + ctx = aes_alloc_ctx(key, sizeof(key)); + if(!ctx) { + perror("aes_alloc_ctx"); + return EXIT_FAILURE; + } + printf("Encrypted[HEX]..: "); + aes_encrypt(ctx, ptext, ctext); + PRINT_BYTES(ctext, sizeof(ctext), 0); + aes_decrypt(ctx, ctext, decptext); + printf("Decrypted[HEX]..: "); + PRINT_BYTES(decptext, sizeof(decptext), 0); + printf("Decrypted[ASCII]: "); + puts((char*)decptext); + + aes_free_ctx(ctx); + return EXIT_SUCCESS; +} + |