当前位置:文档之家› AES加密解密算法的设计与实现

AES加密解密算法的设计与实现

AES加密解密算法的设计与实现
AES加密解密算法的设计与实现

目录

1.引言 (1)

2.AES加密解密原理 (2)

3.AES加密解密算法的组成部分 (6)

3.1密钥部分 (6)

3.1.1 AES的S盒 (6)

3.1.2 AES的逆S盒 (7)

3.1.3 轮常量 (8)

3.1.4密钥移位函数 (8)

3.1.5密钥字代换函数 (8)

3.1.6密钥扩展算法 (9)

3.2加密的部分 (10)

3.2.1轮密钥加变换AddRoundKey(与密钥扩展的异或运算) (10)

3.2.2字节代换SubBytes(即S盒变换) (11)

3.2.3行移位变换ShiftRows (13)

3.2.4列混淆变换MixColumns (14)

3.3解密的部分 (15)

3.3.1逆行移位变换InvShiftRows (15)

3.3.2逆向字节代换(即逆S盒变换) (16)

3.3.3轮密钥加变换 (17)

3.3.4逆列混淆变换 (17)

4.AES加密解密算法的改进 (18)

5.结束语 (19)

1.引言

对称密码算法主要用于保证数据的机密性,通信双方在加密/解密过程中使用它们共享的单一密钥。对称密码算法的使用相当广泛,密码学界已经对它们进行了深入的研究[1]。最常用的对称密码算法是数据加密标准(DES) 算法,它是由IBM在美国国家安全局(NSA) 授意之下研制的一种使用56 位密钥的分组密码算法[2]。该算法从1977 年公布成为美国政府的商用加密标准后,使用了30 多年。

随着社会的发展,科学技术日新月异,密码分析水平、芯片处理能力和计算技术也不断地进步,二十世纪七十年代到现在应用广泛的DES数据加密标准算法因为其密钥长度较小(仅有56位),已经越来越难适应当今社会的加密技术和安全要求,其实现速度、代码大小和跨平台性也不足以适应新的各种应用要求。

1997年,RSA安全赞助了一系列的竞赛,奖励第一个成功破解以DES加密的信息的队伍1万美元,洛克·韦尔谢什(Rocke Verser),马特·柯廷(Matt Curtin)和贾斯廷·多尔斯基(Justin Dolske)领导的DESCHALL计划获胜,该计划使用了数千台连接到互联网的计算机的闲置计算能力[3]。证明了DES的密钥长度(56位),能被当前社会加密解密技术破解,其安全性有待提高。1998年,电子前哨基金会(EFF,一个信息人权组织)制造了一台DES破解器[4]。虽然其制造价格约$250,000,但是它用两天多一点儿的时间就暴力破解了一个密钥,显示出迅速破解DES的可能性,说明了DES的安全性已经开始降低。

DES 的主要问题是其密钥长度较短(仅56位),已经不适应当今分布式开放网络对数据加密安全性的要求。随着计算机能力的突飞猛进,已经超期服役的DES终于显得力不从心。在这种形势下,迫切需要设计一种强有力的算法作为新的一代分组加密标准,所以在DES 每隔五年的评估会议中, 1997年美国国家标准技术研究院(NIST,National Institute of Standards and Technology)公开征集新的数据加密标准,最后一次美国政府终于决定不再继续延用DES作为联邦加密标准,也就表明了DES 将退出加密标准的舞台,而新的标准:高级加密标准AES(Advanced Encryption Standard) 走上了历史的舞台[5]。该算法作为新一代的数据加密标准汇聚了安全性、效率、密钥灵活性、多样性、简单性和对称性等优点。

因此1997年美国国家标准技术研究院(NIST,National Institute of Standards and Technology)公开征集新的数据加密标准,即AES[6]。该算法作为新一代的数据加密标准

1

汇聚了安全性、效率、密钥灵活性、多样性、简单性和对称性等优点。

