密码学实验报告AESRSA资料.docx
- 文档编号:9938345
- 上传时间:2023-05-22
- 格式:DOCX
- 页数:20
- 大小:253.90KB
密码学实验报告AESRSA资料.docx
《密码学实验报告AESRSA资料.docx》由会员分享,可在线阅读,更多相关《密码学实验报告AESRSA资料.docx(20页珍藏版)》请在冰点文库上搜索。
密码学实验报告AESRSA资料
华北电力大学
实验报告
|
|
实验名称现代密码学课程设计
课程名称现代密码学
|
|
专业班级:
学生姓名:
学号:
成绩:
指导教师:
实验日期:
[综合实验一]AES-128加密算法实现
一、实验目的及要求
(1)用C++实现;
(2)具有16字节的加密演示;
(3)完成4种工作模式下的文件加密与解密:
ECB,CBC,CFB,OFB.
二、所用仪器、设备
计算机、VisualC++软件。
三.实验原理
3.1、设计综述
AES中的操作均是以字节作为基础的,用到的变量也都是以字节为基础。
State可以用4×4的矩阵表示。
AES算法结构对加密和解密的操作,算法由轮密钥开始,并用Nr表示对一个数据分组加密的轮数(加密轮数与密钥长度的关系如表2所示)。
AES算法的主循环State矩阵执行
轮迭代运算,每轮都包括所有4个阶段的代换,分别是在规范中被称为SubBytes(字节替换)、ShiftRows(行位移变换)、MixColumns(列混合变换)和AddRoundKey,(由于外部输入的加密密钥K长度有限,所以在算法中要用一个密钥扩展程序(Keyexpansion)把外部密钥K扩展成更长的比特串,以生成各轮的加密和解密密钥。
最后执行只包括3个阶段(省略MixColumns变换)的最后一轮运算。
表2AES参数
密钥长度(bits)
128
192
256
明文分组长度(bits)
128
128
128
轮数
10
12
14
每轮密钥长度(bits)
128
128
128
扩展密钥长度(bytes)
176
206
240
基本要求按标准分组,以128比特为分组大小。
所以轮数为10轮,密钥长度也为128比特。
3.2、字节代替(SubBytes)
AES定义了一个S盒,State中每个字节按照如下方式映射为一个新的字节:
把该字节的高4位作为行值,低4位作为列值,然后取出S盒中对应行和列的元素作为输出。
例如,十六进制数{84}。
对应S盒的行是8列是4,S盒中该位置对应的值是{5F}。
S盒是一个由16x16字节组成的矩阵,包含了8位值所能表达的256种可能的变换。
S盒按照以下方式构造:
(1)逐行按照升序排列的字节值初始化S盒。
第一行是{00},{01},{02},…,{OF};第二行是{10},{l1},…,{1F}等。
在行X和列Y的字节值是{xy}。
(2)把S盒中的每个字节映射为它在有限域GF(
)中的逆。
GF代表伽罗瓦域,GF(
)由一组从0x00到0xff的256个值组成,加上加法和乘法。
。
{00}被映射为它自身{00}。
(3)把S盒中的每个字节记成
。
对S盒中每个字节的每位做如下变换:
上式中
是指值为{63}字节C第i位,即
。
符号(
)表示更新后的变量的值。
AES用以下的矩阵方式描述了这个变换:
最后完成的效果如图:
3.3、行移位(ShiftRows)
一.State的第一行字节保持不变,State的第二行字节循环左移一个字节,State的第三行字节循环左移两个字节,State的第四行循环左移三个字节。
行移位左偏移量:
变化如图2所示。
3.4、列混合(MixColumn)
一.列混合变换是一个替代操作,是AES最具技巧性的部分。
它只在AES的第0,1,…,Nr一1轮中使用,在第Nr轮中不使用该变换。
乘积矩阵中的每个元素都是一行和一列对应元素的乘积之和。
在MixColumns变换中,乘法和加法都是定义在GF(
)上的。
State的每一列(
)1=0,…,3;J=0,…,
被理解为GF(
)上的多项式,该多项式与常数多项式
相乘并模
约化。
这个运算需要做GF(
)上的乘法。
但由于所乘的因子是三个固定的元素02、03、01,所以这些乘法运算仍然是比较简单的(注意到乘法运算所使用的模多项式为
)。
设一个字节为b=(b7b6b5b4b3b2b1b0),则
bב01’=b;
bב02’=(b6b5b4b3b2b1b00)+(000b7b70b7b7);
bב03’=bב01’+b×’02’。
(请注意,加法为取模2的加法,即逐比特异或)
写成矩阵形式为:
最后完成的效果如图:
3.5、轮密钥加(AddRoundKey)
AddRoundKey称为轮密钥加变换,128位的State按位与128位的密钥XOR:
对j=0,…,L-1轮密钥加变换很简单,却影响了State中的每一位。
密钥扩展的复杂性和AES的其他阶段运算的复杂性,却确保了该算法的安全性。
最后完成的效果如图:
3.6.逆字节替换
通过逆S盒的映射变换得到
3.7.逆行移位InvShiftRow
与加密时的行移位区别在于移位方向相反。
3.8.逆列混淆
3.9加密与解密模式
电子密码本ECB模式:
ECB模式是最古老,最简单的模式,将加密的数据分成若干组,每组的大小跟加密密钥长度相同;然后每组都用相同的密钥加密,比如DES算法,如果最后一个分组长度不够64位,要补齐64位;定义:
Enc(X,Y)是加密函数Dec(X,Y)是解密函数Ci(i=0,1…n)是密文块,大小为64bit;XOR(X,Y)是异或运算;IV是初始向量(一般为64位)ECB加密算法可表示为:
C0=Enc(Key,XOR(IV,P0)
Ci=Enc(Key,XOR(Ci-1,Pi)
ECB解密算法可以表示为:
P0=XOR(IV,Dec(Key,C0))
Pi=XOR(Ci-1,Dec(Key,Ci))
算法特点:
每次加密的密文长度为64位(8个字节);当相同的明文使用相同的密钥和初始向量的时候CBC模式总是产生相同的密文;密文块要依赖以前的操作结果,所以,密文块不能进行重新排列;可以使用不同的初始化向量来避免相同的明文产生相同的密文,一定程度上抵抗字典攻击;一个错误发生以后,当前和以后的密文都会被影响;
四、实验方法与步骤
4.1字节替换
SubBytes()变换是一个基于S盒的非线性置换,它用于将输入或中间态的每一个字节通过一个简单的查表操作,将其映射为另一个字节。
映射方法是把输入字节的高四位作为S盒的行值,低四位作为列值,然后取出S盒中对应的行和列的元素作为输出。
unsignedcharsubbytes(unsignedcharstate[4][4])
{printf("aftersubbyte:
\n");//取出中间态state映射到S盒中的值赋给中间态state
for(i=0;i<4;i++)
{for(j=0;j<4;j++)
state[i][j]=sbox[state[i][j]];}
for(i=0;i<4;i++)//输出到屏幕显示state
{for(j=0;j<4;j++)
printf("\t\t%02x",state[i][j]);
printf("\n");
}
printf("\n");
return0;
}
4.2行移位
ShiftRows()完成基于行的循环移位操作,变换方法是第0行不动,第一行循环左移一个字节,第二位循环左移两个字节,第三行循环左移三个字节。
unsignedcharshiftrows(unsignedcharstate[4][4])
{printf("aftershiftrows:
\n");//在中间态的行上,
k=state[1][0];//第0行不变
state[1][0]=state[1][1];//第一行循环左移一个字节
state[1][1]=state[1][2];//第二行循环左移两个字节
state[1][2]=state[1][3];//第三行循环左移三个字节
state[1][3]=k;
k=state[2][0];
state[2][0]=state[2][2];
state[2][2]=k;
k=state[2][1];
state[2][1]=state[2][3];
state[2][3]=k;
k=state[3][0];
state[3][0]=state[3][3];
state[3][3]=state[3][2];
state[3][2]=state[3][1];
state[3][1]=k;
for(i=0;i<4;i++)//输出到屏幕显示state
{for(j=0;j<4;j++)
printf("\t\t%02x",state[i][j]);
printf("\n");
}
printf("\n");
return0;
}
4.3列混合
MixColumns()实现逐列混合,方法是s’(x)=c(x)*s(x)mod(x^4+1)
unsignedcharmixcolumns(unsignedcharstate[4][4])
{printf("aftermixcolumns:
\n");//实现(02030101)与中间态state分别相乘后异或得相应值
for(i=0;i<4;i++)//(01020301)
{//(01010203)
k=state[0][i];//(03010102)
temp[0]=state[0][i]^state[1][i]^state[2][i]^state[3][i];
temp[1]=state[0][i]^state[1][i];temp[1]=xtime(temp[1]);state[0][i]^=temp[1]^temp[0];
temp[1]=state[1][i]^state[2][i];temp[1]=xtime(temp[1]);state[1][i]^=temp[1]^temp[0];
temp[1]=state[2][i]^state[3][i];temp[1]=xtime(temp[1]);state[2][i]^=temp[1]^temp[0];
temp[1]=state[3][i]^k;temp[1]=xtime(temp[1]);state[3][i]^=temp[1]^temp[0];
}
for(i=0;i<4;i++)//输出到屏幕显示state
{for(j=0;j<4;j++)
printf("\t\t%02x",state[i][j]);
printf("\n");
}
printf("\n");
return0;
}
4.4轮密钥加
AddRoundKey()用于将输入或中间态S的每一列与一个密钥字ki进行按位异或,每一个轮密钥由Nb个字组成。
unsignedcharaddroundkey(unsignedcharstate[4][4],unsignedcharw[4][4])
{printf("addroundkey%d:
\n",round++);
//将中间态state中的每一列与一个密钥字(w[4][4]中的一列)进行按位异或
for(i=0;i<4;i++)//完了又赋值给state
{for(j=0;j<4;j++)
state[i][j]^=w[i][j];}
for(i=0;i<4;i++)//输出到屏幕显示出来state
{for(j=0;j<4;j++)
printf("\t\t%02x",state[i][j]);
printf("\n");}
printf("\n");
return0;
}
4.5密钥扩展
通过生成器产生Nr+1个轮密钥,每个轮密钥由Nb个字组成,共有Nb(Nr+1)个字。
在加密过程中,需要Nr+1个轮密钥,需要构造4(Nr+1)个32位字。
首先将输入的4个字节直接复制到扩展密钥数组的前4个字中,得到W[0],W[1],W[2],W[3];然后每次用4个字填充扩展密钥数余下的部分。
//keyexpand
printf("afterkeyexpand:
\n");
for(i=4;i<8;i++)
{
if(i%4==0)
{rotword[0]=w[1][i-1];
rotword[1]=w[2][i-1];
rotword[2]=w[3][i-1];
rotword[3]=w[0][i-1];
printf("rotword():
");
for(j=0;j<4;j++)printf("%02x",rotword[j]);
for(j=0;j<4;j++)
subword[j]=sbox[rotword[j]];
printf("\nsubword():
");
for(j=0;j<4;j++)printf("%02x",subword[j]);printf("\n\n");
for(j=0;j<4;j++)
rcon[j]=subword[j]^Rcon[N][j];
printf("after^Rcon():
");
for(j=0;j<4;j++)printf("%02x",rcon[j]);printf("\n\n");
for(j=0;j<4;j++)
w[j][i%4]=rcon[j]^w[j][i-4];
printf("w[%d]:
",count);
for(j=0;j<4;j++)printf("%02x",w[j][i%4]);
count++;
}
else
{
for(j=0;j<4;j++)
w[j][i%4]=w[j][i%4]^w[j][(i%4)-1];
printf("w[%d]:
",count);
for(j=0;j<4;j++)printf("%02x",w[j][i%4]);
count++;
}
printf("\n\n");
}
printf("密钥扩展Roundkey:
\n");
for(i=0;i<4;i++)
{for(j=0;j<4;j++)printf("\t\t%02x",w[i][j]);
printf("\n");}
printf("\n");
4.6逆字节替换
与字节代替类似,逆字节代替基于逆S盒实现。
unsignedcharInvSubbytes(unsignedcharstate[4][4])
{for(i=0;i<4;i++)//基于逆S盒的映射替代
{for(j=0;j<4;j++)
{state[i][j]=rsbox[state[i][j]];}
}
printf("afterInvSubbyte:
\n");
for(i=0;i<4;i++)
{for(j=0;j<4;j++)//输出到屏幕显示state
printf("\t\t%02x",state[i][j]);
printf("\n");
}
printf("\n");
return0;
}
4.7逆行移位
与行移位相反,逆行移位将态state的后三行按相反的方向进行移位操作,即第0行保持不变,第1行循环向右移一个字节,第2行循环向右移动两个字节,第3行循环向右移动三个字节。
unsignedcharInvShiftRows(unsignedcharstate[4][4])
{k=state[1][3];
state[1][3]=state[1][2];//对中间态state进行移位操作
state[1][2]=state[1][1];//第0行保持不变
state[1][1]=state[1][0];//第1行循环右移一个字节
state[1][0]=k;//第2行循环右移两个字节
//第3行循环右移三个字节
k=state[2][0];
state[2][0]=state[2][2];
state[2][2]=k;
k=state[2][1];
state[2][1]=state[2][3];
state[2][3]=k;
k=state[3][0];
state[3][0]=state[3][1];
state[3][1]=state[3][2];
state[3][2]=state[3][3];
state[3][3]=k;
printf("afterInvShiftRows:
\n");
for(i=0;i<4;i++)//输出到屏幕显示state
{for(j=0;j<4;j++)
printf("\t\t%02x",state[i][j]);
printf("\n");
}
printf("\n");
return0;
}
4.8逆列混合
逆列混淆的处理办法与MixColumns()类似,每一列都通过与一个固定的多项式d(x)相乘进行交换。
unsignedcharInvMixColumns(unsignedcharstate[4][4])
{printf("afterInvMixColumns:
\n");
//实现(0e0b0d09)与中间态state分别相乘后异或得相应值
for(i=0;i<4;i++)//(090e0b0d)
{temp[0]=state[0][i];//(0d090e0b)
temp[1]=state[1][i];//(0b0d090e)
temp[2]=state[2][i];
temp[3]=state[3][i];
state[0][i]=Multiply(temp[0],0x0e)^Multiply(temp[1],0x0b)^Multiply(temp[2],0x0d)^Multiply(temp[3],0x09);
state[1][i]=Multiply(temp[0],0x09)^Multiply(temp[1],0x0e)^Multiply(temp[2],0x0b)^Multiply(temp[3],0x0d);
state[2][i]=Multiply(temp[0],0x0d)^Multiply(temp[1],0x09)^Multiply(temp[2],0x0e)^Multiply(temp[3],0x0b);
state[3][i]=Multiply(temp[0],0x0b)^Multiply(temp[1],0x0d)^Multiply(temp[2],0x09)^Multiply(temp[3],0x0e);
}
for(i=0;i<4;i++)//输出到屏幕显示state
{for(j=0;j<4;j++)
printf("\t\t%02x",state[i][j]);
printf("\n");}
printf("\n");
return0;
}
4.9加密
加密部分我分了两种情况,一种是自动检查加密程序的正确性,之前在程序里给明文和密钥赋上初值,运行程序检验结果是否正确;另一种是用户手动输入32位的十六进制数,进行加密,我是把每一具体项模块化,将功能在每个具体模块中实现,只需要直接调用,视觉效果强,一目了然。
下面是实现加密功能一些关键代码
voidAES_encrypt(unsignedcharState[][N],unsignedcharRoundKey[][N])
{message[16]={0x32,0x43,0xf6,0xa8,0x88,0x5a,0x30,0x8d,0x31,0x31,0x98,0xa2,0xe0,0x37,0x07,0x34};
key[16]={0x2b,0x7e,0x15,0x16,0x28,0xae,0xd2,0xa6,0xab,0xf7,0x15,0x88,0x09,0xcf,0x4f,0x3c};
for(i=0;i<4;i++){for(j=0;j<4;j++)//分别获取明文和密钥
{state[j][i]=message[m];w[j][i]=key[m];m++;}
}.
addroundkey(state,w);
for(round=2;round<11;round++)
{printf("第%d轮加密:
\n",round);
subbytes(state);
shiftrows(state);
mixcolumns(state);
keyexpand(w,round);
addroundkey(state,w);
}
subbytes(state);//最后一轮
shiftrows(state);
keyexpand(w,10);
addroundkey(state,w);
}
4.10解密
AES解密我也是分成了两个部分,第一部分是在程序中对密文和密钥赋初值,通过与标准对照检查解密过程的正确性;第二部分是用户手动输入密文和密钥,程序对其进行解密,得到最后的明文。
解密过程基本如下:
1)获取输入的明文和密钥2)通过密钥扩展过程获取各轮密钥3)轮密钥加变换过程4)逆行移位5)逆字节替代6)轮密钥加变换7)逆列混淆
4—7步共9次循环,最后一轮实现4—6步,完成解密过程。
主要代码如下:
voidAES_decrypt(unsignedcharState[][N],unsignedcharw[][N])
{key[16]={0x2b,0x7e,0x15,0x16,0x28,0xae,0xd2,0xa6,0xab,0xf7,0x15,0x88,0x09,0xcf,0x4f,0x3c};
cipher[16]={0x39,0x25,0x84,0x1d,0x02,0xdc,0x09,0xfb,0xdc,0x11,0x85,0x97,0x19,0x6a,0x0b,0x32};
printf("%02x",key[i]);printf("\n");/获取密文和密钥
for(i=0;i<4;i++)
{for(j=0;j<4;j++)
{state[j][i]=cipher[m];w[j][i]=key[m];m++;}
}
Keyexpand(w,round);//获得密钥扩展列表
AddRoundKey(Stat
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 密码学 实验 报告 AESRSA 资料