# AES密码算法
## 【实验目的】
1) 学习AES密码算法原理
2) 学习AES密码算法编程实现
## 【实验原理】
算法原理 
1997年美国国家标准技术研究所(NIST)向全球发起征集保护敏感联邦信息的对称密钥加密算法。
1999年8月上旬公布了对它们的第一轮评估结果,并选定了入围第二轮评估的五个算法(MARS, RC6, Rijndael,SERPENT and Twofish)。
这五个算法最终角逐,其中Rijndael于2000年9月被定为21世纪美国的高级加密标准(Advanced Encryption Standard—AES)。 AES的加解密过程见流程图,下面简述各个过程的具体实现。 密钥产生 AES首先将初始密钥按照列优先的顺序,输入到一个4*4矩阵中,如下图所示。
密钥扩展算法部分流程图
 

这个4*4矩阵的每一列的4个字节组成一个字,矩阵4列的4个字一次命名为w[0],w[1],w[2],w[3]。它们构成了一个以字为单位的数组w。
接着,对数组w扩充40个新列,构成总共44列的扩展密钥数组。新列按照以下的递归方式产生: 
(1)如果i不是4的倍数,那么第i列由如下等式确定:w[i]=w[i-4] ⨁w[i-1]; 
(2)如果i是4的倍数,那么第i列由如下等式确定:w[i]=w[i-4] ⨁T(w[i-1]),其中,T是一个复杂函数。这一过程如下图所示:
AES密钥扩展图
 
 函数T由3部分组成:字循环、字节代换和轮常量异或,这3部分的作用分别如下: 
(1)字循环:将1个字中的4个字节循环左移一个字节,即将输入字[b0,b1,b2,b3]变换成[b1,b2,b3,b0]。 
(2)字节代换:对字循环的结果使用AES的S盒进行字节代换。
(3)轮常量异或:将前两步的结果同轮常量Rcon[j]进行异或,其中j表示轮数。 
字节代换 
字节代换操作和字节代换逆操作 
AES的字节代换操作可以简化成一个简单的查表操作。AES定义了一个S盒和一个逆S盒。S盒用于加密查表,逆S盒用于解密查表。
他们都是由16*16字节组成的矩阵,即矩阵共有256元素,每个元素的内容是一个字节(8bit)的值,且每元素各不相同。 行移位 (1)行移位操作 此次操作中,只是将字节矩阵通过简单的左循环位移操作。当密钥长度为128bit时,状态矩阵的第Vi行左移i个字节,其中i=0,1,2,3。
这使得列完全进行了重排,即在移位后的每列中,都包含有未移位前每列的一个字节。 (2)行移位逆变换 行移位逆变换是将状态矩阵的每一列执行相反的移位操作,例如AES-128中,状态矩阵的第i行右移i个字节。 列混合 (1)列混合操作 列混合变换是通过矩阵相乘来实现的,经行移位后的状态矩阵与固定矩阵相乘,得到混淆后的状态矩阵,状态矩阵中的第j列(j=0,1,2,3)的列混合可以表示为:
(2)列混合逆运算 
逆向列混合变换可由下式的矩阵乘法定义: 
显然,逆变换矩阵同正交变换矩阵的乘积恰好为单位矩阵。
轮密钥加
轮密钥加是将128位轮密钥Ki同状态中的数据进行逐位异或操作。该过程可以看成是字逐位异或的结果,也可以看成字节级别或者位级别的操作。
算法参数
在执行AES算法操作时,主要用到的算法参数如下表1—表3所示,其中表1为轮常数值表,用于加解密时的密钥扩展;表2、表3为S盒置换表和逆S盒置换表,用于加解密过程中的字节代换。

 

 

算法流程
AES算法加解密的主要流程如下

 

 AES算法加解密流程图



## 【实验环境】
Windows 7
工具:C:\tools\密码学课程\01密码学算法\04 分组密码\03 aes密码算法
## 【实验步骤】
### 一、字符串加解密
1.1 运行文件【AES.exe】,程序运行界面。如图1所示

1.2 在第一个框格中输入【helloworld】,点击【字符串加密】,即可在第一个框格中输出密文。如图2所示
1.3 将得到的密文字符串拷贝到第二个框格中。如图3所示
1.4 点击【字符串解密】,即可得到明文。如图4所示
### 二、文件加解密
2.1 点击【浏览】,选择要加密的文件【aes-test.txt】(文件需要自己创建),如图5所示
2.2 文件内容。如图6所示
2.3 点击【文件加密】,会提示加密成功,并生成一个以【.en】,为后缀名的文件。如图7所示