高级加密标准(AES),这个标准用来替代上一个世纪的DES,已经被多方分析并且广为全世界所使用。经过长达五年的甄选流程,得出了结果[7]。高级加密标准由美国国家标准与技术研究院(NIST)在2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准[8]。2006年,高级加密标准(AES)发展成为了对称密钥加密中最流行的算法之一。

AES是美国国家标准技术研究所NIST旨在取代DES的新一代的加密标准。NIST 对AES候选算法的基本要求是:对称分组密码体制;密钥长度支持128、192、256位;明文分组长度128 位;算法应易于各种硬件和软件实现。1998年NIST开始AES 第一轮征集、分析、测试,共产生了15 个候选算法。1999 年3 月完成了第二轮AES 的分析、测试。1999 年8 月NIST公布了五种算法(MARS,RC6,Rijndael,Serpent,Twofish) 成为候选算法[9]。经过激烈的角逐,Rijndael ,由比利时人设计的算法与其它候选算法在成为高级加密标准(AES) 的竞争中取得成功,于2000 年10月被NIST宣布成为取代DES 的新一代的数据加密标准,即AES(这也是为什么人们将AES算法叫作Rijndael算法的原因) [10]。尽管人们对AES还有不同的看法,但总体来说,Rijndael作为新一代的数据加密标准汇聚了强安全性、高性能、高效率、易用和灵活等优点。AES的三个密钥长度:128、192和256 比特。它与DES相比,它的128 比特密钥比DES的56 比特密钥要强上10^21倍。

2.AES加密解密原理

AES和Rijndael加密法并不完全一样(虽然在实际应用中二者可以互换),因为Rijndael加密法可以支持更大范围的区块和密钥长度:AES的区块长度固定为128 比特,密钥长度则可以是128,192或256比特;而Rijndael使用的密钥和区块长度可以是32位的整数倍,以128位为下限,256比特为上限。加密过程中使用的密钥是由Rijndael密钥生成方案产生[11]。

AES 算法基于排列和置换运算。排列是对数据重新进行安排,置换是将一个数据单元替换为另一个。AES 使用几种不同的方法来执行排列和置换运算。大多数AES 计算是在一个特别的有限域完成的。

AES加密过程是在一个4×4的字节矩阵上运作,这个矩阵又称为“体(state)”,其初值就是一个明文区块(矩阵中一个元素大小就是明文区块中的一个Byte)[12]。

2

(Rijndael加密法因支持更大的区块,其矩阵行数可视情况增加)加密时,各轮AES 加密循环(除最后一轮外)均包含4个步骤:

轮密钥加变换AddRoundKey—矩阵中的每一个字节都与该次回合密钥(round key)做XOR运算;每个子密钥由密钥生成方案产生。

字节代换(通常叫做S盒变换)SubBytes—将字节变换方法制成S盒表格,通过查表把每个字节进行快速变换成对应的字节。

行移位变换ShiftRows—将矩阵中的每个横列进行循环式移位。

列混淆变换MixColumns—为了充分混合矩阵中各个直行的操作。这个步骤使用线性转换来混合每内联的四个字节。最后一个加密循环中省略MixColumns步骤,而以另一个AddRoundKey取代[13]。

AES是一个迭代的、对称密钥分组的密码,它可以使用128、192和256位密钥长度,并且用128位分组长度加密和解密数据。该算法输入分组、输出分组、状态长度均为128比特[14]。

对于AES算法的运算是在一个称为状态的二维字节数组上进行。一个状态由四行组成,每一行包括Nb个字节,Nb等于分组长度除以32,AES分组长度为128位,因此,Nb=4,该值反应了状态中32-bit字的个数(列数);密钥长度128、192和256位可分别表示为Nk=4、6或8,反应了密钥中32-bit字的个数(列数)[15]。而AES算法的轮数Nr仅依赖于密钥长度Nk,轮数和密钥长度的关系可以表示为:Nr=6+Nk密钥长度—分组长度—轮数的关系如表2.1所示。

表2.1 Key-Block-Round三者之间关系

