AES加密算法原理图文Word下载.docx
《AES加密算法原理图文Word下载.docx》由会员分享,可在线阅读,更多相关《AES加密算法原理图文Word下载.docx(14页珍藏版)》请在冰豆网上搜索。
变量Nk代表以32位字为单位的种子密钥长度。
稍后我分析AES实现时你将清楚地看到w[]是怎样产生的。
关键是这里现在有许多密钥使用而不只是一个。
这些新的密钥被称为轮密钥(roundkeys)以将它们与原始种子密钥区别开来。
Figure4State(态)数组
AES加密例程开始是拷贝16字节的输入数组到一个名为
State(态)的4×
4字节矩阵中。
(参见Figure4)。
AES加密算法取名为Cipher,它操作State[],其过程描述的伪代码参见Figure5。
在规范中,加密算法实现的一个预备的处理步骤被称为AddRoundKey(轮密钥加)。
AddRoundKey用密钥调度表中的前四行对State矩阵实行一个字节一个字节的异或(XOR)操作,并用轮密钥表w[c,r]异或输入State[r,c]。
举个例子,如果State矩阵的第一行保存的字节是{00,44,88,cc},第一列密钥调度表是{00,04,08,0c},那么新的State[0,2]值是用w[2,0](0x08或0x80)异或State[0,2](0x88)的结果:
1000100000001000XOR10000000
AES算法的主循环对State矩阵执行四个不同的操作,在规范中被称为SubBytes(字节替换)、ShiftRows(行位移变换)、MixColumns(列混合变换)和AddRoundKey。
除了每次循环AddRoundKey都被调用并使用密钥调度表的下面四行外,AddRoundKey与预备处理步骤中的AddRoundKey相同。
SubBytes例程是一个代替操作,它将State矩阵中的每个字节替换成一个由Sbox决定的新字节。
比如,如果State[0,1]的值是0x40如果你想找到它的代替者,你取State[0,1]的值(0x40)并让x等于左边的数字(4)并让y等于右边的数字(0)。
然后你用x和y作为索引进到Sbox表中寻找代替值,如Figure2所示。
ShiftRows是一个置换操作,它将State矩阵中的字节向左旋转。
Figure6示范了ShiftRows如何操作State[]。
State的第0行被向左旋转0个位置,State的第1行被向左旋转1个位置,State的第2行被向左旋转2个位置,而State的第3行被向左旋转3个位置。
Figure6对State进行ShiftRows操作
MixColumns是一个代替操作,它是理解AES算法时最具技巧(或者说是最需要动脑筋的部分)的部分。
它用State字节列的值进行数学域加和域乘的结果代替每个字节。
我将在下一节中详细解释专门的域加和域乘细节。
假设State[0,1]的值是0x09,并且列1上的其它值分别为0x60,0xe1和0x04,那么State[0,1]的新值计算如下:
[cpp]
viewplaincopy
1.State[0,1]
=
(State[0,1]
*
0x01)
+
(State[1,1]
0x02)
+(State[2,1]
0x03)
+(State[3,1]
0x01)=
(0x09
(0x60
(0xe1
+(0x04
0x57
此处加法和乘法是专门的数学域操作,而不是平常整数的加法和乘法。
SubBytes、ShiftRows、MixColumns和AddRoundKey四个操作在一个执行Nr次的循环里被调用,Nr为给定密钥大小的轮数减1。
加密算法使用的轮数要么是10,12,要么是14,这依赖于种子密钥长度是128位、192位还是256位。
在这个例子中,因为Nr等于12,则这四个操作被调用11次。
该迭代完成后,在拷贝State矩阵到输出参数前,加密算法调用SubBytes、ShiftRows和AddRoundKey后结束。
大致说来,AES加密算法的核心有四个操作。
AddRoundKey使用从种子密钥值中生成的轮密钥代替4组字节。
SubBytes替换用一个代替表替换单个字节。
ShiftRows通过旋转4字节行的4组字节进行序列置换。
MixColumns用域加和域乘的组合来替换字节。
有限域GF(28)的加法和乘法
正如你所看到的,AES加密算法使用相当简单明了的技术来代替和置换,除MixColumns例程以外。
MixColumns使用特殊的加法和乘法。
AES所用的加法和乘法是基于数学(译者注:
近世代数)的域论。
尤其是AES基于有限域GF(28)。
GF(28)由一组从0x00到0xff的256个值组成,加上加法和乘法,因此是(28)。
GF代表伽罗瓦域,以发明这一理论的数学家的名字命名。
GF(28)的一个特性是一个加法或乘法的操作的结果必须是在{0x00...0xff}这组数中。
虽然域论是相当深奥的,但GF(28)加法的最终结果却很简单。
GF(28)加法就是异或(XOR)操作。
然而,GF(28)的乘法有点繁难。
正如你稍后将在C#实现中所看到的,AES的加密和解密例程需要知道怎样只用七个常量0x01、0x02、0x03、0x09、0x0b、0x0d和0x0e来相乘。
所以我不全面介绍GF(28)的乘法,而只是针对这七种特殊情况进行说明。
在GF(28)中用0x01的乘法是特殊的;
它相当于普通算术中用1做乘法并且结果也同样—任何值乘0x01等于其自身。
现在让我们看看用0x02做乘法。
和加法的情况相同,理论是深奥的,但最终结果十分简单。
只要被乘的值小于0x80,这时乘法的结果就是该值左移1比特位。
如果被乘的值大于或等于0x80,这时乘法的结果就是左移1比特位再用值0x1b异或。
它防止了“域溢出”并保持乘法的乘积在范围以内。
一旦你在GF(28)中用0x02建立了加法和乘法,你就可以用任何常量去定义乘法。
用0x03做乘法时,你可以将0x03分解为2的幂之和。
为了用0x03乘以任意字节b,因为0x03=0x02+0x01,因此:
b*0x03=b*(0x02+0x01)=(b*0x02)+(b*0x01)这是可以行得通的,因为你知道如何用0x02和0x01相乘和相加,同哩,用0x0d去乘以任意字节b可以这样做:
1.b
0x0d
2.
b
(0x08
0x04
3.
(b
0x08)
0x04)
4.
0x02
在加解密算法中,AESMixColumns例程的其它乘法遵循大体相同的模式,如下所示:
0x09
0x01)b
0x0b
0x0e
5.
6.
总之,在GF(28)中,加法是异或操作。
其乘法将分解成加法和用0x02做的乘法,而用0x02做的乘法是一个有条件的左移1比特位。
AES规范中包括大量有关GF(28)操作的附加信息。
密钥扩展
AES加密和解密算法使用了一个由种子密钥字节数组生成的密钥调度表。
AES规范中称之为密钥扩展例程(KeyExpansion)。
从本质上讲,从一个原始密钥中生成多重密钥以代替使用单个密钥大大增加了比特位的扩散。
虽然不是无法抵御的困难,但理解KeyExpansion仍是AES算法中的一个难点。
KeyExpansion例程高级伪代码如下所示:
KeyExpansion(byte[]key,byte[][4]w){copytheseedkeyintothefirstrowsofwforeachremainingrowofw{usetwoofthepreviousrowstocreateanewrow}}“用前面两行来产生一个新行”(“usetwoofthepreviousrowstocreateanewrow”)的例程用到了两个子例程,RotWord和SubWord以及一个名为“Rcon”的常数表(作为“轮常数”)。
让我们先来逐个看一下这三东西,然后再回到整个KeyExpansion的讨论中来。
RotWord例程很简单。
它接受一个4个字节的数组并将它们向左旋转一个位置。
因为轮调度表w[]有四列,RotWord将w[]的1行左旋。
注意KeyExpansion使用的这个RotWord函数与加密算法使用的
ShiftRows(行位移变换)例程非常相似,只是它处理的是单行密钥调度w[],而不是整个加密状态表State[]。
SubWord例程使用替换表Sbox对一给定的一行密钥调度表w[]进行逐字节替换。
KeyExpansion操作中的替换实际上就像在加密算法中的替换一样。
被代替的输入字节被分成(x,y)对,它被当作进入替换表Sbox的索引。
举例来说,0x27的代替结果是x=2和y=7,并且Sbox[2,7]返回0xcc。
KeyExpansion例程使用一个被称为轮常数表的数组Rcon[]。
这些常数都是4个字节,每一个与密钥调度表的某一行相匹配。
AES的KeyExpansion例程需要11个轮常数。
你可以在Figure7中看到这些常数清单。
每个轮常数的最左边的字节是GF(28)域中2的幂次方。
它的另一个表示方法是其每个值是前一个值乘上0x02,正如前一部分讨论GF(28)乘法时所描述的那样。
注意0x80×
0x02=0x1b是0x80左移1个比特位后紧接着与0x1b进行异或,如前所述。
现在让我们更进一步看看KeyExpansion内幕中的循环。
这里所用的伪码比以前更为详细,这个循环是:
1.for
(row
Nk;
row
<
(4
Nr+1);
++row)
2.{
temp
w[row-1]
if
%
Nk
==
0)
SubWord(RotWord(temp))
xor
Rcon[row/Nk]
else
(Nk
8
and
4)
SubWord(temp)
w[row]
w[row-Nk]
7.}
先不要去看if子句,你将看到密钥调度表w[]的每一行都是前面一行与行Nk异或的结果(4,6,或8取决于密钥的长度)。
if条件的第一部分用SubWord、RotWord以及与轮常数的异或修改密钥调度表的每个第4、第6或第8行,取决于是否密钥的长度是128、192或256位。
这个条件的第二部分将修改行12、20和28等等——对于256位密钥而言——每一个第8行都将添加密钥调度额外的可变性。
让我们用本文开头所举的例子来考察KeyExpansion是如何开始的。
种子密钥是192-bit/6-word值:
000102030405060708090a0b0c0d0e0f1011121314151617 密钥调度字节表w[]的维数是4列并且Nb×
(Nr+1)等于4×
(12+1),或52行。
KeyExpansion将种子密钥的值拷贝到密钥调度字节表w[]的第一行。
因为我的种子密钥是192位(24字节),并且w[]表总是4列,在这种情况下KeyExapansion将种子密钥拷贝到w[]的前面6行。
现在让我们看看KeyExapansion例程是如何填充密钥调度表其余部分的。
在我的例子里,第一个被计算的行是第6行,因为第0-5行已被种子密钥的值填上了:
temp=w[row-1]=14151617条件(row%Nk==0)为真,因此首先RotWord子程序被应用:
temp=15161714这时SubWord被应用:
temp=5947f0fa用Rcon[row/Nk]=Rcon[6/6]=01000000进行异或:
temp=5847f0fa这时用w[row-Nk]=w[6-6]=00010203异或,产生了下面结果:
w[6]=5846f2f9密钥调度表w[]中其余所有行来重复这个过程本身。
总而言之,AES加密和解密的一个重要部分就是从最初的种子密钥中生成多重轮密钥。
这个KeyExapansion算法生成一个密钥调度并以某种方式进行替代和置换,在这种方式中,加密和解密算法极其相似。
一.AES对称加密:
AES加密
分组
二.分组密码的填充
分组密码的填充
PKCS#5填充方式
三.流密码
四.分组密码加密中的四种模式:
3.1ECB模式
优点:
1.简单;
2.有利于并行计算;
3.误差不会被传送;
缺点:
1.不能隐藏明文的模式;
2.可能对明文进行主动攻击;
3.2CBC模式:
优点:
1.不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL、IPSec的标准。
缺点:
1.不利于并行计算;
2.误差传递;
3.需要初始化向量IV3.3CFB模式:
1.隐藏了明文模式;
2.分组密码转化为流模式;
3.可以及时加密传送小于分组的数据;
1.不利于并行计算;
2.对明文的主动攻击是可能的;
3.误差传送:
一个明文单元损坏影响多个单元;
2.误差传送:
3.唯一的IV;
3.4OFB模式:
下面是示例代码:
[java]
1.package
mini.code.test.t20120810;
3.import
javax.crypto.*;
4.import
javax.crypto.spec.*;
6.public
class
AES
7.{
8.
public
static
String
asHex(byte
buf[])
9.
{
10.
StringBuffer
strbuf
new
StringBuffer(buf.length
2);
11.
int
i;
12.
for
(i
0;
i
buf.length;
i++)
13.
14.
(((int)
buf[i]
&
0xff)
0x10)
15.
strbuf.append("
0"
);
16.
strbuf.append(Long.toString((int)
0xff,
16));
17.
}
18.
return
strbuf.toString();
19.
20.
21.
void
main(String[]
args)
throws
Exception
22.
23.
24.
message
"
这是个加密的例子"
;
25.
System.out.println("
原文:
message);
26.
原文转换格式显示:
asHex(message.getBytes()));
//
string=》byte=》Hex
27.
======生成密码
28.
KeyGenerator
kgen
KeyGenerator.getInstance("
AES"
获取密匙生成器
29.
kgen.init(128);
生成128位的AES密码生成器
30.
SecretKey
skey
kgen.generateKey();
生成密匙
31.
byte[]
raw
skey.getEncoded();
编码格式
32.
SecretKeySpec
skeySpec
SecretKeySpec(raw,
生成一组扩展密钥,并放入一个数组之中
33.
Cipher
cipher
Cipher.getInstance("
34.
cipher.init(Cipher.ENCRYPT_MODE,
skeySpec);
用ENCRYPT_MODE模式,用skeySpec密码组,生成AES加密方法
35.
========加密message
36.
encrypted
cipher.doFinal(message.getBytes());
加密message
37.
加密后:
encrypted);
打印密文
38.
密文转换格式后:
asHex(encrypted));
把密文转换成16进制格式
39.
=======解密
40.
cipher.init(Cipher.DECRYPT_MODE,
41.
original
cipher.doFinal(encrypted);
解密
42.
originalString
String(original,
UTF8"
重新显示明文
43.