C++实现AES算法,ECB/CBC模式,PKCS#7填充加解密

https://blog.csdn.net/qq_28205153/article/details/55798628

首先附上大佬的博文,写得很清楚了,AES-128的加解密。阅读量不是摆着看的,如果非要对内容作深究,

那么也可以结合一下评论,可以算是勘误。

https://zhuanlan.zhihu.com/p/360393988

知乎的这一篇,可以算是对上一篇博客的扩展,毕竟上一篇是固化为了128位密钥。

深入理解以后,肯定知道扩展为192/256位密钥是需要一些修改的。

当然了,知乎这一篇也是有一些错误的。

将(3)里面的
w[i] = w[i-6] xor temp;/*将上一个字(处理或没处理过) 改成 w[i] = w[i-8] xor temp;/*将上一个字(处理或没处理过) 即可。作者应该是复制修改,然后最后一处忘了改了。

本人所写,则结合两篇内容独立进行编写。

https://www.cnblogs.com/hhhhan1025/p/10115567.html

这一篇博客关于密钥扩展的描述些得更加清晰一点,也很推荐。

直接附上代码,内含详细注释。

  1 #ifndef MYAES_H
  2 #define MYAES_H
  3 #include <iostream>
  4 #include <vector>
  5 #include <string.h>
  6 
  7 using namespace std;
  8 
  9 /*
 10  *加密时用于字节代换的S盒
 11  * */
 12 const static unsigned char sbox[16][16]  =
 13 {{0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76},
 14 {0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0},
 15 {0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15},
 16 {0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75},
 17 {0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84},
 18 {0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf},
 19 {0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8},
 20 {0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2},
 21 {0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73},
 22 {0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb},
 23 {0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79},
 24 {0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08},
 25 {0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a},
 26 {0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e},
 27 {0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf},
 28 {0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16}};
 29 
 30 /*
 31  * 解密时用于字节代换的逆S盒
 32  * */
 33 const static unsigned char rsbox[16][16] =
 34 {{0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb},
 35 {0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb},
 36 {0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e},
 37 {0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25},
 38 {0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92},
 39 {0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84},
 40 {0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06},
 41 {0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b},
 42 {0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73},
 43 {0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e},
 44 {0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b},
 45 {0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4},
 46 {0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f},
 47 {0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef},
 48 {0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61},
 49 {0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d}};
 50 
 51 /*
 52  * 用于扩展密钥的轮常量
 53  * */
 54 const static unsigned char rcon[13][4] =
 55 {
 56     {0x01,0x0,0x0,0x0},{0x2,0x0,0x0,0x0},{0x4,0x0,0x0,0x0},{0x8,0x0,0x0,0x0},{0x10,0x0,0x0,0x0},
 57     {0x20,0x0,0x0,0x0},{0x40,0x0,0x0,0x0},{0x80,0x0,0x0,0x0},{0x1b,0x0,0x0,0x0},{0x36,0x0,0x0,0x0},
 58     {0x6c,0x0,0x0,0x0},{0xd8,0x0,0x0,0x0},{0xab,0x0,0x0,0x0}
 59 };
 60 
 61 /*
 62  * 加密时的列混合矩阵
 63  * */
 64 const static unsigned char mixcol[4][4] =
 65 {
 66     {0x2,0x3,0x1,0x1},{0x1,0x2,0x3,0x1},{0x1,0x1,0x2,0x3},{0x3,0x1,0x1,0x2}
 67 };
 68 
 69 /*
 70  * 解密时的列混合矩阵
 71  * */
 72 const static unsigned char rmixcol[4][4] =
 73 {
 74     {0xe,0xb,0xd,0x9},{0x9,0xe,0xb,0xd},{0xd,0x9,0xe,0xb},{0xb,0xd,0x9,0xe}
 75 };
 76 
 77 struct sixteenbyte{
 78     unsigned char s[4][4];
 79 };
 80 struct fourbyte{
 81     unsigned char s[4];
 82 };
 83 enum MODE{
 84     AES_128_ECB,AES_192_ECB,AES_256_ECB,AES_128_CBC,AES_192_CBC,AES_256_CBC
 85 };
 86 enum PADDING{
 87     NOPADDING,ZEROPADDING,PKCS7,OLDPADDING
 88 };
 89 //NOPADDING:不足128bit的部分,不会加密
 90 //ZEROPADDING:不足128bit的部分,使用字节0x0填充,如果数据末尾恰好为0x0,就没办法咯
 91 //PKCS7:不足128bit的部分,缺少几个字节,就填几个字节的几
 92 //OLDPADDING:貌似已经不是标准,这里暂且认为是最后缺少几个字节,前面的字节填0x0,最后一个字节填充几
 93 
 94 class MyAes
 95 {
 96 public:
 97     MyAes();
 98     MyAes(MODE mode = AES_128_ECB,PADDING pad = PKCS7);
 99     unsigned char* encrypt(unsigned char key[],unsigned char textA[],int Textlength = 16);
100     unsigned char* decrypt(unsigned char key[],unsigned char textA[],int Textlength = 16);
101     unsigned char* decrypt_cbc(unsigned char key[],unsigned char textA[],unsigned char ivA[],int Textlength = 16);
102     unsigned char* encrypt_cbc(unsigned char key[],unsigned char textA[],unsigned char ivA[],int Textlength = 16);
103     unsigned char getSBox(unsigned char old);
104     unsigned char getRSBox(unsigned char old);
105     static void printInfo();//打印一些类的使用说明
106     void printTime();//测试的时候打印一下运行时间
107     void printText();
108     unsigned char calcValue_original(unsigned char old,unsigned char value);//有限域内的乘法
109     unsigned char calcValue(unsigned char old,unsigned char value);//有限域内的乘法
110     char basicMulti(char a);//最基本的二元乘法
111     void setMode(MODE mode);//设置加密模式,其实还是长度
112     void setPad(PADDING pad);//设置填充模式
113 
114 private:
115     sixteenbyte text;
116     unsigned char* key;
117     fourbyte* mixWord;//[44]
118 
119     sixteenbyte iv;
120 
121     sixteenbyte* rword;//decrypt2太慢了
122 
123     int keyLength;//128、192、256
124     int wordLength;
125     int keyword;//密钥有多少个字长
126     int encryptTimes;//轮数
127     int beforeTimes;
128     int keybyte;
129 
130     string mod;//enum 定义各种模式
131 
132     MODE m_mode;
133 
134     PADDING m_pad;
135     int time;
136     bool nopad;
137 
138     sixteenbyte moveX(sixteenbyte st);//行移位
139     sixteenbyte rmoveX(sixteenbyte st);//逆行移位
140     void setKey(unsigned char* c);//设置密钥
141     void setText(unsigned char* c);//设置文本
142     void setKeyLength(int length);
143     void colTorow();//密文行列转置
144     void setIv(unsigned char* c);//设置偏移量
145     void addRoundKey(int round);//轮钥密加
146     sixteenbyte changeByte(sixteenbyte old);//加密时的字节代换
147     sixteenbyte rchangeByte(sixteenbyte old);//解密时的字节代换
148     char calc(unsigned char old[],int col);//对加密时对一列数据进行计算
149     char rcalc(unsigned char old[],int col);//解密时对一列数据进行计算
150     sixteenbyte mixCol(sixteenbyte old);//加密时的列混合
151     sixteenbyte rmixCol(sixteenbyte old);//解密时的列混合
152     void encrypt();//最基本的ecb加密
153     void decrypt();//最基本的ecb解密
154     void encrypt_cbc();//最基本的cbc加密
155     void decrypt_cbc();//最基本的cbc解密
156     void xorWithiv();//和偏移向量进行异或
157 
158 };
159 
160 #endif // MYAES_H
  1 #include "myaes.h"
  2 
  3 MyAes::MyAes()
  4 {
  5     setMode(AES_128_ECB);
  6     setPad(PKCS7);
  7     time = 0;
  8 }
  9 
 10 MyAes::MyAes(MODE mode ,PADDING pad)
 11 {
 12     setMode(mode);
 13     setPad(pad);
 14 }
 15 
 16 unsigned char *MyAes::encrypt(unsigned char key[], unsigned char textA[], int Textlength)
 17 {
 18     setKey(key);
 19     unsigned char str[16];
 20     unsigned char* result;
 21     int len = Textlength;
 22     int padLength = 16-len%16;
 23     result = (unsigned char*)malloc(len+padLength);
 24     memcpy(result,textA,len);
 25     len-=16;
 26     memset(str,0,16);
 27     int i=0;
 28     for(i=0;i<=len;i+=16)
 29     {
 30         memcpy(str,textA+i,16);
 31         setText(str);
 32         encrypt();
 33         colTorow();
 34         memcpy(result+i,text.s,16);
 35     }
 36 
 37     if(!nopad)
 38     {
 39         cout<<"tianchong length = "<<padLength<<endl;
 40         if(m_pad == ZEROPADDING)
 41             padLength = 0;
 42         memset(str,padLength,16);
 43         memcpy(str,result+i,len%16);
 44         setText(str);
 45         encrypt();
 46         colTorow();
 47         memcpy(result+i,text.s,16);
 48     }
 49     return result;
 50 }
 51 
 52 unsigned char *MyAes::decrypt(unsigned char key[], unsigned char textA[], int Textlength)
 53 {
 54     setKey(key);
 55     unsigned char str[16];
 56     unsigned char* result;
 57     int len = Textlength;
 58     result = (unsigned char*)malloc(len);
 59     memcpy(result,textA,len);
 60     len-=16;
 61     memset(str,0,16);
 62     for(int i=0;i<=len;i+=16)
 63     {
 64         memcpy(str,textA+i,16);
 65         setText(str);
 66         decrypt();
 67         colTorow();
 68         memcpy(result+i,text.s,16);
 69     }
 70     if(!nopad)
 71     {
 72         len+=16;
 73         int padLength = 0;
 74         if(m_pad == ZEROPADDING)
 75         {
 76             unsigned char temp[16];
 77             memcpy(temp,text.s,16);
 78             for(int j=15;j>=0;j--)
 79             {
 80                 if(temp[j]==0)
 81                     padLength++;
 82             }
 83         }
 84         else
 85         {
 86             padLength = text.s[3][3];
 87 
 88         }
 89         int leftLength = len-padLength;
 90         cout<<leftLength<<endl;
 91         unsigned char* tmp;
 92         tmp = (unsigned char*)malloc(leftLength);
 93         memcpy(tmp,result,leftLength);
 94         return tmp;
 95     }
 96     return result;
 97 }
 98 
 99 //解密必是16的整数倍