2.4 点击【浏览】,选择加密后的文件,点击【文件解密】,即可生成一个以【.de】为后缀名的文件。如图8所示

2.5 用记事本打开文件【.de】,即可查看被解密的明文文件。如图9所示
### 三、源码阅读
下面是AES算法关键环节的源码。
`********************AES源码*********************`
```
ISD_Aes::ISD_KeyExpansion()             //密钥扩展
{

	memset(w,0,16*15);
	for(int row=0;row<Nk;row++)       //拷贝seed 密钥
	{
		w[4*row+0] =  key[4*row];
		w[4*row+1] =  key[4*row+1];
		w[4*row+2] =  key[4*row+2];
		w[4*row+3] =  key[4*row+3];
	}
	byte* temp = new byte[4];
	for(row=Nk;row<4*(Nr+1);row++)
	{
		temp[0]=w[4*row-4];     //当前列的前一列  
		temp[1]=w[4*row-3];
		temp[2]=w[4*row-2];
		temp[3]=w[4*row-1];
		if(row%Nk==0)           //逢nk时,对当前列的前一列作特殊处理
		{
			temp=ISD_SubWord(ISD_RotWord(temp));   //先移位,再代换,最后和轮常量异或
			temp[0] = (byte)( (int)temp[0] ^ (int) AesRcon[4*(row/Nk)+0] );   
			temp[1] = (byte)( (int)temp[1] ^ (int) AesRcon[4*(row/Nk)+1] );
			temp[2] = (byte)( (int)temp[2] ^ (int) AesRcon[4*(row/Nk)+2] );
			temp[3] = (byte)( (int)temp[3] ^ (int) AesRcon[4*(row/Nk)+3] );
        }
		else if ( Nk > 6 && (row % Nk == 4) )  
        {
			temp = ISD_SubWord(temp);
        }
        w[4*row+0] = (byte) ( (int) w[4*(row-Nk)+0] ^ (int)temp[0] );
		w[4*row+1] = (byte) ( (int) w[4*(row-Nk)+1] ^ (int)temp[1] );
		w[4*row+2] = (byte) ( (int) w[4*(row-Nk)+2] ^ (int)temp[2] );
		w[4*row+3] = (byte) ( (int) w[4*(row-Nk)+3] ^ (int)temp[3] );
	} }
ISD_Aes::ISD_MixColumns()                          //列混合
{
unsigned char temp[4*4];
int i,j;
for(j=0;j<4;j++)                                   //2 3 1 1  列混淆矩阵
{												//1 2 3 1
for(i=0;i<4;i++)								//1 1 2 3
{											//3 1 1 2
temp[4*i+j]=State[i][j];
}
}
for(j=0;j<4;j++)
{
State[0][j] = (unsigned char) ( (int)ISD_gfmultby02(temp[0+j]) ^ (int)ISD_gfmultby03(temp[4*1+j]) ^
(int)ISD_gfmultby01(temp[4*2+j]) ^ (int)ISD_gfmultby01(temp[4*3+j]) );
State[1][j] = (unsigned char) ( (int)ISD_gfmultby01(temp[0+j]) ^ (int)ISD_gfmultby02(temp[4*1+j]) ^
(int)ISD_gfmultby03(temp[4*2+j]) ^ (int)ISD_gfmultby01(temp[4*3+j]) );
State[2][j] = (unsigned char) ( (int)ISD_gfmultby01(temp[0+j]) ^ (int)ISD_gfmultby01(temp[4*1+j]) ^
(int)ISD_gfmultby02(temp[4*2+j]) ^ (int)ISD_gfmultby03(temp[4*3+j]) );
State[3][j] = (unsigned char) ( (int)ISD_gfmultby03(temp[0+j]) ^ (int)ISD_gfmultby01(temp[4*1+j]) ^
(int)ISD_gfmultby01(temp[4*2+j]) ^ (int)ISD_gfmultby02(temp[4*3+j]) );
}

}
ISD_Aes::ISD_ShiftRows()
{
	unsigned char temp[4*4];                                //行移位
	int i,j;
	for(j=0;j<4;j++)
	{
		for(i=0;i<4;i++)
		{
			temp[4*i+j]=State[i][j];
		}
	}
	for(i=1;i<4;i++)
	{
		for(j=0;j<4;j++)
		{
if(i==1)State[i][j]=temp[4*i+(j+1)%4];					//第一行左移1位
else if(i==2)State[i][j]=temp[4*i+(j+2)%4];				//第二行左移2位
else if(i==3)State[i][j]=temp[4*i+(j+3)%4];//第三行左移3位
}
}

}
```
`***************AES源码**********************`
## 【实验思考】
1.AES的解密过程是怎样的?


