AES加密反馈式硬件结构的实现及sv测试平台搭建

发布时间:2019-03-13 10:23:04   来源:文档文库   
字号:

AES加密的反馈式硬件结构实现

赵重阳

2016.3.4完成全部编写调试工作及报告的撰写 总计十天

RijndaelAES加密算法属于加密算法中的私钥加密算法,其特点是算法简便,加密过程和解密过程对称,速度快,吞吐量大。在效率方面要由于非对称加密的的公钥加密体系,如ECC加密,RSA加密等。其密钥长度在之前的DES加密基础上做了延伸,涵盖128位,192位,256位三种密码长度,安全性较之DES更强。

由于AES加密是私钥匙加密,故在主加密过程开始之前需要产生加密所需的密钥。我们会输入一个种子密钥,通过密钥扩展过程产生一个加密所需的密钥。

128192256位所需的种子密钥依次是4行(一行32bit,称为一个字),6行和8行,主加密过程轮数依次是101214。密钥扩展的过程主要包括下面三个阶段:行左移、字节替换、异或,之后再与前面一行密钥做异或得到新的一行密钥。我们用NR来表示种子密钥的行数,ROUND来表示加密过程的轮数。

算法的软件代码如下:

for (int i = NR; i < NK * (ROUND + 1); i++)
{
    TEMP temp;
temp = w[i-1]; //在上一行密钥的基础上扩展
if (i%NR == 0){ //如果扩展的轮数可以整除NR
rotWord(temp);
subWord(sbox, temp);
makeXor(i,temp);ه
}
else if ((NR == 8) && (i%NR == 4))
{
subWord(sbox,temp);
}
w[i] = temp[j] ^ w[i - NR]; //最后与前NR行做异或

一、密钥扩展模块

考虑密钥扩展模块的硬件实现结构,没有必要使用ROUND个相同的流水线电路结构来实现该模块,非反馈的流水线方式可以提高电路的吞吐量和效率,但是面积和占用的资源会很大。因为在同一个加密过程中密钥一般是不变的,所以在密钥扩展过程一般只运行一次即可,没有必要做成流水线结构。我们使用一个计数器来记下扩展的轮数 ,使用反馈式的电路结构,将每一轮的输出连接至轮输入,轮数作为循环反馈工作的判断条件来使电路正常工作。

密钥扩展模块的硬件设计框图如下所示:

本文中实现的加密算法密钥长度为192位,故密钥扩展需要NK*(ROUND+1)-NR轮,需要45个时钟周期,在加上读取种子密钥的一个时钟周期,共46个时钟周期后得到密钥输出。

2、密钥扩展系统的输入输出,及重要信号的时序图,及RTL仿真结果:

2.1 重要信号:

<1> 端口信号:

输入 INPUT:

时钟信号:clk

复位信号:reset

密钥种子:key_seed [5:0][31:0]

扩展启动信号:key_begin

输出OUTPUT

扩展密钥: key_out [51:0][31:0]

扩展结束信号:key_done

<2> 内部寄存器信号:

现态寄存器:currentstate enum类型

次态寄存器:nextstate enum类型

扩展轮数寄存信号:counter [5:0]

轮常数寻址信号:rcon_i [3:0]

<3> 内部memoryLUT

Rcon [10:0][31:0] 存放轮常数

Uk0_sbox 实例化的sbox模块用于一行中一个字节替换

Uk1_sbox 同上

Uk2_sbox 同上

Uk3_sbox 同上

2.2 时序设计:

word/media/image2_1.png

word/media/image3_1.png

2.3 RTL仿真结果

该仿真中的种子密钥使用随机数发生器获得,为

7AF66D6D_4CE92F76_B8E7C823_92D49422_500803F0_A4503228

经过硬件密钥扩展后的仿真结果为:

51 : 43b4c843 49d305bd 18d78b8f c7d3a48f

47 : 1954e63c 63698dbb 0a67cdfe 51048e32

43 : df042f00 675d4f5b 7a3d6b87 690e4045

39 : 5b6343cc 8e00a132 b859605b 00225881

35 : 13332bc2 326d0389 d563e2fe 3659c169

31 : b87b38da e3d37dfc 215e284b e70ee177

27 : e33a2397 8e22f9b3 5ba84526 abe7ce01

23 : c650c93c 0434c2e0 6d18da24 d58abc95

19 : f04f8b27 f03a25b5 c2640bdc 692c18c4

15 : b89266b1 25c537b2 0075ae92 b711a390

11 : ab481318 d1be7e75 9d575103 25b09920

7 : b7640d02 e76c0ef2 7af66d6d 4ce92f76

3 : b8e7c823 92d49422 500803f0 a4503228

2.4软件验证:

编写C语言AES 加密程序,将相同的种子密钥输入,经过软件密钥扩展后得到的密钥调度表为:

其结果与我们硬件仿真的结果完全相同,证明了密钥扩展模块的正确性。

3、主加密模块:

3.1 主加密模块原理(循环内部流水线原理)

主加密模块采用的电路结构与密钥扩展模块相似,加密需要ROUND+1轮,本文中ROUND12,也是采用非反馈模式,即没有为每一轮都重新赋值一次相同的电路结构。但cipher模块的电路却与上文中的不完全相同,因为我设计的cipher电路为了最大程度上提高电路的并行工作能力,并且考虑到了寄存器资源和面积的问题,我采用了内部流水线结构。我将加密主模块中的轮运算:字节替换、字节移位、列混合、轮密钥加这四个运算的中间结果做了寄存,如果单单加密一组数据即128字节(4个字),那么对中间结果做寄存那么只是简化了每一级的组合逻辑,用寄存器资源的增加消除了组合逻辑的竞争与险象,在提高时钟频率时使得输出更加可靠。但是,我注意到内部增加了四个寄存器,便可以很方便的将其设计为循环结构的四级流水线。那么,输入明文的字宽可以增加到16个字,事实上4级循环流水线最多也只能同时处理16字的数据量,循环的过程中4组数据依次读入,第一组数据在加密的进度上最快,后面的数据总比前面一组慢一步。比如:第一组的数据加密过程进行到了第8轮的轮密钥加,得到了第8轮轮密钥加的寄存结果。这时第二组数据进行到了第八轮的列混合并得到了列混合的结果。事实上,第一组数据和第四组数据的加密过程紧密首尾咬合,一个时钟周期也不能错。在第nclk上升沿,第一组数据将第i步的结果进行计算得到第i+1步结果;于此同时第四组数据将第i-3步的结果进行计算得到第i-2结果。细心可以发现,第i+1和第i-3步在循环结构里表示同一个点。这中一步也不能差的循环内部流水线反馈结构最大程度上保证了资源的复用和数据并行的协调。

3.2 循环内部流水线结构图

3.3 cipher模块输入输出信号及重要内部信号、memoryLUT

<1> 端口信号

输入信号:

时钟信号: clk

置位信号: reset

输入明文: textIn [15:0][31:0]

输入种子: key_seed [5:0][31:0]

密钥开始: key_begin

加密开始: cipher_begin

输出信号:

加密忙: cipher_busy

加密完成: cipher_done

密钥完成: key_done

密文输出: cipher_out [15:0][31:0]

<2> 内部重要信号

钥匙:Cipher_key [51:0][31:0]

流水迭代次数信号:iterator [7:0]

现态信号: currentstate {Idle,Precipher,ciphering,lastroud,done}

次态信号: nextstate {Idle,Precipher,ciphering,lastroud,done}

密钥调度表指针: wn [7:0] wire信号

输入明文指针: textInPtr [4:0]

输出密文指针: textOut[4:0]

轮密钥加寄存信号:logic [3:0][31:0] state_add;

字节替换寄存信号:logic [3:0][31:0] state_sub;

状态移位寄存信号:logic [3:0][31:0] state_shift;

列混合寄存信号:logic [3:0][31:0] state_mix;

<3> 内部memoryLUT

uc00_sboxuc01_sboxuc02_sboxuc03_sbox

Uc10_sboxuc11_sboxuc12_sboxuc13_sbox

Uc20_sboxuc21_sboxuc22_sboxuc23_sbox

Uc30_sboxuc31_sboxuc32_sboxuc33_sbox

u_key_expand

3.4 列混合组合电路的设计及GF256)乘法

