2022年06月28日
导语
本文介绍AES和SM4 S盒的复合域实现方法,该方法由D.Canright在《A Very Compact Rijndael S-box》一文中提出,是分组密码bitslice实现、受限资源算法硬件实现和一些掩码方案的基础。
1背景
是的,你没看错。本文要讲一下如何实现 AES 和 SM4 的 S 盒实现。你可能好奇,S 盒实现有什么好讲的,c
语言一个unsigned int Sbox[256] = {...}
,verilog
一个always case xxx:
解决问题。没错,查表实现是S盒最基本的实现方法。高端一点的查表,可以将 S 盒的实现结合线性变换(AES 的 MixColumn,SM4 的 L)形成8→32的大表 T-Table 进行加速,例如openssl的查表实现。
其实,我们本文将探讨一种不通过查表,只是通过逻辑运算的 S 盒实现方法。
AES 和 SM4 的 S 盒都是由 GF(28) 有限域上的运算进行生成的。我们可以直接基于其实现方法,对 S 盒进行计算实现。在 AES 和 SM4 的 S 盒生成公式中,均设计在 GF(28) 的求逆运算,该运算比较耗时。有限域中求逆运算可以转化幂运算,例如 AES 的 S 盒可以表达为:
S(x)=63+05x254+09x253+F9x251+25x247+01x223+B5x191+8Fx127.
该运算定义在GF(28)上,直接实现同样较为复杂。
还有一种方法,是使用布尔函数对 S 盒进行表达,利用布尔函数进行实现。该方法其实可以看作GF(2)上的表达。On Deviations of the AES S-box when Represented as Vector Valued Boolean Function对 AES 的 S 盒进行了分析,得到其布尔函数表达式,例如,其中第0比特可表示为:
布尔函数非常复杂,直接利用布尔函数表达式也不是一个好的思路。
D.Canright在A Very Compact Rijndael S-box一文中,提出一种实现思路:基于复合域进行实现。文章提出该方法实现在资源有限情况下的该类 S 盒的实现方式,后该方法被用于构造掩码实现(抵抗DPA攻击)和bitslice实现上。本文将对这个方法进行介绍。
2原理
AES 和 SM4 的 S 盒生成都是基于GF(28)进行构造的,利用逆运算和仿射变换(affine)。仿射变换本身就能表示成逻辑运算,我们重点关注求逆运算。AES 和 SM4 的表达都是基于多项式基,以 AES 的有限域为例,假设A为多项式x8+x4+x3+x+1的根,即A8+A4+A3+A+1=0。那么任何一个元素x可以表示为x=x7A7+x6A6+x5A5+x4A4+x3A3+x2A2+x1A+x0。这种做法是将GF(28)直接看作GF(2)的8次扩域。我们也可以不这么看,将GF(28)看成GF(24)的2次扩域,GF(24)可以进一步看作GF(22)的2次扩域,再进一步GF(22)可以看作GF(2)的2次扩域。而GF(28)的求逆运算,可以通过数学表达式,转换为GF(24)的求逆和一些乘、加操作。这些操作可以进一步向下转化。下面我们详细说明一下。
K=GF(qn)为GF(q)的n次扩域,β 为多项式的根,那么多项式基为{1,β,β2,…,βn−1},任何一个元素x,可以表示为x=xn−1βn−1+…+x1β+x0,这也是AES 和 SM4 所采用的基表示方式。此外,除了多项式基以外,域的表达方式还可以使用正规基进行表达,正规基为{β,βq,βq2,…,βqn−1},正规基使用了多项式的全部根。
GF(28),可以看作GF(24)的2次扩域,也就是在GF(24)上寻找一个不可约二次多项式,r(y)=y2+τy+υ,其中,τ 和 υ 为 GF(24) 的元素。设 Y 为 r(y) 的根,则 GF(28) 元素的多项式基为 Y,1,正规基为Y,Y16。Canright在文章中讨论了多项式基和正规基两种方式,我们这里只看正规基。对于GF(28)的元素 g=γ1Y16+γ0Y,求逆 d=δ1Y16+δ0Y,γi 和 δi 都是GF(24)的元素, gd=1,待定系数求解,可得出
{
δ1=[γ1γ0τ2+(γ21+γ20)υ]−1γ0δ0=[γ1γ0τ2+(γ21+γ20)υ]−1γ1
文内有详细推导方法,不再赘述。观察系数,其达到的效果就是,GF(28)的求逆运算,转化成为GF(24)的乘法、平方和求逆,特别的,可以选择不可约多项式为r(y)=y2+y+υ,也就是 τ 取1来降低求解复杂度,这样,对g=γ1Y16+γ0Y的求逆可简化为如下图:
同样,GF(24)可以看作GF(22)的二次扩域,也就是在GF(22)寻找一个不可约二次多项式,s(z)=z2+Tz+N,设Z 为该多项式的根,取正规基{Z4,Z}。和GF(28)计算方法相同,可计算GF(24)元素υ=Γ1Z4+Γ0Z 的逆为δ=ΔZ4+ΔZ,其中,
也可以取T=1降低复杂度,那么在GF(24)求逆运算如下图所示:
在GF(28)求逆时,也涉及到了GF(24)的乘法。GF(24)的乘法υδ=(Γ1Z4+Γ0Z)(Δ1Z4+Δ0Z)可按照如下公式计算:
如下图:
进一步,GF(22)可以看作GF(2)的二次扩域,在GF(2)上的不可约多项式只有t(ω)=ω2+ω+1,取正规基W2,W,则Γ=g1W2+g0W,逆为Δ=d1W2+d0W,其中,
GF(22)的乘法,ΓΔ=(g1W2+g0W)(d1W2+d0W),计算如下:
如下图:
将GF(28)进行转化,我们还有一些操作未介绍,包括 υγ2、NΓ2 和 NΓ。这些值可通过选择不同的 υ 和 N 进行简化。文章详细讨论了选取的方法。我们直接给结论:
对于GF(22),不可约多项式为t(ω)=ω2+ω+1,正规基{W2,W}
对于GF(24)/GF(22),不可约多项式为s(z)=z2+z+N,N=W2,正规基Z4,Z,N(g1W2+g2W)2=W2(g1W2+g2W)=g1W2+(g1+g0)W
对于GF(28)/GF(24),不可约多项式为r(y)=y2+y+υ,υ=N2Z,如此,υ(AZ4+BZ)2=(A+B)2Z4+N2B2
复合域下,实际上是以
表示GF(28)的一个元素。
而 S 盒的输入是以多项式基表示进行输入的。要利用复合域进行运算,需要将输入表示进行转换。以线性空间的角度看,这复合域表示相当于是给GF(28)找了一组新基。两组基有如下关系:
找到w2z4y16等在多项式基下的表示,形成矩阵X:
计算X−1,乘以多项式基下的表示即可得到复合域基下的表示。S盒计算完成后,再进行反变换即可。
3AES S盒实现方法
AES的S盒是定义在GF(28)(不可约多项式x8+x4+x3+x+1),其表达式为S(x)=Ax−1+c,具体如下:
4求矩阵X和逆
求 X 和 X−1,我们需要计算 w,z 和 y,计算 w2z4y16等一系列系数值。Canright在文章中给出了 GF(28) 生成元 B 的 对数表,方便计算。这里我们直接通过搜索进行计算。
from pyfinite import ffield
gen = 0b100011011
F = ffield.FField(8, gen, useLUT=0) # 这里一定要写useLUT=0,不然会出问题。。。
def field_pow2(x, F): #计算在F域上的平方
return F.Multiply(x, x)
def field_pow3(x, F): #计算在F域上的三次方
return F.Multiply(x, field_pow2(x, F))
def field_pow4(x, F): #计算在F域上的四次方
return field_pow2(field_pow2(x, F), F)
首先,搜索GF(22)的正规基{W2,W},我们求出其在GF(28)下多项式基的表示。
for i in range(256):
if field_pow2(i, F)^i^1 == 0: # 搜索 w^2+w+1 = 0的根
print(hex(i))
我们可得到,W=0xbd,W2=0xbc(一定要注意,这是GF(28)的多项式基表示)
2. 然后,搜索GF(24)/GF(22)的正规基Z4,Z,我们求出其在GF(28)下多项式基的表示。s(z)=z2+z+N,N=W2=0xbc
for i in range(256):
if field_pow2(i, F)^i^0xbc == 0: # 搜索 z^2+z+0xbc = 0的根
print(hex(i))
于是我们又得到,Z=0x5c,Z4=0x5d
3. 最后,搜索GF(28)/GF(24)的正规基{Y16,Y},我们求出其在GF(28)下多项式基的表示。r(y)=y2+y+υ,υ=N2Z
u = F.Multiply(field_pow2(0xbc, F), 0x5c)
for i in range(256):
if field_pow2(i, F)^i^0xec == 0: # 搜索 z^2+z+0xbc = 0的根
print(hex(i))
于是我们又得到,Y=0xff,Y16=0xfe
w = 0xbd
w_2 = 0xbc
z = 0x5c
z_4 = 0x5d
y = 0xff
y_16 = 0xfe
w_2_z_4_y_16 = F.Multiply(F.Multiply(w_2, z_4), y_16)
w_z_4_y_16 = F.Multiply(F.Multiply(w, z_4), y_16)
w_2_z_y_16 = F.Multiply(F.Multiply(w_2, z), y_16)
w_z_y_16 = F.Multiply(F.Multiply(w, z), y_16)
w_2_z_4_y = F.Multiply(F.Multiply(w_2, z_4), y)
w_z_4_y = F.Multiply(F.Multiply(w, z_4), y)
w_2_z_y = F.Multiply(F.Multiply(w_2, z), y)
w_z_y = F.Multiply(F.Multiply(w, z), y)
print('w_2_z_4_y_16\t', hex(w_2_z_4_y_16))
print('w_z_4_y_16\t', hex(w_z_4_y_16))
print('w_2_z_y_16\t', hex(w_2_z_y_16))
print('w_z_y_16\t', hex(w_z_y_16))
print('w_2_z_4_y\t', hex(w_2_z_4_y))
print('w_z_4_y\t\t', hex(w_z_4_y))
print('w_2_z_y\t\t', hex(w_2_z_y))
print('w_z_y\t\t', hex(w_z_y))
得到多项式基在复合域基下表示如下:
求X−1,可得到复合域基下多项式基的表示:
from pyfinite import genericmatrix
XOR = lambda x,y: x^y
AND = lambda x,y: x&y
DIV = lambda x,y: x
m = genericmatrix.GenericMatrix(size=(8, 8),zeroElement=0,identityElement=1,add=XOR,mul=AND,sub=XOR,div=DIV)
m.SetRow(0, [0, 0, 0, 1, 0, 0, 1, 0])
m.SetRow(1, [1, 1, 1, 0, 1, 0, 1, 1])
m.SetRow(2, [1, 1, 1, 0, 1, 1, 0, 1])
m.SetRow(3, [0, 1, 0, 0, 0, 0, 1, 0])
m.SetRow(4, [0, 1, 1, 1, 1, 1, 1, 0])
m.SetRow(5, [1, 0, 1, 1, 0, 0, 1, 0])
m.SetRow(6, [0, 0, 1, 0, 0, 0, 1, 0])
m.SetRow(7, [0, 0, 0, 0, 0, 1, 0, 0])
print(m)
print(m.Inverse())
5具体函数实现
基础函数定义
g2b = [0b10011000, 0b11110011, 0b11110010, 0b01001000, 0b00001001, 0b10000001, 0b10101001, 0b11111111]
b2g = [0b01100100, 0b01111000, 0b01101110, 0b10001100, 0b01101000, 0b00101001, 0b11011110, 0b01100000]
def G4_mul(x, y):
'''
GF(2^2)的乘法运算,正规基{W^2, W}
'''
a = (x & 0x02)>>1
b = x & 0x01
c = (y & 0x02)>>1
d = y & 0x01
e = (a ^ b) & (c ^ d)
return (((a & c) ^ e) << 1)|((b & d) ^ e)
def G4_mul_N(x):
'''
GF(2^2)的乘N操作,N = W^2
'''
a = (x & 0x02)>>1
b = x & 0x01
p = b
q = a ^ b
return (p<<1)|q
def G4_mul_N2(x):
'''
GF(2^2)的乘N^2操作,N = W^2
'''
a = (x & 0x02)>>1
b = x & 0x01
return ((a ^ b)<<1)|a
def G4_inv(x):
'''
GF(2^2)的求逆操作,该操作和GF(2^2)的平方操作等价
'''
a = (x & 0x02)>>1
b = x & 0x01
return (b<<1)|a
def G16_mul(x, y):
'''
GF(2^4)的乘法操作,正规基{Z^4, Z}
'''
a = (x & 0xc)>>2
b = x & 0x03
c = (y & 0xc)>>2
d = y & 0x03
e = G4_mul(a ^ b, c ^ d)
e = G4_mul_N(e)
p = G4_mul(a, c) ^ e
q = G4_mul(b, d) ^ e
return (p<<2) | q
def G16_sq_mul_u(x):
'''
GF(2^4)的平方后乘u操作, u = N^2Z, N = W^2
'''
a = (x & 0xc)>>2
b = x & 0x03
p = G4_inv(a ^ b) # G4平方和求逆等价
q = G4_mul_N2(G4_inv(b))
return (p<<2)|q
def G16_inv(x):
'''
GF(2^4)的求逆操作
'''
a = (x & 0xc)>>2
b = x & 0x03
c = G4_mul_N(G4_inv(a ^ b))
d = G4_mul(a, b)
e = G4_inv(c ^ d)
p = G4_mul(e, b)
q = G4_mul(e, a)
return (p<<2)|q
def G256_inv(x):
'''
GF(2^8)的求逆操作
'''
a = (x & 0xF0)>>4
b = x & 0x0F
c = G16_sq_mul_u(a ^ b)
d = G16_mul(a, b)
e = G16_inv(c ^ d)
p = G16_mul(e, b)
q = G16_mul(e, a)
return (p<<4)|q
def G256_new_basis(x, b):
'''
x在新基b下的表示
'''
y = 0
for i in range(8):
if x & (1<<(7-i)):
y ^= b[i]
return y
计算S盒输出值
A = [0b10001111, 0b11000111, 0b11100011, 0b11110001, 0b11111000, 0b01111100, 0b00111110, 0b00011111] #仿射变换矩阵乘
def AES_SBOX(x):
t = G256_new_basis(x, g2b)
t = G256_inv(t)
t = G256_new_basis(t, b2g)
t = G256_new_basis(t, A) #仿射变换乘
return t ^ 0x63
sbox = []
for i in range(256):
sbox.append(AES_SBOX(i)) # 生成sbox
for i,s in enumerate(sbox):
print(f'%02x'%s,', ', end='')
if (i+1)%16==0:
print()
6SM4 S盒实现方法
SM4 的 S 盒和 AES 不同, 定义在GF(28)采用的不可约多项式为x8+x7+x6+x5+x4+x2+1,生成方式为S(x)=A(Ax+c)−1+c,其中:
7求矩阵X和逆
不可约多项式不同,X 矩阵也不相同。下面我们为 SM4 求 X 和 X−1,我们需要计算 w,z 和 y,计算 w2z4y16等一系列系数值
from pyfinite import ffield
gen = 0b111110101
F = ffield.FField(8, gen, useLUT=0) # 这里一定要写useLUT=0,不然会出问题。。。
首先,搜索GF(22)的正规基{W2,W},我们求出其在GF(28)下多项式基的表示。
for i in range(256):
if field_pow2(i, F)^i^1 == 0: # 搜索 w^2+w+1 = 0的根
print(hex(i))
我们得到,W=0x5d,W2=0x5c(一定要注意,这是GF(28)的多项式基表示)
然后,搜索GF(24)/GF(22)的正规基Z4,Z,我们求出其在GF(28)下多项式基的表示。s(z)=z2+z+N,N=W2=0x5c
for i in range(256):
if field_pow2(i, F)^i^0x5c == 0: # 搜索 z^2+z+0x5c = 0的根
print(hex(i))
于是我们又得到,Z=0x0c,Z4=0x0d
最后,搜索GF(28)/GF(24)的正规基Y16,Y,我们求出其在