C++ Implementation of AES Encryption Algorithms

Keywords: iOS Google network github

Introduction to AES

AES (Advanced Encryption Standard), also known as Rijndael encryption method in cryptography, is a block encryption standard adopted by the federal government of the United States. This standard is used to replace the original DES, which has been widely used all over the world and has become one of the most popular symmetric key algorithms.

Before the advent of AES, the most commonly used symmetric key algorithm was DES Encryption Algorithms It's in In 1977, it was published as the commercial encryption standard of the U.S. government. The main problem of DES is that the key length is short, and it is not suitable for the requirement of data encryption security in distributed open network. Therefore, in 1998, the U.S. government decided not to continue using DES as the federal encryption standard, and launched a campaign to solicit AES candidate algorithms. The basic requirements for AES are: faster than triple DES, at least as secure as triple DES, 128 bits of data packet length and 128/192/256 bits of key length.

After more than three years of selection, the Rijndael algorithm designed by Belgian cryptographers finally emerged as a new generation of advanced encryption standards, which was published by the National Institute of Standards and Technology (NIST) in 2001. FIPS PUB 197.


Two, AES Algorithm principle

AES algorithm (Rijndael algorithm) is a symmetric block cipher algorithm. The length of the data packet must be 128 bits, and the length of the key used should be 128, 192 or 256 bits. For three AES algorithms with different key lengths, they are called "AES-128", "AES-192", "AES-256". (Rijndael The design can also handle other packet length and key length, but not in AES standard.

The following is the overall flow chart of AES encryption and decryption:


Here we need to know three symbols: Nb - the number of columns (32-bit words) contained in the State state State, that is, Nb=4; Nk—— The number of 32-bit words contained in the key, that is, Nk=4, 6 or 8; Nr - the number of rounds encrypted, for different key lengths, the number of rounds is different, as shown in the following figure:


The AES algorithm is divided into three parts: key expansion, block encryption and block decryption. I will try to be as concise as possible. If you don't understand it, please go to Google by yourself.

1) Key Extension

AES algorithm generates Nb(Nr+1) words by extending the key K input by the user through Key Expansion, and stores them in a linear array w[Nb*(Nr+1)]. Specifically as follows:

  1. The position transformation function RotWord() accepts a word [a0, A1, a2, a3] as input, and output [a1, a2, a3, a0] after moving one byte to the left of the loop.

  2. S-box transformation function SubWord(), accepts a word [a0, a1, a2, a3] as input. The S box is a 16x16 table, with each element being a byte. For each byte input, the first four bits constitute the hexadecimal number x as the line number, and the last four bits constitute the hexadecimal number y as the column number to find the corresponding values in the table. Finally, the function outputs a 32-bit word consisting of four new bytes.

  3. Wheel constant Rcon [], how to calculate, let alone directly regard it as a constant array.

  4. The first Nk elements of the extended key array w [] are external keys K, the subsequent element w[i] is equal to the previous element w[i-1] and the previous element w[i-1]. The exclusive or of the Nk elements w[i-Nk], i.e. w[i] = w[i-1] XOR w[i-Nk]; but if I is a multiple of Nk, w[i] = w[i-Nk] XOR SubWord(RotWord(w[i-1]) XOR Rcon[i/Nk-1].

Note that the fourth step above is suitable for AES-128 and AES-192. The detailed pseudocode is as follows:

C++ code for key extender (AES-128):

  1. #include <iostream>  
  2. #include <bitset>  
  3. using namespace std;   
  4. typedef bitset<8> byte;  
  5. typedef bitset<32> word;  
  6.   
  7. const int Nr = 10;  //AES-128 requires 10 rounds of encryption  
  8. const int Nk = 4;   //Nk Represents the number of word s that are input keys  
  9.   
  10. byte S_Box[16][16] = {  
  11.     {0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76},  
  12.     {0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0},  
  13.     {0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15},  
  14.     {0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75},  
  15.     {0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84},  
  16.     {0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF},  
  17.     {0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8},  
  18.     {0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2},  
  19.     {0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73},  
  20.     {0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB},  
  21.     {0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79},  
  22.     {0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08},  
  23.     {0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A},  
  24.     {0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E},  
  25.     {0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF},  
  26.     {0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16}  
  27. };  
  28.   
  29. //Round constant, used in key expansion. (AES-128 only takes 10 rounds)  
  30. word Rcon[10] = {0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,   
  31.                  0x20000000, 0x40000000, 0x80000000, 0x1b000000, 0x36000000};  
  32.   
  33. /** 
  34.  * Convert four byte s to one word. 
  35.  */  
  36. word Word(byte& k1, byte& k2, byte& k3, byte& k4)  
  37. {  
  38.     word result(0x00000000);  
  39.     word temp;  
  40.     temp = k1.to_ulong();  // K1  
  41.     temp <<= 24;  
  42.     result |= temp;  
  43.     temp = k2.to_ulong();  // K2  
  44.     temp <<= 16;  
  45.     result |= temp;  
  46.     temp = k3.to_ulong();  // K3  
  47.     temp <<= 8;  
  48.     result |= temp;  
  49.     temp = k4.to_ulong();  // K4  
  50.     result |= temp;  
  51.     return result;  
  52. }  
  53.   
  54. /** 
  55.  *  Cyclic left shift by byte 
  56.  *  That is to say, [a0, a1, a2, a3] becomes [a1, a2, a3, a0] 
  57.  */  
  58. word RotWord(word& rw)  
  59. {  
  60.     word high = rw << 8;  
  61.     word low = rw >> 24;  
  62.     return high | low;  
  63. }  
  64.   
  65. /** 
  66.  *  S-box transformation for each byte in input word 
  67.  */  
  68. word SubWord(word& sw)  
  69. {  
  70.     word temp;  
  71.     for(int i=0; i<32; i+=8)  
  72.     {  
  73.         int row = sw[i+7]*8 + sw[i+6]*4 + sw[i+5]*2 + sw[i+4];  
  74.         int col = sw[i+3]*8 + sw[i+2]*4 + sw[i+1]*2 + sw[i];  
  75.         byte val = S_Box[row][col];  
  76.         for(int j=0; j<8; ++j)  
  77.             temp[i+j] = val[j];  
  78.     }  
  79.     return temp;  
  80. }  
  81.   
  82. /** 
  83.  *  Key Extension Function - Extended 128-bit key to w[4*(Nr+1)] 
  84.  */   
  85. void KeyExpansion(byte key[4*Nk], word w[4*(Nr+1)])  
  86. {  
  87.     word temp;  
  88.     int i = 0;  
  89.     //The first four of w [] are input key s  
  90.     while(i < Nk)   
  91.     {  
  92.         w[i] = Word(key[4*i], key[4*i+1], key[4*i+2], key[4*i+3]);  
  93.         ++i;  
  94.     }  
  95.   
  96.     i = Nk;  
  97.   
  98.     while(i < 4*(Nr+1))  
  99.     {  
  100.         temp = w[i-1]; //Record the previous word  
  101.         if(i % Nk == 0)  
  102.             w[i] = w[i-Nk] ^ SubWord(RotWord(temp)) ^ Rcon[i/Nk-1];  
  103.         else   
  104.             w[i] = w[i-Nk] ^ temp;  
  105.         ++i;  
  106.     }  
  107. }  
  108.   
  109. int main()  
  110. {  
  111.     byte key[16] = {0x2b, 0x7e, 0x15, 0x16,   
  112.                     0x28, 0xae, 0xd2, 0xa6,   
  113.                     0xab, 0xf7, 0x15, 0x88,   
  114.                     0x09, 0xcf, 0x4f, 0x3c};  
  115.   
  116.     word w[4*(Nr+1)];  
  117.   
  118.     cout << "KEY IS: ";  
  119.     for(int i=0; i<16; ++i)  
  120.         cout << hex << key[i].to_ulong() << " ";  
  121.     cout << endl;  
  122.   
  123.     KeyExpansion(key, w);  
  124.     //Testing  
  125.     for(int i=0; i<4*(Nr+1); ++i)  
  126.         cout << "w[" << dec << i << "] = " << hex << w[i].to_ulong() << endl;  
  127.   
  128.     return 0;  
  129. }  

test Output results:


2) encryption

