Jump to content
Nytro

[C] AES Implementation

Recommended Posts

Posted

[h=1][C] AES Implementation[/h]Author:

[h=3]X-N2O[/h]

I joined all the source inside the code tags.

If you wanna use it you have the separate files aes.c, aes.h and main.c inside the zip file.

Enjoy.

// 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 <a href="http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf" class="bbc_url" title="External link" rel="nofollow external">http://csrc.nist.gov...97/fips-197.pdf</a>
// 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;

defaut:
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, j;

// 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);
}

int main(int argc, char *argv[])
{
unsigned char key[KEY_128] = "uber strong key!";
unsigned char ptext[16] = "Attack at dawn!";
unsigned char ctext[16];
unsigned char decptext[16];
aes_ctx_t *ctx;

init_aes();
ctx = aes_alloc_ctx(key, sizeof(key));
if(!ctx) {
perror("aes_alloc_ctx");
return EXIT_FAILURE;
}
aes_encrypt(ctx, ptext, ctext);
aes_decrypt(ctx, ctext, decptext);
puts(decptext);

aes_free_ctx(ctx);
return EXIT_SUCCESS;
}

In the attached zip you will also find the compiled ELF binary.

Download:

http://www.rohitab.com/discuss/index.php?app=core&module=attach&section=attach&attach_id=2875

Sursa: [C] AES Implementation - rohitab.com - Forums

Posted

Acelasi lucru se poate face si cu openssl library . Mai ales daca aplicatia ruleaza sub linux deoarece nu stiu vreo distributie de linux care sa nu aiba openssl in afara de versiunile facute pt procesoare RISC care folosesc Matrix SSL.

Exemplu:


/**
AES encryption/decryption demo program using OpenSSL EVP apis
gcc -Wall openssl_aes.c -lcrypto

this is public domain code.

Saju Pillai (saju.pillai@gmail.com)
**/

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <openssl/evp.h>

/**
* Create an 256 bit key and IV using the supplied key_data. salt can be added for taste.
* Fills in the encryption and decryption ctx objects and returns 0 on success
**/
int aes_init(unsigned char *key_data, int key_data_len, unsigned char *salt, EVP_CIPHER_CTX *e_ctx,
EVP_CIPHER_CTX *d_ctx)
{
int i, nrounds = 5;
unsigned char key[32], iv[32];

/*
* Gen key & IV for AES 256 CBC mode. A SHA1 digest is used to hash the supplied key material.
* nrounds is the number of times the we hash the material. More rounds are more secure but
* slower.
*/
i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), salt, key_data, key_data_len, nrounds, key, iv);
if (i != 32) {
printf("Key size is %d bits - should be 256 bits\n", i);
return -1;
}

EVP_CIPHER_CTX_init(e_ctx);
EVP_EncryptInit_ex(e_ctx, EVP_aes_256_cbc(), NULL, key, iv);
EVP_CIPHER_CTX_init(d_ctx);
EVP_DecryptInit_ex(d_ctx, EVP_aes_256_cbc(), NULL, key, iv);

return 0;
}

/*
* Encrypt *len bytes of data
* All data going in & out is considered binary (unsigned char[])
*/
unsigned char *aes_encrypt(EVP_CIPHER_CTX *e, unsigned char *plaintext, int *len)
{
/* max ciphertext len for a n bytes of plaintext is n + AES_BLOCK_SIZE -1 bytes */
int c_len = *len + AES_BLOCK_SIZE, f_len = 0;
unsigned char *ciphertext = malloc(c_len);

/* allows reusing of 'e' for multiple encryption cycles */
EVP_EncryptInit_ex(e, NULL, NULL, NULL, NULL);

/* update ciphertext, c_len is filled with the length of ciphertext generated,
*len is the size of plaintext in bytes */
EVP_EncryptUpdate(e, ciphertext, &c_len, plaintext, *len);

/* update ciphertext with the final remaining bytes */
EVP_EncryptFinal_ex(e, ciphertext+c_len, &f_len);

*len = c_len + f_len;
return ciphertext;
}

/*
* Decrypt *len bytes of ciphertext
*/
unsigned char *aes_decrypt(EVP_CIPHER_CTX *e, unsigned char *ciphertext, int *len)
{
/* plaintext will always be equal to or lesser than length of ciphertext*/
int p_len = *len, f_len = 0;
unsigned char *plaintext = malloc(p_len);

EVP_DecryptInit_ex(e, NULL, NULL, NULL, NULL);
EVP_DecryptUpdate(e, plaintext, &p_len, ciphertext, *len);
EVP_DecryptFinal_ex(e, plaintext+p_len, &f_len);

*len = p_len + f_len;
return plaintext;
}

int main(int argc, char **argv)
{
/* "opaque" encryption, decryption ctx structures that libcrypto uses to record
status of enc/dec operations */
EVP_CIPHER_CTX en, de;

/* 8 bytes to salt the key_data during key generation. This is an example of
compiled in salt. We just read the bit pattern created by these two 4 byte
integers on the stack as 64 bits of contigous salt material -
ofcourse this only works if sizeof(int) >= 4 */
unsigned int salt[] = {12345, 54321};
unsigned char *key_data;
int key_data_len, i;
char *input[] = {"a", "abcd", "this is a test", "this is a bigger test",
"\nWho are you ?\nI am the 'Doctor'.\n'Doctor' who ?\nPrecisely!",
NULL};

/* the key_data is read from the argument list */
key_data = (unsigned char *)argv[1];
key_data_len = strlen(argv[1]);

/* gen key and iv. init the cipher ctx object */
if (aes_init(key_data, key_data_len, (unsigned char *)&salt, &en, &de)) {
printf("Couldn't initialize AES cipher\n");
return -1;
}

/* encrypt and decrypt each input string and compare with the original */
for (i = 0; input[i]; i++) {
char *plaintext;
unsigned char *ciphertext;
int olen, len;

/* The enc/dec functions deal with binary data and not C strings. strlen() will
return length of the string without counting the '\0' string marker. We always
pass in the marker byte to the encrypt/decrypt functions so that after decryption
we end up with a legal C string */
olen = len = strlen(input[i])+1;

ciphertext = aes_encrypt(&en, (unsigned char *)input[i], &len);
plaintext = (char *)aes_decrypt(&de, ciphertext, &len);

if (strncmp(plaintext, input[i], olen))
printf("FAIL: enc/dec failed for \"%s\"\n", input[i]);
else
printf("OK: enc/dec ok for \"%s\"\n", plaintext);

free(ciphertext);
free(plaintext);
}

EVP_CIPHER_CTX_cleanup(&en);
EVP_CIPHER_CTX_cleanup(&de);

return 0;
}

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...