AES 使用 C++ 可直接使用版本

此版本使用 AES/ECB/PKCS5Padding,會將字串加密後輸出 base64 ,解密則是將base64字串解密後輸出原字串

需要的人請直接複製使用

程式碼

#include <iostream>
#include <iomanip> // 為了使用 std::setw 和 std::setfill
using namespace std;

#define BYTE unsigned char
#define AES_BLOCK_SIZE 16
	
/******************************************************************************/
	
// The following lookup tables and functions are for internal use only!
BYTE AES_Sbox[] = {99,124,119,123,242,107,111,197,48,1,103,43,254,215,171,
		118,202,130,201,125,250,89,71,240,173,212,162,175,156,164,114,192,183,253,
		147,38,54,63,247,204,52,165,229,241,113,216,49,21,4,199,35,195,24,150,5,154,
		7,18,128,226,235,39,178,117,9,131,44,26,27,110,90,160,82,59,214,179,41,227,
		47,132,83,209,0,237,32,252,177,91,106,203,190,57,74,76,88,207,208,239,170,
		251,67,77,51,133,69,249,2,127,80,60,159,168,81,163,64,143,146,157,56,245,
		188,182,218,33,16,255,243,210,205,12,19,236,95,151,68,23,196,167,126,61,
		100,93,25,115,96,129,79,220,34,42,144,136,70,238,184,20,222,94,11,219,224,
		50,58,10,73,6,36,92,194,211,172,98,145,149,228,121,231,200,55,109,141,213,
		78,169,108,86,244,234,101,122,174,8,186,120,37,46,28,166,180,198,232,221,
		116,31,75,189,139,138,112,62,181,102,72,3,246,14,97,53,87,185,134,193,29,
		158,225,248,152,17,105,217,142,148,155,30,135,233,206,85,40,223,140,161,
		137,13,191,230,66,104,65,153,45,15,176,84,187,22};
	
BYTE AES_ShiftRowTab[] = {0,5,10,15,4,9,14,3,8,13,2,7,12,1,6,11};
	
BYTE AES_Sbox_Inv[256];
BYTE AES_ShiftRowTab_Inv[16];
BYTE AES_xtime[256];
bool initialized = false;


void printBytes(BYTE b[], int len) {
    int i;
    for (i=0; i<len; i++)
        std::cout << std::hex << std::setw(2) << std::setfill('0')<<(int)b[i] << " ";
    std::cout << std::endl;
}

void AES_SubBytes(BYTE state[], BYTE sbox[]) {
		int i;
		for(i = 0; i < 16; i++)
				state[i] = sbox[state[i]];
}
	
void AES_AddRoundKey(BYTE state[], BYTE rkey[]) {
		int i;
		for(i = 0; i < 16; i++)
				state[i] ^= rkey[i];
}
	
void AES_ShiftRows(BYTE state[], BYTE shifttab[]) {
		BYTE h[16];
		memcpy(h, state, 16);
		int i;
		for(i = 0; i < 16; i++)
				state[i] = h[shifttab[i]];
}
	
void AES_MixColumns(BYTE state[]) {
	int i;
	for(i = 0; i < 16; i += 4) {
		BYTE s0 = state[i + 0], s1 = state[i + 1];
		BYTE s2 = state[i + 2], s3 = state[i + 3];
		BYTE h = s0 ^ s1 ^ s2 ^ s3;
		state[i + 0] ^= h ^ AES_xtime[s0 ^ s1];
		state[i + 1] ^= h ^ AES_xtime[s1 ^ s2];
		state[i + 2] ^= h ^ AES_xtime[s2 ^ s3];
		state[i + 3] ^= h ^ AES_xtime[s3 ^ s0];
	}
}
	
void AES_MixColumns_Inv(BYTE state[]) {
	int i;
	for(i = 0; i < 16; i += 4) {
		BYTE s0 = state[i + 0], s1 = state[i + 1];
		BYTE s2 = state[i + 2], s3 = state[i + 3];
		BYTE h = s0 ^ s1 ^ s2 ^ s3;
		BYTE xh = AES_xtime[h];
		BYTE h1 = AES_xtime[AES_xtime[xh ^ s0 ^ s2]] ^ h;
		BYTE h2 = AES_xtime[AES_xtime[xh ^ s1 ^ s3]] ^ h;
		state[i + 0] ^= h1 ^ AES_xtime[s0 ^ s1];
		state[i + 1] ^= h2 ^ AES_xtime[s1 ^ s2];
		state[i + 2] ^= h1 ^ AES_xtime[s2 ^ s3];
		state[i + 3] ^= h2 ^ AES_xtime[s3 ^ s0];
	}
}

void AES_Init() {
    if(initialized){
        return;
    }
    int i;
    for(i = 0; i < 256; i++)
            AES_Sbox_Inv[AES_Sbox[i]] = i;
        
    for(i = 0; i < 16; i++)
            AES_ShiftRowTab_Inv[AES_ShiftRowTab[i]] = i;

    for(i = 0; i < 128; i++) {
            AES_xtime[i] = i << 1;
            AES_xtime[128 + i] = (i << 1) ^ 0x1b;
    }
    initialized = true;
}

