AES算法及具体步骤

  • AES 高级加密标准
  • 前言
  • AES背景
  • 算法描述
  • 算法流程图
  • State Matrix
  • Key Expansion
  • g函数
  • AddRoundKey
  • Round Function
  • 1. SubBytes
  • 2. ShiftRows
  • 3. MixColumns
  • 4. Add round key
  • Final Round

AES 高级加密标准

前言

之前一直想写CSDN博客但是没有找到可以写的内容,趁着最近刚好在学密码学就可以把自己学习时候的笔记贴上来啦。因为比较菜…所以内容几乎都是参考了教材、百度和wiki里面的,自己整理重述了一下~

AES背景

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

该算法为比利时密码学家Joan Daemen和Vincent Rijmen所设计,结合两位作者的名字,以Rijndael为名投稿高级加密标准的甄选流程。(Rijndael的发音近于"Rhine doll")

算法描述

在原始的Rijndael算法中分组长度和密钥长度都可变,各自可以独立的指定为128 bit、192 bit、256 bit。在AES中,分组长度只能是128 bit,也就是16个字节。(1个字节等于8位,1 Byte = 8 Bit)。密钥长度可以为三者中的任意一种。最广泛 的使用是密钥128 bit,迭代轮数10轮。

AES算法

密钥长度(32 bit)

分组长度(32 bit)

加密和解密轮数

AES-128

4

4

10

AES-192

6

4

12

AES-256

8

4

14

对称密钥使用相同的密钥进行加密和解密,因此发送者和接受者都必须知道并使用相同的秘密密钥。 本文主要基于AES-128。

算法流程图

这个流程图是在github上看到的,自己画的有点简陋,这个图非常清晰就拿来了2333

(后面有几张图好像也是,我把原链接贴在这里)

图源 link

aes key生产_流程图

自己重新整理了一下画的流程图大概长这样:

Round Function

9 times

Final Round

PlainText

AddRoundKey

Key

KeyExpansion

SubBytes

ShiftRows

MixColumns

AddRoundKey

SubBytes

ShiftRows

AddRoundKey

CipherText

下面就详细的讲一些流程图里面的每一个部分

State Matrix

Block cipher is a cryptosystem which encrypts data not by bit but by block,which is group of bits,applying algorithm per block.

分组密码不是按位对数据进行加密,而是按每一组对数据进行整体加密算法。所以首先对明文、密钥进行分组,每一组为1 byte(8 bit),16 x 8=128 bit,因此一共分成了16组,用 4 x 4矩阵表示,该矩阵就称为状态矩阵(State Matrix)。对应上图AddRoundKey和Key Expansion上方的矩阵。

aes key生产_算法_02

用C++实现如下:

//将明文分组拷贝到状态矩阵中
unsigned char state[16];
for (int i = 0; i < 16; i++)
{
	state[i] = message[i];
}

Key Expansion

Key Expansion是将用户输入的key扩展生成多组轮密钥。对应AES-128,AES-192,AES-256,分别扩展出11,13,15组。

假设我们所用的加密方法为AES-128标准,则需要将4个字(1 word = 32 bit)的原始密钥扩展成44个字的轮密钥(4 x 11轮)。具体步骤如下图所示:

图源link

aes key生产_aes key生产_03

g函数

g函数是一个复杂函数,由三个步骤构成:字循环,字节代换和轮常量异或。

  1. 字循环将1个字的4个字节循环左移1个字节,即将字[b0,b1,b2,b3]变为[b1,b2,b3,b0]。
  2. 字节代换基于S盒对输入字中的每个字节进行S代替。
  3. 轮常量异或轮常量Rcon[i]数据表如下:
  4. aes key生产_流程图_04

eg: 假如第8回合的回合密钥为:

EA D2 73 21 B5 8D BA D2 31 2B F5 60 7F 8D 29 2F

那么,第9回合密钥的前4个字节(第一列)的计算过程如下:

temp

字循环

字节代换

Rcon[9]

XOR Rcon

w[i-4]

w[i]

7F8D292F

8D292F7F

5DA515D2

1B000000

46A515D2

EZD27321

AC7766F3

  • temp存第8回合密钥的最后一个字(最后一列)
  • 字循环和字节代换都是对temp数组里的数据
  • Rcon[9]由上图数据表得出
  • XOR Rcon是将temp与Rcon[9]异或此时完成了上图中w到w’的步骤
  • w[i-4]是第8回合密钥的第1个字(第一列)
  • w[i]为最后结果,w[i]=w’ XOR w[i-4]

AddRoundKey

Add round key其实就是将128位的密钥和128位的明文进行逐位异或操作。

aes key生产_流程图_05

用C++实现如下

void AddRoundKey(state, roundkey)
{
	//roundkey 和 state XOR!
	for (int i = 0; i < 16; i++)
	{
		state[i] ^= roundkey[i];
	}
}

