课程设计报告
AES加密解密软件的实现
目录
1、选题背景2 2、设计的目标2 2.1基本目标:2 2.2较高目标:3 3、功能需求分析3 4、模块划分4 4.1、密钥调度4 4.2、加密6
4.2.1、字节代替(SubBytes)6 4.2.2、行移位(ShiftRows)7 4.2.3、列混合(MixColumn)7 4.2.4、轮密钥加(AddRoundKey)9 4.2.5、加密主函数9 4.3、解密11
4.3.1、逆字节替代(InvSubBytes)11 4.3.2、逆行移位(InvShiftRows)11 4.3.3、逆列混合(InvMixCloumns)12 4.3.4、轮密钥加(AddRoundKey)13 4.3.5、解密主函数13 5.测试报告14
5.1主界面14
5.2测试键盘输入明文和密钥加密14 5.3测试键盘输入密文和密钥加密15 5.3测试文件输入明文和密钥加密15 5.4测试文件输入密文和密钥加密15 5.5软件说明15
6.课程设计报告总结15 7.参考文献16
1、选题背景
高级加密标准(Advanced Encryption Standard,AES),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院(NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。2006年,高级加密标准已然成为对称密钥加密中最流行的算法之一。该算法为比利时密码学家Joan Daemen和Vincent Rijmen所设计,结合两位作者的名字,以Rijndael之命名之,投稿高级加密标准的甄选流程。(Rijndael的发音近于 \) 严格地说,AES和Rijndael加密法并不完全一样(虽然在实际应用中二者可以互换),因为Rijndael加密法可以支援更大范围的区块和密钥长度:AES的区块长度固定为128 位元,密钥长度则可以是128,192或256位元;而Rijndael使用的密钥和区块长度可以是32位元的整数倍,以128位元为下限,256位元为上限。加密过程中使用的密钥是由Rijndael密钥生成方案产生。大多数AES计算是在一个特别的有限域完成的。 截至2006年,针对AES唯一的成功攻击是旁道攻击
旁道攻击不攻击密码本身,而是攻击那些实作于不安全系统(会在不经意间泄漏资讯)上的加密系统。2005年4月,D.J. Bernstein公布了一种缓存时序攻击法,他以此破解了一个装载OpenSSL AES加密系统的客户服务器[6]。为了设计使该服务器公布所有的时序资讯,攻击算法使用了2亿多条筛选过的明码。有人认为[谁?],对于需要多个跳跃的国际互联网而言,这样的攻击方法并不实用[7]。 Bruce Schneier称此攻击为“好的时序攻击法”[8]。 2005年10月,Eran Tromer和另外两个研究员发表了一篇论文,展示了数种针对AES的缓存时序攻击法。其中一种攻击法只需要800个写入动作,费时65毫秒,就能得到一把完整的AES密钥。但攻击者必须在执行加密的系统上拥有执行程式的权限,方能以此法破解该密码系统。
虽然高级加密标准也有不足的一面,但是,它仍是一个相对新的协议。因此,安全研究人员还没有那么多的时间对这种加密方法进行破解试验。我们可能会随时发现一种全新的攻击手段会攻破这种高级加密标准。至少在理论上存在这种可能性。
2、设计的目标
2.1基本目标:
(1)在深入理解AES加密/解密算法理论的基础上,能够设计一个AES加密/解密软件系统,采用控制台模式,使用VS2010进行开发,所用语言为C语言进行编程,实现加密解密;
(2)能够完成只有一个明文分组的加解密,明文和密钥是ASCII码,长度都为16个字符(也就是固定明文和密钥为128比特),输入明文和密钥,输出密文,进行加密后,能够进行正确的解密;
(3)程序运行时,能够按照要求输出最后两轮的轮密钥,以及最后两轮加密或解密之后的值,16进制表示;
(4)程序有良好的人机交互操作;
(5)能够实现从两个文件分别读取明文和密钥,并在程序中输出明文及密钥; (6)要求有与标准fips-197进行比较的独立模块;
(7)最后提供所设计系统的报告及完整的软件,关键代码等。
2.2较高目标:
能完成以下全部或部分功能:
(1)如果从文件读取的明文不止一个分组,程序能完成分组,然后加密;最后一个分组长度不足时要求完成填充;输入信息可以是文本文档,或者普通文件。进行加密后,能够进行正确的解密;
(2)密钥包括128bit、192bit、256bit三种情况,有三种情况时与标准fips-197进行比较的独立模块,且从文本文件读取。
(3)程序代码有比较好的结构,模块划分合理,如用类进行封装,通过调用类的成员函数实现加密解密功能,函数的参数及返回值设置合理等;
(4)对加密大文件的考虑; (5)多线程的使用;
(6)界面友好,程序设计实现有创新。
3、功能需求分析
AES中的操作均是以字节作为基础的,用到的变量也都是以字节为基础。State可以用4×4的矩阵表示。AES算法结构对加密和解密的操作,算法由轮密钥开始,并用Nr表示对一个数据分组加密的轮数(加密轮数与密钥长度的关系如表2所示)。AES算法的主循环State矩阵执行轮迭代运算,每轮都包括所有 4
个阶段的代换,分别是在规范中被称为 SubBytes(字节替换)、ShiftRows(行位移变换)、MixColumns(列混合变换) 和AddRoundKey,(由于外部输入的加密密钥K长度有限,所以在算法中要用一个密钥扩展程序(Keyexpansion)把外部密钥 K 扩展成更长的比特串,以生成各轮的加密和解密密钥。)最后执行只包括 3个阶段 (省略 MixColumns变换)的最后一轮运算。
表2 AES参数
密钥长度(bits) 明文分组长度(bits) 轮数 每轮密钥长度(bits) 扩展密钥长度(bytes) 128 128 10 128 176 192 128 12 128 206 256 128 14 128 240 基本要求按标准分组,以128比特为分组大小。所以轮数为10轮,密钥长度也为128比特
4、模块划分
划分为三个部分,密钥调度,加密,解密,
4.1、密钥调度
一.密钥调度包括两个部分:密钥扩展和轮密钥选取。
密钥扩展的作用是在数据加密/解密前得到轮变换中中使用的轮密钥,其基本原则是: 1) 轮密钥的密钥长度为分组长乘以(1 +Nr),如果分组长为128bit,轮数为了10,则轮密钥的长度为128*(10+1)= 1408bit;
2) 种子密钥扩展为扩展密钥,种子密钥长度为4*NK个字节;
3) 轮密钥由以下方法从扩展密钥中获得:对第1轮密钥由前Nb个字构成;第2轮密钥由第二个Nb个字节即第Nb + 1个字到第2Nb个字构成;以下依次类推。 扩展密钥用数组w(Nb*(Nr + 1))表示,前Nk个字是原密钥,其它密钥字通过计算方法生成。 子字节变换是一个返回4个字节的函数,每个字节都是它输入字中相应位置字节通过S盒作用后的结果。
循环左移变换返回的是这4个字节经循环置换后的字,即将该字循环左移一个字节,如输入字为w = (a0,a1,a2,a3),则变换后输出字为w = (a1,a2,a3,a0)。 扩展密钥的前Nk个字由种子密钥构成,随后的字w[i]等于字w[i-1]经一些变换后得到的字temp和字W[i-Nk]异或而成;而且对位置为Nk倍数的字变换中不仅运用了循环左移变换和子字节变换,还运用了轮常数Rcon对变换后的字temp进行异或。 对轮常数的定义为:
Rcon[i] = (Rc[i],00,00,00)
8i-1
而Rc[i]表示在有限域GF(2)中x的值,即:
Rc[i] = 1 (即01)
i-1
Rc[i]=x·(Rc[i-1]) = x 二.关键代码
//先将密钥数组的元素值存储在3维数组中,然后对其扩展,扩展方式氛围两种,条件是Ki是否是4的倍数,两种密钥方式不同,复杂的是当为4的倍数时,要进行生成T[i-1],先是行移位,然后是进入S盒字节替代,最后与轮常数异或得到,再将此T与K[i-4]异或
void KeyExpansion(unsignedchar *Key,unsignedchar ExpandKey[][4][4]) {
unsignedchar RC[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36}; //轮常数 int i,j,m,n;
for(m=0;m<4;m++)
{ {
ExpandKey[0][m][n]=Key[n*4+m]; } } { {
for(n=0;n<4;n++)
for(i=1;i<11;i++) for(j=0;j<4;j++)
unsignedchar Temp[4]; for(m=0; m<4; m++)
{
Temp[m] = j ? ExpandKey[i][m][j-1] : ExpandKey[i-1][m][3];
//进行两种划分,先把密钥存在一个变量数组中,
} { if(j == 0)
unsignedchar t = Temp[0]; for(m=0; m<3; m++) }
{
Temp[m] = Sbox[Temp[(m+1)%4]]; }
Temp[3] = Sbox[t]; Temp[0] ^= RC[i-1]; }
{
ExpandKey[i][m][j] =ExpandKey[i-1][m][j] ^ Temp[m]; // } } }
for(m=0; m<4; m++)