列混合是对态数组中的每一列与一个固定多项式c(x)= ‘03’x^3+’01’x^2+’01’x^1+’02’,之后再模x^4+1,来保证结果的正确性。那么就有了三个运算,就是GF(256)1,乘2,乘3。乘1的结果就是它本身,乘2的规则如下:

若被乘数小于0x80那么结果为被乘数左移一位;如果被乘数大于等于0x80,那么被乘数左移一位后在异或0x1b

该逻辑若采用一般的比较被乘数与0x80的大小来实现,则综合出的电路很复杂。我们直接 使用组合逻辑来实现,那就有了:

Gfmulti02={b[6:0],1’b0}^{8’h1b&8{{b[7]}}};

小于0x80则最高为为0,与任何数相与都为0,再与移位后的结果相异或,得到的结果就是移位后的结果;若大于等于0x80,最高位b[7]1,与后的结果就是0x1b。最终结果是移位后再异或0x1b

用一个简单的函数来实现gfmulti02

function [7:0] gfmulti02;

input [7:0] x;

begin

gfmulti02={x[6:0],1'b0} ^ (8'h1b&{8{x[7]}}); //a^1=a~ a^0=a;

end

endfunction

至于Gfmul03(x)就等于Gfmulti02(x)^(x)

3.5 状态机的设计(四组数据在加密的第i轮处于不同的步骤,如何控制其正确的读取密钥调度表进行运算 ——iterator的判断条件、状态划分、wn的变化) 亮点在于此

