So for the past few days I've been working on a AES-128 encrypt/decipher class. I needed something very scaled down from Cryptolib so that I didn't have to constantly import the .lib file on all my programming computers (work, home, laptop1, laptop2) So i decided since I will only every use AES-128 for one my programs (related to NFC desfire stuff) I wanted to make a small and easily portable class. I have the following up for review. I asked a question at stack overflow when I was having a issue and one of the members mentioned that i had memory leaks. Well I'm a C#/Java programmer at heart and C++ is only a few months old in me so sorry about mistakes like that.
I don't have room to put the Galois files, I will however just put the mockup of it
Aes128.h
#pragma once
#include "ByteUtil.h"
#include "Galois.h"
class AES128
{
public:
void SetKey(const BYTE* key);
void SetIV(const BYTE* iv);
void EncryptData(BYTE** outBlock, const BYTE* inBlock, size_t length);
void DecryptData(BYTE** outBlock, const BYTE* inBlock, size_t length);
private:
void EncryptBlock(BYTE* outBlock, const BYTE* inBlock, const BYTE* cipherBlock);
void DecryptBlock(BYTE* outBlock, const BYTE* inBlock, const BYTE* cipherBlock);
BYTE* Key;
BYTE* IV;
};
Aes128.cpp
#include "stdafx.h"
#include "AES128.h"
/*
Public Methods
*/
void AES128::SetKey(const BYTE* key)
{
Key = (BYTE*)malloc(16);
memcpy(Key, key, 16);
}
void AES128::SetIV(const BYTE* iv)
{
IV = (BYTE*)malloc(16);
memcpy(IV, iv, 16);
}
void AES128::EncryptData(BYTE** outBlock, const BYTE* inBlock, size_t length)
{
float blockSize = (float)(length/16);
blockSize = ceilf(blockSize);
size_t newLength = (size_t)(blockSize*16);
BYTE* temp = (BYTE*)malloc(newLength);
BYTE* padd = (BYTE*)malloc(newLength);
memset(temp, 0, newLength);
memcpy(padd, inBlock, length);
EncryptBlock(temp, padd, IV);
for (int i=1; i<blockSize; i++)
{
EncryptBlock(&temp[i*16], &padd[i*16], &temp[(i-1)*16]);
}
*outBlock = (BYTE*)malloc(newLength);
memcpy((*outBlock), temp, newLength);
}
void AES128::DecryptData(BYTE** outBlock, const BYTE* inBlock, size_t length)
{
float blockSize = (float)(length/16);
blockSize = ceilf(blockSize);
size_t newLength = (size_t)(blockSize*16);
BYTE* temp = (BYTE*)malloc(newLength);
BYTE* padd = (BYTE*)malloc(newLength);
memset(temp, 0, newLength);
memcpy(padd, inBlock, length);
DecryptBlock(temp, padd, IV);
for (int i=1; i<blockSize; i++)
{
DecryptBlock(&temp[i*16], &padd[i*16], &temp[(i-1)*16]);
}
*outBlock = (BYTE*)malloc(newLength);
memcpy((*outBlock), temp, newLength);
}
/*
Private Methods
*/
void AES128::EncryptBlock(BYTE* outBlock, const BYTE* inBlock, const BYTE* cipherBlock)
{
BYTE temp[16] = {0x00};
Galois::XorBlock(temp, inBlock);
Galois::XorBlock(temp, cipherBlock);
BYTE expandedKey[176] = {0x00};
memcpy(expandedKey, Key, 16);
Galois::expand_key(expandedKey);
Galois::XorBlock(temp, expandedKey);
for(int i=16; i<160; i+=16)
{
Galois::DoRound(temp, &expandedKey[i]);
}
Galois::SubBytes(temp);
Galois::ShiftRows(temp);
Galois::XorBlock(temp, &expandedKey[160]);
memcpy(outBlock, temp, 16);
}
void AES128::DecryptBlock(BYTE* outBlock, const BYTE* inBlock, const BYTE* cipherBlock)
{
BYTE temp[16] = {0x00};
Galois::XorBlock(temp, inBlock);
BYTE expandedKey[176] = {0x00};
BYTE* invExpandedKey;
memcpy(expandedKey, Key, 16);
Galois::expand_key(expandedKey);
Galois::InvertExpandedKey(&invExpandedKey, expandedKey);
Galois::XorBlock(temp, invExpandedKey);
Galois::InvShiftRows(temp);
Galois::InvSubBytes(temp);
for(int i=0x10; i<0xA0; i+=0x10) //change i<0xA0
{
Galois::InvDoRound(temp, &invExpandedKey[i]);
}
Galois::XorBlock(temp, &invExpandedKey[160]);
Galois::XorBlock(temp, cipherBlock);
memcpy(outBlock, temp, 16);
}
Galois.h
class Galois
{
private:
static BYTE gadd(const BYTE a, const BYTE b);
static BYTE gmul(const BYTE a, const BYTE b);
static BYTE gmul_Inverse(const BYTE in);
static void gmul_mix_column(BYTE* row);
static void inv_mix_column(BYTE *r);
//AES Key Expansion Functions
static void RotWord(BYTE* in);
static BYTE Rcon(BYTE in);
static void schedule_core(BYTE* in, BYTE i);
static void expand_key(BYTE* in);
static void InvertExpandedKey(BYTE** out, const BYTE* in);
static void SubBytes(BYTE* dest);
static void InvSubBytes(BYTE* dest);
static void ShiftRows(BYTE* dest);
static void InvShiftRows(BYTE* dest);
static void MixColumns(BYTE* row);
static void InvMixColumns(BYTE* row);
static void xorRow(BYTE* row1, const BYTE* row2);
static void XorBlock(BYTE* block1, const BYTE* block2);
static void SubWord(BYTE* in);
static void SubBytes(BYTE* dest);
static void InvSubWord(BYTE* in);
static void InvSubBytes(BYTE* dest);
public:
static void DoRound(BYTE* dest, const BYTE* roundKey);
static void InvDoRound(BYTE* dest, const BYTE* roundKey);
};
I plan on refactoring Galois a bit to seperate some of the Rijandel methods and then just use the math from Galois. That should clean it up nicely. So how bad is it?