基于FPGA的AES加密解密vivado仿真,verilog开发,包含testbench

发布时间 2023-04-08 22:42:22作者: 我爱C编程

1.算法描述

         AES, 高级加密标准, 是采用区块加密的一种标准, 又称Rijndael加密法. 严格上来讲, AESRijndael又不是完全一样, AES的区块长度固定为128比特, 秘钥长度可以是128, 192或者256. Rijndael加密法可以支持更大范围的区块和密钥长度, Rijndael使用的密钥和区块长度均可以是128192256比特. AES是对称加密最流行的算法之一.

 

       AES算法在对明文加密的时候,并不是把整个明文一股脑的加密成一整段密文,而是把明文拆分成一个个独立的明文块,每一个明文块长度128bit。这些明文块经过AES加密器复杂处理,生成一个个独立的密文块,这些密文块拼接在一起,就是最终的AES加密的结果。

 

       但这里涉及到一个问题,假如一段明文长度是196bit,如果按每128bit一个明文块来拆分的话,第二个明文块只有64bit,不足128bit。这时候怎么办呢?就需要对明文块进行填充(Padding) 。

 

       需要注意的是,如果在AES加密的时候使用了某一种填充方式,解密的时候也必须采用同样的填充方式。

 

        殊的加法和乘法。AES 所用的加法和乘法是基于数学(译者注:近世代数)的域论。尤其是 AES 基于有限域GF(2^8)

       GF(2^8)由一组从 0x00 0xff 256个值组成,加上加法和乘法,因此是(2^8)GF代表伽罗瓦域,以发明这一理论的数学家的名字命名。GF(2^8) 的一个特性是一个加法或乘法的操作的结果必须是在{0x00 ... 0xff}这组数中。虽然域论是相当深奥的,但GF(2^8)加法的最终结果却很简单。GF(2^8) 加法就是异或(XOR)操作。

        然而,GF(2^8)的乘法有点繁难。AES的加密和解密例程需要知道怎样只用七个常量 0x010x020x030x090x0b0x0d 0x0e 来相乘。所以我不全面介绍GF(2^8)的乘法,而只是针对这七种特殊情况进行说明。

  GF(2^8)中用0x01的乘法是特殊的;它相当于普通算术中用1做乘法并且结果也同样—任何值乘0x01等于其自身。

       现在让我们看看用0x02做乘法。和加法的情况相同,理论是深奥的,但最终结果十分简单。只要被乘的值小于0x80,这时乘法的结果就是该值左移1比特位。如果被乘的值大于或等于0x80,这时乘法的结果就是左移1比特位再用值0x1b异或。它防止了“域溢出”并保持乘法的乘积在范围以内。

       一旦你在GF(2^8)中用0x02建立了加法和乘法,你就可以用任何常量去定义乘法。用0x03做乘法时,你可以将 0x03 分解为2的幂之和。为了用 0x03 乘以任意字节b, 因为 0x03 = 0x02 + 0x01,因此:

b * 0x03 = b * (0x02 + 0x01) = (b * 0x02) + (b * 0x01)

       这是可以行得通的,因为你知道如何用 0x02 0x01 相乘和相加,同理,用0x0d去乘以任意字节b可以这样做:

 

b * 0x0d   = b * (0x08 + 0x04 + 0x01)

 

= (b * 0x08) + (b * 0x04) + (b * 0x01)

 

= (b * 0x02 * 0x02 * 0x02) + (b * 0x02 * 0x02) + (b * 0x01)

 

在加解密算法中,AES MixColumns 例程的其它乘法遵循大体相同的模式,如下所示:

 

b * 0x09   = b * (0x08 + 0x01)

 

= (b * 0x02 * 0x02 * 0x02) + (b * 0x01)b * 0x0b

 

= b * (0x08 + 0x02 + 0x01)

 

= (b * 0x02 * 0x02 * 0x02) + (b * 0x02) + (b * 0x01)b * 0x0e

 

= b * (0x08 +0x04 + 0x02)

 

= (b * 0x02 * 0x02 * 0x02) + (b * 0x02 * 0x02) + (b * 0x02)  

 

总之,在GF(2^8)中,加法是异或操作。其乘法将分解成加法和用0x02做的乘法,而用0x02做的乘法是一个有条件的左移1比特位。AES规范中包括大量有关GF(2^8)操作的附加信息。

 

         密钥是AES算法实现加密和解密的根本。对称加密算法之所以对称,是因为这类算法对明文的加密和解密需要使用同一个密钥。

 

