您的位置:首页 > 编程语言 > C语言/C++

【密码学】AES加解密原理及其C++实现算法

2017-04-14 00:21 691 查看

AES简介

高级加密标准(Advanced Encryption Standard,AES),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院(NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。2006年,高级加密标准已然成为对称密钥加密中最流行的算法之一。

AES基于被称为代换-置换网络的设计原理,代换和置换的组合,并且在软件和硬件中都很能有效实现,与其前身DES不同,AES不使用Feistel网络。AES是Rijndael的变体,其固定块大小为128位,密钥大小为128,192或256位。 相比之下,Rijndael规范本身是以块和密钥大小来指定的,这些大小可以是32位的任意倍数,最小值为128,最多为256位。

AES操作建立在称为“State”(状态)的4×4列的列主序字节矩阵,尽管某些版本的Rijndael具有较大的块大小,并且在该状态中具有其他列。大多数AES计算是在特定的有限域中完成的。

举个例子,这里有16个字节b0,b1,……,b15,用矩阵表示为:



AES是一个迭代性密码,轮数取决于密钥长度,轮数如下:

密钥长度为128比特,则轮数为10

密钥长度为192比特,则轮数为12

密钥长度为256比特,则轮数为14

每轮由几个处理步骤组成,每个处理步骤包含四个相似但不同的阶段,包括依赖于密钥本身的阶段。 使用一组反向轮来用相同的密钥将密文转换回原始明文。

加解密过程



AES的加密过程描述如下:

KeyExpansions—轮密钥使用Rijndael算法的密钥编排密码密钥导出。AES需要为每个回合加一个单独的128位的循环密钥块。

InitialRound

AddRoundKey—状态的每个字节用按位异或的轮密钥块组合

Rounds

SubBytes—非线性替代步骤,其中根据查找表将每个字节替换为另一个。

ShiftRows—一种转置步骤,其中状态的最后三行循环地移动一定数量的步骤。

MixColumns—混合操作,其操作在状态的列上,组合每列中的四个字节。

AddRoundKey

Final Round (no MixColumns)

SubBytes

ShiftRows

AddRoundKey

SubBytes



操作SubBytes使用一个S盒对State的每一个字节都进行一个独立的代换,其中S盒是一个16*16的矩阵,其中行号和列号都用十六进制表示。

比如:00通过S盒的代换为S[0][0]=63。若是逆向字节替换,那么S-1[6][3]=00

S盒的矩阵表示为:

// 0     1     2     3     4     5     6     7     8     9     a     b     c     d     e     f
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, // 0
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, // 1
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, // 2
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, // 3
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, // 4
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, // 5
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, // 6
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, // 7
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, // 8
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, // 9
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, // a
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, // b
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, // c
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, // d
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, // e
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16, // f


S盒的逆表示为:

// 0     1     2     3     4     5     6     7     8     9     a     b     c     d     e     f
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, // 0
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, // 1
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, // 2
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, // 3
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, // 4
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, // 5
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, // 6
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, // 7
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, // 8
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, // 9
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, // a
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, // b
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, // c
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, // d
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, // e
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d, // f


ShiftRows



对State的ShiftRows操作为:第一行保存不变,第二行循环左移1个字节,第三行循环左移2个字节,第四行循环左移3个字节。

用公式表示为:State[i][j] = State[i][(i+j) % 4]

若是逆向行移位,则是相反操作,公式为:State[i][j] = state[i][(4+i-j) % 4]

MixColumns



State的每一列都被一个新列替代,这个新列由原列乘上域F(2^8)中的元素组成的矩阵而来。矩阵如下:

02 03 01 01
01 02 03 01
01 01 02 03
03 01 01 02


这里的“乘”是指域F(2^8)中的乘法。需要注意如下几点:

将某个字节所对应的值乘以2,其结果就是将该值的二进制位左移一位,如果该值的最高位为1(表示该数值不小于128),则还需要将移位后的结果异或00011011

乘法对加法满足分配率。例如:07·S00=(01⊕02⊕04)·S00= S00⊕(02·S00)(04·S00)

此处的矩阵乘法与一般意义上矩阵的乘法有所不同,各个值在相加时使用的是模2加法(相当于是异或运算)

假设某一列的值如下图,运算过程如下:



同理可以求出另外几个值。

若是逆向列混淆,则密文通过乘以域F(2^8)中元素矩阵的逆矩阵,即可恢复原文。逆矩阵如下:

0E 0B 0D 09
09 0E 0B 0D
0D 09 0E 0B
0B 0D 09 0E


AddRoundKey



加密过程中,每轮的输入与轮密钥异或一次。

任何数和自身的异或结果为0。因此,解密时再异或上该轮的密钥即可恢复输入。

密钥扩展



密钥扩展的描述为:对10轮版本的AES,需要11个轮密钥,每个轮密钥由16个字节组成。密钥编排算法是面向字的(一个字由4个字节组成,即32bits)。因此,每一个轮密钥由4个字组成。轮密钥的并联叫做扩展密钥,共包含44个字,表示为w[0],…,w[43],其中每个w[i]都是一个字。

密钥扩展过程说明:

将初始密钥以列为主,转化为4个32bits的字,分别记为w[0],…w[3]

按照如下方式,依次计算w[j],其中j是整数并且属于[4,43]

若j%4=0,则w[j]=w[j-4]⊕g(w[j-1]),否则w[j]=w[j-4]⊕w[j-1]

函数g的流程说明:

将w循环左移一个字节

分别对每个字节按S盒进行映射

与32bits的常量(RC[j/4],0,0,0)进行异或,RCon是一个一维数组,其值如下。(RCon的值只需要有10个,而此处用了11个,实际上RCon[0]在运算中没有用到,增加RCon[0]是为了便于程序中用数组表示。由于j的最小取值是4,j/4的最小取值则是1,因此不会产生错误)

RCon[0]=00000000
RCon[1]=01000000
RCon[2]=02000000
RCon[3]=04000000
RCon[4]=08000000
RCon[5]=10000000
RCon[6]=20000000
RCon[7]=40000000
RCon[8]=80000000
RCon[9]=1B000000
RCon[10]=36000000


源代码

此源代码来自Github

https://github.com/dhuertas/AES/blob/master/aes.c
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  AES 加解密 密码学 C++