According to the overall flow chart of AES encryption (at the beginning of this article), the pseudocode is as follows:


From the pseudocode description, we can see that the subprograms involved in AES encryption are SubBytes(), ShiftRows(), MixColumns(), and AdRoundKey (). Let's introduce one by one:

① S-box transformation-SubBytes()

As already mentioned in the key extension section, the S-box is a table of 16 rows and 16 columns, in which each element is a byte. The S-box transformation is simple: the function SubBytes() accepts one The byte matrix of 4x4 is used as input. For each byte, the first four bits constitute the hexadecimal number x as the line number, and the last four bits constitute the hexadecimal number y as the column number. The corresponding values in the lookup table replace the bytes in the original position.

② Line transformation - ShiftRows()

Line transformation is also very simple. It simply shifts each row of the matrix in bytes: the first row remains unchanged, the second row moves one bit to the left, the third row moves two to the left, and the fourth row moves three to the left. As shown in the following figure:


③ Column transformation - MixColumns()

The function MixColumns() also accepts a 4x4 byte matrix as input and transforms the matrix column by column in the following way:


Note that the multiplication used in the formula is Multiplication over Galois Fields (GF, Finite Fields) Advanced Encryption Standard Documents fips-197 As mentioned above, if you still don't understand, please Google yourself.


④ XOR-AddRoundKey() with Extended Key

Extended keys are only involved in this step. According to the number of rounds currently encrypted, four extended keys in w [] are bitwise exclusive or with four columns of the matrix. The following picture:


All right, here we are going to finish all the parts of AES encryption. The C++ source code implemented by the algorithm is in the third part after the article.

3) decryption

According to the overall flow chart of AES decryption (at the beginning of this article), the pseudocode is as follows:


As can be seen from the pseudo code, we need to implement inversion transforms InvShiftRows(), InvSubBytes() and InvMixColumns() of S-box transformation, row transformation and column transformation, respectively. The following three inverse transformations are briefly discussed:

① Inverse transformation - InvShiftRows()

As mentioned above, ShiftRows() is a circular left shift for each row of a matrix, so InvShiftRows() is a circular right shift for each row of a matrix.


② Inverse S-box transformation-InvSubBytes()

Like S-box transformation, it looks up tables in the same way, except that it looks up another replacement table (S-Box inverse table).

③ Inverse transformation - InvMixColumns()

Just like column transformation, the coefficient matrix of the calculation formula has changed. The following picture:


Okay, AES decryption is over here. It is easy to implement AES decryption algorithm based on pseudo-code after writing three functions of inverse transformation.


C++ Implementation

Next, I use C++ to implement the encryption and decryption algorithm of AES, and realize the encryption and decryption of files. Here I use bitset of C++ STL to define two types: byte and word. It should be mentioned that for multiplication over finite fields, we can either look up tables (6 result tables) or write a function. Of course, looking up tables is more efficient, but considering posting code, here I use a function to achieve.

