精华内容
下载资源
问答
  • AES算法有限域GF(2**8)上的x乘法运算Verilog实现 不可约多项式为: 有限域上的x乘法: x的乘法实现Verilog代码: module mul( input[7:0] data_in, output[7:0] data_out ); reg[7:0] dat; always @...

    AES算法有限域GF(2**8)上的x乘法运算Verilog实现

    不可约多项式为:

    有限域上的x乘法:
    在这里插入图片描述
    x的乘法实现Verilog代码:

    module mul( 
     	input[7:0] data_in, 
    	output[7:0] data_out
     ); 
     	reg[7:0] dat; 
     	always @(data_in) 
     	begin  
      		dat <= {data_in[6:0],1'b0};  
      		if(data_in[7] == 1)  
      		begin   
       			dat[4:0] <= 5'b11011 ^ {data_in[3:0],1'b0};  
      		end 
     	end 
     	assign data_out = dat;
    endmodule
    

    x的更高次乘法可以通过重复应用x的乘法实现Verilog代码:
    用空间换取时间,组合逻辑只需要一个时钟周期

    module mul(	
    	input[7:0] data_in,	
    	input[7:0] data_sys,	
    	output[7:0] data_out
    );	
    	reg [7:0] dat1 [7:0];	
    	reg [7:0] dat;		
    	always @(data_in,data_sys)	
    	begin		
    		dat1[0] = data_in;		
    		dat1[1] = {data_in[6:0],1'b0};		
    		dat = 8'b00000000;		
    		if(data_in[7] == 1)		
    		begin			
    			dat1[1][4:0] = 5'b11011 ^ {data_in[3:0],1'b0};		
    		end		
    		dat1[2] = {dat1[1][6:0],1'b0};		
    		if(dat1[1][7] == 1)		
    		begin			
    			dat1[2][4:0] = 5'b11011 ^ {dat1[1][3:0],1'b0};		
    		end		
    		dat1[3] = {dat1[2][6:0],1'b0};		
    		if(dat1[2][7] == 1)		
    		begin			
    			dat1[3][4:0] = 5'b11011 ^ {dat1[2][3:0],1'b0};
    		end		
    		dat1[4] = {dat1[3][6:0],1'b0};		
    		if(dat1[3][7] == 1)		
    		begin			
    			dat1[4][4:0] = 5'b11011 ^ {dat1[3][3:0],1'b0};		
    		end		
    		dat1[5] = {dat1[4][6:0],1'b0};		
    		if(dat1[4][7] == 1)		
    		begin			
    			dat1[5][4:0] = 5'b11011 ^ {dat1[4][3:0],1'b0};		
    		end		
    		dat1[6] = {dat1[5][6:0],1'b0};		
    		if(dat1[5][7] == 1)		
    		begin			
    			dat1[6][4:0] = 5'b11011 ^ {dat1[5][3:0],1'b0};		
    		end		
    		dat1[7] = {dat1[6][6:0],1'b0};		
    		if(dat1[6][7] == 1)		
    		begin			
    			dat1[7][4:0] = 5'b11011 ^ {dat1[6][3:0],1'b0};		
    		end		
    		if(data_sys[0]) dat = dat1[0];		
    		if(data_sys[1]) dat = dat ^ dat1[1];		
    		if(data_sys[2]) dat = dat ^ dat1[2];		
    		if(data_sys[3]) dat = dat ^ dat1[3];		
    		if(data_sys[4]) dat = dat ^ dat1[4];		
    		if(data_sys[5]) dat = dat ^ dat1[5];		
    		if(data_sys[6]) dat = dat ^ dat1[6];		
    		if(data_sys[7]) dat = dat ^ dat1[7];	
    		end	
    	assign data_out = dat;
    endmodule
    
    展开全文
  • 非常值得参考的是官方文档,它详细介绍了AES及其实验过程。博文AES加密算法的C++实现就是基于该文档的介绍及实现,是难得的一篇好文,故在本文最后会附上该文,以作备份。
  • 博文AES加密算法的C++实现就是基于该文档的介绍及实现,是难得的一篇好文,故在本文最后会附上该文,以作备份。  还有很值得推荐的就是AES的动画演示,做的很形象,非常有助于理解!  对AES而言,它采用了“代换...

       非常值得参考的是官方文档,它详细介绍了AES及其实验过程。博文AES加密算法的C++实现就是基于该文档的介绍及实现,是难得的一篇好文,故在本文最后会附上该文,以作备份。

      还有很值得推荐的就是AES的动画演示,做的很形象,非常有助于理解!

        对AES而言,它采用了“代换-置换网络”结构(Substitution-Permutation Network, SPN)。其最复杂的计算在于列混淆,而列混淆的复杂又来自有限域的乘法;另外,一方面,我们还要考虑加密过程中需要考虑的字节填充。下边将进行介绍。

    1. 有限域乘法

      这部分主要参考自《密码编码学与网络安全——原理与实践》(第五版)(P. 96-97)。

      在该书中,作者提到“本质上说,域就是一个集合,我们可以在其上进行加法、减法、乘法和除法而不脱离该集合”。有限域是域的一种,它指的是阶(元素个数,记为p)有限的域,记为GF(p),其中有限域的阶必须是一个素数的幂p'^n(p'为素数,n为正整数)。GF(2^n)是在密码学中用得很多的有限域,它表示该域总共只有2^n个元素。特别地,GF(2^8)被用于AES的加解密。GF(2^8)是一个包含256个元素的域,它的每一个元素被赋值为0~2^8-1中的唯一整数(注意这里提到的,它意味着GF(2^8)的每一个元素同样可以取其他范围的值(不在0~2^8-1),但就是要满足域的条件)。在AES中,用到的有限域是GF(2^8),它的每一个元素被赋值为0~2^8-1中的唯一整数。

      同时,在该书中,作者还提出GF(2^n)的乘法计算公式如下:

     

      

      详细推导请参考该书P. 96。

      下边参考博文有限域GF(2^8)内乘法代码实现以及原理(这篇博文开头对有限域的说明有点问题,作者貌似是把有限域理解成因为该域内的元素的值是有范围的,所以才叫有限域)的例子来说明如何进行GF(2^8)有限域乘法。

      在二进制中,所有的数都能用0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80异或得到,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80的二进制表示如下:

      

          后一个分别是前一个的2倍。假设任意一个数a,他的二进制表示为10101101,可以由以下组合组成:

      

           而任何一个数x和a相乘都可以表示为

      

      所以只要计算出

      

    最后再对这些结果进行异或就可以求出最终的乘法结果。那如何求0x3a*0x24?

          首先0x3a=00111010,分别求

      

      0x24=00100100,所以0x3a*0x24=0x3a*00100100=0x04*0x3a^0x20*0x3a=0xe8^0x01=0xe9.

      作者还附带了一个C/C++程序来计算GF(2^8)有限域乘法:

    unsigned char XTIME(unsigned char x) 
    {
        return ((x << 1) ^ ((x & 0x80) ? 0x1b : 0x00));
    }
    unsigned char multiply(unsigned char a, unsigned char b) 
    {
        unsigned char temp[8] = { a };
        unsigned char tempmultiply = 0x00;
        int i = 0;
        for (i = 1; i < 8; i++) 
        {
            temp[i] = XTIME(temp[i - 1]);
        }
        tempmultiply = (b & 0x01) * a;
        for (i = 1; i <= 7; i++) 
        {
            tempmultiply ^= (((b >> i) & 0x01) * temp[i]);
        }
        return tempmultiply;
    }

      关于程序的解释可以参考该博文。

    2. 字节填充

      AES是分块计算,当数据内容不足,16字节(128 bit AES),24字节(192 bit AES),32字节(256 bit AES),不足部分就需要填充。维基百科翻译)上面列举填充方式有如下几种:
      1)ANSI X.923
      不足部分填充0,最后一字节为填充字节数。如下面8字节的块,需要填充4字节时:
      … | DD DD DD DD DD DD DD DD | DD DD DD DD 00 00 00 04 |
      2)ISO 10126
      不足部分填充随机数字,最后一字节为填充字节数。如下面8字节的块,需要填充4字节时:
      … | DD DD DD DD DD DD DD DD | DD DD DD DD BC DA EF 04 |
      3)PKCS7与PKCS5
      不足部分填充为需要填充字节数。若数据大小是分块大小N的倍数时,则增加一个全为N的分块。如下面8字节的块,需要填充4字节时:
      … | DD DD DD DD DD DD DD DD | DD DD DD DD 04 04 04 04 |
      4)ISO/IEC 7816-4
      不足的部分,首先填充一个0×80,剩余部分全为0。如下面8字节的块,需要填充4字节时:
      … | DD DD DD DD DD DD DD DD | DD DD DD DD 80 00 00 00 |
      要求数据内容本身不包含0×80
      5)Zero padding
      不足部分全部填充0。如下面8字节的块,需要填充4字节时:
      … | DD DD DD DD DD DD DD DD | DD DD DD DD 00 00 00 00 |
      这种方法不能区分数据内容本身末尾包含0的情况,因而也不是标准的填充方式。

      本人在实现的时候采用的是ANSI X.923标准。

     

    3. 个人实现

       代码请见Github.

    4. 博文AES加密算法的C++实现摘录

      摘要:作为新一代的加密标准,AES 旨在取代 DES(请看《DES加密算法的C++实现》),以适应当今分布式开放网络对数据加密安全性的要求。本文在分析了 AES 加密原理的基础上着重说明了算法实现的具体步骤,并用 C++ 实现了对文件的加密和解密。

      一、AES 介绍

      AES(高级加密标准,Advanced Encryption Standard),在密码学中又称 Rijndael 加密法,是美国联邦政府采用的一种分组加密标准。这个标准用来替代原先的 DES,目前已经广为全世界所使用,成为对称密钥算法中最流行的算法之一。

      在 AES 出现之前,最常用的对称密钥算法是 DES 加密算法,它在 1977 年被公布成为美国政府的商用加密标准。DES 的主要问题是密钥长度较短,渐渐不适合于分布式开放网络对数据加密安全性的要求。因此,1998年美国政府决定不再继续延用 DES 作为联邦加密标准,并发起了征集 AES 候选算法的活动。征集活动对 AES 的基本要求是: 比三重DES快、至少与三重DES一样安全、数据分组长度为128比特、密钥长度为128/192/256比特。

      经过三年多的甄选,比利时的密码学家所设计的 Rijndael 算法最终脱颖而出,成为新一代的高级加密标准,并于 2001 年由美国国家标准与技术研究院(NIST)发布于 FIPS PUB 197

      二、AES 算法原理

      AES算法(即 Rijndael 算法)是一个对称分组密码算法。数据分组长度必须是 128 bits,使用的密钥长度为 128,192 或 256 bits。对于三种不同密钥长度的 AES 算法,分别称为“AES-128”、“AES-192”、“AES-256”。(Rijndael 的设计还可以处理其它的分组长度和密钥长度,但 AES 标准中没有采用)

      下图是 AES 加密解密的整体流程图:

      

      这里我们需要知道3个符号:Nb—— 状态 State 包含的列(32-bit 字)的个数,也就是说 Nb=4;Nk—— 密钥包含的 32-bit 字的个数,也就是说 Nk=4,6 或 8;Nr—— 加密的轮数,对于不同密钥长度,轮数不一样,具体如下图所示:

      

      下面分为密钥扩展、分组加密、分组解密三个部分来讲 AES 算法,我会尽可能地简明扼要,若还有不懂的,请自行 Google。

      1)密钥扩展

      AES 算法通过密钥扩展程序(Key Expansion)将用户输入的密钥 K 扩展生成 Nb(Nr+1)个字,存放在一个线性数组w[Nb*(Nr+1)]中。具体如下:

    1. 位置变换函数RotWord(),接受一个字 [a0, a1, a2, a3] 作为输入,循环左移一个字节后输出 [a1, a2, a3, a0]。

    2. S盒变换函数SubWord(),接受一个字 [a0, a1, a2, a3] 作为输入。S盒是一个16x16的表,其中每一个元素是一个字节。对于输入的每一个字节,前四位组成十六进制数 x 作为行号,后四位组成的十六进制数 y 作为列号,查找表中对应的值。最后函数输出 4 个新字节组成的 32-bit 字。

    3. 轮常数Rcon[],如何计算的就不说了,直接把它当做常量数组。

    4. 扩展密钥数组w[]的前 Nk 个元素就是外部密钥 K,以后的元素w[i]等于它前一个元素w[i-1]与前第 Nk 个元素w[i-Nk]的异或,即w[i] = w[i-1] XOR w[i-Nk];但若 i 为 Nk 的倍数,则w[i] = w[i-Nk] XOR SubWord(RotWord(w[i-1])) XOR Rcon[i/Nk-1]

      注意,上面的第四步说明适合于 AES-128 和 AES-192,详细的伪代码如下:

      

      密钥扩展程序的 C++ 代码(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需要 10 轮加密
      8 const int Nk = 4;   // Nk 表示输入密钥的 word 个数
      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 // 轮常数,密钥扩展中用到。(AES-128只需要10轮)
     30 word Rcon[10] = { 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
     31 0x20000000, 0x40000000, 0x80000000, 0x1b000000, 0x36000000 };
     32 
     33 /**
     34 * 将4个 byte 转换为一个 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 *  按字节 循环左移一位
     56 *  即把[a0, a1, a2, a3]变成[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 *  对输入word中的每一个字节进行S-盒变换
     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 *  密钥扩展函数 - 对128位密钥进行扩展得到 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     // w[]的前4个就是输入的key
     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]; // 记录前一个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     // 测试
    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 }
    KeyExpansion

      测试输出结果:

      

      2)加密

      根据 AES 加密的整体流程图(本文开头),伪代码如下:

      

      从伪代码描述中可以看出,AES 加密时涉及到的子程序有SubBytes()ShiftRows()MixColumns()AddRoundKey()。下面我们一个一个进行介绍:

      ① S盒变换-SubBytes()

      在密钥扩展部分已经讲过了,S盒是一个 16 行 16 列的表,表中每个元素都是一个字节。S盒变换很简单:函数SubBytes()接受一个 4x4 的字节矩阵作为输入,对其中的每个字节,前四位组成十六进制数 x 作为行号,后四位组成的十六进制数 y 作为列号,查找表中对应的值替换原来位置上的字节。

      ② 行变换-ShiftRows()

    行变换也很简单,它仅仅是将矩阵的每一行以字节为单位循环移位:第一行不变,第二行左移一位,第三行左移两位,第四行左移三位。如下图所示:

      

      ③ 列变换-MixColumns()

      函数MixColumns()同样接受一个 4x4 的字节矩阵作为输入,并对矩阵进行逐列变换,变换方式如下:

      

      注意公式中用到的乘法是伽罗华域(GF,有限域)上的乘法,高级加密标准文档 fips-197 上有讲,如果还是不懂,请自行Google。

      

      ④ 与扩展密钥的异或-AddRoundKey()

      扩展密钥只参与了这一步。根据当前加密的轮数,用w[]中的 4 个扩展密钥与矩阵的 4 个列进行按位异或。如下图:

      

      好了,到这里 AES 加密的各个部分就讲完了。算法实现的 C++ 源码在文章后面第三部分。

       3)解密

      根据 AES 解密的整体流程图(本文开头),伪代码如下:

      

      从伪代码可以看出,我们需要分别实现 S 盒变换、行变换和列变换的逆变换InvShiftRows()InvSubBytes()InvMixColumns()。下面就简单的讲一下这三个逆变换:

      ① 逆行变换-InvShiftRows()

      上面讲到ShiftRows()是对矩阵的每一行进行循环左移,所以InvShiftRows()是对矩阵每一行进行循环右移。

      

      ② 逆 S 盒变换-InvSubBytes()

      与 S 盒变换一样,也是查表,查表的方式也一样,只不过查的是另外一个置换表(S-Box的逆表)。

      ③ 逆列变换-InvMixColumns()

      与列变换的方式一样,只不过计算公式的系数矩阵发生了变化。如下图:

      

      好了,AES 解密到这里也讲完了。只要写出三个逆变换的函数,然后根据伪代码就很容易实现 AES 解密算法了。

      三、C++实现

      下面我用 C++ 实现 AES 的加密和解密算法,并实现了对文件的加密和解密。这里我使用 C++ STL 的bitset定义了两个类型:byteword。需要提到的是,对于有限域上的乘法,我们既可以通过查表(6个结果表),也可以写一个函数来实现。当然,查表的效率会更高,但考虑到贴代码,这里我就用一个函数来实现的。

      下面是 AES-128 对一个 128 位数据加密和解密的源代码:

      1 /*************************************************************************
      2 > File Name: AES.cpp
      3 > Author: SongLee
      4 > E-mail: lisong.shine@qq.com
      5 > Created Time: 2014年12月12日 星期五 20时15分50秒
      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需要 10 轮加密
     16 const int Nk = 4;   // Nk 表示输入密钥的 word 个数
     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 // 轮常数,密钥扩展中用到。(AES-128只需要10轮)
     57 word Rcon[10] = { 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
     58 0x20000000, 0x40000000, 0x80000000, 0x1b000000, 0x36000000 };
     59 
     60 /**********************************************************************/
     61 /*                                                                    */
     62 /*                              AES算法实现                           */
     63 /*                                                                    */
     64 /**********************************************************************/
     65 
     66 /******************************下面是加密的变换函数**********************/
     67 /**
     68 *  S盒变换 - 前4位为行号,后4位为列号
     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 *  行变换 - 按字节循环移位
     82 */
     83 void ShiftRows(byte mtx[4 * 4])
     84 {
     85     // 第二行循环左移一位
     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     // 第三行循环左移两位
     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     // 第四行循环左移三位
     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 *  有限域上的乘法 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 *  列变换
    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 *  轮密钥加变换 - 将每一列与扩展密钥进行异或
    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 /**************************下面是解密的逆变换函数***********************/
    162 /**
    163 *  逆S盒变换
    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 *  逆行变换 - 以字节为单位循环右移
    177 */
    178 void InvShiftRows(byte mtx[4 * 4])
    179 {
    180     // 第二行循环右移一位
    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     // 第三行循环右移两位
    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     // 第四行循环右移三位
    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 /******************************下面是密钥扩展部分***********************/
    215 /**
    216 * 将4个 byte 转换为一个 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 *  按字节 循环左移一位
    238 *  即把[a0, a1, a2, a3]变成[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 *  对输入word中的每一个字节进行S-盒变换
    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 *  密钥扩展函数 - 对128位密钥进行扩展得到 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     // w[]的前4个就是输入的key
    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]; // 记录前一个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 /******************************下面是加密和解密函数**************************/
    292 /**
    293 *  加密
    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 *  解密
    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 /*                              测试                                  */
    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     // 输出密钥
    363     cout << "密钥是:";
    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     // 输出待加密的明文
    372     cout << endl << "待加密的明文:" << 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     // 加密,输出密文
    382     encrypt(plain, w);
    383     cout << "加密后的密文:" << 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     // 解密,输出明文
    393     decrypt(plain, w);
    394     cout << "解密后的明文:" << 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 }
    View Code

      测试用例如下图:

      

      测试结果截图:

      

      可见,测试结果和预期输出相同,表明对数据的加密和解密成功!!!

      下面我们来写 AES 对文件的加密和解密,在对 128 位的数据加解密成功以后,对文件的加解密就很简单了!只需要每次读 128 位,加密以后,将 128 位的密文写入另外一个文件…..如此循环,直到文件尾。下面是对一张图片进行 AES 加密和解密的测试代码(效率先不管了,有时间我再优化):

     1 //#include <fstream>
     2 typedef bitset<8> byte;
     3 typedef bitset<32> word;
     4 /**
     5 *  将一个char字符数组转化为二进制
     6 *  存到一个 byte 数组中
     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 *  将连续的128位分成16组,存到一个 byte 数组中
    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 *  将16个 byte 合并成连续的128位
    30 */
    31 bitset<128> mergeByte(byte in[16])
    32 {
    33     bitset<128> res;
    34     res.reset();  // 置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     // 密钥扩展
    51     word w[4 * (Nr + 1)];
    52     KeyExpansion(key, w);
    53 
    54     bitset<128> data;
    55     byte plain[16];
    56     // 将文件 flower.jpg 加密到 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();  // 置0
    68     }
    69     in.close();
    70     out.close();
    71 
    72     // 解密 cipher.txt,并写入图片 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();  // 置0
    82     }
    83     in.close();
    84     out.close();
    85 
    86     return 0;
    87 }
    View Code

      (全文完)

     

      更新 —— 2014.12.21

      有限域 GF(28) 上的乘法改用查表的方式实现,AES的加密速度马上提升 80% 以上,所以建议最好使用查表的方式。下面是 AES 算法中用到的 6 个乘法结果表:

     

      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 };
    View Code

     

    转载于:https://www.cnblogs.com/xiehongfeng100/p/4315395.html

    展开全文
  • AES有限域的多项式乘法逆元求解

    千次阅读 2017-11-07 17:23:00
    求解算法,扩展的欧几里得算法 /* @author tilltheendwjx @blog http://blog.csdn.net/wjh200821或者http://www.cnblogs.com/tilltheendwjx/ */ #include using namespace std; int indexofmax1(int value) { in

    题目:


    求解算法,扩展的欧几里得算法

    /*
    @author tilltheendwjx
    @blog http://blog.csdn.net/wjh200821或者http://www.cnblogs.com/tilltheendwjx/ 
    */ 
    #include<iostream>
    using namespace std;
    int indexofmax1(int value)
    {
        int tmp=1;
        int count=0;
        for(int i=0;i<sizeof(int)*8;++i)
        {
              if((value&tmp))
                 count=i;
              tmp=tmp*2;
        }
        return count;
    }
    void polynomialtostring(int value)
    {
        int tmp=1;
        int flag=0;
        int c=indexofmax1(value);
        for(int i=0;i<sizeof(int)*8;++i)
        {
              if((value&tmp))
              {
                 if(i==0)
                 {
                   cout<<"1";
                 }else if(i==1)
                 {
                   cout<<"x";
                 }else
                 {
                   cout<<"x^"<<i;
                 }
                 flag=1;
                 if(i<c)
                   cout<<"+";
              }   
              tmp=tmp*2;
        }
        if(flag==0)
          cout<<"0";
    }
    int powofvalue(int value)
    {
        return 1<<(value);
    }
    int divide(int m,int b,int &remainvalue)
    {
        int mindex=indexofmax1(m);
        int vindex=indexofmax1(b);
        if(mindex<vindex)
        {
            remainvalue=m;
            return 0;
        }
        int c=mindex-vindex;
        int tmp=b;
        tmp=tmp<<c;
        m=m^tmp;
        return powofvalue(c)|divide(m,b,remainvalue);
    }
    int Tx(int ax,int q,int bx)
    {
        //cout<<endl;
        //cout<<ax<<"\t"<<bx<<"\t";
        int tmp=1;
        int value=0;
        for(int i=0;i<sizeof(int)*8;++i)
        {
              if((q&tmp))
              {
                 value=value^((bx<<i));   
              }   
              tmp=tmp*2;
        }
        //cout<<ax<<"\t"<<value<<"\t";
        //cout<<endl;
        return ax^(value);
    }
    int extent_gcd(int m,int b,int &x,int &y)
    {
       int a1=1,a2=0,a3=m;
       int b1=0,b2=1,b3=b;
       int remainvalue=0;
       while(1)
       {
               polynomialtostring(a1);
               cout<<"    ";
               polynomialtostring(a2);
               cout<<"    ";
               polynomialtostring(a3);
               cout<<"    ";
               polynomialtostring(b1);
               cout<<"    ";
               polynomialtostring(b2);
               cout<<"    ";
               polynomialtostring(b3);
               cout<<"    ";
              if(b3==0)
                  return a3;
              if(b3==1)
                   return b3;
              int q=divide(a3,b3,remainvalue);
              int t1=Tx(a1,q,b1);
              int t2=Tx(a2,q,b2);
              int t3=remainvalue;
              cout<<t1<<endl;
              cout<<t2<<endl;
              a1=b1;a2=b2;a3=b3;
              b1=t1;b2=t2;b3=t3;
              x=b2;y=b3;
              polynomialtostring(q);
              cout<<endl;
       } 
    }
    int main(void)
    {
    int m=283,b=83,x=0,y=0;
    cout<<"中间结果如下:"<<endl; 
    cout<<"a1   a2    a3    b1    b2    b3    q"<<endl;
    int reault=extent_gcd(m,b,x,y);
    cout<<endl;
    cout<<"多项式(";polynomialtostring(b);cout<<")mod(";polynomialtostring(m);cout<<")的乘法逆元是(";polynomialtostring(x);cout<<")"<<endl;
    system("pause"); 
    return 0;
    }
    

    运行结果如下图


    展开全文
  • AES算法

    2020-01-22 10:04:18
    一、实验目的及要求 1. 掌握AES算法的原理 2.... 二、实验设备(环境)及要求 ... 建立s盒矩阵、轮常量表、辅助函数(有限域*2乘法、*3、*4、*8等),以及逆s盒矩阵。 接下来编写字...

    一、实验目的及要求

    1. 掌握AES算法的原理

    2. 编写程序实现这个算法

     

    二、实验设备(环境)及要求

       PC机, VC++等

    三、实验内容与步骤

    1、AES(对代码中的主要内容进行分析讲解)

    步骤:

    1. 建立s盒矩阵、轮常量表、辅助函数(有限域*2乘法、*3、*4、*8等),以及逆s盒矩阵。
    2. 接下来编写字节代替,通过s盒,s盒字节代换替换明文,以及它的逆过程;
    3. 接下来就是行移位操作,将矩阵的第k行循环左移k-1位,以及它的逆操作,就是将矩阵的第k行循环右移k-1位。
    4. 然后编写列混淆操作:用一个常数矩阵去乘以矩阵state来得到新的state矩阵,以及它的逆过程使用另一个常数矩阵去乘以矩阵state来得到新的state矩阵。
    5. 接着编写轮密钥加:将state矩阵与密钥矩阵相异或。
    6. 接着编写密钥扩展:第0组,[0-3]直接拷贝;第1-10组,将k循环左移一个字节,分别对每个字节按S盒进行映射,与32 bits的常量(RCON/4],0,0,0)进行异或。
    7. 最后编写加密函数:第0轮时轮密钥加,第1-9轮按顺序执行2-5步骤,第10轮执行2、3、5步骤。解密函数为其的逆过程。

    代码:

    #include <stdio.h>
    /*aes_small.c*/
    //辅助矩阵
    /*s盒矩阵:The AES Substitution Table*/// 256 位的密匙256 位支持长度为32 个字符
    static const unsigned char sbox[256]={	//static:内部变量  const:只读,不可变常量
    	0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,
    	0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,
    	0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,
    	0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
    	0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,
    	0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,
    	0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,
    	0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,
    	0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,
    	0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,
    	0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,
    	0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
    	0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,
    	0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
    	0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,
    	0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,
    	0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,
    	0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,
    	0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,
    	0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
    	0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,
    	0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,
    	0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,
    	0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,
    	0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,
    	0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
    	0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,
    	0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,
    	0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,
    	0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,
    	0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,
    	0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16,
    };
    //逆向S 盒矩阵
    static const unsigned char contrary_sbox[256]={
    	0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38,
    	0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb,
    	0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87,
    	0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb,
    	0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d,
    	0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e,//0x4e
    	0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2,
    	0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25,
    	0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16,
    	0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92,
    	0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda,
    	0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84,
    	0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a,
    	0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06,
    	0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02,
    	0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b,
    	0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea,
    	0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73,
    	0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85,
    	0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e,
    	0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89,
    	0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b,
    	0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20,
    	0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4,
    	0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31,
    	0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f,
    	0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d,
    	0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef,
    	0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0,
    	0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61,
    	0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26,
    	0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d,
    };
    /*轮常量表 The key schedule rcon table*/
    static const unsigned char Rcon[10]={
    	0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1b,0x36};
     
    //辅助函数
    /*有限域*2乘法 The x2time() function */
    static unsigned char x2time(unsigned char x)
    {
    	if (x&0x80)
    	{
    		return (((x<<1)^0x1B)&0xFF);
    	}
    	return x<<1;
    }
    /*有限域*3乘法 The x2time() function */
    static unsigned char x3time(unsigned char x)
    {
    	return (x2time(x)^x);
    }
    /*有限域*4乘法 The x4time() function */
    static unsigned char x4time(unsigned char x)
    {
    	return ( x2time(x2time(x)) );
    }
    /*有限域*8乘法 The x8time() function */
    static unsigned char x8time(unsigned char x)
    {
    	return ( x2time(x2time(x2time(x))) );
    }
    /*有限域9乘法 The x9time() function */
    static unsigned char x9time(unsigned char x)	//9:1001
    {
    	return ( x8time(x)^x );
    }
    /*有限域*B乘法 The xBtime() function */
    static unsigned char xBtime(unsigned char x)	//B:1011
    {
    	return ( x8time(x)^x2time(x)^x );
    }
    /*有限域*D乘法 The xDtime() function */
    static unsigned char xDtime(unsigned char x)	//D:1101
    {
    	return ( x8time(x)^x4time(x)^x );
    }
    /*有限域*E乘法 The xEtime() function */
    static unsigned char xEtime(unsigned char x)	//E:1110
    {
    	return ( x8time(x)^x4time(x)^x2time(x) );
    }
     
    
    /*第三类操作:列混淆*/
    static void MixColumns(unsigned char *col)//列混合
    {
    	unsigned char tmp[4],xt[4];
    	int i;
    	for(i=0;i<4;i++,col+=4)  //col代表一列的基地址,col+4:下一列的基地址
    	{
    		
    		tmp[0]=x2time(col[0])^x3time(col[1])^col[2]^col[3];	//2 3 1 1
    		tmp[1]=col[0]^x2time(col[1])^x3time(col[2])^col[3];	//1 2 3 1
    		tmp[2]=col[0]^col[1]^x2time(col[2])^x3time(col[3]);	//1 1 2 3
    		tmp[3]=x3time(col[0])^col[1]^col[2]^x2time(col[3]);	//3 1 1 2
    		//修改后的值 直接在原矩阵上修改
    		col[0]=tmp[0];
    		col[1]=tmp[1];
    		col[2]=tmp[2];
    		col[3]=tmp[3];
    	}
    }
    //逆向列混淆
    static void Contrary_MixColumns(unsigned char *col)
    {
    	unsigned char tmp[4];
    	unsigned char xt2[4];//colx2
    	unsigned char xt4[4];//colx4
    	unsigned char xt8[4];//colx8
    	int x;
    	for(x=0;x<4;x++,col+=4)
    	{
    		
    		tmp[0]=xEtime(col[0])^xBtime(col[1])^xDtime(col[2])^x9time(col[3]);
    		tmp[1]=x9time(col[0])^xEtime(col[1])^xBtime(col[2])^xDtime(col[3]);
    		tmp[2]=xDtime(col[0])^x9time(col[1])^xEtime(col[2])^xBtime(col[3]);
    		tmp[3]=xBtime(col[0])^xDtime(col[1])^x9time(col[2])^xEtime(col[3]);
    		col[0]=tmp[0];
    		col[1]=tmp[1];
    		col[2]=tmp[2];
    		col[3]=tmp[3];
    	}
    }
    /*第二类操作:行移位*/
    static void ShiftRows(unsigned char *col)//正向行移位
    {
    	
    	unsigned char t;
    	/*1nd row*///左移1位
    	t=col[1];col[1]=col[5];col[5]=col[9];col[9]=col[13];col[13]=t;
    	/*2rd row*///左移2位,交换2次数字来实现
    	t=col[2];col[2]=col[10];col[10]=t;
    	t=col[6];col[6]=col[14];col[14]=t;
    	/*3th row*///左移3位,相当于右移1次
    	t=col[15];col[15]=col[11];col[11]=col[7];col[7]=col[3];col[3]=t;
    	/*4th row*/	//第4行不移位
    }
    //逆向行移位
    static void Contrary_ShiftRows(unsigned char *col)
    {
    	unsigned char t;
    	/*1nd row*/
    	t=col[13];col[13]=col[9];col[9]=col[5];col[5]=col[1];col[1]=t;
    	/*2rd row*/
    	t=col[2];col[2]=col[10];col[10]=t;
    	t=col[6];col[6]=col[14];col[14]=t;
    	/*3th row*/
    	t=col[3];col[3]=col[7];col[7]=col[11];col[11]=col[15];col[15]=t;
    	/*4th row*/	//第4行不移位
    }
    /*第一类操作:字节代换*/
    static void SubBytes(unsigned char *col)//字节代换
    {
    	int x;
    	for(x=0;x<16;x++)
    	{
    		col[x]=sbox[col[x]];
    	}
    }
    //逆向字节代换
    static void Contrary_SubBytes(unsigned char *col)
    {
    	int x;
    	for(x=0;x<16;x++)
    	{
    		col[x]=contrary_sbox[col[x]];
    	}
    }
    /*第四类操作:轮密钥加 */
    static void AddRoundKey(unsigned char *col,unsigned char *expansionkey,int round)//密匙加
    {
    	
    	int x;				
    	for(x=0;x<16;x++)	
    	{
    		col[x]^=expansionkey[(round<<4)+x];
    	}
    }
    /* AES加密总函数 10轮4类操作 Encrypt a single block with Nr Rounds(10,12,14)*/
    void AesEncrypt(unsigned char *blk,unsigned char *expansionkey,int Nr)//加密一个区块
    {
    	
    	int round;
    	//第0轮:轮密钥加
    	AddRoundKey(blk,expansionkey,0);
    	//第1-9轮:4类操作:字节代换、行移位、列混合、轮密钥加
    	for(round=1;round<=(Nr-1);round++)	
    	{
    		SubBytes(blk);		//输入16字节数组,直接在原数组上修改
    		ShiftRows(blk);		//输入16字节数组,直接在原数组上修改
    		MixColumns(blk);	//输入16字节数组,直接在原数组上修改
    		AddRoundKey(blk,expansionkey,round);
    	}
    	//第10轮:不进行列混合
    	SubBytes(blk);
    	ShiftRows(blk);
    	AddRoundKey(blk,expansionkey,Nr);
    }
    //AES 解密总函数
    void Contrary_AesEncrypt(unsigned char *blk,unsigned char *expansionkey,int Nr)
    {
    	int x;
    
    	AddRoundKey(blk,expansionkey,Nr);
    	Contrary_ShiftRows(blk);
    	Contrary_SubBytes(blk);
    	for(x=(Nr-1);x>=1;x--)
    	{
    		AddRoundKey(blk,expansionkey,x);
    		Contrary_MixColumns(blk);
    		Contrary_ShiftRows(blk);
    		Contrary_SubBytes(blk);
    	}
    	AddRoundKey(blk,expansionkey,0);
    }
    
    void ScheduleKey(unsigned char *inkey,unsigned char *outkey,int Nk,int Nr)//密钥扩展
    {
    
    	unsigned char temp[4],t;
    	int x,i;
    
    	for(i=0;i<(4*Nk);i++)
    	{
    		outkey[i]=inkey[i];
    	}
    	//第1-10组:[4-43]
    	i=Nk;
    	while(i<(4*(Nr+1)))
    	{
    		for(x=0;x<4;x++) 
    			temp[x]=outkey[(4*(i-1))+x];	
    		//i是4的倍数的时候
    		if(i%Nk==0)
    		{
    			/*字循环:循环左移1字节 RotWord()*/
    			t=temp[0];temp[0]=temp[1];temp[1]=temp[2];temp[2]=temp[3];temp[3]=t;
    			/*字节代换:SubWord()*/
    			for(x=0;x<4;x++)
    			{
    				temp[x]=sbox[temp[x]];
    			}
    			/*轮常量异或:Rcon[j]*/
    			temp[0]^=Rcon[(i/Nk)-1];
    		}
    	
    		for(x=0;x<4;x++)
    		{
    			outkey[(4*i)+x]=outkey[(4*(i-Nk))+x]^temp[x];
    		}
    		++i;
    	}
    }
    int main(void){
    	
     
    	unsigned char pt[17],key[17];
    	unsigned char expansionkey[15*16];
    	int i;
    	int j;
    	printf("please input plaintext(字符个数<=16)\n");
    	scanf("%s",pt);
    	printf("please input key(6<=字符个数<=16)\n");
    	scanf("%s",key);
     
    	/*加密*/
    	ScheduleKey(key,expansionkey,4,10);	//1、密钥扩展生成
    	AesEncrypt(pt,expansionkey,10);		//2、AES 加密
    	printf("密文: ");
    	for (i = 0; i < 16; i++) 
    	{
    		printf("%02x ", pt[i]);
    	}
    	printf("\n");
    	printf("\n");
     
    	/*解密*/
    	Contrary_AesEncrypt(pt,expansionkey,10);//AES 解密
    	printf("解密: ");
    	for (i = 0; i < 16; i++)
    	{
    		printf("%c ", pt[i]);
    	}
    	printf("\n");
    	printf("\n");
    	getchar();
    	return 0;
    }
    

    四、实验结果与数据处理

    五、分析与讨论

    通过这个实验,我明白了AES算法的4个过程及它们的实现方法:

    (1)轮密钥加:当前分组和扩展密钥的一部分进行按位XOR(异或)。

    (2)字节代替: 用一个S盒完成分组的字节到字节的代替。

    (3)行移位:一个简单的置换。

    (4)列混淆:利用域GF(28)上的算术特性的一个代替

     

    展开全文
  • AES算法简介

    2020-11-11 11:03:42
    AES算法简介转载自https://www.cnblogs.com/block2016/p/5596676.html 转载自https://www.cnblogs.com/block2016/p/5596676.html 本人主要对这篇对s盒的计算过程感兴趣。 AES是一个对称密码,旨在取代DES成为广泛...
  • AES算法学习总结

    千次阅读 2016-05-04 09:35:19
    AES加密算法研究分析 AES(The Advanced Encryption Standard)是美国国家标准与技术研究所用于加密电子数据的规范。它被预期能成为人们公认的加密包括金融、电信和政府数字信息的方法。本文展示了 AES的概貌并...
  • 什么是AES算法

    千次阅读 2020-02-02 20:37:52
    加密算法分为单向加密和双向加密。单向加密包括MD5,SHA等摘要算法。单向加密算法是不可逆的,也就是无法将加密后的数据恢复成原始数据,除非采取碰撞攻击和穷举的方式。像是银行账户密码的存储,一般采用的就是单向...
  • 分组密码之AES算法

    千次阅读 2017-05-19 11:40:00
    AES算法本质上是一种对称分组密码体制,采用代替/置换网络,每轮由三层组成:线性混合层确保多轮之上的高度扩散,非线性层由16个S盒并置起到混淆的作用,密钥加密层将子密钥异或到中间状态。AES是一个迭代分组密码,...
  • AES算法 Python实现

    2020-05-13 22:55:56
    AES加解密算法 Python实现 实现了AES加解密算法。初次尝试,能力有限,代码粗糙,仅供交流学习。五种工作模式也实现了,有需要的可以私聊我。 Talk is cheap. Show me the code.
  • AES算法介绍

    2009-03-24 10:36:56
    高级加密标准(Advanced Encryption Standard)美国国家技术标准委员会(NIST)在2000年10月选定了比利时的研究成果"Rijndael"作为AES的基础。...结合昨天提供的AES算法的Flash演示动画...
  • AES算法分析与实现

    2013-08-19 15:12:11
    AES算法的主要数学基础是抽象代数,其中算法中的许多运算是按单字节(8bits)和4字节(32bits)定义的,单字节可看成有限域GF(28)中的一个元素,而4字节则可以看成系数在GF(28)中并且次数小于4的多项式(亦可以理解...
  • AES加解密创作团队写的算法的pdf: https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/aes-development/rijndael-ammended.pdf xtime函数就是左移一位并且如果结果大于8...
  • AES加密算法的数学基础

    千次阅读 2018-04-14 22:58:01
    AES加密算法的数学基础 目录 AES加密算法的数学基础 目录 1.数学基础 1.1群的概念 1.2域的概念 ...有限域有时也称为伽罗瓦域,它指的是拥有有限个元素的集合。大致来讲, 伽罗瓦域是一个由有限个元素组...
  • 最近在复习现代密码理论中的AESAES中的字节变换的核心操作就是求GF(28)GF(2^8)GF(28)上的多项式逆元,这个问题困扰了我一段时间,今天终于得到解决,其实计算方式和数论中求两个数的Bezout算法是一样的,这里感谢...
  • 文章目录一、前言二、数学基础1、GF(2⁸)有限域内的多项式2、不可约多项式3、多项式模运算3、乘法逆元三、算法步骤1、扩展欧几里得算法2、多项式除法3、多项式乘法四、代码实现1、多项式除法2、多项式乘法3、...
  • 有限域中的乘法逆元

    万次阅读 2012-06-28 15:21:23
    本文介绍在有限域中求乘法逆元。包括对于整数和多项式的。利用了扩展的Euclid算法。有伟大的高德纳提出。 1. 乘法逆元w' :任意的w属于Zp, w!=0,存在z属于Zp使得w*z==1 (mod p); 举例如下:求5关于mod 14 的乘法...
  • 【密码学】DES算法和AES算法(Rijndael算法)数学原理及实现 背景 DES,Data Encryption Standard, 数据加密标准。 尽管DES是一个很宽泛的名字,但是它指代的只是一个具体的标准。它在1970年代被美国NBS接受为信息...
  • AES与DES一样都是迭代...AES的核心主要围绕着以下三个方面进行设计的:\color{gray}AES的核心主要围绕着以下三个方面进行设计的:AES的核心主要围绕着以下三个方面进行设计的: 加密算法 密钥生成算法 脱密算法 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 574
精华内容 229
关键字:

aes算法有限域乘法