void AES_Done() {}
		
int AES_ExpandKey(BYTE key[], int keyLen) {
		int kl = keyLen, ks, Rcon = 1, i, j;
		BYTE temp[4], temp2[4];
		switch (kl) {
				case 16: ks = 16 * (10 + 1); break;
				case 24: ks = 16 * (12 + 1); break;
				case 32: ks = 16 * (14 + 1); break;
				default: 
						printf("AES_ExpandKey: Only key lengths of 16, 24 or 32 bytes allowed!");
		}
		for(i = kl; i < ks; i += 4) {
				memcpy(temp, &key[i-4], 4);
				if (i % kl == 0) {
						temp2[0] = AES_Sbox[temp[1]] ^ Rcon;
						temp2[1] = AES_Sbox[temp[2]];
						temp2[2] = AES_Sbox[temp[3]];
						temp2[3] = AES_Sbox[temp[0]];
						memcpy(temp, temp2, 4);
						if ((Rcon <<= 1) >= 256)
								Rcon ^= 0x11b;
				}
				else if ((kl > 24) && (i % kl == 16)) {
						temp2[0] = AES_Sbox[temp[0]];
						temp2[1] = AES_Sbox[temp[1]];
						temp2[2] = AES_Sbox[temp[2]];
						temp2[3] = AES_Sbox[temp[3]];
						memcpy(temp, temp2, 4);
				}
				for(j = 0; j < 4; j++)
						key[i + j] = key[i + j - kl] ^ temp[j];
		}
		return ks;
}
	
// AES_Encrypt: encrypt the 16 byte array 'block' with the previously expanded key 'key'.
void AES_Encrypt(BYTE block[], BYTE key[], int keyLen) {
		int l = keyLen, i;
		AES_AddRoundKey(block, &key[0]);
		for(i = 16; i < l - 16; i += 16) {
			AES_SubBytes(block, AES_Sbox);
			AES_ShiftRows(block, AES_ShiftRowTab);
			AES_MixColumns(block);
			AES_AddRoundKey(block, &key[i]);
		}
		AES_SubBytes(block, AES_Sbox);
		AES_ShiftRows(block, AES_ShiftRowTab);
		AES_AddRoundKey(block, &key[i]);
}
	
// AES_Decrypt: decrypt the 16 byte array 'block' with the previously expanded key 'key'.
void AES_Decrypt(BYTE block[], BYTE key[], int keyLen) {
		int l = keyLen, i;
		AES_AddRoundKey(block, &key[l - 16]);
		AES_ShiftRows(block, AES_ShiftRowTab_Inv);
		AES_SubBytes(block, AES_Sbox_Inv);
		for(i = l - 32; i >= 16; i -= 16) {
				AES_AddRoundKey(block, &key[i]);
				AES_MixColumns_Inv(block);
				AES_ShiftRows(block, AES_ShiftRowTab_Inv);
				AES_SubBytes(block, AES_Sbox_Inv);
		}
		AES_AddRoundKey(block, &key[0]);
}

void convertToByte(const uint8_t* key_bytes, BYTE* key, size_t size) {
    for (size_t i = 0; i < size; ++i) {
        key[i] = (key_bytes[i]);  // 將每個 uint8_t 值轉換為 bitset<8>
    }
}

std::string base64_encode(const unsigned char* data, size_t len) {
    static const char encoding_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    std::string output;
    size_t i = 0;

    // 每3個字節轉換為4個字元
    while (i < len) {
        uint32_t octet_a = i < len ? data[i++] : 0;
        uint32_t octet_b = i < len ? data[i++] : 0;
        uint32_t octet_c = i < len ? data[i++] : 0;

        uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;

        output.push_back(encoding_table[(triple >> 3 * 6) & 0x3F]);
        output.push_back(encoding_table[(triple >> 2 * 6) & 0x3F]);
        output.push_back(encoding_table[(triple >> 1 * 6) & 0x3F]);
        output.push_back(encoding_table[(triple >> 0 * 6) & 0x3F]);
    }

    // 添加 '=' 填充
    size_t mod = len % 3;
    if (mod > 0) {
        for (size_t j = 0; j < (3 - mod); ++j) {
            output[output.size() - 1 - j] = '=';
        }
    }

    return output;
}

std::vector<uint8_t> base64_decode(const std::string& encoded) {
    const std::string BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    std::vector<uint8_t> decoded_data;

    int val = 0, valb = -8;
    for (unsigned char c : encoded) {
        if (BASE64_CHARS.find(c) == std::string::npos) {
            break;
        }

        val = (val << 6) + BASE64_CHARS.find(c);
        valb += 6;

        if (valb >= 0) {
            decoded_data.push_back((val >> valb) & 0xFF);
            valb -= 8;
        }
    }

    return decoded_data;
}