主要是第一轮及最后一轮,看起来简单,但是确实仿真了很多次,经历了一个状态一个状态查错的过程。

状态机的状态包括:Idle,Precipher,Ciphering,LastRound,Done.

Idle: Idle状态中电路中的各个中间寄存器state_add,state_sub,state_mix,state_shift都锁存其值;iteratorwntextIn_ptrtextOut_ptr都置0;等待key_begin拉高后进入Precipher状态。

Precipher: 这个状态中循环流水电路开始进行工作,依次在连续的4个时钟周期内读入4组块数据,使得电路中的寄存器都被数据“占据”;于此同时cipher_busy拉高,表示电路已经处于工作状态,外部输入端口不可再增加第五组输入数据,iterator迭代寄存器开始迭代。值得注意的是,此时的addroundkey寄存器输入端口接的是数据state的组合逻辑运算值。循环结构还未行成。

Ciphering: 循环加密的状态,循环流水电路开始工作state_add的输入端接state_mix的组合逻辑结果,行成闭环。电路工作一直进行到iterator等于’d47的时候,即到了下一个时钟上升沿就进行轮密钥加输出的时候。这样设计确保了下个状态中立刻就能得到最终的加密结果,并且轮循环中addroundkey的部分各组数据都能在密钥调度表中使用正确的密钥。

LastRound 最后一个状态中iterator一次迭代到’d51,连续四个周期输出加密后的密文。这时候是将 shift后的结果做轮密钥加,其值赋给cipher_out,利用textOut_ptr做寻址,在相应的位置填入数据。

必须注意!!!这一轮中虽然没有mixcolumn操作,但是mixcolumn寄存器还寄存着第四组数据!!!电路仍需要仍需要将这组数据取出,第四组数据还处于前一轮的状态,还需要对它做轮密钥加操作,密钥当然是上一轮的密钥[wn-4,wn-1]

