2

基于Xilinx ISE使用Verilog实现SM4算法

 2 years ago
source link: https://iamywang.github.io/2020/sm4-verilog/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

0x01 环境配置

  • Win7虚拟机+Xilinx ISE 14.7

0x02 SM4基本原理

SM4算法是一种分组密码算法。分组长度为128比特,密钥长度也为128比特。

加密算法与密钥扩展算法均采用32轮非线性迭代结构。以字(32位)为单位进行加密运算,每一次迭代运算均为一轮变换函数F。

SM4算法加/解密算法的结构相同,只是使用轮密钥相反,其中解密轮密钥是加密轮密钥的逆序。

0x03 轮密钥生成模块

取CK的值

根据index返回对应的值,32bit。

module ck (input clk,
input [4:0] count,
output reg [31:0] cki_out);
always@(posedge clk)
case(count)
5'b0_0000 : cki_out <= 32'h00070e15;
5'b0_0001 : cki_out <= 32'h1c232a31;
5'b0_0010 : cki_out <= 32'h383f464d;
5'b0_0011 : cki_out <= 32'h545b6269;

输入两个4bit,输出置换后的值。

module sbox (input [7:0] data_in,
output reg [7:0] res_out);

always@(*)
case(data_in)
8'h00 : res_out <= 8'hd6;
8'h01 : res_out <= 8'h90;
8'h02 : res_out <= 8'he9;
8'h03 : res_out <= 8'hfe;

非线性变换

用到4个S盒。

sbox s0(.data_in(byte_0), .res_out(re_0));
sbox s1(.data_in(byte_1), .res_out(re_1));
sbox s2(.data_in(byte_2), .res_out(re_2));
sbox s3(.data_in(byte_3), .res_out(re_3));

循环移位的结果,我提前计算好了。

assign res_out = re ^ {re[18:0], re[31:19]} ^ {re[8:0], re[31:9]};

一轮密钥生成

和FK做异或运算。

assign k0 = word_0 ^ FK0;
assign k1 = word_1 ^ FK1;
...

然后进行变换。

trans_rk t_rk(.data_in(trans_in), .res_out(trans_out));

再次异或生成这一轮的rk。

assign res_out = count_round == 'd0 ? {k1, k2, k3, trans_out ^ k0} : {word_1, word_2, word_3, trans_out ^ word_0};

完成32轮所有的密钥生成:这里主要是使用的always块。

0x04 加解密模块

经过分析,就是对上一步加密结果切割为4个字,word 0~3,word 0进行加密,word 1~3左移,加密后的word 0放在最后。迭代32轮。

assign {word_0, word_1, word_2, word_3} = data_in;
assign trans_in = word_1 ^ word_2 ^ word_3 ^ round_key;
assign res_out = {word_1, word_2, word_3, trans_out ^ word_0};
trans_enc t_enc(.data_in(trans_in), .res_out(trans_out));

完成32轮加密

具体迭代32次时,因为下一次的输入为上一次的输出,因此需要存储中间结果。

// 32 rounds
one_round_enc round_00 (.data_in(data), .round_key(rk_00), .res_out(res_00));
one_round_enc round_01 (.data_in(res_00), .round_key(rk_01), .res_out(res_01));
one_round_enc round_02 (.data_in(res_01), .round_key(rk_02), .res_out(res_02));
...

Round 28~31加密的数据反序就是最终的结果。

0x05 流水线设计

原有的工作流程

首先,根据用户的密钥进行轮密钥的生成。迭代32轮。

然后,在密钥导出完成后(通过标志位进行判断),进行32轮加密运算,得到密文。

轮密钥的生成和加密都需要用到S盒变换和线性变换。

可并行分析

非线性变换和线性变换可综合:(这里设计单轮迭代内部的四级流水)

4个S盒的非线性变换的输入输出是互不干扰的,可以并行执行。而线性变换因为用到了非线性变换的输出,需要在非线性变换后执行。之前学习到模块调用是并行的,而且S盒置换本质上就是一个switch-case的过程,因此我将他单独作为一个模块来使用。

边加密边生成密钥:(这里两级流水)

我感觉这是影响最重要的一点。对于SM4算法来说,轮密钥与待加密的密文无关,而且每轮加密只需要用到这一轮的轮密钥。那么,其实完全没有必要在密钥完全扩展完成后再加密。我的想法是,生成round key 0后就执行encrypt 0,而且生成round key 1可以与encrypt 0同时开始,以此类推,可以有效缩短时间。

0x06 综合仿真

未使用流水线

3.png

使用流水线

4.png

0x07 生成比特流

按照步骤走完即可。
5.png

生成的比特流文件:
6.png

配置到目标:
我没有板子,没做到最后。
7.png


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK