上篇,我们学习了AES加密算法,你以为这就完了吗?还没有;今天我们向底层讲解,将它学透,为下一篇打下基础。哈哈,还有下一篇,你怕了么。这一篇比较枯燥,给学有余力的同学来完成。
1、AES加密过程
AES算法主要有四种操作处理,分别是轮密钥加层(Add Round Key)、字节代换层(SubBytes)、行位移层(Shift Rows)、列混淆层(Mix Columns)。AES加密的过程,并不是明文和密钥简单xor。以AES128为例,它要执行10轮加密。实际的执行过程是这样的:
第0轮,将原始数据和原始密钥进行异或;
第1-9轮,执行SubBytes,ShiftRows,MixColumns,AddRoundKey的完整流程;
第10轮,执行SubBytes,ShiftRows,不执行MixColumns。
2、加密过程代码示例
type
PState = ^TState;
TState = array[0..3, 0..3] of Byte;
PRoundKey = ^TRoundKey;
TRoundKey = array of Byte;
procedure Cipher(state: PState; RoundKey: PRoundKey);
var
round: Byte;
begin
// 添加第一轮密钥
AddRoundKey(0, state, RoundKey);
// 一共有n轮。
for round := 1 to Nr - 1 do
begin
SubBytes(state);
ShiftRows(state);
MixColumns(state);
AddRoundKey(round, state, RoundKey);
end;
// 最后一轮
SubBytes(state);
ShiftRows(state);
AddRoundKey(Nr, state, RoundKey);
end;
(1)SBox:定义AES算法中使用的S盒(Substitution Box)
const SBox: array[0..255] of Byte = ( $63, $7C, $77, $7B, $F2, $6B, $6F, $C5, $30, $01, $67, $2B, $FE, $D7, $AB, $76, // 省略剩余的S盒内容 );
s盒,一张16*16的查找表。对于每个输入的字节,例如输入字节的十六进制形式位0xAB,则在表格的纵坐标中定位A,再在纵坐标中定位B,最后使用s(a,b)的值来替换这个字节的值。通过这个步骤,我们的输入数据D1-D16,变成了S1-S16。
(2)AddRoundKey操作是一种轮密钥加操作,它将状态矩阵与轮密钥进行按位异或运算。轮密钥是根据加密密钥生成的,每一轮都有一个对应的轮密钥。简单来说就是把密钥和混淆后的结果进行xor运算,但在每一轮使用的密钥都是根据上一轮的密钥变换而来的。
以下是AddRoundKey函数示例,包括轮密钥加操作:
procedure AddRoundKey(round: Byte; state: PState; RoundKey: PRoundKey);
var
i, j: Integer;
begin
for i := 0 to 3 do
begin
for j := 0 to 3 do
begin
state[i, j] := state[i, j] xor RoundKey[round * 16 + i * 4 + j];
end;
end;
end;
在上述AddRoundKey函数代码中,根据AES算法规范对状态矩阵进行了轮密钥加操作。遍历状态矩阵中的每个字节,并与对应轮密钥进行按位异或运算。
(3)SubBytes操作是一种字节替换操作,它将状态矩阵中的每个字节替换为一个新的字节,这个替换是通过一个固定的S盒来完成的。S盒是一个固定的256字节的查找表,它将每个输入字节映射到一个唯一的输出字节。
以下是SubBytes函数示例,包括S盒的定义和字节替换操作:
procedure SubBytes(state: PState);
var
i, j: Integer;
begin
for i := 0 to 3 do
begin
for j := 0 to 3 do
begin
// 获取当前状态矩阵中的字节值
state[i, j] := SBox[state[i, j]];
end;
end;
end;
在上述代码中,定义了一个256字节的S盒并使用这个S盒来实现SubBytes操作。在SubBytes函数中,遍历状态矩阵中的每个字节,并使用S盒来替换字节的值。注意,实际的AES算法可能使用不同的S盒,需要根据AES算法规范来使用相应的S盒进行字节替换。
(4)ShiftRows操作是一种行移位操作,它将状态矩阵中的每一行进行循环左移。在AES算法中,将16个S盒变换后的字节,从上往下、从左到右地写成了一个矩阵。第一行保持不动,第二行向左移动1格,第三行向左移动2格,第四行向左滑移动3格,如图所示:
以下是ShiftRows函数示例,包括行移位操作:
procedure ShiftRows(state: PState);
var
temp: Byte;
begin
// 第二行循环左移1个字节
temp := state[1, 0];
state[1, 0] := state[1, 1];
state[1, 1] := state[1, 2];
state[1, 2] := state[1, 3];
state[1, 3] := temp;
// 第三行循环左移2个字节
temp := state[2, 0];
state[2, 0] := state[2, 2];
state[2, 2] := temp;
temp := state[2, 1];
state[2, 1] := state[2, 3];
state[2, 3] := temp;
// 第四行循环左移3个字节
temp := state[3, 3];
state[3, 3] := state[3, 2];
state[3, 2] := state[3, 1];
state[3, 1] := state[3, 0];
state[3, 0] := temp;
end;
在上述代码中,按照AES算法规范对状态矩阵中的每一行进行了相应的行移位操作。注意,实际的AES算法可能有不同的行移位规则,需要根据AES算法规范来实现相应的行移位操作。
(5)MixColumns操作是AES算法中的一种列混淆操作,它将状态矩阵的每一列进行线性变换。在AES算法中,MixColumns操作使用下面这个矩阵和ShiftRows之后的结果相乘。列混淆操作混淆了输入矩阵的每一列,使输入的每个字节都会影响到4个输出字节。
以下是MixColumns函数示例,包括列混淆操作:
procedure MixColumns(state: PState);
var
i: Integer;
a, b, c, d: Byte;
temp: Byte;
begin
for i := 0 to 3 do
begin
a := state[0, i];
b := state[1, i];
c := state[2, i];
d := state[3, i];
state[0, i] := Mul2(a) xor Mul3(b) xor c xor d;
state[1, i] := a xor Mul2(b) xor Mul3(c) xor d;
state[2, i] := a xor b xor Mul2(c) xor Mul3(d);
state[3, i] := Mul3(a) xor b xor c xor Mul2(d);
end;
end;
function Mul2(x: Byte): Byte;
begin
if x < 0x80 then
Result := x shl 1
else
Result := (x shl 1) xor $1B;
end;
function Mul3(x: Byte): Byte;
begin
Result := Mul2(x) xor x;
end;
在上述MixColumns函数代码中,根据AES算法规范对状态矩阵的每一列进行了列混淆操作。使用了固定的矩阵乘法运算来实现列混淆。注意,实际的AES算法可能使用不同的列混淆规则,需要根据AES算法规范来实现相应的列混淆操作。
3、AES解密过程
procedure InvCipher(state: PState; RoundKey: PRoundKey);
var
round: Byte;
begin
// Add the First round key
AddRoundKey(Nr, state, RoundKey);
// There will be Nr rounds.
for round := (Nr - 1) downto 1 do
begin
InvShiftRows(state);
InvSubBytes(state);
AddRoundKey(round, state, RoundKey);
InvMixColumns(state);
end;
// The last round is given below.
InvShiftRows(state);
InvSubBytes(state);
AddRoundKey(0, state, RoundKey);
end;
对应上面的加密过程的逆向过程,这里是 for round := (Nr - 1) downto 1 do。
4、AES加密模式和Padding
AES只能对固定长度的数据进行加密,对于不定长的数据,我们需要把它切分成若干定长的数据,再进行加密解密,这就是我们常说的分组加密。我们简单介绍下CBC模式以及Padding的对加密解密的影响,作为上篇的一个小补充吧。
CBC模式对于每个待加密的密码块在加密前会先与前一个密码块的密文异或然后再用加密器加密,第一个明文块与一个叫初始化向量IV的数据块异或。具体见下图:
完成加密或解密后会更新初始化向量IV,CBC模式安全性更高,但由于对每个数据块的加密依赖前一个数据块的加密,加密是无法并行的。
Padding:在AES加密与解密的过程中,如果需要加密的数据不是16的倍数的时候,需要对原来的数据做填充操作。填充的方式有pkcs7padding/zeropadding/NoPadding等。
我们看看不同的填充方式是如何进行填充的,例设一开始的数据是FF FF FF FF FF FF FF FF FF
PKCS7填充:FF FF FF FF FF FF FF FF FF 07 07 07 07 07 07 07
Zeros填充:FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00
NoPadding:不填充,需要自己保证数据是16的倍数。
显然,不同的padding对加密与解密是有影响的,所以在加密和解密的时候需要保证padding的方式是一致的。
总结:理论上大部分的算法都是可以破解的,只是需要很长时间的计算,AES加密算法直接破解几乎是不可能的;使用AES-128就可以满足我们的需求,现在很多硬件芯片和软件工具都对AES支持,是个性能非常高的加解密算法。
原文始发于微信公众号(MicroPest):跟我来学习AES加密算法(二)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论