zoukankan      html  css  js  c++  java
  • 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
    ",j,temp.s[j]);
    485                 temp.s[j] = mixWord[i-1].s[(j+1)%4];//字循环
    486 //                    printf("j = %d temp = %0x
    ",j,temp.s[j]);
    487                 temp.s[j] = getSBox(temp.s[j]);//字节代换
    488 //                    printf("daihuan j = %d temp = %0x
    ",j,temp.s[j]);
    489 //                    printf("lunzi %0x 
    ",rcon[((i%4)-1)][j]);
    490                 temp.s[j] = temp.s[j]^rcon[(i/keyword-1)][j];//轮常量异或
    491 //                    printf("ron j = %d temp = %0x
    ",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语言,但是几乎没用过位操作,以前看见位操作的算法,就敬而远之。

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

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

  • 相关阅读:
    fiddler抓包
    Fiddler简介
    selenium自动化测试-处理iframe
    selenium自动化-获取元素属性信息
    selenium自动化测试-鼠标键盘操作
    selenium自动化测试-定位元素神器Katalon Recorder
    selenium自动化测试-By定位及如何确定元素唯一
    day34-WEB框架
    WORD 通配符
    jquery-day32
  • 原文地址:https://www.cnblogs.com/dayq/p/15359184.html
Copyright © 2011-2022 走看看