AES支持三种长度的密钥: 128位,192位,256

 

        平时大家所说的AES128AES192AES256,实际上就是指AES算法对不同长度密钥的使用。三种密钥的区别:

 

         从安全性来看,AES256安全性最高。从性能看,AES128性能最高。本质原因是它们的加密处理轮数不同。

 

        AES原理:AES是对数据按128位,也就是16个字节进行分组进行加密的,每次对一组数据加密需要运行多轮,而输入密钥的长度可以为128192256位,也就是16个字节、24个字节和32个字节,如果用户输入的密钥长度不是这几种长度,也会补成这几种长度。

 

  无论输入密钥是多少字节,加密还是以16字节的数据一组来进行的,密钥长度的不同仅仅影响加密运行的轮数。

 

         AES算法是一个对称分组密码算法。数据分组长度必须是 128 bits,使用的密钥长度为 128192 256 bits。对于三种不同密钥长度的 AES 算法,分别称为“AES-128”、“AES-192”、“AES-256”。AES加密算法涉及4种操作:字节替代(SubBytes)、行移位(ShiftRows)、列混(MixColumns)和轮密钥加(AddRoundKey)。

 

​         从AES的加密和解密的流程图中可知:解密算法的每一步分别对应加密算法的逆操作。加解密所有操作的顺序正好是相反的,正是这样才保证了算法的正确性。加解密中每轮的密钥分别由种子密钥经过密钥扩展算法得到,算法中16字节的明文、密文和轮子密钥都以一个4x4的矩阵表示。

 

 

2.仿真效果预览

vivado2019.2仿真结果如下:

 

 

 

 

 

 

3.verilog核心程序

 

wire	[31:0]	w0, w1, w2, w3;
reg	[127:0]	text_in_r;
reg	[127:0]	text_out;
reg	[7:0]	sa00, sa01, sa02, sa03;
reg	[7:0]	sa10, sa11, sa12, sa13;
reg	[7:0]	sa20, sa21, sa22, sa23;
reg	[7:0]	sa30, sa31, sa32, sa33;
wire	[7:0]	sa00_next, sa01_next, sa02_next, sa03_next;
wire	[7:0]	sa10_next, sa11_next, sa12_next, sa13_next;
wire	[7:0]	sa20_next, sa21_next, sa22_next, sa23_next;
wire	[7:0]	sa30_next, sa31_next, sa32_next, sa33_next;
wire	[7:0]	sa00_sub, sa01_sub, sa02_sub, sa03_sub;
wire	[7:0]	sa10_sub, sa11_sub, sa12_sub, sa13_sub;
wire	[7:0]	sa20_sub, sa21_sub, sa22_sub, sa23_sub;
wire	[7:0]	sa30_sub, sa31_sub, sa32_sub, sa33_sub;
wire	[7:0]	sa00_sr, sa01_sr, sa02_sr, sa03_sr;
wire	[7:0]	sa10_sr, sa11_sr, sa12_sr, sa13_sr;
wire	[7:0]	sa20_sr, sa21_sr, sa22_sr, sa23_sr;
wire	[7:0]	sa30_sr, sa31_sr, sa32_sr, sa33_sr;
wire	[7:0]	sa00_mc, sa01_mc, sa02_mc, sa03_mc;
wire	[7:0]	sa10_mc, sa11_mc, sa12_mc, sa13_mc;
wire	[7:0]	sa20_mc, sa21_mc, sa22_mc, sa23_mc;
wire	[7:0]	sa30_mc, sa31_mc, sa32_mc, sa33_mc;
reg		done, ld_r;
reg	[3:0]	dcnt;
 
....................................................................
aes_key_expand_128 u0(
	.clk(		clk	),
	.kld(		ld	),
	.key(		key	),
	.wo_0(		w0	),
	.wo_1(		w1	),
	.wo_2(		w2	),
	.wo_3(		w3	));
 
aes_sbox us00(	.a(	sa00	), .d(	sa00_sub	));
aes_sbox us01(	.a(	sa01	), .d(	sa01_sub	));
aes_sbox us02(	.a(	sa02	), .d(	sa02_sub	));
aes_sbox us03(	.a(	sa03	), .d(	sa03_sub	));
aes_sbox us10(	.a(	sa10	), .d(	sa10_sub	));
aes_sbox us11(	.a(	sa11	), .d(	sa11_sub	));
aes_sbox us12(	.a(	sa12	), .d(	sa12_sub	));
aes_sbox us13(	.a(	sa13	), .d(	sa13_sub	));
aes_sbox us20(	.a(	sa20	), .d(	sa20_sub	));
aes_sbox us21(	.a(	sa21	), .d(	sa21_sub	));
aes_sbox us22(	.a(	sa22	), .d(	sa22_sub	));
aes_sbox us23(	.a(	sa23	), .d(	sa23_sub	));
aes_sbox us30(	.a(	sa30	), .d(	sa30_sub	));
aes_sbox us31(	.a(	sa31	), .d(	sa31_sub	));
aes_sbox us32(	.a(	sa32	), .d(	sa32_sub	));
aes_sbox us33(	.a(	sa33	), .d(	sa33_sub	));
 
endmodule