【AES加密专题】4.Sbox的解析和生成
目录
1.Sbox
一、Sbox 的核心功能:“搅乱” 数据,制造非线性
二、Sbox 的结构:两步运算形成的固定映射表
第一步:求 GF (2⁸) 上的乘法逆元
第二步:仿射变换(Affine Transformation)
最终:固定的映射表
三、sbox的生成
1.有限域乘法
2.逆元
3.反射变换函数
总结
专题:
【AES加密专题】1.AES的原理详解和加密过程-CSDN博客
【AES加密专题】2.AES头文件详解-CSDN博客
【AES加密专题】3.工具函数的编写(1)-CSDN博客
1.Sbox
在 AES 加密算法中,Sbox(Substitution Box,字节替换表) 是最核心的 “非线性变换” 部件,相当于一个 “密码本”,负责把输入的 8 位字节(0-255 之间的数)映射成另一个 8 位字节,目的是让明文和密文之间的关系变得极其复杂,难以被破解。
一、Sbox 的核心功能:“搅乱” 数据,制造非线性
AES 的加密过程本质是对数据做一系列变换(比如移位、混合、与密钥结合),但如果这些变换都是 “线性的”(比如简单的加减乘),攻击者很容易通过数学规律反推明文或密钥。
Sbox 的作用就是提供非线性变换:输入的微小变化(比如某一位从 0 变 1)会导致输出完全不同,就像 “蝴蝶效应”,让数据的关联性被彻底打乱。这种非线性是 AES 安全性的关键 —— 没有它,AES 很容易被 “线性攻击” 破解。
二、Sbox 的结构:两步运算形成的固定映射表
Sbox 不是随便设计的,而是通过严格的数学运算生成的固定 8×8 表格(256 个输入对应 256 个输出)。它的构造分两步,核心是 “有限域运算” 和 “仿射变换”:
第一步:求 GF (2⁸) 上的乘法逆元
首先,对输入的 8 位字节(记为b
)做 “乘法逆元” 运算:
-
如果
b
不是 0(即非零字节),计算它在有限域 GF (2⁸) 中的 “逆元”(类似普通数学中 “倒数” 的概念,比如 2 的倒数是 0.5,因为 2×0.5=1)。在 GF (2⁸) 中,每个非零字节b
都有唯一的逆元b⁻¹
,满足b × b⁻¹ = 1
(这里的乘法是有限域内的多项式乘法,模之前说的 0x1B 多项式)。 -
如果
b
是 0,则逆元仍为 0(特殊处理,避免无意义运算)。
第二步:仿射变换(Affine Transformation)
为了进一步增强非线性,对第一步得到的逆元再做一次 “仿射变换”。这一步是线性变换 + 常数偏移,可以理解为 “按固定规则打乱比特位并加一个固定值”。
具体来说,仿射变换的数学表达是:对 8 位字节的每一位y_i
(输出),由第一步结果的 8 位x_j
(输入)通过如下公式计算:y_i = x_i + x_(i+1) + x_(i+2) + x_(i+3) + x_(i+4) + c_i
其中:
-
加法是 “异或”(GF (2) 中的加法,1+1=0,1+0=1);
-
i+1
等超过 7 时循环(比如i=7
时,i+1
是 0); -
c_i
是固定的常数向量,对应二进制1100011
(即十六进制 0x63),用于增加随机性。
最终:固定的映射表
经过上面两步运算后,每个输入字节(0-255)都会对应一个唯一的输出字节。这些映射关系被预先计算好,做成一个 8×32 的表格(或 256 个元素的数组),就是 Sbox。
例如:
-
输入 0x00 → 经过逆元(0x00)和仿射变换 → 输出 0x63;
-
输入 0x01 → 逆元是 0x01(因为 1×1=1),仿射变换后 → 输出 0x7c;
-
所有 AES 实现都用同一个 Sbox(标准规定),确保加密解密的一致性。
三、sbox的生成
1.有限域乘法
#include <stdio.h>// 定义AES中GF(2^8)有限域的不可约多项式,十六进制0x1B对应多项式x⁸ + x⁴ + x³ + x + 1
#define AES_MOD 0x11B /*** @brief 计算两个8位字节在GF(2^8)有限域中的乘法* @param a 乘数(8位无符号整数,范围0-255)* @param b 乘数(8位无符号整数,范围0-255)* @return 乘积结果(8位无符号整数,经过模AES_MOD处理,确保在GF(2^8)范围内)* 原理:模拟二进制乘法的分步计算,结合有限域的模运算规则(超过8位时用AES_MOD修正)*/
unsigned char gmul(unsigned char a, unsigned char b) {unsigned char p = 0; // 初始化乘积结果为0(GF(2^8)中加法的初始值)while (b) { // 循环处理乘数b的每一个二进制位(直到b的所有位都处理完)// 如果b的最低位为1(即当前位需要参与乘法),则将a累加到结果p中// GF(2^8)中的"加法"等价于异或(XOR),因为1+1=0,1+0=1,符合有限域加法规则if (b & 1) {p ^= a; }// 将a左移1位(等价于乘以x,即多项式乘法中次数加1)// 若a的最高位(第7位,对应0x80)为1,左移后会产生第8位(溢出)// 此时需要用不可约多项式AES_MOD进行模运算,通过异或AES_MOD消除溢出位,确保结果仍为8位a = (a << 1) ^ ((a & 0x80) ? AES_MOD : 0); // 将b右移1位,处理下一个二进制位(从低位到高位依次处理)b >>= 1;}return p; // 返回最终的乘积结果(已确保在GF(2^8)范围内)
}
2.逆元
// 使用暴力搜索找到 GF(2^8)中的逆元
unsigned char ginv(unsigned char x) {if (x == 0) return 0; //0 没有逆元for (unsigned char i = 1; i < 256; i++) {if (gmul(x, i) == 1) {return i;}}return 0; // 不应该到达此行
}
3.反射变换函数
// 仿射变换函数:AES中Sbox生成的第二步操作,用于增强非线性特性
// 输入:有限域GF(2^8)中元素的乘法逆元(8位字节x)
// 输出:经过仿射变换后的8位字节(Sbox的最终输出之一)
// 原理:通过循环移位实现线性变换,叠加固定常数偏移,进一步打乱输入字节的比特关系
unsigned char affineTransform(unsigned char x)
{// 计算仿射变换结果,由三部分组成:// 1. 原始输入x// 2. 四次循环移位的结果(分别循环左移1/2/3/4位),通过异或组合实现线性变换// 3. 固定常数偏移0x63(二进制01100011,AES标准规定)unsigned char result = x ^ ((x << 1) | (x >> 7)) // 循环左移1位:左移1位后,用原最高位(x>>7)补充最低位^ ((x << 2) | (x >> 6)) // 循环左移2位:左移2位后,用原高2位(x>>6)补充低2位^ ((x << 3) | (x >> 5)) // 循环左移3位:左移3位后,用原高3位(x>>5)补充低3位^ ((x << 4) | (x >> 4)) // 循环左移4位:左移4位后,用原高4位(x>>4)补充低4位^ 0x63; // 叠加固定常数偏移(AES标准规定的仿射变换常数)return result & 0xFF; // 确保结果为8位(虽然运算后天然为8位,此操作增强代码健壮性)
}
void generate_aes_sbox(unsigned char sbox[256]) {for (int i = 0; i < 256; i++) {unsigned char x= ginv(i); //计算逆元素sbox[i] =affineTransform(x); // 应用仿射变换}sbox[0]=0x63; // S-Box[0] 的特例处理
}// 生成 AES 逆 S-Box
void generate_aes_inverse_sbox(const unsigned char sbox[256],unsigned char inv_sbox[256]){ for (int i = 0; i < 256; i++) {inv_sbox[sbox[i]] = i;}
}int main() {unsigned char sbox[256];unsigned char inv_sbox[256];// 生成 AES 加密的 S-Boxgenerate_aes_sbox(sbox);// 生成 AES 解密的逆 S-Boxgenerate_aes_inverse_sbox(sbox, inv_sbox);printf("AES Inverse S-Box: \n");for (int i = 0; i < 256; i++) {printf("0x%02X", inv_sbox[i]);if ((i + 1) % 16 == 0) printf("\n");else printf(", ");}
return 0;
}
总结
Sbox 的功能是通过非线性映射 “搅乱” 数据,打破明文和密文的简单关联;其结构是通过 “有限域逆元 + 仿射变换” 生成的固定表格,既保证了安全性(难以破解映射关系),又保证了效率(直接查表即可,无需实时计算)。它是 AES 中 “混淆” 思想的核心体现 —— 让攻击者无法通过密文反向推导出明文或密钥的规律。