Is there a library that's easy to setup and use with Visual Studio 2010 for AES encryption/decryption?

I've been fiddling with CryptoPP and it's endless link errors and iterator_level_not_equal error messages for an hour now, so I think it's time to look for an installer or a new lib.

Any suggestions?

AES isn't especially difficult to implement from the specification. Ignoring the usual caveats of reinventing the wheel on important stuff like encryption, you could write your own class:

#ifndef JSW_AES_PROVIDER_H
#define JSW_AES_PROVIDER_H

#include <vector>

namespace jsw {
    namespace encryption {
        typedef std::vector<unsigned char> bytes_t;
        
        class aes_provider {
        public:
            aes_provider(bytes_t key) { reset(key); }

            void normalize(bytes_t& bytes);
            bytes_t encrypt(const bytes_t& bytes);
            bytes_t decrypt(const bytes_t& bytes);
        private:
            static bytes_t::value_type Sbox[][16];
            static bytes_t::value_type Sbox_inverse[][16];
            static bytes_t::value_type Rcon[][4];
        private:
            int Nb; // Input block length in 32-bit increments (always 4)
            int Nk; // Key length in 32-bit increments (4, 6, or 8)
            int Nr; // Number of rounds corresponding to key size (4:10, 6:12, 8:14)

            bytes_t key;                // Seed key
            std::vector<bytes_t> w;     // Key schedule
            std::vector<bytes_t> state; // State matrix

            void reset(bytes_t key);
            void key_expansion();
            void add_round_key(int round);
            void sub_bytes(bytes_t::value_type Sbox[][16]);
            void shift_rows();
            void inverse_shift_rows();
            void mix_columns();
            void inverse_mix_columns();
            bytes_t sub_word(bytes_t word);
            bytes_t rot_word(bytes_t word);
            unsigned char gfield_mul(unsigned char a, unsigned char b);
        };
    }
}

#endif
#include <stdexcept>
#include <vector>
#include "aes_provider.h"

namespace jsw {
    namespace encryption {
        void aes_provider::normalize(bytes_t& bytes)
        {
            // Add null padding to the input (modulo 128-bits for AES)
            while (bytes.size() % 16 != 0)
                bytes.push_back(0);
        }
        
        bytes_t aes_provider::encrypt(const bytes_t& bytes)
        {
            state = std::vector<bytes_t>(4, bytes_t(Nb));

            // Input to state
            for (int r = 0; r < 4; r++) {
                for (int c = 0; c < Nb; c++)
                    state[r][c] = bytes[r + 4 * c];
            }

            add_round_key(0);

            for (int round = 1; round < Nr; round++) {
                sub_bytes(Sbox);
                shift_rows();
                mix_columns();
                add_round_key(round);
            }

            sub_bytes(Sbox);
            shift_rows();
            add_round_key(Nr);

            bytes_t output(4 * Nb);

            // State to output
            for (int r = 0; r < 4; r++) {
                for (int c = 0; c < Nb; c++)
                    output[r + 4 * c] = state[r][c];
            }

            return output;
        }

        bytes_t aes_provider::decrypt(const bytes_t& bytes)
        {
            state = std::vector<bytes_t>(4, bytes_t(Nb));

            // Input to state
            for (int r = 0; r < 4; r++) {
                for (int c = 0; c < Nb; c++)
                    state[r][c] = bytes[r + 4 * c];
            }

            add_round_key(Nr);

            for (int round = Nr - 1; round > 0; round--) {
                inverse_shift_rows();
                sub_bytes(Sbox_inverse);
                add_round_key(round);
                inverse_mix_columns();
            }

            inverse_shift_rows();
            sub_bytes(Sbox_inverse);
            add_round_key(0);

            bytes_t output(4 * Nb);

            // State to output
            for (int r = 0; r < 4; r++) {
                for (int c = 0; c < Nb; c++)
                    output[r + 4 * c] = state[r][c];
            }

            return output;
        }

