AES实验报告
本次实验分工:
卢上游 C022012023:
密钥扩展:keyexpansion(),keyexpansion_Inv()
主程序main()
文件读写FileWrite(),FileRead()
实验报告撰写
罗希 C022012024:
S盒查找:S(),S_Inv()
脱密:DeEncrtpt()
彭年 C022012026:
字节乘法 byte_mul()
加密:Encrypt()
彭泽斌C022012027:
行移位:LineShift(),LineShift_Inv()
列混合:RowMix(),RowMix_Inv()
一、本程序实现过程:
加密:
解密:
二、函数说明:
1.int S(int a) / int S_Inv(int a):
查找S盒函数,参数a存储8位的数据的变量,该函数返回值为S[a],S[256]为按顺序存储的S盒。
int S(int a) // S盒查找
{
int S[256]= {……………};
return(S[a]);
}
int S_Inv(int a) // 逆S盒查找
{
int S_Inv[256]={……………};
return(S_Inv[a]);
}
2.int LineShift(int b[16])/ int LineShift_Inv(int b[16]):
表示行移位变换函数,数组b[16]存储共128位的数据,每个数组成员存储8位的数据,函数功能将数组内数据的按一定规则进行交换,并返回给b[16];
int LineShift(int b[16]) //行移位
{
int a[16]={0},i=0;
for (i=0;i<16;i++) //赋值给中间量
a[i]=b[i];
b[1]=a[5];
b[2]=a[10];
b[3]=a[15];
b[4]=a[4];
b[5]=a[9];
b[6]=a[14];
b[7]=a[3];
b[8]=a[8];
b[9]=a[13];
b[10]=a[2];
b[11]=a[7];
b[12]=a[12];
b[13]=a[1];
b[14]=a[6];
b[15]=a[11];
return 0;
}
int LineShift_Inv(int b[16]) //逆行移位
{
int a[16]={0},i=0;
for (i=0;i<16;i++) //赋值给中间量
a[i]=b[i];
b[1]=a[13];
b[2]=a[10];
b[3]=a[7];
b[4]=a[4];
b[5]=a[1];
b[6]=a[14];
b[7]=a[11];
b[8]=a[8];
b[9]=a[5];
b[10]=a[2];
b[11]=a[15];
b[12]=a[12];
b[13]=a[9];
b[14]=a[6];
b[15]=a[3];
return 0;
}
3.int byte_mul(int a,int b):
表示字节乘法函数,参数a,b表示进行字节乘法的两个变量,均存储一个字节的数据,经过查字节乘法表(256*256),然后返回结果即为a与b的字节的乘法结果。字节乘法表由于是对称距阵,因此表中只存储了对角线的左下角的一部分,字节乘法表见附录。
int byte_mul(int a,int b) //字节乘法
{
int x[32896]={。。。。。。。}
int c;
if(b>a)
return(x[(b+b*b)/2+a]);
else
return (x[(a+a*a)/2+b]);
}
4.int RowMix(int m[16])/int RowMix_Inv(int c[16]):
表列混合函数,数组m[16]/c[16]表示128位的数据,每个数组成员存储8位的数据,函数的功能是将数组内的数据进行距阵相乘之后,将结果按规定次序返回给m[16]。
int RowMix(int m[16]) //列混合
{
int a[16],i;
for(i=0;i<4;i++) //按列与距阵字节相乘
{
a[i*4]=byte_mul(2,m[i*4])^byte_mul(3,m[i*4+1])^m[i*4+2]^m[i*4+3];
a[i*4+1]=byte_mul(2,m[i*4+1])^byte_mul(3,m[i*4+2])^m[i*4]^m[i*4+3];
a[i*4+2]=byte_mul(2,m[i*4+2])^byte_mul(3,m[i*4+3])^m[i*4]^m[i*4+1];
a[i*4+3]=byte_mul(2,m[i*4+3])^byte_mul(3,m[i*4])^m[i*4+2]^m[i*4+1];
}
for (i=0;i<16;i++) //返回给m[16]
m[i]=a[i];
return 0;
}
int RowMix_Inv(int c[16]) //逆列混合
{
int a[16],i=0;
for(i=0;i<4;i++) //按列与距阵字节相乘
{
a[i*4]=byte_mul(0x0e,c[i*4])^byte_mul(0x0b,c[i*4+1])^byte_mul(0x0d,c[i*4+2])^byte_mul(0x09,c[i*4+3]);
a[i*4+1]=byte_mul(0x09,c[i*4])^byte_mul(0x0e,c[i*4+1])^byte_mul(0x0b,c[i*4+2])^byte_mul(0x0d,c[i*4+3]);
a[i*4+2]=byte_mul(0x0d,c[i*4])^byte_mul(0x09,c[i*4+1])^byte_mul(0x0e,c[i*4+2])^byte_mul(0x0b,c[i*4+3]);
a[i*4+3]=byte_mul(0x0b,c[i*4])^byte_mul(0x0d,c[i*4+1])^byte_mul(0x09,c[i*4+2])^byte_mul(0x0e,c[i*4+3]);
}
for (i=0;i<16;i++) //返回给c[16]
c[i]=a[i];
return 0;
}
5.unsigned KeyExpansion(unsigned int Key[4]):
表加密密钥生成函数:数组key[4]保存128位的基本密钥,数组中每个成员保存32位的数据,经过密钥扩展算法得到unsigned int W[44], W[44]为全局变量,每个数组成员按顺序保存圈密钥的32位,按顺序每四个数组成员保存一个圈密钥。
unsigned KeyExpansion(unsigned int Key[4])//密钥扩展
{
unsigned int i=0,a[5]={0},j=0;
for (i=0;i<4;i++) //初始第一圈密钥
{
W[i]=Key[i];
}
for (i=1;i<11;i++) //找出w的每个字节
{
a[4]=W[i*4-1];
a[3]=a[4]&0x000000ff;
a[2]=(a[4]&0x0000ff00)>>8;
a[1]=(a[4]&0x00ff0000)>>16;
a[0]=(a[4]&0xff000000)>>24;
for (j=0;j<4;j++) //对每个字节查询S盒
a[j]=S(a[j]);
a[4]=a[0]^(a[1]<<24)^(a[2]<<16)^(a[3]<<8); //按字节循环左移一位操作,并合成为四个字节的字,a[4]为temp值
W[i*4]=W[(i-1)*4]^a[4]^Rcon(i);
W[i*4+1]=W[i*4-3]^W[i*4];
W[i*4+2]=W[i*4-2]^W[i*4+1];
W[i*4+3]=W[i*4-1]^W[i*4+2];
}
return 0;
}
6.unsigned KeyExpansion_Inv():
表脱密密钥生成函数:在此过程中,利用全局变量W[44],经过逆列混合变换,最终得到脱密密钥,并按顺序保存在W[44]中,每四个数组成员保存一个圈密钥。
unsigned KeyExpansion_Inv() //密钥逆扩展
{
unsigned int i=0,b[16]={0},j=0,temp=0;
int a[16]={0};
for(j=1;j<10;j++)
{
for (i=0;i<4;i++) //取出每个字节
{
temp=W[i+j*4];
W[i+j*4]=0;
a[3+4*i]=temp&0x000000ff;
a[2+4*i]=(temp&0x0000ff00)>>8;
a[1+4*i]=(temp&0x00ff0000)>>16;
a[4*i]=(temp&0xff000000)>>24;
}
RowMix_Inv(a); //进行列混合变换
for (i=0;i<4;i++) //合成为四个字节的字
W[i+j*4]=a[3+4*i]^(a[2+4*i]<<8)^(a[1+4*i]<<16)^(a[4*i]<<24);
}
return 0;
}
7.int FileRead(int mingwen[n][16]):
读文件函数:从指定文件中读取全部数据并返回给mingwen[n][16],n通过#define n 3定义,为需加密的数据规模(共n个128bit)。
int FileRead(int mingwen[n][16])
{
FILE *fp;
int i=0,j=0;
char ss[20]; //ss[]为需加、解密的明文或密文指定路径的文件名
printf("请输入读取数据的文件路径:(如c:jiami.txt)");
scanf("%s",ss);
if((fp = fopen(ss, "r+")) == NULL)//文件设置为可读写
printf("文件打开失败 \n");
else
for(j=0;j<n;j++) //从文件中读取数据按每段16个字节读取,共n段
for (i=0;i<16;i++)
{
fscanf(fp, "%2x",&mingwen[j][i]);
}
fclose(fp);
return 0;
}
8.int FileWrite(int m[16],char ssm[20]):
写文件函数,ssm[]为文件名,功能是将数组m[16]中的数据写入到指定文件名中。
int FileWrite(int m[],char ssm[])//ssm[]表示密文保存到指定路径的文件名
{
FILE *fp;
int i=0;
if((fp = fopen(ssm, "a+")) == NULL)//文件可读、写,写入数据时,文件指针移到文件末尾,即在文件末尾添加数据
printf("文件打开失败 \n");
else
for (i=0;i<16;i++)
{
if(m[i]<=0xf)
{
fprintf(fp,"%x",0);
fprintf(fp,"%x",m[i]);
}
else
fprintf(fp, "%2x",m[i]);
}
fclose(fp);
return 0;
}
9.void Encrypt(int m[16],unsigned int key[4]):
数据加密函数:数组m[16]保存着共128bit的需要加密的数据,参数key[4]为基本密钥,经过加密后的数据仍然保存在m[16]中。
void Encrypt(int m[],unsigned int key[])
{
int i=0,k[11][4][4]={0},j=0,l=0;
KeyExpansion(key);
for (i=0;i<11;i++)
{
for (j=0;j<4;j++) //由W存储了4个字节的部分密钥,为了运算方便,把各个字节的密钥按顺序取出
{
k[i][j][0]=W[i*4+j]>>24;
k[i][j][1]=(W[i*4+j]&0x00ff0000)>>16;
k[i][j][2]=(W[i*4+j]&0x0000ff00)>>8;
k[i][j][3]=W[i*4+j]&0x000000ff;
}
}
for (i=0;i<10;i++)//十一圈
{
for (j=0;j<4;j++)//明文与圈密钥异或之后再查找S盒
for (l=0;l<4;l++)
{
m[j*4+l]=m[j*4+l]^k[i][j][l];
m[j*4+l]=S(m[j*4+l]);
}
LineShift(m); //行移位变换
if (i!=9) //第十圈不需要列混合变换
RowMix(m); //列混合变换
if (i==9) //与最后一圈密钥相与
{
for (j=0;j<4;j++)
for (l=0;l<4;l++)
m[j*4+l]=m[j*4+l]^k[10][j][l];
}
}
}
10.void DeEncrtpt(int m[16],unsigned int key[4]):
数据解密函数:数组m[16]保存着共128bit的需要解密的数据,数组key[4]为基本密钥,经过加密后数据仍然保存在m[16]中。
void DeEncrtpt(int m[],unsigned int key[]) //脱密算法
{
int i=0,k[11][4][4]={0},j=0,l=0;
KeyExpansion(key); //产生加密密钥
KeyExpansion_Inv(); //由加密密钥得脱密密钥
for (i=10;i>=0;i--) //共十一圈
{
for (j=0;j<4;j++)//以字节为单位取出的密钥
{
k[10-i][j][0]=W[i*4+j]>>24;
k[10-i][j][1]=(W[i*4+j]&0x00ff0000)>>16;
k[10-i][j][2]=(W[i*4+j]&0x0000ff00)>>8;
k[10-i][j][3]=W[i*4+j]&0x000000ff;
}
}
for (i=0;i<10;i++)
{
for (j=0;j<4;j++) //密文与密钥异或并进行S盒查找
for (l=0;l<4;l++)
{
m[j*4+l]=m[j*4+l]^k[i][j][l];
m[j*4+l]=S_Inv(m[j*4+l]);
}
LineShift_Inv(m); //逆行变换
if (i!=9)
RowMix_Inv(m); //逆列混合
if (i==9) // 最后一圈与密钥异或
{
for (j=0;j<4;j++)
for (l=0;l<4;l++)
m[j*4+l]=m[j*4+l]^k[10][j][l];
}
}
}
11.int main()
主要是对以上函数的调用及整合,从而实现批量从txt文件中读取数据并进行加密/脱密,并写入到指定的txt文件中。
int main()
{
clock_t start,end,start_ReadFile,end_ReadFile;
int select=0;
int m[16]={0},i=0,mingwen[n][16]={0},j=0;
unsigned int key[4]={0x2b7e1516,0x28aed2a6,0xabf71588,0x09cf4f3c};
char ssm[20]={NULL};
printf("加密请按1,解密请按0\n");
scanf("%d",&select);
/*printf("请输入密钥:(范例:2b7e1516,28aed2a6,abf71588,09cf4f3c,)\n");
for(i=0;i<4;i++)
scanf("%x,",&key[i]);*/
start=clock(); //计时开始
start_ReadFile=clock();
FileRead(mingwen); //读取文件中的数据
end_ReadFile=clock();
printf("请输入写入数据的文件路径:(如c:jiami.txt)");
scanf("%s",ssm);
for(j=0;j<n;j++) //共n段数据进行加密,每段16个字节
{
printf("文件中第%d段数据为:\n",j+1);
for (i=0;i<16;i++)
{
m[i]=mingwen[j][i]; //文件中数据赋值批量 给 m[16]
printf("%x,",m[i]);
}
printf("\n");
if (select==1) //加密部分
{
Encrypt(m,key); //加密算法,加密后数据返回给 m[16]
printf("密文为:");
for (i=0;i<16;i++) //打印密文
{
printf("%x,",m[i]);
}
printf("\n");
}
if (select==0) //解密部分
{
DeEncrtpt(m,key); //解密算法
printf("脱密后明文为:");
for (i=0;i<16;i++)
printf("%x,",m[i]);
printf("\n");
}
FileWrite(m,ssm); //将加密或解密后的数据分批写入到文件中
}
end=clock(); //计时结束
printf("文件读运行时间是:%5.2f\n",difftime(end_ReadFile,start_ReadFile)); //写文件所用时间
printf("加密或解密+文件读写运行时间是:%5.2f\n",difftime(end,start)); //运行时间输出时间;
}
12.unsigned int Rcon(int k)
输入为k,输出0x02的k-1次方对应的字节。
unsigned int Rcon(int k)
{
unsigned int rcon=0x01;
for (int j=0;j<k-1;j++)
rcon=byte_mul(0x02,rcon);//0x02的k-1次方
return(rcon<<24); //向左平移24位并返回
}
三、本程序主要实现及功能:
1. 考虑到密钥扩展时W[i]有32位,因此类型定义为unsigned int 。
2. 为方便将W[i]中各个字节提取出来,采用相与并移位的方式按字节提取出密钥;同理,可合并多个字节数据到一个变量中。
3. 本程序采用文件操作,可从txt文件中读取明文或密文,可将密文或明文写入到txt文件中。
4. 本程序可对明文或密文进行批量处理,每次处理128bit。其中n值为处理的规模(n个128bit,本程序中n=3)。
5. 本程序有计时操作,并打印出整个加密或解密过程中所用的时间,由于文件读写操作所花时间较多,因此整个时间花费较大。
备注:为节省操作,基本密钥已经在程序代码中给出:
unsigned int key[4]={0x2b7e1516,0x28aed2a6,0xabf71588,0x09cf4f3c}
四、实验结果截图:
加密:
解密:
txt文件内容:
附录: