一种基于非线性双射的SM4白盒实现
本文档主要介绍基于非线性双射的SM4白盒实现方案,包括设计原理、代码实现的详细流程、安全性分析、与现有SM4白盒实现的比较以及白盒API调用示例。
1 设计原理
本方案采用了非线性双射置乱编码技术,用于对SM4算法中的查找表进行有效地混淆和保护。与传统的线性仿射变换[1]相比,非线性双射的设计显著提高了查找表的安全性,这种设计避免了在白盒实现中常见的、攻击者可能利用的数学特征,从而使得查找表能够成功抵御那些专门针对白盒实现的攻击。此外,本方案还对SM4算法的每一轮加解密计算过程进行了细致的拆分,将其分为个若干独立的部分,这一拆分过程遵循了如图1-1所 示的构造方法,通过精心设计的置乱编码生成查找表,每一部分都应用了经过特别设计的置乱编码技术,以实现对查找表的混淆。这种混淆机制有效地隐藏了密钥信息,从而在白盒攻击环境下确保了SM4算法的加解密过程的安全性。

图1-1 非线性双射白盒SM4方案架构图
方案具体实现如图1-1所示。其中,表示四个并行的8位随机非线性双射,表示四个并行的8位随机仿射变换,而和除了所对应的常数项中所有元素的值均被置为0之外,变换和完全一致,变换和完全一致。这里所提到的仿射变换可以与有限域上的矩阵运算等效,上述四个变换的设计原理在于,对于仿射变换,其变换结果在互相进行按位异或操作后,常数部分会被抵消,即在中满足式(1):
在图1-1中,函数如式(2)所示,其中表示加密轮次。是轮密钥的组成部分,,如式(3)所示:
线性变换可以表示为与一个上的32×32位的矩阵相乘,该矩阵的定义如式(4)所示,其组成元素是由1和0组成的矩阵。
基于每一轮SM4算法的计算过程,图1-1中每一部分所实现的功能如下:Part 1和Part 4-1实现三者的按位异或运算;Part 2和Part 4-2实现该计算结果与轮密钥的按位异或运算,再将结果进行变换操作;最后,Part 3和Part 4-3实现上述变换的结果与的按位异或计算。
在本方案中,我们将前述的运算过程以查找表的形式进行表示,并将这些查找表存储于本地设备上,需要特别指出的是,此处仅保存了每一部分运算中经过一系列变换复合后得到的最终变换所对应的查找表。如果为每个单独的变换都创建并存储其对应的查找表,那么置乱编码的关键信息将有可能被直接暴露,从而无法确保白盒实现方法的安全性。为了确保查找表能够准确反映每一部分的输入与输出之间的关系,对于每个可能的输入值,都必须存储其相应的输出值,因此,为了防止查找表的体积过大,我们不能为输入数据分配过多的位数。同时,为了确保查找表具有足够的混淆效果,输入数据的位数也不能设置得过少,在SM4算法中,每一轮的输入数据被划分为4个区块,每个区块包含32位,经过编码处理后,每个区块的长度仍然保持为32位。考虑到避免查找表占用过多内存,本实现方案将每一部分的输入数据以8位为单位进行细分。因此,上文中提到的混淆操作全部是基于四个并行的8位变换来实现的。对于Part 1、Part 2和Part 3,每张查找表的输入数据 长度为8位,这意味着需要存储条数据。而对于Part 4-1、Part 4-2和Part 4-3,由于需要实现包含编码和解码操作的按位异或功能,每张查找表的输入数据长度为16位,因此需要存储条数据。通过这种设计,我们能够在保证查找表具有足够混淆效果的同时,有效控制查找表的体积,从而在白盒环境下实现SM4算法的安全运算。
显然,Part 4-1、 Part 4-2 和 Part 4-3 中的查找表占据了大部分的存储空间。因此本方案对有关查找表的编码与解码函数进行设计,使得 Part 4-1与 Part 4-2的查找表能够重复利用,从而降低了对存储空间的需求。如图1-1所示,对 Part 4-1和Part 4-2,其中一个输入的解码函数,即和,与输出的编码函数,即和相匹配。为了进一步提升查找表的多样性和含混度,在输出编码时分别引入仿射变换和,可以在不影响查找表功能,同时不增加内存占用的前提下,有效提升其安全性。由于仿射变换的引入,其他部分的查找表也需要增加相应的混淆函数,具体的添加方式如图1-1所示。通过以上的设计,部分查找表可实现复用,进而使得所需要的总存储空间减少了大约一半。大部分设备的内存空间足够用来存储本实现方法,可以保证本方案在大多数情况下的实用性。
2 代码实现的详细流程
基于非线性双射的白盒SM4实现代码包括查找表生成与加密算法实现两部分,加解密流程如图2-1所示。代码主要参考了Xiao-Lai白盒SM4实现[2]和Bai-Wu白盒SM4实现[3]和 Xiao-Lai白盒AES实现[4]。本文对应的代码实现链接为nonlinearwbsm4。