        bytes_t::value_type aes_provider::Sbox[][16] = {
            {0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76},
            {0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0},
            {0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15},
            {0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75},
            {0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84},
            {0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf},
            {0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8},
            {0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2},
            {0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73},
            {0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb},
            {0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79},
            {0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08},
            {0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a},
            {0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e},
            {0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf},
            {0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16} 
        };

        bytes_t::value_type aes_provider::Sbox_inverse[][16] = {
            {0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb},
            {0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb},
            {0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e},
            {0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25},
            {0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92},
            {0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84},
            {0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06},
            {0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b},
            {0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73},
            {0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e},
            {0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b},
            {0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4},
            {0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f},
            {0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef},
            {0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61},
            {0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d}
        };

        bytes_t::value_type aes_provider::Rcon[][4] = {
            {0x00, 0x00, 0x00, 0x00},  
            {0x01, 0x00, 0x00, 0x00},
            {0x02, 0x00, 0x00, 0x00},
            {0x04, 0x00, 0x00, 0x00},
            {0x08, 0x00, 0x00, 0x00},
            {0x10, 0x00, 0x00, 0x00},
            {0x20, 0x00, 0x00, 0x00},
            {0x40, 0x00, 0x00, 0x00},
            {0x80, 0x00, 0x00, 0x00},
            {0x1b, 0x00, 0x00, 0x00},
            {0x36, 0x00, 0x00, 0x00}
        };

        void aes_provider::reset(bytes_t key)
        {
            Nb = 4;

            switch (key.size()) {
            case 32:
                Nk = 8;
                Nr = 14;
                break;
            case 24:
                Nk = 6;
                Nr = 12;
                break;
            case 16:
                Nk = 4;
                Nr = 10;
                break;
            default:
                throw std::invalid_argument("Not a valid key size");
            }

            this->key = key;
            key_expansion();
        }

        void aes_provider::key_expansion()
        {
            bytes_t temp(4);

            w = std::vector<bytes_t>(Nb * (Nr + 1), bytes_t(4, 0));

            for (int i = 0; i < Nk; i++) {
                for (int byte = 0; byte < 4; byte++)
                    w[i][byte] = key[4 * i + byte];
            }

            for (int i = Nk; i < Nb * (Nr + 1); i++) {
                for (int byte = 0; byte < 4; byte++)
                    temp[byte] = w[i - 1][byte];

                if (i % Nk == 0) {
                    temp = sub_word(rot_word(temp));

                    for (int byte = 0; byte < 4; byte++)
                        temp[byte] ^= Rcon[i / Nk][byte];
                }
                else if (Nk > 6 && i % Nk == 4) {
                    temp = sub_word(temp);
                }

                for (int byte = 0; byte < 4; byte++)
                    w[i][byte] = w[i - Nk][byte] ^ temp[byte];
            }
        }

        void aes_provider::add_round_key(int round)
        {
            for (int r = 0; r < 4; r++) {
                for (int c = 0; c < Nb; c++)
                    state[r][c] ^= w[round * 4 + c][r];
            }
        }

        void aes_provider::sub_bytes(bytes_t::value_type Sbox[][16])
        {
            for (int r = 0; r < 4; r++) {
                for (int c = 0; c < Nb; c++)
                    state[r][c] = Sbox[state[r][c] >> 4][state[r][c] & 0x0f];
            }
        }

        void aes_provider::shift_rows()
        {
            std::vector<bytes_t> temp = state;

            for (int r = 1; r < 4; r++) {
                for (int c = 0; c < Nb; c++)
                    state[r][c] = temp[r][(c + r) % Nb];
            }
        }

        void aes_provider::inverse_shift_rows()
        {
            std::vector<bytes_t> temp = state;

            for (int r = 1; r < 4; r++) {
                for (int c = 0; c < Nb; c++)
                    state[r][(c + r) % Nb] = temp[r][c];
            }
        }