对于加密和解密变换,AES算法使用的轮函数由4个不同的以字节为基本单位的变换复合而成,该过程由四个不同的阶段组成]:

(1)S盒变换,用一个S盒完成分组中的按字节代替;(2)行移位变换,一个简单的置换;(3)列混淆变换,一个利用在域GF(28) 上的算术性的代替;(4)轮密钥加变换,

3

一个利用当前分组和扩展密钥的一个部分进行按位异或[16]。

AES对数据的加密过程是通过把输入的明文和密钥由轮函数经Nr轮迭代来实现的,结尾轮与前Nr-1轮不同。前Nr-1轮依次进行S盒变换、行移位变换、列混淆变换和轮密钥加变换;结尾轮与前Nr-1轮相比去掉了列混淆变换[17]。

而解密过程与加密过程相反,通过把输入的密文和密钥由轮函数经Nr轮迭代来实现的,结尾轮与前Nr-1轮不同[18]。前Nr-1轮依次进行逆行移位变换、逆S盒变换、轮密钥加变换和逆列混淆变换;结尾轮与前Nr-1轮相比去掉了逆列混淆变换。

AES算法的加密解密过程如下所示:

4

5

3.AES加密解密算法的组成部分

3.1密钥部分

3.1.1 AES的S盒

static unsigned char AesSbox[16*16]=

{

// AES的S盒

/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */

/*0*/ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,

/*1*/ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,

/*2*/ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,

/*3*/ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,

/*4*/ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,

/*5*/ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,

/*6*/ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,

/*7*/ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,

/*8*/ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,

/*9*/ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,

/*a*/ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,

/*b*/ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,

/*c*/ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,

/*d*/ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,

/*e*/ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,

/*f*/ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16

6

};

3.1.2 AES的逆S盒

static unsigned char AesiSbox[16*16]=

{

// AES的逆S盒

/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */

/*0*/ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,

/*1*/ 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,

/*2*/ 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,

/*3*/ 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,

/*4*/ 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,

/*5*/ 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,

/*6*/ 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,

/*7*/ 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,

/*8*/ 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,

/*9*/ 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,

/*a*/ 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,

/*b*/ 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,

/*c*/ 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,

/*d*/ 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,

/*e*/ 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,

/*f*/ 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d

};

7

3.1.3 轮常量

static unsigned char AesRcon[11*4]=

{

// 轮常量最右边三个字总为0

0x00, 0x00, 0x00, 0x00,

0x01, 0x00, 0x00, 0x00,

0x02, 0x00, 0x00, 0x00,

0x04, 0x00, 0x00, 0x00,

0x08, 0x00, 0x00, 0x00,

0x10, 0x00, 0x00, 0x00,

0x20, 0x00, 0x00, 0x00,

0x40, 0x00, 0x00, 0x00,

0x80, 0x00, 0x00, 0x00,

0x1b, 0x00, 0x00, 0x00,

0x36, 0x00, 0x00, 0x00

};

3.1.4密钥移位函数

unsigned char* RotWord(unsigned char* word)

{

byte* temp = new byte[4];

temp[0] = word[1]; //实现左移一个字节

temp[1] = word[2];

temp[2] = word[3];

temp[3] = word[0];

return temp;

};

3.1.5密钥字代换函数

unsigned char* SubWord(unsigned char* word)

{

byte* temp = new byte[4];

for(int j=0;j<4;j++)

{

temp[j] = AesSbox[16*(word[j] >> 4)+(word[j] & 0x0f)]; //将该字节的高4位作为行值,低4位作为列值,取出S盒中对应元素作为输出

8

}

return temp;

};

3.1.6密钥扩展算法

AES加密解密过程中,每一轮都需要一个与输入分组具有相同长度的扩展密钥W[i]的参与[19]。由于外部输入的加密密钥长度有限,所以在算法中要用一个密钥扩展程序把外部密钥扩展成更长的比特串,以生成各轮的加密和解密密钥。AES算法利用外部输入密钥,涉及上述的模块:轮常量AesRcon,密钥移位函数RotWord,密钥字代换函数SubWord。

