有限域GF(2^8)和AES-SBox生成

有限域GF(2^8)和AES-sBox生成

一、前置知识

1.1、域是什么?

  • 域F,有时记为 { F , + , × } \{F,+,\times\} {F,+,×},是个有两个二元运算的集合,这两个二元运算分别称为 加法乘法,且对于$ F $中的任意元素 满足一下要求:
    1. 封闭性:如果 元素 a 、 b a、b ab都属于 G 那么 a ∗ b a * b ab 也属于 G
    2. 结合律:对于G中的任意元素 a 、 b 、 c a 、b、c abc 都有 a ∗ ( b ∗ c ) = ( a ∗ b ) ∗ c a * (b * c) = (a*b)*c a(bc)=(ab)c成立
    3. 单位元:G中存在一个元素 e ,对于 G 中任意元素 a 都有 a ∗ e = e ∗ a = a a * e = e * a = a ae=ea=a 成立
    4. 逆元:对于 G 中任意元素 a, G中都存在一个元素 a’ 使得 a ∗ a − 1 = a − 1 ∗ a a * a^{-1} = a^{-1} * a aa1=a1a 成立
    5. 交换律:对于G中任意元素 a 、b都有 a ∗ b = b ∗ a a * b = b * a ab=ba 成立

上述一个重要性质就是集合中两个元素做运算后的结果还是属于该集合

1.2、模运算和逆元

  • 如果a是一个整数,n是正整数,则定义 a 除以 n 所得的余数为 a 模 n。整数 n 称为模数。表达式为 ( a   m o d   n ) (a\ mod\ n) (a mod n)
  • ( a   m o d   n ) = = ( b   m o d   n ) (a \ mod \ n)==(b \ mod \ n) (a mod n)==(b mod n)则称 a 和 b 是模n同余的。表示为 a ≡ b ( m o d   n ) a\equiv b(mod \ n) ab(mod n)
  • 逆元定义:如果一个线性同余方程 a x ≡ 1   ( m o d   b ) ax \equiv 1 \ (mod\ b) ax1 (mod b)则称 x 为 a   m o d   b a\ mod \ b a mod b 的逆元,记作 a − 1 a^{-1} a1

1.3、欧几里得算法(求公因子)

定义一个函数gcd(int a,int b)用来求 a 和 b 的最大公因子 d

根据前人的智慧我们是可以得出这样的结论:a 和 b 和 a%b 三者的公因子 d 是相等的

证明如下:
证明 { a 、 b 、 a % b } 三者公因子相等。并设该公因子为 d g c d ( a , b ) = = g c d ( b , a % b ) ( 1 )    a d = k 1 ,       b d = k 2 ( 2 )    b d = k 2 ,     a % b = a − ⌊ a b ⌋ b ( 3 )    a − ⌊ a b ⌋ b d = a d − ⌊ a b ⌋ ∗ b d = k 1 + ⌊ a b ⌋ ∗ k 2 = k 3 证明\{a、b、a\%b \}三者公因子相等。并设该公因子为d\\ gcd(a,b) == gcd(b,a\%b)\\ (1) \ \ \frac{a}{d} = k_1,\ \ \ \ \ \frac{b}{d} = k2\\ (2)\ \ \frac{b}{d} = k_2,\ \ \ a\%b = a - \lfloor \frac{a}{b} \rfloor b \\ (3)\ \ \frac{a - \lfloor \frac{a}{b} \rfloor b}{d} = \frac{a}{d} - \lfloor \frac{a}{b} \rfloor * \frac{b}{d} = k_1 + \lfloor \frac{a}{b} \rfloor * k_2 = k_3 证明{aba%b}三者公因子相等。并设该公因子为dgcd(a,b)==gcd(b,a%b)(1)  da=k1,     db=k2(2)  db=k2,   a%b=abab(3)  dabab=dabadb=k1+bak2=k3
根据上述的演算可以看到 { k 1 , k 2 , k 3 } ∈ Z \{k_1,k_2,k_3\} \in Z {k1,k2,k3}Z 因此三者公因子都是d证明成立。因此根据上述的推导过程可以递归实现求公因数

由此我们可以实现代码如下:

/*
* 根据上述的演算得出该算法,并且随着递归,两个数字不断变小
* 根据 0 和任何数 a 的公因子 是 a 得出算法终结条件
*/
int gcd(int a,int b){
    if(b == 0) return a;
    return gcd(b,a%b);
}

1.4、拓展欧几里算法(求逆元)

下面介绍欧几里得算法的拓展,它对于有限域中的计算及RSA等密码算法非常重要。对于给定的整数 a 和 b,拓展欧几里得算法不仅可以计算出最大公因子d,而且可以得到两个整数 x 和 y,它们满足如下方程:
a x + b y = d = g c d ( a , b ) ax + by = d = gcd(a,b) ax+by=d=gcd(a,b)
应该明白的是,x和y一定具有相反的正负号