The following is the AES-128 source code for encrypting and decrypting a 128-bit data:

  1. /*************************************************************************   
  2.     > File Name: AES.cpp  
  3.     > Author: SongLee   
  4.     > E-mail: lisong.shine@qq.com   
  5.     > Created Time: 2014 Friday, December 12, 20:15, 50 seconds 
  6.     > Personal Blog: http://songlee24.github.com   
  7.  ************************************************************************/   
  8. #include <iostream>  
  9. #include <bitset>  
  10. #include <string>  
  11. using namespace std;   
  12. typedef bitset<8> byte;  
  13. typedef bitset<32> word;  
  14.   
  15. const int Nr = 10;  //AES-128 requires 10 rounds of encryption  
  16. const int Nk = 4;   //Nk Represents the number of word s that are input keys  
  17.   
  18. byte S_Box[16][16] = {  
  19.     {0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76},  
  20.     {0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0},  
  21.     {0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15},  
  22.     {0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75},  
  23.     {0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84},  
  24.     {0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF},  
  25.     {0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8},  
  26.     {0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2},  
  27.     {0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73},  
  28.     {0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB},  
  29.     {0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79},  
  30.     {0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08},  
  31.     {0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A},  
  32.     {0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E},  
  33.     {0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF},  
  34.     {0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16}  
  35. };  
  36.   
  37. byte Inv_S_Box[16][16] = {  
  38.     {0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB},  
  39.     {0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB},  
  40.     {0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E},  
  41.     {0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25},  
  42.     {0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92},  
  43.     {0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84},  
  44.     {0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06},  
  45.     {0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B},  
  46.     {0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73},  
  47.     {0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E},  
  48.     {0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B},  
  49.     {0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4},  
  50.     {0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F},  
  51.     {0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF},  
  52.     {0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61},  
  53.     {0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D}  
  54. };  
  55.   
  56. //Round constant, used in key expansion. (AES-128 only takes 10 rounds)  
  57. word Rcon[10] = {0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,   
  58.                  0x20000000, 0x40000000, 0x80000000, 0x1b000000, 0x36000000};  
  59.   
  60. /**********************************************************************/    
  61. /*                                                                    */    
  62. /*                              AES Algorithmic Implementation*/    
  63. /*                                                                    */    
  64. /**********************************************************************/   
  65.   
  66. /******************************Here is the encrypted transformation function ****************************************************/  
  67. /** 
  68.  *  S Box Conversion - The first four bits are line numbers and the last four bits are column numbers 
  69.  */  
  70. void SubBytes(byte mtx[4*4])  
  71. {  
  72.     for(int i=0; i<16; ++i)  
  73.     {  
  74.         int row = mtx[i][7]*8 + mtx[i][6]*4 + mtx[i][5]*2 + mtx[i][4];  
  75.         int col = mtx[i][3]*8 + mtx[i][2]*4 + mtx[i][1]*2 + mtx[i][0];  
  76.         mtx[i] = S_Box[row][col];  
  77.     }  
  78. }  
  79.   
  80. /** 
  81.  *  Line Transform - Byte Cyclic Shift 
  82.  */  
  83. void ShiftRows(byte mtx[4*4])  
  84. {  
  85.     //The second line circle moves one bit to the left  
  86.     byte temp = mtx[4];  
  87.     for(int i=0; i<3; ++i)  
  88.         mtx[i+4] = mtx[i+5];  
  89.     mtx[7] = temp;  
  90.     //The third line circle moves two places to the left  
  91.     for(int i=0; i<2; ++i)  
  92.     {  
  93.         temp = mtx[i+8];  
  94.         mtx[i+8] = mtx[i+10];  
  95.         mtx[i+10] = temp;  
  96.     }  
  97.     //The fourth line moves three left circles  
  98.     temp = mtx[15];  
  99.     for(int i=3; i>0; --i)  
  100.         mtx[i+12] = mtx[i+11];  
  101.     mtx[12] = temp;  
  102. }  
  103.   
  104. /** 
  105.  *  Multiplication over Finite Fields GF(2^8) 
  106.  */  
  107. byte GFMul(byte a, byte b) {   
  108.     byte p = 0;  
  109.     byte hi_bit_set;  
  110.     for (int counter = 0; counter < 8; counter++) {  
  111.         if ((b & byte(1)) != 0) {  
  112.             p ^= a;  
  113.         }  
  114.         hi_bit_set = (byte) (a & byte(0x80));  
  115.         a <<= 1;  
  116.         if (hi_bit_set != 0) {  
  117.             a ^= 0x1b; /* x^8 + x^4 + x^3 + x + 1 */  
  118.         }  
  119.         b >>= 1;  
  120.     }  
  121.     return p;  
  122. }  
  123.   
  124. /** 
  125.  *  Column transformation 
  126.  */  
  127. void MixColumns(byte mtx[4*4])  
  128. {  
  129.     byte arr[4];  
  130.     for(int i=0; i<4; ++i)  
  131.     {  
  132.         for(int j=0; j<4; ++j)  
  133.             arr[j] = mtx[i+j*4];  
  134.   
  135.         mtx[i] = GFMul(0x02, arr[0]) ^ GFMul(0x03, arr[1]) ^ arr[2] ^ arr[3];  
  136.         mtx[i+4] = arr[0] ^ GFMul(0x02, arr[1]) ^ GFMul(0x03, arr[2]) ^ arr[3];  
  137.         mtx[i+8] = arr[0] ^ arr[1] ^ GFMul(0x02, arr[2]) ^ GFMul(0x03, arr[3]);  
  138.         mtx[i+12] = GFMul(0x03, arr[0]) ^ arr[1] ^ arr[2] ^ GFMul(0x02, arr[3]);  
  139.     }  
  140. }  
  141.   
  142. /** 
  143.  *  Round Key Plus Transform - XOR each column with the extended key 
  144.  */  
  145. void AddRoundKey(byte mtx[4*4], word k[4])  
  146. {  
  147.     for(int i=0; i<4; ++i)  
  148.     {  
  149.         word k1 = k[i] >> 24;  
  150.         word k2 = (k[i] << 8) >> 24;  
  151.         word k3 = (k[i] << 16) >> 24;  
  152.         word k4 = (k[i] << 24) >> 24;  
  153.           
  154.         mtx[i] = mtx[i] ^ byte(k1.to_ulong());  
  155.         mtx[i+4] = mtx[i+4] ^ byte(k2.to_ulong());  
  156.         mtx[i+8] = mtx[i+8] ^ byte(k3.to_ulong());  
  157.         mtx[i+12] = mtx[i+12] ^ byte(k4.to_ulong());  
  158.     }  
  159. }  
  160.   
  161. /**************************Here is the decrypted inverse transform function *******************************************************/  
  162. /** 
  163.  *  Inverse S-box transformation 
  164.  */  
  165. void InvSubBytes(byte mtx[4*4])  
  166. {  
  167.     for(int i=0; i<16; ++i)  
  168.     {  
  169.         int row = mtx[i][7]*8 + mtx[i][6]*4 + mtx[i][5]*2 + mtx[i][4];  
  170.         int col = mtx[i][3]*8 + mtx[i][2]*4 + mtx[i][1]*2 + mtx[i][0];  
  171.         mtx[i] = Inv_S_Box[row][col];  
  172.     }  
  173. }  
  174.   
  175. /** 
  176.  *  Reverse Transform - Cyclic Right Shift in Bytes 
  177.  */  
  178. void InvShiftRows(byte mtx[4*4])  
  179. {  
  180.     //The second line circle moves one bit to the right  
  181.     byte temp = mtx[7];  
  182.     for(int i=3; i>0; --i)  
  183.         mtx[i+4] = mtx[i+3];  
  184.     mtx[4] = temp;  
  185.     //The third line circle moves two to the right  
  186.     for(int i=0; i<2; ++i)  
  187.     {  
  188.         temp = mtx[i+8];  
  189.         mtx[i+8] = mtx[i+10];  
  190.         mtx[i+10] = temp;  
  191.     }  
  192.     //Fourth line circle moves three to the right  
  193.     temp = mtx[12];  
  194.     for(int i=0; i<3; ++i)  
  195.         mtx[i+12] = mtx[i+13];  
  196.     mtx[15] = temp;  
  197. }  
  198.   
  199. void InvMixColumns(byte mtx[4*4])  
  200. {  
  201.     byte arr[4];  
  202.     for(int i=0; i<4; ++i)  
  203.     {  
  204.         for(int j=0; j<4; ++j)  
  205.             arr[j] = mtx[i+j*4];  
  206.   
  207.         mtx[i] = GFMul(0x0e, arr[0]) ^ GFMul(0x0b, arr[1]) ^ GFMul(0x0d, arr[2]) ^ GFMul(0x09, arr[3]);  
  208.         mtx[i+4] = GFMul(0x09, arr[0]) ^ GFMul(0x0e, arr[1]) ^ GFMul(0x0b, arr[2]) ^ GFMul(0x0d, arr[3]);  
  209.         mtx[i+8] = GFMul(0x0d, arr[0]) ^ GFMul(0x09, arr[1]) ^ GFMul(0x0e, arr[2]) ^ GFMul(0x0b, arr[3]);  
  210.         mtx[i+12] = GFMul(0x0b, arr[0]) ^ GFMul(0x0d, arr[1]) ^ GFMul(0x09, arr[2]) ^ GFMul(0x0e, arr[3]);  
  211.     }  
  212. }  
  213.   
  214. /******************************Following is the key extension section ***************************************************************/  
  215. /** 
  216.  * Convert four byte s to one word. 
  217.  */  
  218. word Word(byte& k1, byte& k2, byte& k3, byte& k4)  
  219. {  
  220.     word result(0x00000000);  
  221.     word temp;  
  222.     temp = k1.to_ulong();  // K1  
  223.     temp <<= 24;  
  224.     result |= temp;  
  225.     temp = k2.to_ulong();  // K2  
  226.     temp <<= 16;  
  227.     result |= temp;  
  228.     temp = k3.to_ulong();  // K3  
  229.     temp <<= 8;  
  230.     result |= temp;  
  231.     temp = k4.to_ulong();  // K4  
  232.     result |= temp;  
  233.     return result;  
  234. }  
  235.   
  236. /** 
  237.  *  Cyclic left shift by byte 
  238.  *  That is to say, [a0, a1, a2, a3] becomes [a1, a2, a3, a0] 
  239.  */  
  240. word RotWord(word& rw)  
  241. {  
  242.     word high = rw << 8;  
  243.     word low = rw >> 24;  
  244.     return high | low;  
  245. }  
  246.   
  247. /** 
  248.  *  S-box transformation for each byte in input word 
  249.  */  
  250. word SubWord(word& sw)  
  251. {  
  252.     word temp;  
  253.     for(int i=0; i<32; i+=8)  
  254.     {  
  255.         int row = sw[i+7]*8 + sw[i+6]*4 + sw[i+5]*2 + sw[i+4];  
  256.         int col = sw[i+3]*8 + sw[i+2]*4 + sw[i+1]*2 + sw[i];  
  257.         byte val = S_Box[row][col];  
  258.         for(int j=0; j<8; ++j)  
  259.             temp[i+j] = val[j];  
  260.     }  
  261.     return temp;  
  262. }  
  263.   
  264. /** 
  265.  *  Key Extension Function - Extended 128-bit key to w[4*(Nr+1)] 
  266.  */   
  267. void KeyExpansion(byte key[4*Nk], word w[4*(Nr+1)])  
  268. {  
  269.     word temp;  
  270.     int i = 0;  
  271.     //The first four of w [] are input key s  
  272.     while(i < Nk)   
  273.     {  
  274.         w[i] = Word(key[4*i], key[4*i+1], key[4*i+2], key[4*i+3]);  
  275.         ++i;  
  276.     }  
  277.   
  278.     i = Nk;  
  279.   
  280.     while(i < 4*(Nr+1))  
  281.     {  
  282.         temp = w[i-1]; //Record the previous word  
  283.         if(i % Nk == 0)  
  284.             w[i] = w[i-Nk] ^ SubWord(RotWord(temp)) ^ Rcon[i/Nk-1];  
  285.         else   
  286.             w[i] = w[i-Nk] ^ temp;  
  287.         ++i;  
  288.     }  
  289. }  
  290.   
  291. /******************************Here are the encryption and decryption functions ********************************************************************/  
  292. /** 
  293.  *  encryption 
  294.  */  
  295. void encrypt(byte in[4*4], word w[4*(Nr+1)])  
  296. {  
  297.     word key[4];  
  298.     for(int i=0; i<4; ++i)  
  299.         key[i] = w[i];  
  300.     AddRoundKey(in, key);  
  301.   
  302.     for(int round=1; round<Nr; ++round)  
  303.     {  
  304.         SubBytes(in);  
  305.         ShiftRows(in);  
  306.         MixColumns(in);  
  307.         for(int i=0; i<4; ++i)  
  308.             key[i] = w[4*round+i];  
  309.         AddRoundKey(in, key);  
  310.     }  
  311.   
  312.     SubBytes(in);  
  313.     ShiftRows(in);  
  314.     for(int i=0; i<4; ++i)  
  315.         key[i] = w[4*Nr+i];  
  316.     AddRoundKey(in, key);  
  317. }  
  318.   
  319. /** 
  320.  *  Decrypt 
  321.  */  
  322. void decrypt(byte in[4*4], word w[4*(Nr+1)])  
  323. {  
  324.     word key[4];  
  325.     for(int i=0; i<4; ++i)  
  326.         key[i] = w[4*Nr+i];  
  327.     AddRoundKey(in, key);  
  328.   
  329.     for(int round=Nr-1; round>0; --round)  
  330.     {  
  331.         InvShiftRows(in);  
  332.         InvSubBytes(in);  
  333.         for(int i=0; i<4; ++i)  
  334.             key[i] = w[4*round+i];  
  335.         AddRoundKey(in, key);  
  336.         InvMixColumns(in);  
  337.     }  
  338.   
  339.     InvShiftRows(in);  
  340.     InvSubBytes(in);  
  341.     for(int i=0; i<4; ++i)  
  342.         key[i] = w[i];  
  343.     AddRoundKey(in, key);  
  344. }  
  345.   
  346. /**********************************************************************/    
  347. /*                                                                    */    
  348. /*                              Testing*/    
  349. /*                                                                    */    
  350. /**********************************************************************/   
  351. int main()  
  352. {  
  353.     byte key[16] = {0x2b, 0x7e, 0x15, 0x16,   
  354.                     0x28, 0xae, 0xd2, 0xa6,   
  355.                     0xab, 0xf7, 0x15, 0x88,   
  356.                     0x09, 0xcf, 0x4f, 0x3c};  
  357.   
  358.     byte plain[16] = {0x32, 0x88, 0x31, 0xe0,   
  359.                     0x43, 0x5a, 0x31, 0x37,  
  360.                     0xf6, 0x30, 0x98, 0x07,  
  361.                     0xa8, 0x8d, 0xa2, 0x34};   
  362.     //Output key  
  363.     cout << "The key is:";  
  364.     for(int i=0; i<16; ++i)  
  365.         cout << hex << key[i].to_ulong() << " ";  
  366.     cout << endl;  
  367.   
  368.     word w[4*(Nr+1)];  
  369.     KeyExpansion(key, w);  
  370.   
  371.     //Output plaintext to be encrypted  
  372.     cout << endl << "Plaintext to be encrypted:"<<endl;  
  373.     for(int i=0; i<16; ++i)  
  374.     {  
  375.         cout << hex << plain[i].to_ulong() << " ";  
  376.         if((i+1)%4 == 0)  
  377.             cout << endl;  
  378.     }  
  379.     cout << endl;  
  380.   
  381.     //Encryption, output ciphertext  
  382.     encrypt(plain, w);  
  383.     cout << "Encrypted ciphertext:"<<endl;  
  384.     for(int i=0; i<16; ++i)  
  385.     {  
  386.         cout << hex << plain[i].to_ulong() << " ";  
  387.         if((i+1)%4 == 0)  
  388.             cout << endl;  
  389.     }  
  390.     cout << endl;  
  391.   
  392.     //Decrypt, output plaintext  
  393.     decrypt(plain, w);  
  394.     cout << "Decrypted plaintext:"<<endl;  
  395.     for(int i=0; i<16; ++i)  
  396.     {  
  397.         cout << hex << plain[i].to_ulong() << " ";  
  398.         if((i+1)%4 == 0)  
  399.             cout << endl;  
  400.     }  
  401.     cout << endl;  
  402.     return 0;  
  403. }  