通过生成器产生Nr+1轮轮密钥,每个轮密钥由Nb个字组成,共有Nb(Nr+1)个字W[i],i=0,1,……,Nb(Nr+1)-1。

void KeyExpansion()

{

int row;

memset(w,0,16*15);

for(row=0;row

{

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=SubWord(RotWord(temp)); //先移位,再代换,最后和轮常量异或

9

10

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 = SubWord(temp);

//

}

// w[row] = w[row-Nk] xor 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] );

}

};

3.2加密的部分

3.2.1轮密钥加变换AddRoundKey (与密钥扩展的异或运算)

轮密钥加变换中,回合密钥(round key )将会与原矩阵合并[20]。在每次的加密循环中,都会由主密钥产生一把回合密钥(通过Rijndael 密钥生成方案产生),这把密钥大小会跟原矩阵一样,以与原矩阵中每个对应的字节作异或加法。轮密钥加变换用于将输入或中间态S 的每一列与一个密钥字W[i]进行按位异或,其中,[](0,1,,4(1)r W i i N =???+-由原始密钥通过密钥扩展算法产生。

void AddRoundKey(int round)

{

int i,j; //i 行 j 列 //因为密钥w 是一列一列排列的,即 k0 k4 k8 k12

for(j=0;j<4;j++) // k1 k5 k9 k13

{

// k2 k6 k10k14

for(i=0;i<4;i++) // k3 k7 k11k15

{

// 所以i行j列的下标是4*((round*4)+j)+i即16*round+4*j+i State[i][j]=(unsigned char)((int)State[i][j]^(int)w[4*((round*4)+j)+i]);

}

}

};

3.2.2字节代换SubBytes(即S盒变换)

S盒变换,是一个基于S盒的非线性置换,它用于输入或中间态的每一个字节通过一个简单的查表操作,将其映射为另一个字节。映射方法是:把输入字节的高4位作为S盒的行值,低4位作为列值,然后取出S盒中对应行和列的元素作为输出。例如,输入为“89”(十六进制)的值所对应的S盒的行值为“8”,列值为“9”,S盒中相应位置的值为“a7”,就说明“89”被映射为“87”。

void SubBytes()

{

int i,j;

for(j=0;j<4;j++)

{

for(i=0;i<4;i++)

{

State[i][j]=AesSbox[State[i][j]];

//因为16*(State[i][j]>>4)+State[i][j]&0x0f=State[i][j]

}

}

}

矩阵中的各字节通过一个8位的S-box进行转换。这个步骤提供了加密法非线性的变换能力。S-box与GF(28)上的乘法反元素有关,已知具有良好的非线性特性。

11

为了避免简单代数性质的攻击,S-box结合了乘法反元素及一个可逆的仿射变换矩阵建构而成。

定义在GF(2^8)上的乘法:

unsigned char gfmultby01(unsigned char b) //乘1

{

return b;

};

unsigned char gfmultby02(unsigned char b) //乘2

{

if (b < 0x80)

return (unsigned char)(int)(b <<1);

else

return (unsigned char)( (int)(b << 1) ^ (int)(0x1b) );

};

unsigned char gfmultby03(unsigned char b) //乘3就是乘以2后再加

{

return (unsigned char) ( (int)gfmultby02(b) ^ (int)b );

};

unsigned char gfmultby09(unsigned char b) //乘9就是乘以2乘以2乘以2后再加

{

return (unsigned char)( (int)gfmultby02(gfmultby02(gfmultby02(b))) ^ (int)b );

};

unsigned char gfmultby0b(unsigned char b) //乘0b 表示为8+2+1

{

return (unsigned char)( (int)gfmultby02(gfmultby02(gfmultby02(b))) ^

(int)gfmultby02(b) ^ (int)b );

};

12

unsigned char gfmultby0d(unsigned char b) //乘0d 表示为8+4+1

{

return (unsigned char)( (int)gfmultby02(gfmultby02(gfmultby02(b))) ^

(int)gfmultby02(gfmultby02(b)) ^ (int)(b) );

};

unsigned char gfmultby0e(unsigned char b) //乘0e 表示为8+4+2

{

return (unsigned char)( (int)gfmultby02(gfmultby02(gfmultby02(b))) ^

(int)gfmultby02(gfmultby02(b)) ^(int)gfmultby02(b) );

};

3.2.3行移位变换ShiftRows

行移位变换完成基于行的循环移位操作,即行移位变换的作用在中间态的行上,第0行不动,第1行循环左移1个字节,第2行循环左移2个字节,第3行循环左移3个字节[21]。在此步骤中,每一行都向左循环位移某个偏移量。在AES中(区块大小128位),第一行维持不变,第二行里的每个字节都向左循环移动一格。同理,第三行及第四行向左循环位移的偏移量就分别是2和3。128位和192比特的区块在此步骤的循环位移的模式相同[21]。经过行移位变换之后,矩阵中每一竖列,都是由输入矩阵中的每个不同列中的元素组成。

void 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];

}

