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语言,但是几乎没用过位操作,以前看见位操作的算法,就敬而远之。
这次写了这个练手,感觉进步还是蛮大的,也理解了那些算法不是为了晦涩难懂才写成那样,而是为了追求极致的效率。
还有就是指针操作,有待加强。