图2-1 非线性双射白盒SM4加解密流程
2.1 查找表生成
1)初始化
- 定义 SM4 算法相关常量,如 S 盒、轮密钥生成所需的 FK 和 CK 常量。
- 声明一系列非线性和仿射变换的变量,用于后续表的生成。
- 调用
wbsm4_gen_init函数,生成 36 轮的Pij和Pij_inv非线性双射对,并将其组合成 32 位的Pi和Pi_inv。同时,生成 32 轮的Ei、Fi、Gi、Ai、Qi、Hi、Bi、Wi、Ci、Di及其逆变换,每个 32 位变换由 4 个 8 位变换组成。
2) 各部分查找表生成
wbsm4_gen_part1:生成 32 轮的查找表part1_table1、part1_table2和part1_table3,每轮有 4 个输入 8 位、输出 8 位的查找表。通过对Pij_inv与Eij_inv、Fij_inv、Gij进行复合运算得到。wbsm4_gen_part2:依赖于 SM4 轮密钥sm4_key,生成查找表part2_table_temp和part2_table。part2_table_temp通过对Eij、Gij_inv、Aij_inv进行复合运算,并与轮密钥异或后查 S 盒得到;part2_table则是对不同移位的输入进行Qi、Wi、Hi变换得到。wbsm4_gen_part3:生成查找表part3_table1、part3_table1_dec和part3_table2。part3_table1和part3_table1_dec通过对Pij_inv与Cij进行复合运算得到;part3_table2通过对Qij_inv、Hij_inv、Bij_inv进行复合运算,并经过Dij变换得到。wbsm4_gen_part4_1:生成 32 轮的查找表part4_1_table,每轮有 4 个输入 16 位、输出 8 位的查找表。通过对Eij和Fij进行异或,再经过Gij和Eij_inv变换得到。wbsm4_gen_part4_2:生成 32 轮的查找表part4_2_table,每轮有 4 个输入 16 位、输出 8 位的查找表。通过对Qij_inv和Wij_inv进行异或,再经过Hi和Qi变换得到。wbsm4_gen_part4_3:生成 32 轮的查找表part4_3_table和part4_3_table_dec,每轮有 4 个输入 16 位、输出 8 位的查找表。通过对Cij_inv和Dij_inv进行异或,再经过Pij变换得到。
查找表生成的函数接口如下:
void Nonlinearwbsm4_generate_tables(const uint8_t key[16], WB_SM4_Tables* tables);
2.2 加密函数的实现
1)输入外部编码
- 把 16 字节的输入数据
IN拆分成 4 个 32 位的整数x0、x1、x2、x3。 - 分别对
x0、x1、x2、x3运用tables->P[0]、tables->P[1]、tables->P[2]、tables->P[3]进行非线性变换。
2)执行核心加密
进行 32 轮迭代,每轮迭代包含以下步骤:
- part1:借助查找表
part1_table1、part1_table2、part1_table3对x1、x2、x3进行变换,得到xt1、xt2、xt3。 - part4-1:把
xt1、xt2、xt3按 8 位分割,利用查找表part4_1_table进行变换,得出x4。 - part2:将
x4按 8 位分割,使用查找表part2_table_temp进行变换,再通过矩阵乘法MatMulNumM32对结果进行处理,接着利用查找表part2_table进一步变换,得到中间结果。 - part4-2:把中间结果按 8 位分割,利用查找表
part4_2_table进行变换,更新x4。 - part3:借助查找表
part3_table1、part3_table2对x0、x4进行变换,得到xt0、xt4。 - part4-3:把
xt0、xt4按 8 位分割,利用查找表part4_3_table进行变换,更新x4。 - 更新
x0、x1、x2、x3的值,即x0 = x1; x1 = x2; x2 = x3; x3 = x4;。
3)输出外部解码
- 分别对
x3、x2、x1、x0运用tables->P_inv[35]、tables->P_inv[34]、tables->P_inv[33]、tables->P_inv[32]进行非线性逆变换,得到out0、out1、out2、out3。 - 把
out0、out1