欧几里得算法的原理是 gcd(a, b) = gcd(b, a mod b) ,通过连续计算余数,直到余数等于 0 为止,最后得到的非 0 余数就是最大公约数。那么如何通过欧几里得算法得到拓展欧几里得算法呢?

知道ax+by = gcd(a, b) 一定有整数解,因此要做的就是求出一个特解

  • 注意到欧几里得算法gcd(a,b)终止条件 a = g c d 且 b = 0 a = gcd 且 b = 0 a=gcdb=0那么可以构造下面等式

( 0 ) 已知 g c d ( a , b ) 终止条件 { a f = g c d , b f = 0 } ( 1 ) 并且已知可构造等式 :    a x + b y = d = g c d ( a , b ) ( 2 ) 构造 :     g c d ∗ X f i n a l + 0 ∗ Y f i n a l = g c d ( 3 ) 因此求得特解 :    { X f i n a l = 1 , Y f i n a l = 0 } \begin{align*} & (0)已知gcd(a,b)终止条件\{a_f = gcd,b_f = 0\}\\\\ & (1)并且已知可构造等式:\ \ ax + by = d = gcd(a,b)\\\\ & (2)构造:\ \ \ gcd * X_{final} + 0 * Y_{final} = gcd\\\\ & (3)因此求得特解: \ \ \{X_{final} = 1,Y_{final} = 0\} \end{align*} (0)已知gcd(a,b)终止条件{af=gcd,bf=0}(1)并且已知可构造等式:  ax+by=d=gcd(a,b)(2)构造:   gcdXfinal+0Yfinal=gcd(3)因此求得特解:  {Xfinal=1,Yfinal=0}

构造出一组特解之后我们再研究回原来的 int gcd(int a,int b)算法
( 1 ) 原算法 g c d (   a   ,   b   ) = = g c d (   b   ,   a % b   ) ( 2 ) 假设我们目前处于 g c d (   b   ,   a % b   ) 函数并且求得上述特解 { X f i n a l = 1 , Y f i n a l = 0 } ( 3 ) 因此可得 :    b ∗ X f i n a l + ( a % b ) ∗ Y f i n a l = g c d   成立 ( 4 ) 知 :    a % b = a − ⌊ a b ⌋ ∗ b ( 5 ) 根据 ( 3 ) 和 ( 4 ) 式子可得 b ∗ X f i n a l + ( a − b ⌊ a b ⌋ ) ∗ Y f i n a l = g c d ( 6 ) 调整上述式子可得下式 : a ∗ Y f i n a l + b ( X f i n a l − Y f i n a l ⌊ a b ⌋ ) = g c d ( 7 ) 因此 g c d ( a , b ) 的一组解 {    X c u r = Y f i n a l ,     Y c u r = X f i n a l − Y f i n a l ⌊ a b ⌋    } \begin{align*} & (1)原算法 gcd(\ a\ ,\ b\ ) == gcd(\ b\ ,\ a\% b\ )\\ & (2)假设我们目前处于 gcd(\ b\ ,\ a\% b\ )函数并且求得上述特解 \{X_{final} = 1,Y_{final} = 0\}\\ & (3)因此可得:\ \ b *X_{final} + (a \% b)* Y_{final} = gcd \ \ 成立\\ & (4)知:\ \ a\%b = a - \lfloor \frac{a}{b} \rfloor *b\\ & (5)根据(3)和(4)式子可得 b * X_{final} + (a - b\lfloor \frac{a}{b} \rfloor)*Y_{final} = gcd\\ & (6)调整上述式子可得下式:a * Y_{final}+ b(X_{final} - Y_{final}\lfloor \frac{a}{b} \rfloor) = gcd\\ & (7)因此gcd(a,b)的一组解\{\ \ X_{cur} = Y_{final},\ \ \ Y_{cur} = X_{final} - Y_{final}\lfloor \frac{a}{b} \rfloor\ \ \} \end{align*} (1)原算法gcd( a , b )==gcd( b , a%b )(2)假设我们目前处于gcd( b , a%b )函数并且求得上述特解{Xfinal=1,Yfinal=0}(3)因此可得:  bXfinal+(a%b)Yfinal=gcd  成立(4):  a%b=abab(5)根据(3)(4)式子可得bXfinal+(abba⌋)Yfinal=gcd(6)调整上述式子可得下式:aYfinal+b(XfinalYfinalba⌋)=gcd(7)因此gcd(a,b)的一组解{  Xcur=Yfinal,   Ycur=XfinalYfinalba  }

  • 通过递归不断返回上一个状态,直到回到最初状态,就能求出最初方程的一个特解了
int ex_gcd(int a,int b,int &x,int &y){
    if(b == 0){
        x = 1,y = 0;
		return a;
    }
    int gcd = ex_gcd( b , a%b , y , x);
    y = y - a/b * x;
	return gcd;
}

1.5、拓展欧几里得求逆元

逆元定义:如果一个线性同余方程 a x ≡ 1   ( m o d   b ) ax \equiv 1 \ (mod\ b) ax1 (mod b)则称 x 为 a   m o d   b a\ mod \ b a mod b 的逆元,记作 a − 1 a^{-1} a1

拓展欧几里得算法核心方程 a x + b y = d = g c d ( a , b ) ax + by = d = gcd(a,b) ax+by=d=gcd(a,b)
根据逆元等式: a x ≡ 1 (   m o d    b )   [ 此时 a 、 b 为已知量 , x 为 a 的逆元 a − 1 ] 转化   a x ≡ 1 (   m o d    b )   ⟹ 【 a x = n b + 1 】 ⟹ 【 a x + n ′ b = 1 】 ( n = − n ′ ) \begin{align*} & 根据逆元等式:ax\equiv 1(\ mod\ \ b)\ [此时a、b为已知量,x为a的逆元a^{-1}]\\ & 转化\ \ ax\equiv 1(\ mod\ \ b)\ \Longrightarrow 【ax = nb + 1】\Longrightarrow【ax + n'b = 1】(n = -n') & \end{align*} 根据逆元等式:ax1( mod  b) [此时ab为已知量,xa的逆元a1]转化  ax1( mod  b) ax=nb+1ax+nb=1(n=n)
将上述逆元的定义方程进行转化后我们来对比转化方程拓展欧几里得核心方程
( 1 ) a x + b n = 1 【逆元转化方程】 ( 2 ) a x + b y = g c d ( a , b ) 【拓展欧几里得核心方程】 \begin{align*} & (1){\color{red}a}x + {\color{red}b}n = 1 【逆元转化方程】\\ & (2){\color{red}a}x + {\color{red}b}y = gcd(a,b) 【拓展欧几里得核心方程】\\ \end{align*} (1)ax+bn=1【逆元转化方程】(2)ax+by=gcd(a,b)【拓展欧几里得核心方程】
可以看到上述两方程的格式不能说相似,只能说一模一样。只需要使用拓展欧几里得算法对互质的两个数求出一组解 ( x , y ) (x,y) (x,y)

就可以获得逆元了。

二、GF有限域相关知识

2.1、有限域GF§

  • 在密码学中,有限域GF§是一个很重要的域,其中p为素数。简单来说,GF§就是 mod p,因为一个数 模p后,结果在 [ 0 , p − 1 ] [0, p-1] [0,p1]之间。对于元素a和b,那么 ( a + b ) m o d p (a+b) mod p (a+b)modp ( a ∗ b ) m o d p (a*b)mod p (ab)modp,其结果都是域中的元素。GF§里面的加法和乘法都是平时用的加法和乘法。GF§的加法和乘法单位元分别是0和1,元素的加法和乘法逆元都很容易理解和求得,这里就不展开讲了,《密码编码学与网络安全》书中有详讲的。

2.2、有限域GF(2^8)

注:为减小篇幅, G F ( 2 ∧ 8 ) GF(2\land8) GF(28)具体的模乘法除法本文不详细说明

  • 不可约多项式:【 x 8 + x 4 + x 3 + x + 1 x^8 + x^4 + x^3 +x +1 x8+x4+x3+x+1

  • G F ( 2 ∧ 8 ) GF(2\land8) GF(28)上的加减法等于 异或操作

  • G F ( 2 ∧ 8 ) GF(2\land8) GF(28)上的模乘法等于 移位+异或+模(不可约多项式)

  • 现在重点讲一下 G F ( 2 n ) GF(2^n) GF(2n),特别是 G F ( 2 8 ) GF(2^8) GF(28)因为8刚好是一个字节的比特数。

  • 前面说到, GF§,p得是一个素数,才能保证集合中的所有元素都有加法和乘法逆元(0除外)。

  • 我们希望0到255这256个数字也能组成一个域。因为很多领域需要用到。mod 256的余数范围就是0到255,但256不是素数。小于256的最大素数为251,所以很多人就直接把大于等于251的数截断为250。在图像处理中,经常会这样做。但如果要求图像无损的话,就不能截断。貌似已经到了死胡同,救星还是有的,那就是 G F ( p n ) GF(p^n) GF(pn),其中p为素数。在这里我们只需令p为2,n为8,即GF(2^8)。

2.3、多项式计算

  • 要弄懂GF(2^n),要先明白多项式运算。这里的多项式和初中学的多项式运算有一些区别。虽然它们的表示形式都是这样的: f ( x ) = x 6 + x 4 + x 2 + x + 1 f(x) = x^6 + x^ 4 + x^2 + x + 1 f(x)=x6+x4+x2+x+1。下面是它的一些特点
  1. 多项式的系数只能是0或者1。当然对于GF(p^n),如果p等于3,那么系数是可以取:0, 1, 2的
  2. 在GF中计算 + 使用的是异或
  3. 合并同类项时,系数们进行异或操作,不是平常的加法操作。比如 x 4 + x 4 = 0 ∗ x 4 x^4 + x^4 = 0*x^4 x4+x4=0x4 。因为两个系数都为1, 进行异或后等于0
  4. 无所谓的减法(减法就等于加法),或者负系数。所以, x 4 – x 4 = x 4 + x 4 x^4 – x^4 = x^4 + x^4 x4x4=x4+x4 。【总的来说加减为异或】

举个例子:
多项式的加减法使用异或操作 f ( x ) = x 6 + x 4 + x 2 + x + 1 g ( x ) = x 7 + x + 1 。 f ( x ) + g ( x ) = x 7 + x 6 + x 4 + x 2 + ( 1 + 1 ) x + ( 1 + 1 ) 1                      = x 7 + x 6 + x 4 + x 2 \begin{align*} & 多项式的加减法使用异或操作\\ &f(x) = x^6 + x^4 + x^2 + x + 1\\ &g(x) = x^7 + x + 1。\\ &f(x) + g(x)= x^7 + x^6 + x^4+ x^2 + (1+1)x + (1+1)1 \\ &\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ = x^7 + x^6 + x^4 + x^2 \end{align*} 多项式的加减法使用异或操作f(x)=x6+x4+x2+x+1g(x)=x7+x+1f(x)+g(x)=x7+x6+x4+x2+(1+1)x+(1+1)1                    =x7+x6+x4+x2

2.4、素多项式模运算

  • 指数小于3的多项式有8个,分别是 0 , 1 , x , x + 1 , x 2 , x 2 + 1 , x 2 + x , x 2 + x + 1 0, 1, x, x+1, x^2, x^2+1, x^2 + x, x^2+x+1 01xx+1x2x2+1x2+xx2+x+1

  • 对于 G F ( 2 ∧ 3 ) GF(2\land3) GF(23)来说,其中一个素多项式为 x 3 + x + 1 x^3+x+1 x3+x+1

  • 上面8个多项式进行四则运算后 m o d ( x 3 + x + 1 ) mod (x^3+x+1) mod(x3+x+1)的结果都是8个之中的某一个。

  • 当然也可以证明这是一个域,所以每一个多项式都是有加法和乘法逆元的(0除外)。注意,这些逆元都是和素多项式相关的,同一个多项式,取不同的素多项式,就有不同的逆元多项式。

  • 对于 G F ( 2 ∧ 8 ) GF(2\land8) GF(28),其中一个素多项式为【 x 8 + x 4 + x 3 + x + 1 x^8 + x^4 + x^3 +x +1 x8+x4+x3+x+1】。对应地,小于8次的多项式有256</个。【核心】

  • 由素多项式得到的域,其加法单位元都是0,乘法单位元是1。

三、AES-SBOX生成

3.1、S-box全貌

  • 首先我们来看看SBOX是什么样子的
0123456789ABCDEF
0637C777BF26B6FC53001672BFED7AB76
1CA82C97DFA5947F0ADD4A2AF9CA472C0
2B7FD9326363FF7CC34A5E5F171D83115
304C723C31896059A071280E2EB27B275
409832C1A1B6E5AA0523BD6B329E32F84
553D100ED20FCB15B6ACBBE394A4C58CF
6D0EFAAFB434D338545F9027F503C9FA8
751A3408F929D38F5BCB6DA2110FFF3D2
8CD0C13EC5F974417C4A77E3D645D1973
960814FDC222A908846EEB814DE5E0BDB
AE0323A0A4906245CC2D3AC629195E479
BE7C8376D8DD54EA96C56F4EA657AAE08
CBA78252E1CA6B4C6E8DD741F4BBD8B8A
D703EB5664803F60E613557B986C11D9E
EE1F8981169D98E949B1E87E9CE5528DF
F8CA1890DBFE6426841992D0FB054BB16

3.1、生成S-Box