std::vector<uint8_t> byteArrayToVector(const BYTE* key, size_t size) {
    std::vector<uint8_t> result;
    result.reserve(size); // 預先分配空間提高效率
    for (size_t i = 0; i < size; ++i) {
        result.push_back(static_cast<uint8_t>(key[i])); // 提取 bitset 的值並存入 vector
    }
    return result;
}
void appendStateToVector(const BYTE state[AES_BLOCK_SIZE], std::vector<uint8_t>& data) {
    for (int i = 0; i < AES_BLOCK_SIZE; ++i) {
        data.push_back(static_cast<uint8_t>(state[i]));
    }
}

void remove_padding(std::vector<uint8_t>& data) {
    if (data.empty()) {
        throw std::runtime_error("Data is empty, cannot remove padding.");
    }

    // 讀取填充值
    uint8_t padding_value = data.back();
    if(padding_value == 0){
        padding_value = 16;
    }

    // 驗證填充值是否合理
    if (padding_value > data.size()) {
        throw std::runtime_error("Invalid padding value.");
    }

    // 移除填充值
    data.resize(data.size() - padding_value);
}

std::string vectorToString(const std::vector<uint8_t>& data) {
    return std::string(data.begin(), data.end());
}

// AES ECB 模式加密
std::string aes_encrypt_ecb(const std::string text_to_encrypt, const std::string key_str) {
	BYTE key[16 * (14 + 1)];
    BYTE state[AES_BLOCK_SIZE] = {0};
	int keyLen = 16;
    size_t len = text_to_encrypt.size();
    size_t padded_len = (len / AES_BLOCK_SIZE + 1) * AES_BLOCK_SIZE;
    std::vector<uint8_t> output(padded_len, 0);
    AES_Init();
    //讀取金鑰
    memcpy(key, key_str.data(), AES_BLOCK_SIZE);

	// std::cout << "原始金鑰:";
    // printBytes(key, keyLen);

	int expandKeyLen = AES_ExpandKey(key, keyLen);	//4* 44 = 176
    // std::cout << "展開金鑰長度:" << std::dec << expandKeyLen<< std::endl;
    // std::cout << "展開金鑰:";
    // printBytes(key, expandKeyLen);

    // 使用 std::vector 替代變數大小陣列
    std::vector<uint8_t> input(padded_len, 0);
    memcpy(input.data(), text_to_encrypt.data(), len);
    // PKCS#5 填充
    uint8_t padding_value = padded_len - len;
    std::fill(input.begin() + len, input.end(), padding_value);
    
    for (size_t i = 0; i < padded_len; i += AES_BLOCK_SIZE) {
        convertToByte(input.data() + i, state, AES_BLOCK_SIZE);
		// std::cout << "加密前:";
		// printBytes(state, AES_BLOCK_SIZE);
		AES_Encrypt(state, key, expandKeyLen);
		// std::cout << "加密完後:";
    	// printBytes(state, AES_BLOCK_SIZE);
        std::vector<uint8_t> tmp = byteArrayToVector(state, AES_BLOCK_SIZE);
        memcpy(output.data() + i, tmp.data(), AES_BLOCK_SIZE);  
    }
    std::string en64 = base64_encode(output.data(), output.size());
    return en64;
}


std::string aes_decrypt_ecb(const std::string text_to_decrypt,  const std::string key_str) {
    std::string output = "";
    std::vector<uint8_t> outputData;
    std::vector<uint8_t> de64 = base64_decode(text_to_decrypt);
    BYTE key[16 * (14 + 1)];
    BYTE state[AES_BLOCK_SIZE] = {0};
	int keyLen = 16;
    size_t len = de64.size();
    AES_Init();
    //讀取金鑰
    memcpy(key, key_str.data(), AES_BLOCK_SIZE);
    //擴展金鑰
    int expandKeyLen = AES_ExpandKey(key, keyLen);	//4* 44 = 176

    // 使用 std::vector 替代變數大小陣列
    std::vector<uint8_t> input(len, 0);
    memcpy(input.data(), de64.data(), len);

    for (size_t i = 0; i < len; i += AES_BLOCK_SIZE) {
        convertToByte(input.data() + i, state, AES_BLOCK_SIZE);
		AES_Decrypt(state, key, expandKeyLen);
        appendStateToVector(state, outputData);
    }

    remove_padding(outputData);
    output= vectorToString(outputData);
    return output;
}

int main(){
	AES_Init();
    std::string key_str = "1234567890ABCDEF";
	std::string text_to_encrypt = "1234567890ABCDEF";

    std::string en64 = aes_encrypt_ecb(text_to_encrypt, key_str);
    cout << "en64:" << endl << en64 << endl;
    std::string de64 = aes_decrypt_ecb(en64, key_str);
    cout << "de64:" << endl << de64 << endl;
    return 0;    
}

編譯方式

g++ -std=c++11 -o aes aes.cpp
./aes

本文大部分程式碼來自下面網站,我只是添加了 base64 與 padding 部分方便我自己使用

參考網站:https://www.codedata.com.tw/social-coding/aes/

發佈留言