利用GF(2^8)乘法逆元,以及矩阵运算,可以构造出AES的SBOX。
求乘法逆元的一般方法是利用扩展欧几里得定理,在这里我取了个巧。
因为我已经有了GF的指数表(见上一篇文),利用指数表可以轻易地构造出乘法逆元表。具体方法如下:
若 x = 3^m, y = 3^n, x 与 y 互为乘法逆元,则有x * y = 3^m * 3^n = 1 = 3^255(任意乘法逆元的255次方必定为1,有点类似费尔马小定理),则m+n=255

#include<iostream> #include<fstream> #include <iomanip> using namespace std; unsigned char exp[256], log[256], inv[256]; unsigned char GFmul(unsigned char a, unsigned char b){ //GF(2^8) 乘法 unsigned char result = 0; if((b&1) == 1)result = a; b >>= 1; for(int i = 1; i < 8; i ++){ if(a > 127){ a = (a << 1) ^ 0x1b; } else{ a <<= 1; } if((b&1) == 1){ result ^= a; } b >>= 1; } return result; } void generateMulTab(){ //选择生成元3作为构造乘法表的基础 const int N = 3; exp[1] = N; log[N] = 1; unsigned char tmp = N; for(int i = 2; i < 256; i ++){ tmp = GFmul(tmp, N); exp[i] = tmp; log[tmp] = i; } } void generateMulInverse(){ //利用exp来构造乘法逆元 inv[0] = 0; inv[1] = 1; //若3^m * 3^n = 1 = 3^255,则 m + n = 255 for(int i = 1; i < 255; i ++){ inv[exp[i]] = exp[255-i]; } } unsigned char SBoxValue(unsigned char x){ //返回SBOX对应的值 bool xb[8]; unsigned char y = inv[x]; //AES规定的常数项 const bool N[8][8] = {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}; const bool C[8] = {1, 1, 0, 0, 0, 1, 1, 0}; //将y转化为数组用作矩阵运算 for(int i = 0; i < 8; i ++){ xb[i] = (y&1); y >>= 1; } //矩阵乘法 bool tmp[8]; for(int i = 0; i < 8; i ++)tmp[i] = 0; for(int i = 0; i < 8; i ++){ for(int j = 0; j < 8; j ++){ tmp[i] ^= (N[i][j] & xb[j]); } tmp[i] ^= C[i]; } //将数组结果转化为数值 unsigned char result = 0; result |= tmp[7]; for(int i = 6; i >= 0; i --){ result <<= 1; if(tmp[i])result |= 1; } return result; } int main(){ //单元测试,输出SBOX的全部值 generateMulTab(); generateMulInverse(); unsigned char SBox[16][16]; for(int i = 0; i < 16; i ++){ for(int j = 0; j < 16; j ++){ unsigned char tmp = i*16 + j; SBox[i][j] = SBoxValue(tmp); } } ofstream write("Test.txt"); for(int i = 0; i < 16; i ++){ for(int j = 0; j < 16; j ++){ write<<setiosflags(ios::left)<<setw(4)<<hex<<(int)SBox[i][j]; } write<<endl; } write.close(); return 0; }