# 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
浙公网安备 33010602011771号