100 unsigned char *MyAes::decrypt_cbc(unsigned char key[], unsigned char textA[], unsigned char ivA[], int Textlength)
101 {
102     setIv(ivA);
103     setKey(key);
104     unsigned char str[16];
105     unsigned char* result;
106     int len = Textlength;
107     result = (unsigned char*)malloc(len);
108     memcpy(result,textA,len);
109     len-=16;
110     memset(str,0,16);
111     for(int i=0;i<=len;i+=16)
112     {
113         memcpy(str,textA+i,16);
114         setText(str);
115         decrypt_cbc();
116         setIv(str);
117         colTorow();
118         memcpy(result+i,text.s,16);
119     }
120     if(!nopad)
121     {
122         len+=16;
123         int padLength = 0;
124         if(m_pad == ZEROPADDING)
125         {
126             unsigned char temp[16];
127             memcpy(temp,text.s,16);
128             for(int j=15;j>=0;j--)
129             {
130                 if(temp[j]==0)
131                     padLength++;
132             }
133         }
134         else
135         {
136             padLength = text.s[3][3];
137 
138         }
139         int leftLength = len-padLength;
140         cout<<leftLength<<endl;
141         unsigned char* tmp;
142         tmp = (unsigned char*)malloc(leftLength);
143         memcpy(tmp,result,leftLength);
144         return tmp;
145     }
146     return result;
147 }
148 
149 unsigned char *MyAes::encrypt_cbc(unsigned char key[], unsigned char textA[], unsigned char ivA[], int Textlength)
150 {
151     setIv(ivA);
152     setKey(key);
153 
154     unsigned char str[16];
155     unsigned char* result;
156     int len = Textlength;
157     int padLength = 16-len%16;
158     result = (unsigned char*)malloc(len+padLength);
159     memcpy(result,textA,len);
160     len-=16;
161     memset(str,0,16);
162     int i=0;
163     for(i=0;i<=len;i+=16)
164     {
165         memcpy(str,textA+i,16);
166         setText(str);
167         encrypt_cbc();
168         iv = text;
169         colTorow();
170 
171         memcpy(result+i,text.s,16);
172     }
173     if(!nopad)
174     {
175         cout<<"tianchong length = "<<padLength<<endl;
176         memset(str,padLength,16);
177 //        memset(str,0,16);//memset貌似不是随意分配,与数据大小相关,目前来看,两种方式都可以
178 //        for(int j=0;j<16;j++)
179 //        {
180 //            str[i]^=padLength;
181 //        }
182 //        cout<<"str = "<<str<<endl;
183         memcpy(str,result+i,len%16);
184         setText(str);
185         encrypt_cbc();
186         colTorow();
187         memcpy(result+i,text.s,16);
188     }
189     return result;
190 }
191 
192 /*
193  * 从S盒进行字节代换
194  * */
195 unsigned char MyAes::getSBox(unsigned char old)
196 {
197     return *(sbox[0]+old);//继续减少运算步骤,稍微快一点点,文件大,才有明显差距
198    /*
199     * 以下算是字节代换最基本的解释
200     * */
201     char high = (old&0xf0)>>4;
202     char low = (old&0x0f);
203     return sbox[high][low];
204 }
205 
206 /*
207  * 从逆S盒进行字节代换
208  * */
209 unsigned char MyAes::getRSBox(unsigned char old)
210 {
211     return *(rsbox[0]+old);//快那么一点点,文件大,比较明显
212     char high = (old&0xf0)>>4;
213     char low = (old&0x0f);
214     return rsbox[high][low];
215 }
216 
217 
218 void MyAes::setKeyLength(int length)
219 {
220     keybyte = length>>3;//密钥的字节数量
221     keyLength = length;//密钥的位数,notused
222     keyword = keybyte>>2;//已经有了多少字
223 
224     encryptTimes = keyword + 6;
225     beforeTimes = encryptTimes-1;
226     wordLength = (encryptTimes+1)<<2;//总字数,
227     mixWord = new fourbyte[wordLength];
228     rword = new sixteenbyte[encryptTimes+1];
229 }
230 
231 void MyAes::printInfo()
232 {
233     cout<<"you can setMode or initialize the class use below constant words or num "<<endl;
234     cout<<"AES_128_ECB "<<"or use num 1."<<endl;
235     cout<<"AES_192_ECB "<<"or use num 2."<<endl;
236     cout<<"AES_256_ECB "<<"or use num 3."<<endl;
237     cout<<"AES_128_CBC "<<"or use num 4."<<endl;
238     cout<<"AES_192_CBC "<<"or use num 5."<<endl;
239     cout<<"AES_256_CBC "<<"or use num 6."<<endl;
240     cout<<"this class use AES_128_ECB mode as default if you don't set mode."<<endl;
241 }
242 
243 void MyAes::printTime()
244 {
245     cout<<"time = "<<time<<endl;
246 }
247 
248 void MyAes::printText()
249 {
250     for(int i=0;i<4;i++)
251     {
252         for(int j=0;j<4;j++)
253         {
254             printf("%0x ",text.s[i][j]);
255         }
256         cout<<endl;
257     }
258 }
259 
260 /*
261  * 以下为有限域内乘法的最基本解释,代入任何值,均可计算,效率显而易见的低。算法已知乘法系数value的值,手动写上针对不同value的计算过程即可。
262  * */
263 unsigned char MyAes::calcValue_original(unsigned char old, unsigned char value)
264 {
265     unsigned char result = old;
266     unsigned char calcIndex = 0x80;//对每一位进行计算,最后的结果再一起异或
267     vector<char> calcResult;//保存基本运算的结果
268     while (calcIndex>0) {
269         unsigned char temp = value&calcIndex;
270         old = result;
271         bool first = false;//标志着进行了运算
272         if(temp==1)
273         {
274             calcResult.push_back(result);
275         }
276         while(temp>=2)//根据位置决定进行多少次基本运算,0x2就是一次,0x4就是两次。。。
277         {
278             first = true;
279             old = basicMulti(old);
280             temp>>=1;
281         }
282         if(first)
283         {
284             calcResult.push_back(old);
285         }
286         calcIndex>>=1;
287     }
288     if(calcResult.size()==0)//代表value为0x1
289     {
290         return result;
291     }
292     result = calcResult[0];
293     for(int i=1;i<calcResult.size();i++)
294     {
295         result^=calcResult[i];
296     }
297     return result;
298 }
299 
300 /*
301  * 某个字节根据列混合矩阵的系数进行运算
302  * */
303 unsigned char MyAes::calcValue(unsigned char old, unsigned char value)
304 {
305     if (value == 0xd)//8+4+1
306     {
307         char tmp = basicMulti(basicMulti(old));
308         return basicMulti(tmp)^tmp^old;
309 //            return basicMulti(basicMulti(basicMulti(old))) ^ basicMulti(basicMulti(old)) ^ old; //这种写法按照加法进行展开,再提取合并以下,实测会更快。
310     }
311     if (value == 0x9)//8+1
312     {
313         return basicMulti(basicMulti(basicMulti(old))) ^ old;
314     }
315     if (value == 0xe)//8+4+2
316     {
317         char a = basicMulti(old);
318         char b = basicMulti(a);
319         return basicMulti(b)^b^a;
320 //            return basicMulti(basicMulti(basicMulti(old))) ^ basicMulti(basicMulti(old)) ^ basicMulti(old);//同样是进行提取
321     }
322     if (value == 0xb)//8+2+1
323     {
324         char a = basicMulti(old);
325         return basicMulti(basicMulti(a))^a^old;
326 //            return basicMulti(basicMulti(basicMulti(old))) ^ basicMulti(old) ^ old;//再次提取,稍微提高了运行效率
327     }
328     if (value == 0x1)//代表value为0x1
329     {
330         return old;
331     }
332     if (value == 0x2)
333     {
334         return basicMulti(old);
335     }
336     if (value == 0x3)//2+1
337     {
338         return basicMulti(old) ^ old;
339     }
340 }
341 
342 /*
343  * 列混合时,对一个字节最基本的计算
344  * */
345 
346 char MyAes::basicMulti(char a)
347 {
348     return (a<<1)^((a>>7&0x1)*0x1b);
349     //        return (a<<1)^(((a>>7&0x1)==0x0)?0x0:0x1b);//只不过是下面的简写而已,还是很慢
350     /*
351      * 基本乘法,判断该字节的第一位是否为1,该字节左移一位,补0,第一位为1,还要和0x1b进行异或;下面的写法就是基操,效率毫无疑问会比上面慢很多
352      * */
353     char first = a>>7&0x1;
354     a<<=1;
355     if(first==1)
356     {
357         a^=0x1b;
358     }
359     return a;
360 }
361 
362 void MyAes::setMode(MODE mode)
363 {
364     switch (mode) {
365     case AES_128_ECB:
366         setKeyLength(128);
367         this->m_mode = mode;
368         break;
369     case AES_192_ECB:
370         setKeyLength(192);
371         this->m_mode = mode;
372         break;
373     case AES_256_ECB:
374         setKeyLength(256);
375         this->m_mode = mode;
376         break;
377     case AES_128_CBC:
378         setKeyLength(128);
379         this->m_mode = mode;
380         break;
381     case AES_192_CBC:
382         setKeyLength(192);
383         this->m_mode = mode;
384         break;
385     case AES_256_CBC:
386         setKeyLength(256);
387         this->m_mode = mode;
388         break;
389     default:
390         setKeyLength(128);
391         this->mod = AES_128_ECB;
392         break;
393     }
394 
395 }
396 
397 //默认为PKCS7
398 void MyAes::setPad(PADDING pad)
399 {
400     nopad = false;
401     switch (pad) {
402     case NOPADDING:
403         this->m_pad = pad;
404         nopad = true;
405         break;
406     case ZEROPADDING:
407         this->m_pad = pad;
408         break;
409     case PKCS7:
410         this->m_pad = pad;
411         break;
412     case OLDPADDING:
413         this->m_pad = pad;
414         break;
415     default:
416         this->m_pad = PKCS7;
417         break;
418     }
419 }
420 
421 /*
422  * 行移位
423  * */
424 sixteenbyte MyAes::moveX(sixteenbyte old)
425 {
426     sixteenbyte ne;
427     for(int i=0;i<4;i++)
428     {
429         for(int j=0;j<4;j++)
430         {
431             ne.s[i][j] = old.s[i][(j+i)%4];
432         }
433     }
434     return ne;
435 }
436 
437 
438 /*
439  * 逆行移位
440  * */
441 sixteenbyte MyAes::rmoveX(sixteenbyte old)
442 {
443     sixteenbyte ne;
444     for(int i=0;i<4;i++)
445     {
446         for(int j=3;j>=0;j--)
447         {
448             ne.s[i][j] = old.s[i][(j-i+4)%4];
449         }
450     }
451     return ne;
452 }
453 
454 /*
455  * 输入密钥,并进行扩展
456  * */
457 void MyAes::setKey(unsigned char *c)
458 {
459     key = (unsigned char*)malloc(keybyte);
460     memcpy(key,c,keybyte);
461 //    cout<<"keybyte = "<<keybyte<<endl;
462 //    cout<<"keyword = "<<keyword<<endl;
463 //    cout<<"wordlength = "<<wordLength<<endl;
464     memcpy(mixWord,key,keybyte);//以密钥作为字
465     for(int i=keyword;i<wordLength;i++)//后40个word
466     {
467         if(i%keyword!=0)//不是4的倍数,word[i] = word[i-4]^word[i-1]
468         {
469             fourbyte temp = mixWord[i-1];
470             for(int j=0;j<4;j++)
471             {
472                 if(i%keyword==4&&keyword>6)
473                 {
474                     temp.s[j] = getSBox(temp.s[j]);
475                 }
476                 mixWord[i].s[j] = mixWord[i-keyword].s[j]^temp.s[j];
477             }
478         }
479         else//4的倍数,word[i] = word[i-4]^T(word[i-1]),T代表字节左移一位,S盒字节代换,根据轮数与轮常量进行异或
480         {
481             fourbyte temp = mixWord[i-1];
482             for(int j=0;j<4;j++)
483             {
484 //                    printf("j = %d old = %0x\n",j,temp.s[j]);
485                 temp.s[j] = mixWord[i-1].s[(j+1)%4];//字循环
486 //                    printf("j = %d temp = %0x\n",j,temp.s[j]);
487                 temp.s[j] = getSBox(temp.s[j]);//字节代换
488 //                    printf("daihuan j = %d temp = %0x\n",j,temp.s[j]);
489 //                    printf("lunzi %0x \n",rcon[((i%4)-1)][j]);
490                 temp.s[j] = temp.s[j]^rcon[(i/keyword-1)][j];//轮常量异或
491 //                    printf("ron j = %d temp = %0x\n",j,temp.s[j]);
492                 mixWord[i].s[j] = mixWord[i-keyword].s[j]^temp.s[j];
493             }
494 
495         }
496     }
497 }
498 
499 void MyAes::setText(unsigned char *c)
500 {
501     for(int i=0;i<4;i++)
502     {
503         for(int j=0;j<4;j++)
504         {
505             text.s[j][i] = (*c++);
506         }
507     }
508 }
509 
510 void MyAes::colTorow()
511 {
512     for(int i=0;i<4;i++)
513     {
514         for(int j=i+1;j<4;j++)
515         {
516             char tmp = text.s[i][j]^text.s[j][i];
517             text.s[i][j]^=tmp;
518             text.s[j][i]^=tmp;
519         }
520     }
521 }
522 
523 /*
524  * 输入偏移量
525  * */
526 void MyAes::setIv(unsigned char *c)
527 {
528     for(int i=0;i<4;i++)
529     {
530         for(int j=0;j<4;j++)
531         {
532             iv.s[j][i] = (*c++);
533         }
534     }
535 }
536 
537 /*
538  * 轮钥密加
539  * */
540 void MyAes::addRoundKey(int round)
541 {
542     for(int i=0;i<4;i++)
543     {
544         fourbyte temp = mixWord[round*4+i];
545         for(int j=0;j<4;j++)
546         {
547             text.s[j][i]^=temp.s[j];
548         }
549     }
550 }
551 
552 /*
553  * 加密时的字节代换
554  * */
555 sixteenbyte MyAes::changeByte(sixteenbyte old)
556 {
557     for(int i=0;i<4;i++)
558     {
559         for(int j=0;j<4;j++)
560         {
561             old.s[i][j] = getSBox(old.s[i][j]);
562         }
563     }
564     return old;
565 }
566 
567 /*
568  * 解密时的逆字节代换
569  * */
570 sixteenbyte MyAes::rchangeByte(sixteenbyte old)
571 {
572     for(int i=0;i<4;i++)
573     {
574         for(int j=0;j<4;j++)
575         {
576             old.s[i][j] = getRSBox(old.s[i][j]);
577         }
578     }
579     return old;
580 }
581 
582 /*
583  * 4字节的数据,分别根据col那一行的列混合矩阵系数进行基本运算,结果一起进行异或
584  * */
585 char MyAes::calc(unsigned char old[], int col)
586 {
587     for(int i=0;i<4;i++)
588     {
589         old[i] = calcValue(old[i],mixcol[col][i]);
590     }
591 
592     return old[0]^old[1]^old[2]^old[3];//4个字节的计算结果异或后返回
593 }
594 
595 char MyAes::rcalc(unsigned char old[], int col)
596 {
597     for(int i=0;i<4;i++)
598     {
599         old[i] = calcValue(old[i],rmixcol[col][i]);
600     }
601     return old[0]^old[1]^old[2]^old[3];
602 }
603 
604 /*
605  * 列混合,实质为4字节的数据根据行数使用列混合矩阵某一行的乘法系数
606  * */
607 sixteenbyte MyAes::mixCol(sixteenbyte old)
608 {
609     sixteenbyte temp;
610     for(int i=0;i<4;i++)
611     {
612         for(int j=0;j<4;j++)
613         {
614             unsigned char tmp[4];//以列为计算方向
615             tmp[0] = old.s[0][j];
616             tmp[1] = old.s[1][j];
617             tmp[2] = old.s[2][j];
618             tmp[3] = old.s[3][j];
619 //                temp.s[i][j] = calc(old.s[j],i);
620             temp.s[i][j] = calc(tmp,i);
621         }
622     }
623     return temp;
624 }
625 
626 sixteenbyte MyAes::rmixCol(sixteenbyte old)
627 {
628     sixteenbyte temp;
629     for(int i=0;i<4;i++)
630     {
631         for(int j=0;j<4;j++)
632         {
633             unsigned char tmp[4];
634             tmp[0] = old.s[0][j];
635             tmp[1] = old.s[1][j];
636             tmp[2] = old.s[2][j];
637             tmp[3] = old.s[3][j];
638             temp.s[i][j] = rcalc(tmp,i);
639         }
640     }
641     return temp;
642 }
643 
644 void MyAes::encrypt()
645 {
646     addRoundKey(0);
647     for(int i=1;i<=beforeTimes;i++)
648     {
649         text = changeByte(text);//字节代换
650         text = moveX(text);//行移位
651         text = mixCol(text);//列混合
652         addRoundKey(i);//轮密钥加
653     }
654     //第10轮
655     text = changeByte(text);//字节代换
656     text = moveX(text);//行移位
657     addRoundKey(encryptTimes);//轮密钥加
658 
659     //        printText();
660 }
661 
662 void MyAes::decrypt()
663 {
664     addRoundKey(encryptTimes);
665     text = rmoveX(text);
666     text = rchangeByte(text);
667     for(int i=beforeTimes;i>=1;i--)
668     {
669         addRoundKey(i);
670         text = rmixCol(text);
671         text = rmoveX(text);
672         text = rchangeByte(text);
673     }
674     addRoundKey(0);
675 }
676 
677 void MyAes::encrypt_cbc()
678 {
679     xorWithiv();
680     addRoundKey(0);
681     for(int i=1;i<=beforeTimes;i++)
682     {
683         text = changeByte(text);//字节代换
684         text = moveX(text);//行移位
685         text = mixCol(text);//列混合
686         addRoundKey(i);//轮密钥加
687     }
688     //第10轮
689     text = changeByte(text);//字节代换
690     text = moveX(text);//行移位
691     addRoundKey(encryptTimes);//轮密钥加
692 }
693 
694 void MyAes::decrypt_cbc()
695 {
696     addRoundKey(encryptTimes);
697     text = rmoveX(text);
698     text = rchangeByte(text);
699     for(int i=beforeTimes;i>=1;i--)
700     {
701         addRoundKey(i);
702         text = rmixCol(text);
703         text = rmoveX(text);
704         text = rchangeByte(text);
705     }
706     addRoundKey(0);
707     xorWithiv();
708 }
709 
710 /*
711  * 和偏移向量进行异或
712  * */
713 void MyAes::xorWithiv()
714 {
715     for(int i=0;i<4;i++)
716     {
717         for(int j=0;j<4;j++)
718         {
719             text.s[i][j]^=iv.s[i][j];
720         }
721     }
722 }

本人其实也只是测试了PKCS7模式的加解密,所得结果和php的openssl一致。其实填充其实也没啥问题。

注释也写得挺详细。

本人只实现了CBC/ECB模式,其他3种不太常用的,直接PASS。效率的话,肯定是有待提高的。反正会比php慢很多。

本人虽然学了挺久的C语言,但是几乎没用过位操作,以前看见位操作的算法,就敬而远之。

这次写了这个练手,感觉进步还是蛮大的,也理解了那些算法不是为了晦涩难懂才写成那样,而是为了追求极致的效率。

还有就是指针操作,有待加强。

posted @ 2021-10-01 12:28  念秋  阅读(5322)  评论(0编辑  收藏  举报