背景
AES加密的几种模式
基本运算
AES加密原理
Matlab实现
Verilog实现
Testbench
本文首发于公众号【两猿社】,重点讲述了AES加密算法的加密模式和原理,用MATLAB和Verilog进行加解密的实现。
美剧《硅谷》第六季居然已经完结了!小猿追了6年的剧就这么结束了,然而结局感觉并不那么喜剧。比尔·盖茨和Twitter前CEO也在最后一集本色出演了。
《硅谷》每一季的内容都紧跟当时科技前沿,最后一季也不例外,焦点聚集于信息安全。经过Richard升级之后的超级AI—Son of Anton2.0,因为能自动破解现存世界上任何一种加密算法,使得世界上再无隐私可言,而迫使Pied Piper宣布解散,至此全季终。剧中提到了一种加密算法:ECC P-256。
ECC是椭圆曲线密码学(Elliptic Curve Cryptography)的简称,而P-256是“P-256”椭圆曲线。
听上去挺唬人,这个P-256加密安全性怎么样呢?
早在2011年,美国国家标准技术研究院(NIST)审查了有关攻击密码算法的学术文献,并对不同算法提供的实际安全性提出了建议。
可以看到,P-256的安全性和AES-128等同。在同等密钥长度密钥条件下,AES的加密安全性超过Hash、RSA和ECC。
AES加密究竟是个什么算法呢?
废话不多说,我们直接进入正题!
(小猿尽可能用浅显易懂的方式讲解,但文中也不可避免的出现了一些公式和计算,篇幅较长,具有一定专业性。如果您仅想要获取源码,请直接跳到文末。)
*ps:*关注公众号【两猿社】,回复【AES】可获取Matlab和Verilog源码,还有NIST FIPS原版AES spec哦!
随着5G等高新技术的快速普及,大众生活水平和认知的同步提高,信息安全逐渐引起普通受众的重视。再加上硬件加密相比软件加密的天生优势,国内加密芯片也开始崭露头角,在IC行业中拥有了一席之位。
AES (Advanced Encryption Standard)是由NIST标准化的对称分组密码,是对称加密事实上的标准(上文提到的ECC属于非对称加密)。由于上一代的DES算法密钥长度小(56bits),容易被破解而被AES取代。可以发现,目前市面上几乎所有的大型SOC芯片中,AES的身影必不可少。
在AES中,数据块固定128bits长度,加解密的密钥长度有三种,分别是128bits,192bits和256bits。本文以AES-128bits为例讲解。其他两种密钥长度在实现上仅是密钥扩展和轮数的差别。
将以32bits为一个字长进行分组,由于数据固有128bits,数据的分组长度Nb常为4,密钥分组长度Nk分别为4(128bits)、6(192bits)和8(256bits)。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hly75dcA-1583044212984)(https://upload-images.jianshu.io/upload_images/21180371-f1d19552e8aa8bb7?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)]
AES加密的几种模式
ECB是最简单的块密码加密模式,加密前根据加密块大小(如AES为128位)分成若干块,将使用相同的密钥和相同的算法对每个块进行加密,解密同理。
ECB模式由于每块数据的加密是独立的,因此加密和解密都可以并行计算,ECB模式最大的缺点是加密相同的明文会得到相同的密文。
CBC模式对于每个待加密的密码块在加密前会先与前一个密码块的密文异或然后再用加密器加密。第一个明文块与初始化向量(IV)异或,IV具有与加密块相同的大小。通常,IV是随机数,而不是定数。
明文分为多个块,需要添加填充数据。首先,我们将对IV使用明文块异或。然后,将结果经过AES核加密得到密文块。在下一个块中,将使用加密结果与明文块进行异或,一直到最后一个块。
在这种模式下,即使加密相同的明文块,也将获得不同的密文块。
与ECB和CBC模式只能够加密块数据不同,CFB能够将块密文(Block Cipher)转换为流密文(Stream Cipher),它仍需要IV。
首先,需加密IV,将其与明文块进行异或运算得到密文。然后将加密结果再加密,与明文进行异或。由于此模式不会直接加密明文,仅使用密文与明文进行异或运算以获取密文。因此,在这种模式下,不需要填充数据。
而且它可以并行解密数据。此模式类似于CBC,如果有坏块,它将影响所有后续块。
OFB是先用块加密器生成密钥流(Keystream),然后再将密钥流与明文流异或得到密文流,解密是先用块加密器生成密钥流,再将密钥流与密文流异或得到明文,由于异或操作的对称性所以加密和解密的流程是完全一样的。
它与CFB不同,它始终对IV进行加密。它不能并行加密/解密IV。
在CTR操作模式下,计数值作为加密器(Encrypt)的输入块,即为IV,计数器的值(Counter,Counter + 1,…,Counter + N – 1)被加密。它也是流加密器。
计数器的大小与所用块的大小相同。如图所示,将加密器的输出块与明文块异或。所有加密块都使用相同的加密密钥。这种模式下,它不会受到坏块的影响。非常像OFB模式。但是CTR每次都会使用计数器进行加密,而不是使用IV。因此,如果可以直接获得计数器,则可以并行加密/解密数据。
注:上文所提到的块加密器即FIPS第197号文中所描述的 AES加密算法,即AES加密核。
咳咳,好了,上面是什么玩意儿不管了,没关系,让我们重新开始学加法和乘法吧…
行行行,你看一遍能懂算我输。
AES算法中,所涉及到的计算都是在有限域GF( 2 8 2^8 28)上的。
GF( 2 8 2^8 28)域是由8位2进制数组成,其空间大小为256(00~ff),因此记为 2 8 2^8 28。
在有限域中进行的加法运算和乘法运算不同于我们平常使用的基本算术运算,下面是它的几个特点:
单比特的相加实则是异或操作。
1⊕1=0
1⊕0=1
0⊕0=0
多比特相加则对应系数异或:
有限域GF( 2 8 2^8 28)上的乘法运算较为复杂,依然满足分配律和结合律。
GF( 2 8 2^8 28)域中的两个多项式做乘法后,其最高次项会在0~14之间,需要对一个最高次项为8的固定不可约分多项式取模。
在AES算法中运算都是以字节为单位的,其不可约分多项式固定为
m ( x ) = x 8 + x 4 + x 3 + x + 1 m(x)=x^8+x^4+x^3+x+1 m(x)=x8+x4+x3+x+1
二进制形式表示为{0000001}{00011011},十六进制为{01}{1b}
。
取模运算后使最终结果的多项式x的最高次项不大于7,才能适应AES算法的字节运算要求。如果做乘法之后的最高次项不大于7,则不需要做取模运算。
由于有限域中乘法运算符合交换律和分配律,多项式与任何数的乘法运算都可以分解为多个乘{02}与{01}后的有限域加法运算,与{02}的乘法运算可以用移位实现,与{01}的乘法运算结果则是其本身。
AES算法中每个计算单位都是8位,乘法分解之后最高次项最大为 x 8 x^8 x8( x 7 x^7 x7•{02}),移位后的等效多项式如下:
m ( x ) = b 7 x 8 + b 6 x 7 + b 5 x 6 + b 4 x 5 + b 3 x 4 + b 2 x 3 + b 1 x 2 + b 0 x m(x)=b_7x^8+b_6x^7+b_5x^6+b_4x^5+b_3x^4+b_2x^3+b_1x^2+b_0x m(x)=b7x8+b6x7+b5x6+b4x5+b3x4+b2x3+b1x2+b0x
如果 x 8 x^8 x8项系数 b 7 b_7 b7为0,则证明结果无溢出;为1则证明结果溢出,需要与{01}{1b}取模运算。由于已经事先知道最高项为8次方项,与{01}取模后的结果为0。因此只用考虑与{1b}的取模运算,而最高次项此时最大为7次方,与{1b}的取模运算和异或操作等同。
加法很简单吧,你说什么,乘法看不懂?没关系,接着往下看。
AES-128bits加密算法中共有十轮迭代变换,每一轮迭代包含4个计算,分别是字节替换(SubBytes)、行移位(ShiftRows)、列混合(MixColumns)及轮密钥加(AddRoundKey)。
可以表示为:
Round (State,RoundKey)
{
SubBytes (state);
ShiftRows (state);
MixColumns (state);
AddRoundKey(state);
}
明文在输入加密核之后,经过第一次轮密钥加,开始轮函数的迭代,即依次通过字节替换,行移位,列混合和轮密钥加运算;而在最后一轮即第十轮变换时,省去了列混合这一步骤。
解密的步骤刚好相反,顺序不同。密文通过一次轮密钥加之后,进入解密轮函数,依次是行移位,字节替换,轮密钥加和列混合的逆运算(由于轮密钥加为异或运算,其逆运算也是异或运算,所以它的逆运算不变),最后一轮同样也没有逆列混合。
注意加密和解密所用的扩展后密钥顺序是相反的,且加解密的最后一个操作都是轮密钥加,这样可以防止攻击者绕过密钥而直接对系统进行攻击,使算法具有很好的安全性。
字节替换(SubBytes)是AES算法中惟一的非线性运算,使用替换表(S-Box)对矩阵中的每一个字节元素进行独立运算。且s-box是可逆的。为了实现方便,使用S-Box替换的方式进行。verilog中使用查找表实现。
转换方式为:假设输入的字节为{ a 7 a_7 a7 a 6 a_6 a6 a 5 a_5 a5 a 4 a_4 a4 a 3 a_3 a3 a 2 a_2 a2 a 1 a_1 a1 a 0 a_0 a0}
则经过S-Box之后的输出值为S[ a 7 a_7 a7 a 6 a_6 a6 a 5 a_5 a5 a 4 a_4 a4][ a 3 a_3 a3 a 2 a_2 a2 a 1 a_1 a1 a 0 a_0 a0]
例如:如输入二进制字节为{10110100},十六进制为{B4},参照S-Box替换表替换后的值为S[B][4]=8D,再经过Inverse S-Box可得到替换前的值 =B4(AES解密中的逆变换会在下一篇讲解)。
行移位(ShiftRows)是实现4×4矩阵内部字节的置换。
实际操作是:第零行不改动,将第一行每个字向左循环移1 byte,第二行每个字向左循环移2 byte,第三行每个字向左循环移3 byte。
列混合(MixColumns)是对GF( 2 8 2^8 28)域某些算术性质的等效,是状态矩阵与域中一个固定多项式做乘法运算,然后与多项式( x 4 + 1 x^4+1 x4+1)取模,其中固定多项式a(x)为:
a ( x ) = ( 03 ) x 3 + ( 01 ) x 2 + ( 01 ) x + ( 02 ) a(x)=(03)x^3+(01)x^2+(01)x+(02) a(x)=(03)x3+(01)x2+(01)x+(02)
()中的数为十六进制字节。则列混合表示为:
s ′ ( x ) = a ( x ) • s ( x ) s'(x)=a(x)•s(x) s′(x)=a(x)•s(x)
用矩阵乘法表示为:
可以看出,固定矩阵的值由3个十六进制字节组成,即{01}、{02}、{03},列混合中的加法运算和乘法运算都是有限域中的算术运算。所以符合以下规则:
- 某个字节的值乘以{02},则是将该字节向左移1 bit,如果该字节最高位为1(移位后溢出),则要将乘2后的值异或{1b},二进制形式为{00011011};
- GF( 2 8 2^8 28)域中的乘法运算满足分配律,例如:
07 • S 0 , 0 = ( 01 ⊕ 02 ⊕ 04 ) S 0 , 0 = S 0 , 0 ⊕ ( 02 • S 0 , 0 ) ⊕ ( 04 • S 0 , 0 ) 07•S_0,_0=(01⊕02⊕04)S_0,_0=S_0,_0⊕(02•S_0,_0)⊕(04•S_0,_0) 07•S0,0=(01⊕02⊕04)S0,0=S0,0⊕(02•S0,0)⊕(04•S0,0)
轮密钥加(AddRoundKey)的计算原理相对简单,将输入状态矩阵中对应的元素与输入的密钥或者扩展后的密钥相异或。
密钥扩展(KeyExpansion)是用输入的128位(AES-128)密钥做为初始密钥,使用特定的计算方法产生新的扩展密钥的操作。
对AES-128来说,密钥扩展共有10轮,每一轮产生4个32bits的子密钥,一共产生10×4×32bits的子密钥。
上图(a)中,k矩阵为输入的128bits初始密钥,按每列4个字节的方式分为4个32bits的字,将这4个初始密钥组合成的字 w 1 w_1 w1, w 2 w_2 w2, w 3 w_3 w3, w 4 w_4 w4作为加密时第一次轮密钥加的轮密钥。然后依次以下面的方法求出 w j w_j wj。
- 若j不为4的整数倍,则 w j w_j wj由下式确定:
w j = w j − 4 ⊕ w j − 1 w_j=w_j-_4⊕w_j-_1 wj=wj−4⊕wj−1- 若j为4的整数倍,则 w j w_j wj由下式确定:
w j = w j − 4 ⊕ g ( w j − 1 ) w_j=w_j-_4⊕g(w_j-_1) wj=wj−4⊕g(wj−1)
g ( w ) g(w) g(w)函数如(b)所示,操作如下:
- 首先将w中的元素循环左移1 byte,
- 每个元素在S-Box进行替换
- 与32bits常量{RC[j/4],00,00,00}异或,其中RC是一个固定的一维数组,RC值如下:RC={00,01,02,04,08,10,20,40,80,1B,36}
ps:原本的RC值有10个(没有RC[0]即00),而此处加上00是为了公式中表示数组时的便利。在g函数的运算过程中,由于j的值最小为4,j/4的值最小为1,所以不会产生影响。
现在加密轮函数和密钥扩展都已经知道了,那按照加密流程中一步步计算,即可得到加密后的密文。
由于篇幅原因,本文只对加密原理进行讲解,解密原理即逆运算原理如有需要会在后续更新,可关注后续文章。
matlab验证结果。(源码获取关注公众号【两猿社】,回复【AES】)
本设计为AES-128bits,输入的128bits明文和初始密钥,对明文(密文)进行十轮加解密之后输出密文(明文)。
该设计包含数据收发模块、Sbox和Inv_Sbox模块、密钥扩展模块以及加解密模块。其中在加密模式下,由于每字节明文对应一个Sbox,则加密时需要16个Sbox(密钥扩展在开始加密前就已经完成,所用的4个Sbox可复用),解密模式下需要16个Inv_Sbox和4个Sbox(密钥扩展)。
考虑到AES-128模式下密钥及明文或密文的宽度都是128bits,如果使用FPGA直接综合,输入和输出至少需要384个IO口,因此为了节约IO口,本设计使用32bits宽度进行数据的传输。
Testbench结构包括发送模型send_model,接收模型receive_model,仿真模型即参考模型refer_model和自动对比模型auto_com。
呼,终于完了,现在你了解AES加密了吗?
关注公众号【两猿社】,微信号 : twomonkeysclub
回复【AES】获取Matlab和Veriolg源码。
在这里,我会分享互联网、IC编程知识,以及一些有趣的想法和经历。