13

}

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位

}

}

}

3.2.4列混淆变换MixColumns

在列混淆变换步骤,每一列的四个字节通过线性变换互相结合[22]。每一列的四个元素分别当作1 , x , x^2 , x^3的系数,合并即为GF(28)中的一个多项式,接着将此多项式和一个固定的多项式c (x) = 3x^3 + x^2 + x + 2在modulo x^4+1下相乘。此步骤亦可视为Rijndael有限域之下的矩阵乘法。MixColumns函数接受4个字节的输入,输出4个字节,每一个输入的字节都会对输出的四个字节造成影响。行移位变换和列混淆变换这两个环节为这个密码系统提供了扩散性。

void 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];

}

14

}

for(j=0;j<4;j++)

{

State[0][j] = (unsigned char) ( (int)gfmultby02(temp[0+j]) ^ (int)gfmultby03(temp[4*1+j]) ^ (int)gfmultby01(temp[4*2+j]) ^ (int)gfmultby01(temp[4*3+j]) );

State[1][j] = (unsigned char) ( (int)gfmultby01(temp[0+j]) ^ (int)gfmultby02(temp[4*1+j]) ^ (int)gfmultby03(temp[4*2+j]) ^ (int)gfmultby01(temp[4*3+j]) );

State[2][j] = (unsigned char) ( (int)gfmultby01(temp[0+j]) ^ (int)gfmultby01(temp[4*1+j]) ^ (int)gfmultby02(temp[4*2+j]) ^ (int)gfmultby03(temp[4*3+j]) );

State[3][j] = (unsigned char) ( (int)gfmultby03(temp[0+j]) ^ (int)gfmultby01(temp[4*1+j]) ^ (int)gfmultby01(temp[4*2+j]) ^ (int)gfmultby02(temp[4*3+j]) );

}

};

3.3解密的部分

解密过程是加密的逆过程,S盒变换、行移位变换、列混淆变换都要进行求逆变换,即逆S盒变换、逆行移位变换、逆列混淆变换。而轮密钥加变换与加密过程相同。

3.3.1逆行移位变换InvShiftRows

与行移位变换相反,逆行移位变换将态State的后三行按相反的方向进行移位操作,即第0行保持不变,第1行向右移1个字节,第2行向右移2个字节,第3行向右移3个字节[23]。

void InvShiftRows() //逆向行移位函数

{

unsigned char temp[4*4];

int i,j;

for(j=0;j<4;j++)

{

for(i=0;i<4;i++)

{

15

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];

if(i==1)State[i][j]=temp[4*i+(j+3)%4]; //第一行右移1位j-1+4=j+3

else if(i==2)State[i][j]=temp[4*i+(j+2)%4]; //第二行右移2位j-2+4=j+2

else if(i==3)State[i][j]=temp[4*i+(j+1)%4]; //第三行右移3位j-3+4=j+2

}

}

};

