#include "AES.h" //CONSTRUCTOR AES::AES() : m_bKeyInit(false), m_keylength(0), m_blockSize(0), m_iROUNDS(0) { } //DESTRUCTOR AES::~AES() { } void AES::Xor(char* buff, char const* chain) { if (false == m_bKeyInit) return; for (int i = 0; i < m_blockSize; i++) *(buff++) ^= *(chain++); } void AES::DefEncryptBlock(char const* in, char* result) { if (false == m_bKeyInit) return; int* Ker = m_Ke[0]; int t0 = ((unsigned char)*(in++) << 24); t0 |= ((unsigned char)*(in++) << 16); t0 |= ((unsigned char)*(in++) << 8); (t0 |= (unsigned char)*(in++)) ^= Ker[0]; int t1 = ((unsigned char)*(in++) << 24); t1 |= ((unsigned char)*(in++) << 16); t1 |= ((unsigned char)*(in++) << 8); (t1 |= (unsigned char)*(in++)) ^= Ker[1]; int t2 = ((unsigned char)*(in++) << 24); t2 |= ((unsigned char)*(in++) << 16); t2 |= ((unsigned char)*(in++) << 8); (t2 |= (unsigned char)*(in++)) ^= Ker[2]; int t3 = ((unsigned char)*(in++) << 24); t3 |= ((unsigned char)*(in++) << 16); t3 |= ((unsigned char)*(in++) << 8); (t3 |= (unsigned char)*(in++)) ^= Ker[3]; int a0, a1, a2, a3; //Apply Round Transforms for (int r = 1; r < m_iROUNDS; r++) { Ker = m_Ke[r]; a0 = (sm_T1[(t0 >> 24) & 0xFF] ^ sm_T2[(t1 >> 16) & 0xFF] ^ sm_T3[(t2 >> 8) & 0xFF] ^ sm_T4[t3 & 0xFF]) ^ Ker[0]; a1 = (sm_T1[(t1 >> 24) & 0xFF] ^ sm_T2[(t2 >> 16) & 0xFF] ^ sm_T3[(t3 >> 8) & 0xFF] ^ sm_T4[t0 & 0xFF]) ^ Ker[1]; a2 = (sm_T1[(t2 >> 24) & 0xFF] ^ sm_T2[(t3 >> 16) & 0xFF] ^ sm_T3[(t0 >> 8) & 0xFF] ^ sm_T4[t1 & 0xFF]) ^ Ker[2]; a3 = (sm_T1[(t3 >> 24) & 0xFF] ^ sm_T2[(t0 >> 16) & 0xFF] ^ sm_T3[(t1 >> 8) & 0xFF] ^ sm_T4[t2 & 0xFF]) ^ Ker[3]; t0 = a0; t1 = a1; t2 = a2; t3 = a3; } //Last Round is special Ker = m_Ke[m_iROUNDS]; int tt = Ker[0]; result[0] = sm_S[(t0 >> 24) & 0xFF] ^ (tt >> 24); result[1] = sm_S[(t1 >> 16) & 0xFF] ^ (tt >> 16); result[2] = sm_S[(t2 >> 8) & 0xFF] ^ (tt >> 8); result[3] = sm_S[t3 & 0xFF] ^ tt; tt = Ker[1]; result[4] = sm_S[(t1 >> 24) & 0xFF] ^ (tt >> 24); result[5] = sm_S[(t2 >> 16) & 0xFF] ^ (tt >> 16); result[6] = sm_S[(t3 >> 8) & 0xFF] ^ (tt >> 8); result[7] = sm_S[t0 & 0xFF] ^ tt; tt = Ker[2]; result[8] = sm_S[(t2 >> 24) & 0xFF] ^ (tt >> 24); result[9] = sm_S[(t3 >> 16) & 0xFF] ^ (tt >> 16); result[10] = sm_S[(t0 >> 8) & 0xFF] ^ (tt >> 8); result[11] = sm_S[t1 & 0xFF] ^ tt; tt = Ker[3]; result[12] = sm_S[(t3 >> 24) & 0xFF] ^ (tt >> 24); result[13] = sm_S[(t0 >> 16) & 0xFF] ^ (tt >> 16); result[14] = sm_S[(t1 >> 8) & 0xFF] ^ (tt >> 8); result[15] = sm_S[t2 & 0xFF] ^ tt; } //Convenience method to decrypt exactly one block of plaintext, assuming //Rijndael's default block size (128-bit). // in - The ciphertext. // result - The plaintext generated from a ciphertext using the session key. void AES::DefDecryptBlock(char const* in, char* result) { if (false == m_bKeyInit) return; int* Kdr = m_Kd[0]; int t0 = ((unsigned char)*(in++) << 24); t0 = t0 | ((unsigned char)*(in++) << 16); t0 |= ((unsigned char)*(in++) << 8); (t0 |= (unsigned char)*(in++)) ^= Kdr[0]; int t1 = ((unsigned char)*(in++) << 24); t1 |= ((unsigned char)*(in++) << 16); t1 |= ((unsigned char)*(in++) << 8); (t1 |= (unsigned char)*(in++)) ^= Kdr[1]; int t2 = ((unsigned char)*(in++) << 24); t2 |= ((unsigned char)*(in++) << 16); t2 |= ((unsigned char)*(in++) << 8); (t2 |= (unsigned char)*(in++)) ^= Kdr[2]; int t3 = ((unsigned char)*(in++) << 24); t3 |= ((unsigned char)*(in++) << 16); t3 |= ((unsigned char)*(in++) << 8); (t3 |= (unsigned char)*(in++)) ^= Kdr[3]; int a0, a1, a2, a3; for (int r = 1; r < m_iROUNDS; r++) // apply round transforms { Kdr = m_Kd[r]; a0 = (sm_T5[(t0 >> 24) & 0xFF] ^ sm_T6[(t3 >> 16) & 0xFF] ^ sm_T7[(t2 >> 8) & 0xFF] ^ sm_T8[t1 & 0xFF]) ^ Kdr[0]; a1 = (sm_T5[(t1 >> 24) & 0xFF] ^ sm_T6[(t0 >> 16) & 0xFF] ^ sm_T7[(t3 >> 8) & 0xFF] ^ sm_T8[t2 & 0xFF]) ^ Kdr[1]; a2 = (sm_T5[(t2 >> 24) & 0xFF] ^ sm_T6[(t1 >> 16) & 0xFF] ^ sm_T7[(t0 >> 8) & 0xFF] ^ sm_T8[t3 & 0xFF]) ^ Kdr[2]; a3 = (sm_T5[(t3 >> 24) & 0xFF] ^ sm_T6[(t2 >> 16) & 0xFF] ^ sm_T7[(t1 >> 8) & 0xFF] ^ sm_T8[t0 & 0xFF]) ^ Kdr[3]; t0 = a0; t1 = a1; t2 = a2; t3 = a3; } //Last Round is special Kdr = m_Kd[m_iROUNDS]; int tt = Kdr[0]; result[0] = sm_Si[(t0 >> 24) & 0xFF] ^ (tt >> 24); result[1] = sm_Si[(t3 >> 16) & 0xFF] ^ (tt >> 16); result[2] = sm_Si[(t2 >> 8) & 0xFF] ^ (tt >> 8); result[3] = sm_Si[t1 & 0xFF] ^ tt; tt = Kdr[1]; result[4] = sm_Si[(t1 >> 24) & 0xFF] ^ (tt >> 24); result[5] = sm_Si[(t0 >> 16) & 0xFF] ^ (tt >> 16); result[6] = sm_Si[(t3 >> 8) & 0xFF] ^ (tt >> 8); result[7] = sm_Si[t2 & 0xFF] ^ tt; tt = Kdr[2]; result[8] = sm_Si[(t2 >> 24) & 0xFF] ^ (tt >> 24); result[9] = sm_Si[(t1 >> 16) & 0xFF] ^ (tt >> 16); result[10] = sm_Si[(t0 >> 8) & 0xFF] ^ (tt >> 8); result[11] = sm_Si[t3 & 0xFF] ^ tt; tt = Kdr[3]; result[12] = sm_Si[(t3 >> 24) & 0xFF] ^ (tt >> 24); result[13] = sm_Si[(t2 >> 16) & 0xFF] ^ (tt >> 16); result[14] = sm_Si[(t1 >> 8) & 0xFF] ^ (tt >> 8); result[15] = sm_Si[t0 & 0xFF] ^ tt; } //Encrypt exactly one block of plaintext. // in - The plaintext. // result - The ciphertext generated from a plaintext using the key. void AES::EncryptBlock(char const* in, char* result) { if (false == m_bKeyInit) return; if (DEFAULT_BLOCK_SIZE == m_blockSize) { DefEncryptBlock(in, result); return; } int BC = m_blockSize / 4; int SC = (BC == 4) ? 0 : (BC == 6 ? 1 : 2); int s1 = sm_shifts[SC][1][0]; int s2 = sm_shifts[SC][2][0]; int s3 = sm_shifts[SC][3][0]; //Temporary Work Arrays int i; int tt; int* pi = t; for (i = 0; i < BC; i++) { *pi = ((unsigned char)*(in++) << 24); *pi |= ((unsigned char)*(in++) << 16); *pi |= ((unsigned char)*(in++) << 8); (*(pi++) |= (unsigned char)*(in++)) ^= m_Ke[0][i]; } //Apply Round Transforms for (int r = 1; r < m_iROUNDS; r++) { for (i = 0; i < BC; i++) a[i] = (sm_T1[(t[i] >> 24) & 0xFF] ^ sm_T2[(t[(i + s1) % BC] >> 16) & 0xFF] ^ sm_T3[(t[(i + s2) % BC] >> 8) & 0xFF] ^ sm_T4[t[(i + s3) % BC] & 0xFF]) ^ m_Ke[r][i]; memcpy(t, a, 4 * BC); } int j; //Last Round is Special for (i = 0, j = 0; i < BC; i++) { tt = m_Ke[m_iROUNDS][i]; result[j++] = sm_S[(t[i] >> 24) & 0xFF] ^ (tt >> 24); result[j++] = sm_S[(t[(i + s1) % BC] >> 16) & 0xFF] ^ (tt >> 16); result[j++] = sm_S[(t[(i + s2) % BC] >> 8) & 0xFF] ^ (tt >> 8); result[j++] = sm_S[t[(i + s3) % BC] & 0xFF] ^ tt; } } //Decrypt exactly one block of ciphertext. // in - The ciphertext. // result - The plaintext generated from a ciphertext using the session key. void AES::DecryptBlock(char const* in, char* result) { if (false == m_bKeyInit) return; if (DEFAULT_BLOCK_SIZE == m_blockSize) { DefDecryptBlock(in, result); return; } int BC = m_blockSize / 4; int SC = BC == 4 ? 0 : (BC == 6 ? 1 : 2); int s1 = sm_shifts[SC][1][1]; int s2 = sm_shifts[SC][2][1]; int s3 = sm_shifts[SC][3][1]; //Temporary Work Arrays int i; int tt; int* pi = t; for (i = 0; i < BC; i++) { *pi = ((unsigned char)*(in++) << 24); *pi |= ((unsigned char)*(in++) << 16); *pi |= ((unsigned char)*(in++) << 8); (*(pi++) |= (unsigned char)*(in++)) ^= m_Kd[0][i]; } //Apply Round Transforms for (int r = 1; r < m_iROUNDS; r++) { for (i = 0; i < BC; i++) a[i] = (sm_T5[(t[i] >> 24) & 0xFF] ^ sm_T6[(t[(i + s1) % BC] >> 16) & 0xFF] ^ sm_T7[(t[(i + s2) % BC] >> 8) & 0xFF] ^ sm_T8[t[(i + s3) % BC] & 0xFF]) ^ m_Kd[r][i]; memcpy(t, a, 4 * BC); } int j; //Last Round is Special for (i = 0, j = 0; i < BC; i++) { tt = m_Kd[m_iROUNDS][i]; result[j++] = sm_Si[(t[i] >> 24) & 0xFF] ^ (tt >> 24); result[j++] = sm_Si[(t[(i + s1) % BC] >> 16) & 0xFF] ^ (tt >> 16); result[j++] = sm_Si[(t[(i + s2) % BC] >> 8) & 0xFF] ^ (tt >> 8); result[j++] = sm_Si[t[(i + s3) % BC] & 0xFF] ^ tt; } } std::string AES::base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) { std::string ret; int i = 0; int j = 0; unsigned char char_array_3[3]; unsigned char char_array_4[4]; while (in_len--) { char_array_3[i++] = *(bytes_to_encode++); if (i == 3) { char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); char_array_4[3] = char_array_3[2] & 0x3f; for (i = 0; (i < 4); i++) ret += base64_chars[char_array_4[i]]; i = 0; } } if (i) { for (j = i; j < 3; j++) char_array_3[j] = '\0'; char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); char_array_4[3] = char_array_3[2] & 0x3f; for (j = 0; (j < i + 1); j++) ret += base64_chars[char_array_4[j]]; while ((i++ < 3)) ret += '='; } return ret; } string AES::base64_decode(std::string const& encoded_string) { int in_len = encoded_string.size(); int i = 0; int j = 0; int in_ = 0; unsigned char char_array_4[4], char_array_3[3]; std::string ret; while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { char_array_4[i++] = encoded_string[in_]; in_++; if (i == 4) { for (i = 0; i < 4; i++) char_array_4[i] = base64_chars.find(char_array_4[i]); char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; for (i = 0; (i < 3); i++) ret += char_array_3[i]; i = 0; } } if (i) { for (j = i; j < 4; j++) char_array_4[j] = 0; for (j = 0; j < 4; j++) char_array_4[j] = base64_chars.find(char_array_4[j]); char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; for (j = 0; (j < i - 1); j++) ret += char_array_3[j]; } return ret; } //Expand a user-supplied key material into a session key. // key - The 128/192/256-bit user-key to use. // chain - initial chain block for CBC and CFB modes. // keylength - 16, 24 or 32 bytes // blockSize - The block size in bytes of this Rijndael (16, 24 or 32 bytes). void AES::MakeKey(char const* key, char const* chain, int keylength, int blockSize) { if (NULL == key) return; if (!(16 == keylength || 24 == keylength || 32 == keylength)) return; if (!(16 == blockSize || 24 == blockSize || 32 == blockSize)) return; m_keylength = keylength; m_blockSize = blockSize; //Initialize the chain memcpy(m_chain0, chain, m_blockSize); memcpy(m_chain, chain, m_blockSize); //Calculate Number of Rounds switch (m_keylength) { case 16: m_iROUNDS = (m_blockSize == 16) ? 10 : (m_blockSize == 24 ? 12 : 14); break; case 24: m_iROUNDS = (m_blockSize != 32) ? 12 : 14; break; default: // 32 bytes = 256 bits m_iROUNDS = 14; } int BC = m_blockSize / 4; int i, j; for (i = 0; i <= m_iROUNDS; i++) { for (j = 0; j < BC; j++) m_Ke[i][j] = 0; } for (i = 0; i <= m_iROUNDS; i++) { for (j = 0; j < BC; j++) m_Kd[i][j] = 0; } int ROUND_KEY_COUNT = (m_iROUNDS + 1) * BC; int KC = m_keylength / 4; //Copy user material bytes into temporary ints int* pi = tk; char const* pc = key; for (i = 0; i < KC; i++) { *pi = (unsigned char)*(pc++) << 24; *pi |= (unsigned char)*(pc++) << 16; *pi |= (unsigned char)*(pc++) << 8; *(pi++) |= (unsigned char)*(pc++); } //Copy values into round key arrays int t = 0; for (j = 0; (j < KC) && (t < ROUND_KEY_COUNT); j++, t++) { m_Ke[t / BC][t % BC] = tk[j]; m_Kd[m_iROUNDS - (t / BC)][t % BC] = tk[j]; } int tt, rconpointer = 0; while (t < ROUND_KEY_COUNT) { //Extrapolate using phi (the round key evolution function) tt = tk[KC - 1]; tk[0] ^= (sm_S[(tt >> 16) & 0xFF] & 0xFF) << 24 ^ (sm_S[(tt >> 8) & 0xFF] & 0xFF) << 16 ^ (sm_S[tt & 0xFF] & 0xFF) << 8 ^ (sm_S[(tt >> 24) & 0xFF] & 0xFF) ^ (sm_rcon[rconpointer++] & 0xFF) << 24; if (KC != 8) for (i = 1, j = 0; i < KC;) tk[i++] ^= tk[j++]; else { for (i = 1, j = 0; i < KC / 2;) tk[i++] ^= tk[j++]; tt = tk[KC / 2 - 1]; tk[KC / 2] ^= (sm_S[tt & 0xFF] & 0xFF) ^ (sm_S[(tt >> 8) & 0xFF] & 0xFF) << 8 ^ (sm_S[(tt >> 16) & 0xFF] & 0xFF) << 16 ^ (sm_S[(tt >> 24) & 0xFF] & 0xFF) << 24; for (j = KC / 2, i = j + 1; i < KC;) tk[i++] ^= tk[j++]; } //Copy values into round key arrays for (j = 0; (j < KC) && (t < ROUND_KEY_COUNT); j++, t++) { m_Ke[t / BC][t % BC] = tk[j]; m_Kd[m_iROUNDS - (t / BC)][t % BC] = tk[j]; } } //Inverse MixColumn where needed for (int r = 1; r < m_iROUNDS; r++) for (j = 0; j < BC; j++) { tt = m_Kd[r][j]; m_Kd[r][j] = sm_U1[(tt >> 24) & 0xFF] ^ sm_U2[(tt >> 16) & 0xFF] ^ sm_U3[(tt >> 8) & 0xFF] ^ sm_U4[tt & 0xFF]; } m_bKeyInit = true; } void AES::Encrypt(char const* in, char* result, size_t n, int iMode) { if (false == m_bKeyInit) return; //n should be > 0 and multiple of m_blockSize if (0 == n || n % m_blockSize != 0) return; int i; char const* pin; char* presult; if (CBC == iMode) //CBC mode, using the Chain { for (i = 0, pin = in, presult = result; i < n / m_blockSize; i++) { Xor(m_chain, pin); EncryptBlock(m_chain, presult); memcpy(m_chain, presult, m_blockSize); pin += m_blockSize; presult += m_blockSize; } } else if (CFB == iMode) //CFB mode, using the Chain { for (i = 0, pin = in, presult = result; i < n / m_blockSize; i++) { EncryptBlock(m_chain, presult); Xor(presult, pin); memcpy(m_chain, presult, m_blockSize); pin += m_blockSize; presult += m_blockSize; } } else //ECB mode, not using the Chain { for (i = 0, pin = in, presult = result; i < n / m_blockSize; i++) { EncryptBlock(pin, presult); pin += m_blockSize; presult += m_blockSize; } } } void AES::Decrypt(char const* in, char* result, size_t n, int iMode) { if (false == m_bKeyInit) return; //n should be > 0 and multiple of m_blockSize if (0 == n || n % m_blockSize != 0) return; int i; char const* pin; char* presult; if (CBC == iMode) //CBC mode, using the Chain { for (i = 0, pin = in, presult = result; i < n / m_blockSize; i++) { DecryptBlock(pin, presult); Xor(presult, m_chain); memcpy(m_chain, pin, m_blockSize); pin += m_blockSize; presult += m_blockSize; } } else if (CFB == iMode) //CFB mode, using the Chain, not using Decrypt() { for (i = 0, pin = in, presult = result; i < n / m_blockSize; i++) { EncryptBlock(m_chain, presult); //memcpy(presult, pin, m_blockSize); Xor(presult, pin); memcpy(m_chain, pin, m_blockSize); pin += m_blockSize; presult += m_blockSize; } } else //ECB mode, not using the Chain { for (i = 0, pin = in, presult = result; i < n / m_blockSize; i++) { DecryptBlock(pin, presult); pin += m_blockSize; presult += m_blockSize; } } } string AES::EncryptionAES(const string& strSrc, const char* key, Mode iMode) { size_t length = strSrc.length(); int block_num = length / BLOCK_SIZE + 1; //���� char* szDataIn = new char[block_num * BLOCK_SIZE + 1]; memset(szDataIn, 0x00, block_num * BLOCK_SIZE + 1); strcpy_s(szDataIn, block_num * BLOCK_SIZE + 1, strSrc.c_str()); //����PKCS7Padding��䡣 int k = length % BLOCK_SIZE; int j = length / BLOCK_SIZE; int padding = BLOCK_SIZE - k; for (int i = 0; i < padding; i++) { szDataIn[j * BLOCK_SIZE + k + i] = padding; } szDataIn[block_num * BLOCK_SIZE] = '\0'; //���ܺ������ char* szDataOut = new char[block_num * BLOCK_SIZE + 1]; memset(szDataOut, 0, block_num * BLOCK_SIZE + 1); //���н���AES��CBCģʽ���� MakeKey(key, key, 16, 16); Encrypt(szDataIn, szDataOut, block_num * BLOCK_SIZE, iMode); string str = base64_encode((unsigned char*)szDataOut, block_num * BLOCK_SIZE); delete[] szDataIn; delete[] szDataOut; return str; } string AES::DecryptionAES(const string& strSrc, const char* key, Mode iMode) { string strData = base64_decode(strSrc); size_t length = strData.length(); //���� char* szDataIn = new char[length + 1]; memcpy(szDataIn, strData.c_str(), length + 1); //���� char* szDataOut = new char[length + 1]; memcpy(szDataOut, strData.c_str(), length + 1); //����AES��ECBģʽ���� MakeKey(key, key, 16, 16); Decrypt(szDataIn, szDataOut, length, iMode); //ȥPKCS7Padding��� if (0x00 < szDataOut[length - 1] <= 0x16) { int tmp = szDataOut[length - 1]; for (int i = length - 1; i >= length - tmp; i--) { if (szDataOut[i] != tmp) { memset(szDataOut, 0, length); break; } else szDataOut[i] = 0; } } string strDest(szDataOut); delete[] szDataIn; delete[] szDataOut; return strDest; }