Examples of test purposes are as follows:


Screenshots of test results:


It can be seen that the test results are the same as the expected output, indicating the success of data encryption and decryption!!!

Now let's write AES to encrypt and decrypt files. After encrypting and decrypting 128 bits of data successfully, it's very simple to encrypt and decrypt files. It only needs to read 128 bits at a time. After encrypting, it writes 128 bits of ciphertext to another file. ... so loop until the end of the file. The following is the test code for AES encryption and decryption of a picture (efficiency is neglected, I will optimize it when I have time):

  1. //#include <fstream>  
  2. typedef bitset<8> byte;  
  3. typedef bitset<32> word;  
  4. /** 
  5.  *  Converting an array of char characters into binary 
  6.  *  Save it in a byte array 
  7.  */  
  8. void charToByte(byte out[16], const char s[16])  
  9. {   
  10.     for(int i=0; i<16; ++i)    
  11.         for(int j=0; j<8; ++j)    
  12.             out[i][j]= ((s[i]>>j) & 1);    
  13. }  
  14.   
  15. /** 
  16.  *  Divide consecutive 128 bits into 16 groups and store them in a byte array 
  17.  */  
  18. void divideToByte(byte out[16], bitset<128>& data)  
  19. {  
  20.     bitset<128> temp;  
  21.     for(int i=0; i<16; ++i)  
  22.     {  
  23.         temp = (data << 8*i) >> 120;  
  24.         out[i] = temp.to_ulong();  
  25.     }  
  26. }  
  27.   
  28. /** 
  29.  *  Merge 16 byte s into 128 consecutive bits 
  30.  */  
  31. bitset<128> mergeByte(byte in[16])  
  32. {  
  33.     bitset<128> res;  
  34.     res.reset();  //Set 0  
  35.     bitset<128> temp;  
  36.     for(int i=0; i<16; ++i)  
  37.     {  
  38.         temp = in[i].to_ulong();  
  39.         temp <<= 8*(15-i);  
  40.         res |= temp;  
  41.     }  
  42.     return res;  
  43. }  
  44.   
  45. int main()  
  46. {  
  47.     string keyStr = "abcdefghijklmnop";  
  48.     byte key[16];   
  49.     charToByte(key, keyStr.c_str());  
  50.     //Key expansion  
  51.     word w[4*(Nr+1)];  
  52.     KeyExpansion(key, w);  
  53.   
  54.     bitset<128> data;  
  55.     byte plain[16];  
  56.     //Encrypt the file flower.jpg into cipher.txt  
  57.     ifstream in;  
  58.     ofstream out;  
  59.     in.open("D://flower.jpg", ios::binary);  
  60.     out.open("D://cipher.txt", ios::binary);  
  61.     while(in.read((char*)&data, sizeof(data)))  
  62.     {  
  63.         divideToByte(plain, data);  
  64.         encrypt(plain, w);  
  65.         data = mergeByte(plain);  
  66.         out.write((char*)&data, sizeof(data));  
  67.         data.reset();  //Set 0  
  68.     }  
  69.     in.close();  
  70.     out.close();  
  71.   
  72.     //Decrypt cipher.txt and write the picture flower1.jpg  
  73.     in.open("D://cipher.txt", ios::binary);  
  74.     out.open("D://flower1.jpg", ios::binary);  
  75.     while(in.read((char*)&data, sizeof(data)))  
  76.     {  
  77.         divideToByte(plain, data);  
  78.         decrypt(plain, w);  
  79.         data = mergeByte(plain);  
  80.         out.write((char*)&data, sizeof(data));  
  81.         data.reset();  //Set 0  
  82.     }  
  83.     in.close();  
  84.     out.close();  
  85.   
  86.     return 0;  
  87. }  