3.3.2逆向字节代换(即逆S盒变换)

与字节代换类似,逆向字节代换是基于逆S盒实现的。

void InvSubBytes() //逆向字节代换

{

int i,j;

for(j=0;j<4;j++)

{

for(i=0;i<4;i++)

{

State[i][j]=AesiSbox[State[i][j]]; //因为16*(State[i][j]>>4)+State[i][j]&0x0f=State[i][j] }

}

16

}

3.3.3轮密钥加变换

轮密钥加变换与上述加密过程的函数相同。

3.3.4逆列混淆变换

逆列混淆变换的处理方法与列混淆变换类似,每一列都通过与一个固定的多项相乘进行变换。

void InvMixColumns() //逆向列混淆

{

unsigned char temp[4*4];

int i,j;

for (i = 0; i < 4; i++) //将State数组拷入到temp[]中

{

for (j = 0; j < 4; j++) //0e 0b 0d 09 逆变换矩阵

{

//09 0e 0b 0d

temp[4*i+j] = State[i][j]; //0d 09 0e 0b

} //0b 0d 09 0e

}

for (j = 0; j < 4; j++)

{

State[0][j] = (unsigned char) ( (int)gfmultby0e(temp[j]) ^ (int)gfmultby0b(temp[4+j]) ^ (int)gfmultby0d(temp[4*2+j]) ^ (int)gfmultby09(temp[4*3+j]) );

State[1][j] = (unsigned char) ( (int)gfmultby09(temp[j]) ^ (int)gfmultby0e(temp[4+j]) ^ (int)gfmultby0b(temp[4*2+j]) ^ (int)gfmultby0d(temp[4*3+j]) );

State[2][j] = (unsigned char) ( (int)gfmultby0d(temp[j]) ^ (int)gfmultby09(temp[4+j]) ^ (int)gfmultby0e(temp[4*2+j]) ^ (int)gfmultby0b(temp[4*3+j]) );

State[3][j] = (unsigned char) ( (int)gfmultby0b(temp[j]) ^ (int)gfmultby0d(temp[4+j]) ^ (int)gfmultby09(temp[4*2+j]) ^ (int)gfmultby0e(temp[4*3+j]) );

}

};

17

4.AES加密解密算法的改进

在完成AES加密解密算法的基础上,对该过程中的密文进行改动,根据时间的变化(星期一至星期天),对密文的前10位中的每一位增加(或删除)一个数值变量(1—7字节,星期一对应1 ,星期二对应2,星期三对应3,以此类推),增加了7种可选择的功能,变化灵活,彼此通信的安全性相比原算法得到提高。

除了使用上述所说的“时间和星期的关系”的方法,还可以用“时间和日期的关系”的方法。假如今天是9号,密文发送时,就对原密文的前10位中每一位加上数值9;如果是23号发送的密文,对原密文的前10位中每一位加上数值23。这些关系是通信双方所设定的,随通信双方的约定而改变,具有很大的灵活性。当今社会,为了保证密码的安全,管理人员经常要隔一定的时间更换一次密钥,本次做出的改动极大地减少了人员频繁更换密钥的烦恼,其多种选择和变换,相比原AES有了更好的安全性。

本次使用128位的AES加密解密算法,设定明文为16位,密钥也是16位。

加密

加密示例。假设今天是星期三,加密方A要发送一个信息给B。A使用AES加密得到密文时,在原来密文的基础上,其中前10位密文中每一位都加上一个数值“3”,这种独特的加密方法仅有双方约定才明白。如图4.1:

图4.1

可知A要发送的信息就是“密文再次输出”的信息。前后两次的密文对面,前10位不同,后6位不变,使密文再次加密。这样,即使加A送的密文被敌人截取,敌人运用到AES来破解,也很难破解出A的明文。

解密

解密示例。假设今在星期三,解密方B收到来自加密方A的密文。B需在来密文的基础上,其中前10位密文每一位都减去一个数值“3”,如下:

图4.2

18

相关主题
文本预览
相关文档 最新文档