        void aes_provider::mix_columns()
        {
            std::vector<bytes_t> temp = state;

            for (int c = 0; c < 4; ++c) {
                state[0][c] = gfield_mul(temp[0][c], 2) ^ gfield_mul(temp[1][c], 3) ^ temp[2][c] ^ temp[3][c];
                state[1][c] = temp[0][c] ^ gfield_mul(temp[1][c], 2) ^ gfield_mul(temp[2][c], 3) ^ temp[3][c];
                state[2][c] = temp[0][c] ^ temp[1][c] ^ gfield_mul(temp[2][c], 2) ^ gfield_mul(temp[3][c], 3);
                state[3][c] = gfield_mul(temp[0][c], 3) ^ temp[1][c] ^ temp[2][c] ^ gfield_mul(temp[3][c], 2);
            }
        }

        void aes_provider::inverse_mix_columns()
        {
            std::vector<bytes_t> temp = state;

            for (int c = 0; c < 4; ++c) {
                state[0][c] = 
                    gfield_mul(temp[0][c], 0x0e) ^ gfield_mul(temp[1][c], 0x0b) ^ 
                    gfield_mul(temp[2][c], 0x0d) ^ gfield_mul(temp[3][c], 0x09);
                state[1][c] = 
                    gfield_mul(temp[0][c], 0x09) ^ gfield_mul(temp[1][c], 0x0e) ^ 
                    gfield_mul(temp[2][c], 0x0b) ^ gfield_mul(temp[3][c], 0x0d);
                state[2][c] = 
                    gfield_mul(temp[0][c], 0x0d) ^ gfield_mul(temp[1][c], 0x09) ^ 
                    gfield_mul(temp[2][c], 0x0e) ^ gfield_mul(temp[3][c], 0x0b);
                state[3][c] =
                    gfield_mul(temp[0][c], 0x0b) ^ gfield_mul(temp[1][c], 0x0d) ^ 
                    gfield_mul(temp[2][c], 0x09) ^ gfield_mul(temp[3][c], 0x0e);
            }
        }

        bytes_t aes_provider::sub_word(bytes_t word)
        {
            bytes_t result(4);

            result[0] = Sbox[word[0] >> 4][word[0] & 0x0f];
            result[1] = Sbox[word[1] >> 4][word[1] & 0x0f];
            result[2] = Sbox[word[2] >> 4][word[2] & 0x0f];
            result[3] = Sbox[word[3] >> 4][word[3] & 0x0f];

            return result;
        }

        bytes_t aes_provider::rot_word(bytes_t word)
        {
            bytes_t result(4);

            result[0] = word[1];
            result[1] = word[2];
            result[2] = word[3];
            result[3] = word[0];

            return result;
        }

        unsigned char aes_provider::gfield_mul(unsigned char a, unsigned char b)
        {
            unsigned char prod = 0;

            for (int i = 0; i < 8; i++) {
                if ((b & 1) == 1)
                    prod ^= a;

                bool is_set = (a & 0x80) == 0x80;

                a <<= 1;

                if (is_set)
                    a ^= 0x1b;

                b >>= 1;
            }

            return prod;
        }
    }
}
#include <algorithm>
#include <climits>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <string>
#include "aes_provider.h"

using namespace jsw::encryption;
using namespace std;

bytes_t random_key(int size)
{
    bytes_t key;

    generate_n(back_inserter(key), size, []{ 
        return rand() % UCHAR_MAX;
    });

    return key;
}

class dump_bytes {
    const bytes_t& _bytes;
public:
    dump_bytes(const bytes_t& bytes): _bytes(bytes) {}
    
    friend ostream& operator<<(ostream& out, const dump_bytes& self)
    {
        for_each(self._bytes.begin(), self._bytes.end(), [&](unsigned b) {
            out<< std::hex << std::setw(3) << b;
        });
    }
};

int main()
{
    string line;

    cout<<"Input: ";

    if (getline(cin, line)) {
        bytes_t bytes(line.begin(), line.end());
        aes_provider cipher(random_key(32));

        cipher.normalize(bytes);
        cout<<"Before:  "<< dump_bytes(bytes) << '\n';
        bytes = cipher.encrypt(bytes);
        cout<<"After:   "<< dump_bytes(bytes) << '\n';
        bytes = cipher.decrypt(bytes);
        cout<<"Restore: "<< dump_bytes(bytes) << '\n';
    }
}

;)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.