(End of the text)


Update - December 21, 2014

Multiplication over finite field GF(28) is implemented by table lookup, and the encryption speed of AES is increased by more than 80%. Therefore, table lookup is recommended. The following are six multiplication results tables used in AES algorithm:

  1. byte Mul_02[256] = {  
  2.     0x00,0x02,0x04,0x06,0x08,0x0a,0x0c,0x0e,0x10,0x12,0x14,0x16,0x18,0x1a,0x1c,0x1e,  
  3.     0x20,0x22,0x24,0x26,0x28,0x2a,0x2c,0x2e,0x30,0x32,0x34,0x36,0x38,0x3a,0x3c,0x3e,  
  4.     0x40,0x42,0x44,0x46,0x48,0x4a,0x4c,0x4e,0x50,0x52,0x54,0x56,0x58,0x5a,0x5c,0x5e,  
  5.     0x60,0x62,0x64,0x66,0x68,0x6a,0x6c,0x6e,0x70,0x72,0x74,0x76,0x78,0x7a,0x7c,0x7e,  
  6.     0x80,0x82,0x84,0x86,0x88,0x8a,0x8c,0x8e,0x90,0x92,0x94,0x96,0x98,0x9a,0x9c,0x9e,  
  7.     0xa0,0xa2,0xa4,0xa6,0xa8,0xaa,0xac,0xae,0xb0,0xb2,0xb4,0xb6,0xb8,0xba,0xbc,0xbe,  
  8.     0xc0,0xc2,0xc4,0xc6,0xc8,0xca,0xcc,0xce,0xd0,0xd2,0xd4,0xd6,0xd8,0xda,0xdc,0xde,  
  9.     0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xee,0xf0,0xf2,0xf4,0xf6,0xf8,0xfa,0xfc,0xfe,  
  10.     0x1b,0x19,0x1f,0x1d,0x13,0x11,0x17,0x15,0x0b,0x09,0x0f,0x0d,0x03,0x01,0x07,0x05,  
  11.     0x3b,0x39,0x3f,0x3d,0x33,0x31,0x37,0x35,0x2b,0x29,0x2f,0x2d,0x23,0x21,0x27,0x25,  
  12.     0x5b,0x59,0x5f,0x5d,0x53,0x51,0x57,0x55,0x4b,0x49,0x4f,0x4d,0x43,0x41,0x47,0x45,  
  13.     0x7b,0x79,0x7f,0x7d,0x73,0x71,0x77,0x75,0x6b,0x69,0x6f,0x6d,0x63,0x61,0x67,0x65,  
  14.     0x9b,0x99,0x9f,0x9d,0x93,0x91,0x97,0x95,0x8b,0x89,0x8f,0x8d,0x83,0x81,0x87,0x85,  
  15.     0xbb,0xb9,0xbf,0xbd,0xb3,0xb1,0xb7,0xb5,0xab,0xa9,0xaf,0xad,0xa3,0xa1,0xa7,0xa5,  
  16.     0xdb,0xd9,0xdf,0xdd,0xd3,0xd1,0xd7,0xd5,0xcb,0xc9,0xcf,0xcd,0xc3,0xc1,0xc7,0xc5,  
  17.     0xfb,0xf9,0xff,0xfd,0xf3,0xf1,0xf7,0xf5,0xeb,0xe9,0xef,0xed,0xe3,0xe1,0xe7,0xe5  
  18. };  
  19.   
  20. byte Mul_03[256] = {  
  21.     0x00,0x03,0x06,0x05,0x0c,0x0f,0x0a,0x09,0x18,0x1b,0x1e,0x1d,0x14,0x17,0x12,0x11,  
  22.     0x30,0x33,0x36,0x35,0x3c,0x3f,0x3a,0x39,0x28,0x2b,0x2e,0x2d,0x24,0x27,0x22,0x21,  
  23.     0x60,0x63,0x66,0x65,0x6c,0x6f,0x6a,0x69,0x78,0x7b,0x7e,0x7d,0x74,0x77,0x72,0x71,  
  24.     0x50,0x53,0x56,0x55,0x5c,0x5f,0x5a,0x59,0x48,0x4b,0x4e,0x4d,0x44,0x47,0x42,0x41,  
  25.     0xc0,0xc3,0xc6,0xc5,0xcc,0xcf,0xca,0xc9,0xd8,0xdb,0xde,0xdd,0xd4,0xd7,0xd2,0xd1,  
  26.     0xf0,0xf3,0xf6,0xf5,0xfc,0xff,0xfa,0xf9,0xe8,0xeb,0xee,0xed,0xe4,0xe7,0xe2,0xe1,  
  27.     0xa0,0xa3,0xa6,0xa5,0xac,0xaf,0xaa,0xa9,0xb8,0xbb,0xbe,0xbd,0xb4,0xb7,0xb2,0xb1,  
  28.     0x90,0x93,0x96,0x95,0x9c,0x9f,0x9a,0x99,0x88,0x8b,0x8e,0x8d,0x84,0x87,0x82,0x81,  
  29.     0x9b,0x98,0x9d,0x9e,0x97,0x94,0x91,0x92,0x83,0x80,0x85,0x86,0x8f,0x8c,0x89,0x8a,  
  30.     0xab,0xa8,0xad,0xae,0xa7,0xa4,0xa1,0xa2,0xb3,0xb0,0xb5,0xb6,0xbf,0xbc,0xb9,0xba,  
  31.     0xfb,0xf8,0xfd,0xfe,0xf7,0xf4,0xf1,0xf2,0xe3,0xe0,0xe5,0xe6,0xef,0xec,0xe9,0xea,  
  32.     0xcb,0xc8,0xcd,0xce,0xc7,0xc4,0xc1,0xc2,0xd3,0xd0,0xd5,0xd6,0xdf,0xdc,0xd9,0xda,  
  33.     0x5b,0x58,0x5d,0x5e,0x57,0x54,0x51,0x52,0x43,0x40,0x45,0x46,0x4f,0x4c,0x49,0x4a,  
  34.     0x6b,0x68,0x6d,0x6e,0x67,0x64,0x61,0x62,0x73,0x70,0x75,0x76,0x7f,0x7c,0x79,0x7a,  
  35.     0x3b,0x38,0x3d,0x3e,0x37,0x34,0x31,0x32,0x23,0x20,0x25,0x26,0x2f,0x2c,0x29,0x2a,  
  36.     0x0b,0x08,0x0d,0x0e,0x07,0x04,0x01,0x02,0x13,0x10,0x15,0x16,0x1f,0x1c,0x19,0x1a  
  37. };  
  38.   
  39. byte Mul_09[256] = {  
  40.     0x00,0x09,0x12,0x1b,0x24,0x2d,0x36,0x3f,0x48,0x41,0x5a,0x53,0x6c,0x65,0x7e,0x77,  
  41.     0x90,0x99,0x82,0x8b,0xb4,0xbd,0xa6,0xaf,0xd8,0xd1,0xca,0xc3,0xfc,0xf5,0xee,0xe7,  
  42.     0x3b,0x32,0x29,0x20,0x1f,0x16,0x0d,0x04,0x73,0x7a,0x61,0x68,0x57,0x5e,0x45,0x4c,  
  43.     0xab,0xa2,0xb9,0xb0,0x8f,0x86,0x9d,0x94,0xe3,0xea,0xf1,0xf8,0xc7,0xce,0xd5,0xdc,  
  44.     0x76,0x7f,0x64,0x6d,0x52,0x5b,0x40,0x49,0x3e,0x37,0x2c,0x25,0x1a,0x13,0x08,0x01,  
  45.     0xe6,0xef,0xf4,0xfd,0xc2,0xcb,0xd0,0xd9,0xae,0xa7,0xbc,0xb5,0x8a,0x83,0x98,0x91,  
  46.     0x4d,0x44,0x5f,0x56,0x69,0x60,0x7b,0x72,0x05,0x0c,0x17,0x1e,0x21,0x28,0x33,0x3a,  
  47.     0xdd,0xd4,0xcf,0xc6,0xf9,0xf0,0xeb,0xe2,0x95,0x9c,0x87,0x8e,0xb1,0xb8,0xa3,0xaa,  
  48.     0xec,0xe5,0xfe,0xf7,0xc8,0xc1,0xda,0xd3,0xa4,0xad,0xb6,0xbf,0x80,0x89,0x92,0x9b,  
  49.     0x7c,0x75,0x6e,0x67,0x58,0x51,0x4a,0x43,0x34,0x3d,0x26,0x2f,0x10,0x19,0x02,0x0b,  
  50.     0xd7,0xde,0xc5,0xcc,0xf3,0xfa,0xe1,0xe8,0x9f,0x96,0x8d,0x84,0xbb,0xb2,0xa9,0xa0,  
  51.     0x47,0x4e,0x55,0x5c,0x63,0x6a,0x71,0x78,0x0f,0x06,0x1d,0x14,0x2b,0x22,0x39,0x30,  
  52.     0x9a,0x93,0x88,0x81,0xbe,0xb7,0xac,0xa5,0xd2,0xdb,0xc0,0xc9,0xf6,0xff,0xe4,0xed,  
  53.     0x0a,0x03,0x18,0x11,0x2e,0x27,0x3c,0x35,0x42,0x4b,0x50,0x59,0x66,0x6f,0x74,0x7d,  
  54.     0xa1,0xa8,0xb3,0xba,0x85,0x8c,0x97,0x9e,0xe9,0xe0,0xfb,0xf2,0xcd,0xc4,0xdf,0xd6,  
  55.     0x31,0x38,0x23,0x2a,0x15,0x1c,0x07,0x0e,0x79,0x70,0x6b,0x62,0x5d,0x54,0x4f,0x46  
  56. };  
  57.   
  58. byte Mul_0b[256] = {  
  59.     0x00,0x0b,0x16,0x1d,0x2c,0x27,0x3a,0x31,0x58,0x53,0x4e,0x45,0x74,0x7f,0x62,0x69,  
  60.     0xb0,0xbb,0xa6,0xad,0x9c,0x97,0x8a,0x81,0xe8,0xe3,0xfe,0xf5,0xc4,0xcf,0xd2,0xd9,  
  61.     0x7b,0x70,0x6d,0x66,0x57,0x5c,0x41,0x4a,0x23,0x28,0x35,0x3e,0x0f,0x04,0x19,0x12,  
  62.     0xcb,0xc0,0xdd,0xd6,0xe7,0xec,0xf1,0xfa,0x93,0x98,0x85,0x8e,0xbf,0xb4,0xa9,0xa2,  
  63.     0xf6,0xfd,0xe0,0xeb,0xda,0xd1,0xcc,0xc7,0xae,0xa5,0xb8,0xb3,0x82,0x89,0x94,0x9f,  
  64.     0x46,0x4d,0x50,0x5b,0x6a,0x61,0x7c,0x77,0x1e,0x15,0x08,0x03,0x32,0x39,0x24,0x2f,  
  65.     0x8d,0x86,0x9b,0x90,0xa1,0xaa,0xb7,0xbc,0xd5,0xde,0xc3,0xc8,0xf9,0xf2,0xef,0xe4,  
  66.     0x3d,0x36,0x2b,0x20,0x11,0x1a,0x07,0x0c,0x65,0x6e,0x73,0x78,0x49,0x42,0x5f,0x54,  
  67.     0xf7,0xfc,0xe1,0xea,0xdb,0xd0,0xcd,0xc6,0xaf,0xa4,0xb9,0xb2,0x83,0x88,0x95,0x9e,  
  68.     0x47,0x4c,0x51,0x5a,0x6b,0x60,0x7d,0x76,0x1f,0x14,0x09,0x02,0x33,0x38,0x25,0x2e,  
  69.     0x8c,0x87,0x9a,0x91,0xa0,0xab,0xb6,0xbd,0xd4,0xdf,0xc2,0xc9,0xf8,0xf3,0xee,0xe5,  
  70.     0x3c,0x37,0x2a,0x21,0x10,0x1b,0x06,0x0d,0x64,0x6f,0x72,0x79,0x48,0x43,0x5e,0x55,  
  71.     0x01,0x0a,0x17,0x1c,0x2d,0x26,0x3b,0x30,0x59,0x52,0x4f,0x44,0x75,0x7e,0x63,0x68,  
  72.     0xb1,0xba,0xa7,0xac,0x9d,0x96,0x8b,0x80,0xe9,0xe2,0xff,0xf4,0xc5,0xce,0xd3,0xd8,  
  73.     0x7a,0x71,0x6c,0x67,0x56,0x5d,0x40,0x4b,0x22,0x29,0x34,0x3f,0x0e,0x05,0x18,0x13,  
  74.     0xca,0xc1,0xdc,0xd7,0xe6,0xed,0xf0,0xfb,0x92,0x99,0x84,0x8f,0xbe,0xb5,0xa8,0xa3  
  75. };  
  76.   
  77. byte Mul_0d[256] = {  
  78.     0x00,0x0d,0x1a,0x17,0x34,0x39,0x2e,0x23,0x68,0x65,0x72,0x7f,0x5c,0x51,0x46,0x4b,  
  79.     0xd0,0xdd,0xca,0xc7,0xe4,0xe9,0xfe,0xf3,0xb8,0xb5,0xa2,0xaf,0x8c,0x81,0x96,0x9b,  
  80.     0xbb,0xb6,0xa1,0xac,0x8f,0x82,0x95,0x98,0xd3,0xde,0xc9,0xc4,0xe7,0xea,0xfd,0xf0,  
  81.     0x6b,0x66,0x71,0x7c,0x5f,0x52,0x45,0x48,0x03,0x0e,0x19,0x14,0x37,0x3a,0x2d,0x20,  
  82.     0x6d,0x60,0x77,0x7a,0x59,0x54,0x43,0x4e,0x05,0x08,0x1f,0x12,0x31,0x3c,0x2b,0x26,  
  83.     0xbd,0xb0,0xa7,0xaa,0x89,0x84,0x93,0x9e,0xd5,0xd8,0xcf,0xc2,0xe1,0xec,0xfb,0xf6,  
  84.     0xd6,0xdb,0xcc,0xc1,0xe2,0xef,0xf8,0xf5,0xbe,0xb3,0xa4,0xa9,0x8a,0x87,0x90,0x9d,  
  85.     0x06,0x0b,0x1c,0x11,0x32,0x3f,0x28,0x25,0x6e,0x63,0x74,0x79,0x5a,0x57,0x40,0x4d,  
  86.     0xda,0xd7,0xc0,0xcd,0xee,0xe3,0xf4,0xf9,0xb2,0xbf,0xa8,0xa5,0x86,0x8b,0x9c,0x91,  
  87.     0x0a,0x07,0x10,0x1d,0x3e,0x33,0x24,0x29,0x62,0x6f,0x78,0x75,0x56,0x5b,0x4c,0x41,  
  88.     0x61,0x6c,0x7b,0x76,0x55,0x58,0x4f,0x42,0x09,0x04,0x13,0x1e,0x3d,0x30,0x27,0x2a,  
  89.     0xb1,0xbc,0xab,0xa6,0x85,0x88,0x9f,0x92,0xd9,0xd4,0xc3,0xce,0xed,0xe0,0xf7,0xfa,  
  90.     0xb7,0xba,0xad,0xa0,0x83,0x8e,0x99,0x94,0xdf,0xd2,0xc5,0xc8,0xeb,0xe6,0xf1,0xfc,  
  91.     0x67,0x6a,0x7d,0x70,0x53,0x5e,0x49,0x44,0x0f,0x02,0x15,0x18,0x3b,0x36,0x21,0x2c,  
  92.     0x0c,0x01,0x16,0x1b,0x38,0x35,0x22,0x2f,0x64,0x69,0x7e,0x73,0x50,0x5d,0x4a,0x47,  
  93.     0xdc,0xd1,0xc6,0xcb,0xe8,0xe5,0xf2,0xff,0xb4,0xb9,0xae,0xa3,0x80,0x8d,0x9a,0x97  
  94. };  
  95.   
  96. byte Mul_0e[256] = {  
  97.     0x00,0x0e,0x1c,0x12,0x38,0x36,0x24,0x2a,0x70,0x7e,0x6c,0x62,0x48,0x46,0x54,0x5a,  
  98.     0xe0,0xee,0xfc,0xf2,0xd8,0xd6,0xc4,0xca,0x90,0x9e,0x8c,0x82,0xa8,0xa6,0xb4,0xba,  
  99.     0xdb,0xd5,0xc7,0xc9,0xe3,0xed,0xff,0xf1,0xab,0xa5,0xb7,0xb9,0x93,0x9d,0x8f,0x81,  
  100.     0x3b,0x35,0x27,0x29,0x03,0x0d,0x1f,0x11,0x4b,0x45,0x57,0x59,0x73,0x7d,0x6f,0x61,  
  101.     0xad,0xa3,0xb1,0xbf,0x95,0x9b,0x89,0x87,0xdd,0xd3,0xc1,0xcf,0xe5,0xeb,0xf9,0xf7,  
  102.     0x4d,0x43,0x51,0x5f,0x75,0x7b,0x69,0x67,0x3d,0x33,0x21,0x2f,0x05,0x0b,0x19,0x17,  
  103.     0x76,0x78,0x6a,0x64,0x4e,0x40,0x52,0x5c,0x06,0x08,0x1a,0x14,0x3e,0x30,0x22,0x2c,  
  104.     0x96,0x98,0x8a,0x84,0xae,0xa0,0xb2,0xbc,0xe6,0xe8,0xfa,0xf4,0xde,0xd0,0xc2,0xcc,  
  105.     0x41,0x4f,0x5d,0x53,0x79,0x77,0x65,0x6b,0x31,0x3f,0x2d,0x23,0x09,0x07,0x15,0x1b,  
  106.     0xa1,0xaf,0xbd,0xb3,0x99,0x97,0x85,0x8b,0xd1,0xdf,0xcd,0xc3,0xe9,0xe7,0xf5,0xfb,  
  107.     0x9a,0x94,0x86,0x88,0xa2,0xac,0xbe,0xb0,0xea,0xe4,0xf6,0xf8,0xd2,0xdc,0xce,0xc0,  
  108.     0x7a,0x74,0x66,0x68,0x42,0x4c,0x5e,0x50,0x0a,0x04,0x16,0x18,0x32,0x3c,0x2e,0x20,  
  109.     0xec,0xe2,0xf0,0xfe,0xd4,0xda,0xc8,0xc6,0x9c,0x92,0x80,0x8e,0xa4,0xaa,0xb8,0xb6,  
  110.     0x0c,0x02,0x10,0x1e,0x34,0x3a,0x28,0x26,0x7c,0x72,0x60,0x6e,0x44,0x4a,0x58,0x56,  
  111.     0x37,0x39,0x2b,0x25,0x0f,0x01,0x13,0x1d,0x47,0x49,0x5b,0x55,0x7f,0x71,0x63,0x6d,  
  112.     0xd7,0xd9,0xcb,0xc5,0xef,0xe1,0xf3,0xfd,0xa7,0xa9,0xbb,0xb5,0x9f,0x91,0x83,0x8d  
  113. }; 

Posted by steadyguy on Wed, 17 Apr 2019 15:00:34 -0700