Round Function

1. SubBytes

将字节代换的各种可能字节的变换结果排成一个表,称为AES的字节代替表或者S盒。状态矩阵中的元素按照下面的方式通过S盒映射为一个新的字节:把该字节的高4位作为行值,低4位作为列值,取出S盒对应行列的元素作为输出。例如,加密时输入字节 0x12,则查找S盒的第 0x01行,0x02 列,得到的值为 0xC9。S盒如下:

aes key生产_流程图_06

用C++实现如下:

void SubBytes(unsigned char* state)
{
	//S盒字节替换
	for (int i = 0; i < 16; i++)
	{
		state[i] = s_box[state[i]];
	}
}
2. ShiftRows

行位移是将状态矩阵的各行进行循环移位,不同状态行的位移量不同。第0行不移动,第1行循环左移1个字节,第2行循环左移2个字节,第3行循环左移3个字节。如图所示:

aes key生产_加密解密_07

图源自link

用C++实现如下:

void ShiftRows(unsigned char* state)
{
	unsigned char tmp[16];

	//tmp暂存行位移的结果
	tmp[0] = state[0];
	tmp[1] = state[5];
	tmp[2] = state[10];
	tmp[3] = state[15];

	tmp[4] = state[4];
	tmp[5] = state[9];
	tmp[6] = state[14];
	tmp[7] = state[3];

	tmp[8] = state[8];
	tmp[9] = state[13];
	tmp[10] = state[2];
	tmp[11] = state[7];

	tmp[12] = state[12];
	tmp[13] = state[1];
	tmp[14] = state[6];
	tmp[15] = state[11];

	//行位移
	for (int i = 0; i < 16; i++)
	{
		state[i] = tmp[i];
	}
}
3. MixColumns

列混合是一个替代操作,是AES算法中最复杂的一步,只在第0到r-1轮中用到,最后一轮不使用该变换。是通过将state矩阵与常矩阵C相乘以达到在列上的扩散,实质是在有限域GF(256)上的多项式乘法运算。

aes key生产_密码学_08

其中常矩阵C为:

aes key生产_流程图_09

用C++实现如下:

void MixColumns(unsigned char* state)
{
	unsigned char tmp[16];

	//用临时数组保存
	tmp[0] = (unsigned char)(mul2[state[0]] ^ mul3[state[1]] ^ state[2] ^ state[3]);
	tmp[1] = (unsigned char)(state[0] ^ mul2[state[1]] ^ mul3[state[2]] ^ state[3]);
	tmp[2] = (unsigned char)(state[0] ^ state[1] ^ mul2[state[2]] ^ mul3[state[3]]);
	tmp[3] = (unsigned char)(mul3[state[0]] ^ state[1] ^ state[2] ^ mul2[state[3]]);

	tmp[4] = (unsigned char)(mul2[state[4]] ^ mul3[state[5]] ^ state[6] ^ state[7]);
	tmp[5] = (unsigned char)(state[4] ^ mul2[state[5]] ^ mul3[state[6]] ^ state[7]);
	tmp[6] = (unsigned char)(state[4] ^ state[5] ^ mul2[state[6]] ^ mul3[state[7]]);
	tmp[7] = (unsigned char)(mul3[state[4]] ^ state[5] ^ state[6] ^ mul2[state[7]]);

	tmp[8] = (unsigned char)(mul2[state[8]] ^ mul3[state[9]] ^ state[10] ^ state[11]);
	tmp[9] = (unsigned char)(state[8] ^ mul2[state[9]] ^ mul3[state[10]] ^ state[11]);
	tmp[10] = (unsigned char)(state[8] ^ state[9] ^ mul2[state[10]] ^ mul3[state[11]]);
	tmp[11] = (unsigned char)(mul3[state[8]] ^ state[9] ^ state[10] ^ mul2[state[11]]);

	tmp[12] = (unsigned char)(mul2[state[12]] ^ mul3[state[13]] ^ state[14] ^ state[15]);
	tmp[13] = (unsigned char)(state[12] ^ mul2[state[13]] ^ mul3[state[14]] ^ state[15]);
	tmp[14] = (unsigned char)(state[12] ^ state[13] ^ mul2[state[14]] ^ mul3[state[15]]);
	tmp[15] = (unsigned char)(mul3[state[12]] ^ state[13] ^ state[14] ^ mul2[state[15]]);

	//将数据复制到state
	for (int i = 0; i < 16; i++)
	{
		state[i] = tmp[i];
	}
}
4. Add round key

与初始Add round key一样。

Final Round

由上面流程图可以看出,最后一轮没有MixColumns,其他SubBytes,ShiftRows,AddRoundKey都与上述步骤一样。

内容基本就是这么多了,可能会有错误的地方,如果有任何问题欢迎评论~蟹蟹