随着集成电路与工艺技术的发展,现在单芯片的处理能力越来越强,传统的加密算法DES已经被证明不太安全了,为此美国国家标准技术研究院(NIST)于2001 年11 月26 日发布了新的加密算法AES用来取代DES算法,并于2002年5月26日制定了新的高级加密标准(AES)规范。,如今AES加密算法已经在金融、电信等多方面获得了广泛的应用。本文基于Spartan-3E FPGA设计AES加解密模块,由于应用中数据吞吐量不大,所以主要的重点是尽量减少面积来实现设计。
一、算法简介
根据AES标准,加密过程主要包括四种操作,分别为字节代换、行移位、列混合和轮密钥加。字节替代是对State中每个字节进行的一个独立非线性变换,一般由查表得到。行移位就是State行进行不同的移位,第一行不移,第二行左移一个字节,第三行左移二个字节,第四行左移个三字节。列混合为有限域GF(28)上的多项式运算。轮密钥加就是数据和密钥的异或。
加密流程用伪码表示如下:
Cipher(byte in[4*Nb], byte out[4*Nb], word w[Nb*(Nr+1)])
begin
byte state[4,Nb]
state = in
AddRoundKey(state, w[0, Nb-1]) //轮密钥加
for round = 1 step 1 to Nr–1
SubBytes(state) //字节代换
ShiftRows(state) //行移位
MixColumns(state) //列混合
AddRoundKey(state, w[round*Nb, (round+1)*Nb-1])
end for
SubBytes(state)
ShiftRows(state)
AddRoundKey(state, w[Nr*Nb, (Nr+1)*Nb-1])
out = state
end
每一轮用的密钥不一样,所以输入的密钥实现要经过密钥扩展。
解密过程是加密过程的反,主要包括四种操作,分别为反字节代换、反行移位、反列混合和轮密钥加(轮密钥加为异或,再异或一次和取反的效果一样),解密流程用伪码表示如下:
InvCipher(byte in[4*Nb], byte out[4*Nb], word w[Nb*(Nr+1)])
begin
byte state[4,Nb]
state = in
AddRoundKey(state, w[Nr*Nb, (Nr+1)*Nb-1]) //轮密钥加
for round = Nr-1 step -1 downto 1
InvShiftRows(state) //反字节代换
InvSubBytes(state) //反行移位
AddRoundKey(state, w[round*Nb, (round+1)*Nb-1])
InvMixColumns(state) //反列混合
end for
InvShiftRows(state)
InvSubBytes(state)
AddRoundKey(state, w[0, Nb-1])
out = state
end
具体的算法操作请参考AES标准,这里就不再描述了。
二、设计时的考虑与总结
1. 首先是复位问题,考虑到实际中密钥不是经常变动,所以没有必要设计成动态扩展密钥, 一般是密钥写入后扩展出所有要用的密钥后存储起来,要用时直接读出就可,所以模块设计时分为两个复位输入,一个复位AES加解密模块,另外一个单独用来复位密钥扩展模块。
2.加解密流程的同构,按AES原始算法, 解密时数据流和加密时方向是反的, 经过各模块的顺序不一样不利于实现, 所以要采用等效算法,标准里也提到了,这里要注意下使用等效算法时扩展密钥的使用顺序和原始解密算法一样,是反着过来的,但第一轮后开始密钥要经过反列混合运算。
3.列混合运算和反列混合运算本质上是矩阵运算,有些类似的部分可以共用,这有利减小实现面积。逆列混和运算可用矩阵表示如下:

从上图中可以看到只要把数据经过一个(最右边的)简单的矩阵运算后再经过列混合运算就可以得到逆列混和运算结果。最右边矩阵的01表示是数据本身,02是数据经过一次xtime运算的结果, 03就是数据本身和一次xtime运算结果的加。xtime运算请参考AES标准。
4.密钥和状态state的存储问题,如果简单用寄存器来保存的话,会占用很多Slice.所以要用内部的块BRAM实现,一种是用IP CORE实现,另外一种是用HDL写RAM程序,希望综合工具(如ISE的XST)能推断为BRAM。用HDL写RAM程序时注意,不要随便在程序其它地方就直接使用内部RAM的值,而是应该通过读写地址的方式使用,否则综合工具可能并不用BRAM来实现,我刚开始设计时在做行移位运算就直接把所有状态state进行硬连线移位,发现这样做特别耗资源。
5. 字节代换的优化问题,字节代换和反字节代换在AES标准中都是由查表实现,这在用FPGA实现AES算法时是可行,因为FPGA存储资源比较多,如XC3S250E的RAMB16s有12个;有文献提到用电路实现,我个人觉的比较耗资源,不如查表来的直接,但考虑到字节代换和反字节代换运算其实有些运算部分是可以共用的。根据AES标准,字节代换运算用公式表示为:
y = M•multiplicative_inver se ( x) + c
其中:

反字节代换运算用公式表示为:
x = multiplicative_inverse-1--M--1- ( y + c) ]
= multiplicative_inver se[ M-1- ( y + c) ]
这里M-1为矩阵M的逆矩阵。
从上面可以看到字节代换和反字节代换运算可以共用有限域GF (28 ) 上的乘法求逆运算,这部分电路比较复杂,我们用一个查表来实现,这样就不用字节代换和反字节代换分别存储一个列表了。
6.最后说明下串行执行时位宽的选择,可以选择8位或16位或32位。选择的位宽越小,字节代换和反字节代换运算、列混合运算和反列混合运算等模块的面积就越小,但随之而来的是控制方面越来越复杂,而在设计实现中控制模块占用面积的比例是比较大的,综合考虑我们用32位宽来实现。
欢迎大家来讨论与交流,本文为“安富利杯”赛灵思FPGA设计技巧与应用创新博文大赛参赛作品。 |