










一、先把问题说清楚
在 SM4 里,每一轮核心是:T(x) = L( Sbox(x) )
展开就是:
把 x 拆成4个字节 → 过 S盒(查表)
拼回32位
再做一堆循环移位 + XOR(L)
T_table优化就是把这两步合成一步。
=================================================
二、核心思想(一句话)
L 是线性的,而 Sbox 是逐字节的 → 可以“提前算好所有结果”
=================================================
三、一步一步拆开
1、把 x 拆成4个字节
x = (a << 24) | (b << 16) | (c << 8) | d
2、过 Sbox
S(x) = (S[a]<<24) | (S[b]<<16) | (S[c]<<8) | S[d]
这一步是逐字节独立的
3、关键点来了:L 是线性的
L 定义 : L(x) = x ^ (x<<<2) ^ (x<<<10) ^ (x<<<18) ^ (x<<<24)
这是一个线性变换, 满足:
L(A ^ B) = L(A) ^ L(B)
=================================================
四、最关键的一步(本质)
L(S(x)) = L(S[a]<<24 ^ S[b]<<16 ^ S[c]<<8 ^ S[d])
= L(S[a]<<24) ^ L(S[b]<<16) ^ L(S[c]<<8) ^ L(S[d])
=================================================
五、于是可以预计算
T0[a] = L(S[a] << 24)
T1[b] = L(S[b] << 16)
T2[c] = L(S[c] << 8)
T3[d] = L(S[d])
运行时就变成
T(x) = T0[a] ^ T1[b] ^ T2[c] ^ T3[d]
// ====== T-table ====== static uint32_t T0[256],T1[256],T2[256],T3[256]; // 预读 S盒, 对每个字节先进行 S+L 计算 void init_ttable(){ for(int i=0;i<256;i++){ uint32_t b=Sbox[i]; T0[i]=L(b<<24); T1[i]=L(b<<16); T2[i]=L(b<<8); T3[i]=L(b); } } // ====== T-table 加密 ====== void sm4_encrypt_t(uint32_t in[4], uint32_t rk[32], uint32_t out[4]) { uint32_t x0 = in[0]; uint32_t x1 = in[1]; uint32_t x2 = in[2]; uint32_t x3 = in[3]; // 32轮计算 X4 = X0 ^ T(X1 ^ X2 ^ X3 ^ rk) for (int i = 0; i < 32; i++) { // 先整体 XOR uint32_t tmp = x1 ^ x2 ^ x3 ^ rk[i]; // 再拆字节(这是 T-table 的入口) uint32_t a = (tmp >> 24) & 0xff; uint32_t b = (tmp >> 16) & 0xff; uint32_t c = (tmp >> 8) & 0xff; uint32_t d = tmp & 0xff; // T-table 查表 uint32_t t = T0[a] ^ T1[b] ^ T2[c] ^ T3[d]; // Feistel 更新 uint32_t newX = x0 ^ t; // 滚动 x0 = x1; x1 = x2; x2 = x3; x3 = newX; } // 反序输出 out[0] = x3; out[1] = x2; out[2] = x1; out[3] = x0; } // ====== T-table 解密 ====== void sm4_decrypt_t(uint32_t in[4], uint32_t rk[32], uint32_t out[4]) { uint32_t x0 = in[0]; uint32_t x1 = in[1]; uint32_t x2 = in[2]; uint32_t x3 = in[3]; for (int i = 0; i < 32; i++) { uint32_t tmp = x1 ^ x2 ^ x3 ^ rk[31 - i]; uint32_t a = (tmp >> 24) & 0xff; uint32_t b = (tmp >> 16) & 0xff; uint32_t c = (tmp >> 8) & 0xff; uint32_t d = tmp & 0xff; uint32_t t = T0[a] ^ T1[b] ^ T2[c] ^ T3[d]; uint32_t newX = x0 ^ t; x0 = x1; x1 = x2; x2 = x3; x3 = newX; } out[0] = x3; out[1] = x2; out[2] = x1; out[3] = x0; } // ====== 测试 ====== int main(){ uint32_t MK[4]={0x01234567,0x89abcdef,0xfedcba98,0x76543210}; uint32_t P[4]={0x01234567,0x89abcdef,0xfedcba98,0x76543210}; uint32_t rk[32],C[4],D[4]; key_schedule(MK,rk); init_ttable(); sm4_encrypt_t(P,rk,C); sm4_decrypt_t(C,rk,D); printf("Plain : %08x %08x %08x %08x\n",P[0],P[1],P[2],P[3]); printf("Cipher: %08x %08x %08x %08x\n",C[0],C[1],C[2],C[3]); printf("Dec : %08x %08x %08x %08x\n",D[0],D[1],D[2],D[3]); return 0; }
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。