基于APB总线的SM4密码协处理器实现(附Verilog代码)
- 本文内容摘要
- 理论依据和设计内容
- SM4分组密码算法
- APB_slave协处理器
- 测试过程与结果
- 调试经历
- 测试结果
- SM4.0部分测试
- APB协处理器部分测试
- 整体代码
本文内容摘要
本文使用Verilog语言实现SM4加密协处理器:
- 使用Verilog完成SM4基本模块;
- 定义所需寄存器,添加APB总线接口,完成兼容APB总线的SM4协处理器设计;
理论依据和设计内容
SM4分组密码算法
基于《信息安全技术 SM4分组密码算法》清晰规定了SM4.0的算法流程。SM4.0算法利用分组加密,分组的长度和密钥长度均为128bit。该算法由密钥扩展算法与加密(解密)算法两部分构成,均采用非线性迭代结构,其加密与解密算法具有相同的结构,只是对输入轮密钥进行反序变换。下面我只对加密的算法进行解读:
首先,需要进行输入密钥的分区,将128bits的密钥输入划分到四个32bits的数组中,此处我采用四个32bits数组拼接并赋予密钥输入值实现。这一步后,开始进行密钥扩展算法,它通过一系列变换生成一组32位的轮密钥。在介绍如何扩展产生轮密钥之前,先介绍几个关键的变换和函数:
- 轮函数,其定义为F(X0,X1,X2,X3,rk)=X0T(X1X2X3rk),即输入为明文和密钥,输出为密文,该函数用于加密中。
- 合成置换函数,其中由两个变换,分别为线性变换和非线性变换。非线性变换为(b0,b1,b2,b3)=(Sbox(a0),Sbox(a1),Sbox(a2),Sbox(a3)),即输入四个8bits的信号,输出查找表后的四个8bit拼接成的32位数据。在得到这个32位数据输出后,要进行下一轮的线性变换,这个变换有两种,一种用于产生轮密钥,其为LN(B)=B(B<<13)(B<<23);另一种为L(B)=B(B<<2)(B<<10)(B<<18)(B<<24),其用于最终产生密文。整个过程需要使用三个常参数矩阵CK,Sbox和FK。
光说很难理清整个SM4.0算法的原理流程,下面将画出算法流程图(结合我最终的代码结构画图):
SM4.0算法流程图如下图所示。
在理解了SM4.0算法的原理和流程后,开始了代码的编程。
最开始的模型我设计的输入仅有明文、密钥、时钟和复位,输出为密文,此模型仅用于编写成正确的SM4.0算法。
首先我在两个always块中分别进行了轮密钥的生成和明文加密,最开始所需要用的两个线性变换我都编写了function,想在always里直接调用函数进行运算,但在调整逻辑后仿真失败,难究问题所在,于是我摒弃了函数的方式,且函数较为简单我就直接在always里进行运算,这两个模块都较为容易的的实现了。然后又在第三个always块里建立了一个计数器,用于32轮轮密钥和密文的计算。对于三个常参数矩阵的初始化,这是三个二维数组,我建立了第四个always块,在其中逐个地址位赋参数,初步完成四个always块完成了SM4.0算法的设计。
在正确完成了算法加密计算后,我又添加了两个输入,分别为输入密钥的有效和输入明文的有效,只有是有效信号时才读入进行计算。并添加了一个状态输出,在没有进行加密时标志位高电平,而在计算过程中输出为低电平。到此,完成了SM4.0基本模块的全部设计。
SM4.0基本模块框图如下:
APB_slave协处理器
本部分是用来设计一个可以用来兼容APB总线的SM4加密协处理器,用来将SM4.0加密模块与APB总线进行对接,使总线发送来的数据可以正常写入并进行加密后并由总线读取。具体可参考之前博客APB总线部分,本文也会给出适用于SM4.0的总线代码。
为了满足apb总线的输入,因此要将apb_slave的输入和输出设置成与总线一致,因此在输入端设置了PSELx(用于在通讯时选择从设备)、PENABLE(APB使能信号,用来指示一次APB传输的第二个时钟周期)、PCLK(APB总线时钟信号,上升沿有效)、PRESETN(APB总线复位信号,低电平有效)、PWRITE(APB写指令信号,高电平为写,低电平为读)、PADDR(APB总线读写地址,最高为32位)、PWDATA(APB总线写数据,最高为32位),SM4_DATA(SM4加密后数据输入端,用来将数据存储起来,以便在apb总线读数据的时候输出),在输出端设置了text_isvaid和mk_isvaid两个输出,用于表示已经接收完毕总线所发送来的数据,此时可以进行加密运算,在输出端设置了两个128位的数据线,用来传输明文以及密钥至SM4模块。
设计完所需要的输入输出之后,便可进行内部设计。由于总线是32位宽,而SM4加密模块是128位明文输入、128位密钥输入、128位密文输出,因此要使用4个32位寄存器,改变总线地址,让数据分别写入4个32位地址之中,并且将数据合并成为128位输出至加密模块进行加密后再以32位数据的方式存储至APB_slave中。
总线程序流程图如下图所示:
测试过程与结果
调试经历
在参考了《信息安全技术 SM4分组密码算法》后,我在激励文件中也赋予示例中的测试值,在modelsim中进行调试,加入观察所有变量的波形和值,找到不对的位置再找到对应代码位置,思考为何出错并调整,一步一步调试,观察几个rom中的值、cnt计数等,返再回纠错,再调试。最终完成了modelsim的验证,确定了算法语法和代码逻辑的正确性。然后我将代码放入Quartus中进行编译,借此检查是否有硬件逻辑错误,其中有一个if造成了锁存,修正后联合Modelsim仿真正确,完成模型的验证。
若要验证APB协处理器是否正确,则应该模拟APB总线的工作条件,设定正确的时序,给出协处理器地址和应写入的数据,观察波形图数据是否正确写入,然后在观察经过加密后的数据是否能够正确读出,与标准加密码表进行对比,观察结果是否正确,并且查看波形图时序,查看逻辑是否正确。在这种思路之上,针对协处理器写出了测试文件,具体测试结果可见后文验证部分。
测试结果
SM4.0部分测试
下图可以看到,当密钥和明文输入有效指令到来后,加密模块开始进入加密过程,且输出状态置为低电平。在计算完成后输出128位密文,同时输出状态置为高电平表示空闲。密文结果与《信息安全技术 SM4.0分组密码算法》给的测试结果对比正确无误,即代表SM4.0加密正确。
当新值输入后,但没有输入有效信号读入,即不是想要的加密信号,加密模块不进入加密过程,输出不变无新值。
APB协处理器部分测试
在Quartus II中建立工程,并将所有HDL文件导入后进行编译,编译后无错误,利用软件生成了硬件RTL图如下图所示,可以看出与设计相符,硬件模型搭建基本正确。
随后进行波形的仿真验证,利用Quartus II软件联合modelsim进行仿真测试,将top_level_tb.v文件导入后,生成了如下测试波形图。
仿真的目的是,能够不断的向总线内写入:
32’h01234567,32’h89ABCDEF,32’hFEDCBA98,32’h76543210,32’h01234567,32’h89ABCDEF,32’hFEDCBA98,32’h76543210
地址分别对应:
32’h00,32’h04,32’h08,32’h0c,32’h10,32’h14,32’h18,32’h1c
下面图1为协处理器写入前4组数据,即128位明文的波形图,图2为协处理器写入后4组数据,即128位密钥的波形图,可以看出来在地址有效时,同时PELx和PWRITE信号有效,延时一个时钟周期后,PENABLE有效,此时开始向协处理器内写入数据,并且在数据传送完成后,PELx、PWRITE、PENABLE均变为0,此时地址变为下一个地址,随机进行下一轮数据传输。
下图为协处理器读出加密后的密文的波形图,可以看出来在地址有效时,同时PELx有效,PWRITE信号为0,延时一个时钟周期后,PENABLE有效,此时协处理器开始读出数据,并且在数据传送完成后,PELx、PWRITE、PENABLE均变为0,此时地址变为下一个地址,随机进行下一轮数据传输。读出的密文数值为68 1e df 34 d2 06 96 5e 86 b3 e9 4f 53 6e 42 46,用此数据与国密标准进行对照,发现结果正确,验证协处理器的正确性。
整体代码
代码见资源,包含APB总线和SM4.0加密模块顶层代码、加密读写代码和激励测试代码
https://download.csdn.net/download/Nirvana_Tai/88650281