# 3DES密码算法
## 【实验目的】
1) 了解3DES的算法原理
2) 学习3DES算法的编程实现
## 【实验原理】
 DES算法的密钥长度已经被证明不能满足当前安全的要求,但为了充分利用现有的DES软件和硬件资源,人们开始提出针对DES的各种改进方案,
最简单的方案是使用多重DES,使用多个不同的DES密钥利用DES加密算法对明文进行多次加密。这样可以增加密钥量,
从而大大提高抵抗对密钥的穷举搜索攻击的能力。而最常用的多主要是三重DES算法。 算法原理 三重DES有4种模式,如下图1所示: (1) DES-EEE3 模式:该模式中共使用3个不同密钥,顺序使用3次DES加密算法。 (2) DES-EDE3 模式:该模式中共使用3个不同密钥,依次用加密—解密—加密。 (3) DES-EEE2 模式:该模式中共使用2个不同密钥,顺序使用3次DES加密算法,其中第一次和第三次加密使用的密钥相同。 (4) DES-EDE2 模式:该模式中共使用2个不同密钥,依次用加密—解密—加密,其中加密算法使用的密钥相同。

 

 



 

 



图1 三重DES的使用模式

 

 

 

 

算法参数
在三重DES算法中,其参数与DES是保持一致的,密钥总长度为64位。其中有效长度为56位,并附加上8位的奇偶校验位。分组长度为64位,初始置换IP,
逆初始置换

 

 ,E盒,S盒均在DES算法中予以说明,这里就不再赘述了。


算法流程
根据在上文中叙述的有关算法的运行原理及加解密流程,我们给出了其用C语言实现的源代码,相关的程序流程图如图3所示。
由于三重DES算法的代码以单重DES算法为基础,除了中间需要一步逆向的解密过程外,其他均是DES的单重加密。所以我们这里仅给出单重DES的加密流程图。

 

 




## 【实验环境】
Windows Server 2012 R2
实验工具在【C:\密码学课程\01密码学算法\04 分组密码\02 3DES密码算法】
## 【实验步骤】
1.打开文件【3DES.exe】,即可得到3DES加密算法的结果。如图4所示
2.3DES核心密码算法
	#include "stdio.h"
	#include "des.h"
	#include "pub.h"
	void main()
	{
	unsigned char key1[] = "12345678";
	unsigned char key2[] = "abcdefgh";
	unsigned char key3[] = "12345678";	//如果只需要两组密钥,则本组密钥可以和密钥1一样。
	unsigned char en_data[] = "Cryptosystem lab";
	unsigned char en_out_put[8];

	printf("\r\n++++++++3DES 加密示例++++++++");
	print_hex("3DES [输入]明文 ", en_data, 8);
	print_hex("3DES [输入]密钥1", key1, 8);
	print_hex("3DES [输入]密钥2", key2, 8);
	print_hex("3DES [输入]密钥3", key3, 8);
	//3DES 加密
	des(en_data, key1, en_out_put, DES_ENCRYPT);
	des(en_out_put, key2, en_data, DES_DECRYPT);
	des(en_data, key3, en_out_put, DES_ENCRYPT);
	print_hex("3DES [输出]密文 ", en_out_put, 8);
	printf("\r\n");
	printf("\r\n++++++++3DES 解密示例++++++++");
	print_hex("3DES [输入]密文 ", en_out_put, 8);
	print_hex("3DES [输入]密钥1", key1, 8);
	print_hex("3DES [输入]密钥2", key2, 8);
	print_hex("3DES [输入]密钥3", key3, 8);
	//3DES 加密
	des(en_out_put, key3, en_data, DES_DECRYPT);
	des(en_data, key2, en_out_put, DES_ENCRYPT);
	des(en_out_put, key1, en_data, DES_DECRYPT);
	print_hex("3DES [输出]明文 ", en_data, 8);
	printf("\r\n");
	return;
	}
##【实验思考】
1.3DES算法与DES算法有什么区别
 
 posted on 2020-08-29 23:59  小希米七  阅读(367)  评论(0)    收藏  举报