看到上述的SBOX下面开始讲述生成上述SBOX的步骤:【请耐心阅读】

  1. 按字节值的升序逐行初始化S盒。第一行是 { 00 } , { 01 } , { 02 } , { 03 } , ⋯   , , { 0 F } \{00\},\{01\},\{02\},\{03\},\cdots ,,\{0F\} {00},{01},{02},{03},,,{0F}第二行是 { 11 } , ⋯   , , { 1 F } \{11\},\cdots ,,\{1F\} {11},,,{1F}。因此在行 Y 列 X的字节值是 { Y X } \{YX\} {YX}

  2. 将S盒中的每个字节映射为它在有限域 G F ( 2 ∧ 8 ) GF(2\land8) GF(28)上的逆元: { 00 } \{00\} {00}被映射为自身 { 00 } \{00\} {00}

  3. 将S盒中的每一个字节的8个构成位记为 ( b 7 , b 6 , b 5 , b 4 , b 3 , b 2 , b 1 , b 0 ) \color{red}(b_7,b_6,b_5,b_4,b_3,b_2,b_1,b_0) (b7,b6,b5,b4,b3,b2,b1,b0)。对于S盒的每个字节的每个位做如下变换:
    b i ’ = b i ⊕ b ( i + 4 ) m o d   8 ⊕ b ( i + 5 ) m o d   8 ⊕ b ( i + 6 ) m o d   8 ⊕ b ( i + 7 ) m o d   8 ⊕ c i \\ b_{i}^{’} = b_{i} \oplus b_{(i+4)mod\ 8}\oplus b_{(i+5)mod\ 8}\oplus b_{(i+6)mod\ 8}\oplus b_{(i+7)mod\ 8}\oplus c_{i} \\ bi=bib(i+4)mod 8b(i+5)mod 8b(i+6)mod 8b(i+7)mod 8ci

    此处的 c i \color{red}c_i ci 表示值为 { 63 } \{63\} {63}的字节 c 的第 i 位。即 ( c 7 , c 6 , c 5 , c 4 , c 3 , c 2 , c 1 , c 0 ) = ( 01100011 ) (c_7,c_6,c_5,c_4,c_3,c_2,c_1,c_0) = (01100011) (c7,c6,c5,c4,c3,c2,c1,c0)=(01100011)。符号 ( ′ ) (') ()表示变量的值要被等式右边的纸更新。AES标准用矩阵形式描述了这个变换

[ b 0 ’ b 1 ’ b 2 ’ b 3 ’ b 4 ’ b 5 ’ b 6 ’ b 7 ’ ] = [ 1 0 0 0 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 0 0 0 0 1 1 1 1 1 0 0 0 0 1 1 1 1 1 ] [ b 0 b 1 b 2 b 3 b 4 b 5 b 6 b 7 ] + [ 1 1 0 0 0 1 1 0 ] \begin{bmatrix} b_{0}^{’}\\ b_{1}^{’}\\b_{2}^{’}\\b_{3}^{’}\\b_{4}^{’}\\b_{5}^{’}\\b_{6}^{’}\\b_{7}^{’} \end{bmatrix}=\begin{bmatrix} 1 & 0 & 0 & 0 & 1 & 1 & 1 & 1\\ 1 & 1 & 0 & 0 & 0 & 1 & 1 & 1\\ 1 & 1 & 1 & 0 & 0 & 0 & 1 & 1\\ 1 & 1 & 1 & 1 & 0 & 0 & 0 & 1\\ 1 & 1 & 1 & 1 & 1 & 0 & 0 & 0\\ 0 & 1 & 1 & 1 & 1 & 1 & 0 & 0\\ 0 & 0 & 1 & 1 & 1 & 1 & 1 & 0\\ 0 & 0 & 0 & 1 & 1 & 1 & 1 & 1\\ \end{bmatrix} \begin{bmatrix} b_{0}\\ b_{1}\\b_{2}\\b_{3}\\b_{4}\\b_{5}\\b_{6}\\b_{7} \end{bmatrix}+\begin{bmatrix} 1 \\ 1 \\ 0 \\ 0\\ 0\\1\\1\\0\end{bmatrix} b0b1b2b3b4b5b6b7 = 1111100001111100001111100001111110001111110001111110001111110001 b0b1b2b3b4b5b6b7 + 11000110

3.3、具体代码实现:生成S-Box

3.3.1、整体结构
  • 根据上述构造Sbox的三个步骤可以知道第一步使用一个遍历既可构造,关键的步骤是第二步和第三步

    1. 【即上述步骤一】==> 遍历生成初始盒子
    2. 【即上述步骤二】==> 求GF(2^8)有限域内各元素的乘法逆元(扩展欧几里得算法)
    3. 【即上述步骤三】==> 对逆元做位变换
    
  • 结合代码做进一步说明:

    //因为使用8位二进制因此使用unsigned char是刚好够用的
    unsigned int GF_ex_gcd(unsigned int a, unsigned int b, unsigned int& x, unsigned int& y) //求逆元
    unsigned char converToInverse(unsigned char token); //对逆元做位变换
        
    //具体SBox生成逻辑
    void generate_Sbox() {
    	for (unsigned int i = 0x00; i < 0xFF; i++) {
    		if (i && i % 16 == 0)puts("");
    		unsigned int x = 0, y = 0;
            //求得元素 i 的逆元 y
    		GF_ex_gcd(0x11b, i, x, y);	//0x11b ==> 不可约多项式(x^8 + x^4 + x^3 + x + 1)
    		unsigned char res = converToInverse(y);
    		printf("%02X ",res);
    	}
    }
    
  • 分析一下函数GF_ex_gcd根据前置知识

    ax + by = d = gcd(a, b)  
    现在如果gcd(a, b) = 1, 有ax + by = 1, 等式两边同mod a得
    [(ax mod a) + (by mod a)]mod a = 1 mod a
    0 + by mod a = 1
    既然by mod a = 1, 则在GF(2^8)中
    y = b^(-1)
    只需令a=m(x)=x^8 + x^4 + x^3 + x + 1=0x11b
    即可求得元素b的乘法逆元y
    
3.3.2、细节:位变换
  • 观察第三步的变换矩阵是从低位到高位的,但是计算机输入的时候是先扫描高位的。就比如扫描 1 D = > ( 00011101 ) 1D => (00011101) 1D=>(00011101)计算机从左到右扫描先扫到高位。

  • 因此我们将上述AES的仿射矩阵变换一下就可以有如下的矩阵显示:
    [ b 0 ’ b 1 ’ b 2 ’ b 3 ’ b 4 ’ b 5 ’ b 6 ’ b 7 ’ ] = [ 1 1 1 1 0 0 0 1 1 1 1 0 0 0 1 1 1 1 0 0 0 1 1 1 1 0 0 0 1 1 1 1 0 0 0 1 1 1 1 1 0 0 1 1 1 1 1 0 0 1 1 1 1 1 0 0 1 1 1 1 1 0 0 0 ] [ b 7 b 6 b 5 b 4 b 3 b 2 b 1 b 0 ] + [ 1 1 0 0 0 1 1 0 ] \begin{bmatrix} b_{0}^{’}\\ b_{1}^{’}\\b_{2}^{’}\\b_{3}^{’}\\b_{4}^{’}\\b_{5}^{’}\\b_{6}^{’}\\b_{7}^{’} \end{bmatrix}= \begin{bmatrix} 1 & 1 & 1 & 1 & 0 & 0 & 0 & 1\\ 1 & 1 & 1 & 0 & 0 & 0 & 1 & 1\\ 1 & 1 & 0 & 0 & 0 & 1 & 1 & 1\\ 1 & 0 & 0 & 0 & 1 & 1 & 1 & 1\\ 0 & 0 & 0 & 1 & 1 & 1 & 1 & 1\\ 0 & 0 & 1 & 1 & 1 & 1 & 1 & 0\\ 0 & 1 & 1 & 1 & 1 & 1 & 0 & 0\\ 1 & 1 & 1 & 1 & 1 & 0 & 0 & 0\\ \end{bmatrix} \begin{bmatrix} b_{7}\\ b_{6}\\b_{5}\\b_{4}\\b_{3}\\b_{2}\\b_{1}\\b_{0} \end{bmatrix}+ \begin{bmatrix} 1 \\ 1 \\ 0 \\ 0\\ 0\\1\\1\\0 \end{bmatrix} b0b1b2b3b4b5b6b7 = 1111000111100011110001111000111100011111001111100111110011111000 b7b6b5b4b3b2b1b0 + 11000110

因此可以根据上述提示可以实现代码

unsigned char mtx[8] = { 0xF1,0xE3,0xC7,0x8F,0x1F,0x3E,0x7C,0xF8 };
const unsigned char c = 0x63;
//token是第二步中传入的逆元
//该函数实现上述的第三步:即对逆元做映射
//对书上的mtx 和列矩阵C进行了掉转,从而使得低位对低位,高位对高位
unsigned char converToInverse(unsigned char token) {
     /*
     * mul是矩阵1某一行每一位对应 * {b0,...b7} 生成的一列结果
     * curBit从mul低位开始异或,即列结果相加
     * 结果就是矩阵1×矩阵2的中间矩阵tmp的某一位的值 0/1
     * 最后curBit左移i位,和tmp相或,就是置该位值
     */
	unsigned char tmp = 0;
	for (int i = 0; i < 8; i++) {
		unsigned char curBit = 0;
		unsigned char mul = mtx[i] & token;
		for (int j = 0; j < 8; j++) {
			curBit ^= (mul & 1);
			mul >>= 1;
		}
		curBit <<= i;
		tmp |= curBit;
	}
	return tmp ^ c;
}

自己根据代码去手算一遍你就好理解这个代码了,而不是复制粘贴

3.3.3、细节:逆元转变

我们知道要求逆元可以使用拓展欧几里得算法,因此首先看回原来的算法

int ex_gcd(int a,int b,int &x,int &y){
    if(b == 0){
        x = 1,y = 0;
		return a;
    }
    int gcd = ex_gcd( b , a%b , y , x);
    y = y - a/b * x;
	return gcd;
}

可以看到原来的算法使用了 %/*法,但是这种基本表达式的运算在有限域 G F ( 2 ∧ 8 ) GF(2\land 8) GF(28)不适用

  • 因此在使用算法求逆元之前我们需要实现多项式的u % v操作 u / v 操作和 u * v操作

注意事项
我们操作的单元一直都是unsigned char【8位】
知GF(2^8)中,我们要求的是元素 u(x)以m(x)为模的乘法逆元,而m(x) = x^8 + x^4 + x^3 + x + 1
0X11B0B100011011, m(x)如果用位来表示,需9bits,故而unsigned char已经无法胜任,所以我们多引入一种类型来兼顾,即unsigned int

首先实现乘法是GF(2^8)内的乘法

利用的是密码编码学与网络安全第七版 William Stallings中介绍的方法 思路简述如下:

首先基于这样一个事实:

G F ( 2 ∧ n ) GF(2\land n) GF(2n)中, x^n mod p(x) = [p(x) - x^n]

比如x^8 mod m(x) = [m(x)-x^8] = x^4 + x^3 + x + 1

我们可以利用这个性质对乘法进行拆分完成,比如f(x) * g(x)

g(x) = 11000001 = (10000000) ⊕ (01000000) ⊕(00000001)

预处理:对于f(x)本身,依次乘以1, 10, 100,…10000000,由于每次只左移一位,所以结果最高次只可能=8,此时需mod m(x),相当于异或x^4 + x^3 + x + 1,或者<8,此时无需进行额外操作。得到了这8个预知结果

f ( x ) ∗ g ( x ) f(x) * g(x) f(x)g(x)其实就是根据g(x)把上面预知的结果异或起来就ok

/*
 * GF(2^8)中的乘法 
 * result = a * b
 */
unsigned char GFmul(unsigned char a, unsigned char b) {
	unsigned char res = 0, tmp;
	if ((b & 1) == 1)res ^= a;
	b >>= 1;
	for (int i = 0; i < 7; i++) {
		tmp = a;
		a <<= 1;
		if (tmp > 127) a ^ 0x1b;
		if ((b & 1) == 1)res ^= a;
		b >>= 1;
	}
	return res;
}

G F ( 2 ∧ 8 ) GF(2\land 8) GF(28)上的模拟除法, m ( x ) / u ( x ) m(x) / u(x) m(x)/u(x)。如果u(x) = 1,那么商的第一项会是x^8 。即需9位标识商,而上述乘法是GF(2^8)内的,最多8位,所以上述乘法不足以应付m(x) / u(x),实现一个一般的多项式乘法供除法调用

/*
 * 一般意义的多项式乘法
 */
unsigned int polMul(unsigned int a, unsigned int b) {
	unsigned int res = 0;
	if ((b & 1) == 1) res = a;
	b >>= 1;
	for (int i = 0; i < 8; ++i) {
		a <<= 1;
		if ((b & 1) == 1) res ^= a;
		b >>= 1;
	}
	return res;
}

然后就可以实现 G F ( 2 ∧ 8 ) GF(2\land 8) GF(28)上的除法

/*
 * GF(2^8)中的除法, 思路是模拟手工
 * 输出: a / b的商 并且通过r返回 余式
 * 留意,在求S-Box时,被除式可能是0x11b, 故而unsigned char无法满足
 * 所以这里的被除式,除式都用ui,但是对于余式,不可能大于0xFF,所以用uc即可
 */
unsigned int GFdiv(unsigned int a, unsigned int b, unsigned char &r) {
	unsigned int res = 0;
	while (a >= b) {
		unsigned int ha = 8, hb = 8;
		unsigned int flag = a;
		while (!(flag & 0x100)) { --ha; flag <<= 1; }
		flag = b;
		while (!(flag & 0x100)) { --ha; flag <<= 1; }

		unsigned int d = ha - hb;
		unsigned int curRes = 0x01 << d;
		res |= curRes;
		unsigned int tmp = polMul(b, curRes);
		a ^= tmp;
	}
	r = a;
	return res;
}

至此生成求逆元所具备的运算规则都已实现因此改进拓展欧几里得算法实现求逆元

unsigned int GF_ex_gcd(unsigned int a, unsigned int b, unsigned int& x, unsigned int& y) {
	if (b == 0) {
		x = 1; y = 0;
		return a;
	}
	unsigned char r; 
	unsigned int q = GFdiv(a, b, r);
	unsigned int res = GF_ex_gcd(b, r, x, y);
	unsigned int tmp = x;
	x = y;
	y = tmp ^ GFmul(q, y);
	return res;
}

至此所有步骤已经实现调用函数即可实现生成S-Box

63 7C 77 7B F2 6B 6F C5 30 01 67 2B FE D7 AB 76 
CA 82 C9 7D FA 59 47 F0 AD D4 A2 AF 9C A4 72 C0 
B7 FD 93 26 36 3F F7 CC 34 A5 E5 F1 71 D8 31 15 
04 C7 23 C3 18 96 05 9A 07 12 80 E2 EB 27 B2 75 
09 83 2C 1A 1B 6E 5A A0 52 3B D6 B3 29 E3 2F 84 
53 D1 00 ED 20 FC B1 5B 6A CB BE 39 4A 4C 58 CF 
D0 EF AA FB 43 4D 33 85 45 F9 02 7F 50 3C 9F A8 
51 A3 40 8F 92 9D 38 F5 BC B6 DA 21 10 FF F3 D2 
CD 0C 13 EC 5F 97 44 17 C4 A7 7E 3D 64 5D 19 73 
60 81 4F DC 22 2A 90 88 46 EE B8 14 DE 5E 0B DB 
E0 32 3A 0A 49 06 24 5C C2 D3 AC 62 91 95 E4 79 
E7 C8 37 6D 8D D5 4E A9 6C 56 F4 EA 65 7A AE 08 
BA 78 25 2E 1C A6 B4 C6 E8 DD 74 1F 4B BD 8B 8A 
70 3E B5 66 48 03 F6 0E 61 35 57 B9 86 C1 1D 9E 
E1 F8 98 11 69 D9 8E 94 9B 1E 87 E9 CE 55 28 DF 
8C A1 89 0D BF E6 42 68 41 99 2D 0F B0 54 BB 16 

四、S-box生成代码汇总

  • 为了方便个别同学下面给出完整代码实现SBOX,详细知识请看第三节AES-SBOX生成
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string>
#include <algorithm>
//#include <bits/stdc++.h>
using namespace std;

unsigned char GFmul(unsigned char a, unsigned char b) {
	unsigned char res = 0, tmp;
	if ((b & 1) == 1)res ^= a;
	b >>= 1;
	for (int i = 0; i < 7; i++) {
		tmp = a;
		a <<= 1;
		if (tmp > 127) a ^ 0x1b;
		if ((b & 1) == 1)res ^= a;
		b >>= 1;
	}
	return res;
}

unsigned int polMul(unsigned int a, unsigned int b) {
	unsigned int res = 0;
	if ((b & 1) == 1) res = a;
	b >>= 1;
	for (int i = 0; i < 8; ++i) {
		a <<= 1;
		if ((b & 1) == 1) res ^= a;
		b >>= 1;
	}
	return res;
}

unsigned int GFdiv(unsigned int a, unsigned int b, unsigned char &r) {
	unsigned int res = 0;
	while (a >= b) {
		unsigned int ha = 8, hb = 8;
		unsigned int flag = a;
		while (!(flag & 0x100)) { --ha; flag <<= 1; }
		flag = b;
		while (!(flag & 0x100)) { --ha; flag <<= 1; }

		unsigned int d = ha - hb;
		unsigned int curRes = 0x01 << d;
		res |= curRes;
		unsigned int tmp = polMul(b, curRes);
		a ^= tmp;
	}
	r = a;
	return res;
}

unsigned int GF_ex_gcd(unsigned int a, unsigned int b, unsigned int& x, unsigned int& y) {
	if (b == 0) {
		x = 1; y = 0;
		return a;
	}
	unsigned char r; 
	unsigned int q = GFdiv(a, b, r);
	unsigned int res = GF_ex_gcd(b, r, x, y);
	unsigned int tmp = x;
	x = y;
	y = tmp ^ GFmul(q, y);
	return res;
}

	
unsigned char mtx[8] = { 0xF1,0xE3,0xC7,0x8F,0x1F,0x3E,0x7C,0xF8 };
const unsigned char c = 0x63;
unsigned char converToInverse(unsigned char token) {
	unsigned char tmp = 0;
	for (int i = 0; i < 8; i++) {
		unsigned char curBit = 0;
		unsigned char mul = token & mtx[i];
		for (int j = 0; j < 8; j++) {
			curBit ^= (mul & 1);
			mul >>= 1;
		}
		curBit <<= i;
		tmp |= curBit;
	}
	return tmp ^ c;
}
void generate_Sbox() {
	for (unsigned int i = 0x00; i < 0xFF; i++) {
		if (i && i % 16 == 0)puts("");
		unsigned int x = 0, y = 0;
		GF_ex_gcd(0x11b, i, x, y);
		unsigned char res = converToInverse(y);
		printf("%02X ",res);
	}
}

signed main() {
	cout << "开始输出SB" << endl;
	generate_Sbox();
	return 0;
}

参考文章

  1. 拓展欧几里得
  2. 有限域GF(2^8)
  3. AES中SBOX的生成
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_橙留香

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值