Done:在这个状态中cipher_done拉高表示加密完成,cipher_out锁存自己使输出密文稳定,并跳至Idle状态,等待下一个cipher_begin拉高。

3.6 时序设计及状态转换图

3.7 系统测试平台的搭建

针对待测设计DUT,我使用system verilog编写了测试激励,并在适当的时刻给DUT加上激励。测试平台和DUT的框图如下:

整个test_bench包括三个initial begin模块,分别是为了控制textIn队列的生成、加密主过程和仿真结束控制。

使用两个class,分别为seed_gentext_gen来产生随机的种子包和明文包,在队列生成的模块中将随机化100次,将这100次的明文依次装入队列中待使用。

Rand bit [`NR-1:0][31:0] seed;

rand bit [15:0][31:0] text;

repeat(nrPkts) begin

tgen = new;

assert(tgen.randomize());

$display("------------------the %4dth text of %4d pkts-------------------"

,i+1,nrPkts);

i=i+1;

tgen.show();

foreach(tgen.text[j])

text_que.push_back(tgen.text[j]);

End

在加密过程的initial begin模块中实例化seed_gen类而得到一个随机化的种子,将种子赋给DUT的输入端口key_seed

assert(sg.randomize());

sg.show();

seed_temp=sg.seed;

ck.reset<=0;

#(10);

ck.reset<=1;

#(40) ck.key_seed <= seed_temp;

#(50) ck.key_begin <= 1;

#(5) ck.key_begin <= 0;

等待密钥扩展完成后紧接着就是向DUT连续按照协议输入nrPkts个明文数据包。当cipher_busy拉低的时候从队列中弹出一个明文数据包给DUTtextIn作为输入,同时拉高cipher_begin进行一个数据包的加密过程,(***值得注意的是***)在加密开始后软件程序的循环部分需要等待硬件代码中的cipher_busy拉高后才进行下一个循环判断,否则会立刻进入下一个循环,又从队列中弹出一个明文数据包。

//loop generations

for(i=0;i!=nrPkts;i++) begin

//if ciphering , cipher_begin =0

while(cipher_busy||!key_done) begin

@(posedge clk)

cipher_begin<=0;

end

if(!cipher_busy) begin

foreach(text_temp[j])

text_temp[j] = text_que.pop_front();

##(1);

@(posedge clk)

textIn<=text_temp; //延迟了两个周期后,cipher_begin拉高,textIn赋值

cipher_begin<=1;

end

//waiting for cipher_busy pull high

while(!cipher_busy) begin

##(1);

end

End

(详细代码请见zcy文件夹的questa_project中编写的的aes_tb.v

3.8 RTL仿真结果

可以看到cipher_begin拉高后进入Precipher,并依次读入textstate_addtextIn_ptr依次加4cipher_busy拉高。进入ciphering后,每四个时钟周期转一圈。

输入四组明文,依次是:

15 : 01707676 037bbb95 8e38c04c 01606da3

11 : 2620b09a ccb9ff39 f9a29a0b 969703b3

7 : f46a0004 d9d728c2 65c6b64b 778f722e

3 : a3c263d5 ceb07427 d716e5d0 23a470d9

硬件机密后仿真后得到的加密结果为:

15 : b8c76024 ea0e5334 3ed4dd9e 1d4d4d7e

11 : 04a16bf1 814abb04 401e2cab d7ac65b3

7 : c3662e6c b9c3f609 0407d44b db99d72d

3 : ac2a6624 886ace0e d2e714eb ec6e837b

3.9 软件验证

输入相同的明文并使用相同的种子,软件验证结果为:

得到的结果与硬件仿真的结果完全正确,整个系统正确性得到了验证!

本文来源:https://www.2haoxitong.net/k/doc/863ab4e6f342336c1eb91a37f111f18583d00cf9.html

《AES加密反馈式硬件结构的实现及sv测试平台搭建.doc》
将本文的Word文档下载到电脑,方便收藏和打印
推荐度:
点击下载文档

文档为doc格式