AES 中 S-Box 生成过程
-
按字节升序初始化 S 盒,例如第一行数据为 {00},{01},{02} , … , {0F}; 第二行为 {00},{01},{02} , … , {0F};一次类推。
-
将 S 盒中的每个字节映射到它在 GF( 2 8 2^8 28) 中的乘法逆元。 {00} 映射到它本身。
-
对 S 盒中的每个字节的每个位 ( b 7 , . . . , b 0 b_7, ...,b_0 b7,...,b0) 做如下变换:
bi’ = 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\bigoplus b_{(i+4) mod8} \bigoplus b_{(i+5) mod8} \bigoplus b_{(i+6) mod8} \bigoplus b_{(i+7) mod8} \bigoplus c_i bi⨁b(i+4)mod8⨁b(i+5)mod8⨁b(i+6)mod8⨁b(i+7)mod8⨁ci
其中 C = {63}
相当于 b i b_i bi 与除了其后三位外的位以及 c i c_i ci 进行异或
证 6.4 等同于 6.9
以 s 0 ′ s_0' s0′ 为例,根据 03 ∗ x = ( 02 ∗ x ) ⨁ x {03} * x = ({02} * x) \bigoplus x 03∗x=(02∗x)⨁x
s 0 ′ = s 0 , j ⨁ T M P ⨁ 2 ( s 0 , j ⨁ s 1 , j ) s_0' = s_{0,j} \bigoplus TMP\bigoplus 2(s_{0,j} \bigoplus s_{1,j}) s0′=s0,j⨁TMP⨁2(s0,j⨁s1,j)
= s 0 , j ⨁ s 0 , j ⨁ s 1 , j ⨁ s 2 , j ⨁ s 3 , j ⨁ 2 ( s 0 , j ⨁ s 1 , j ) =s_{0,j} \bigoplus s_{0,j} \bigoplus s_{1,j} \bigoplus s_{2,j} \bigoplus s_{3,j} \bigoplus 2(s_{0,j} \bigoplus s_{1,j}) =s0,j⨁s0,j⨁s1,j⨁s2,j⨁s3,j⨁2(s0,j⨁s1,j)
= ( 2 ∗ s 0 , j ) ⨁ s 1 , j ⨁ s 2 , j ⨁ s 3 , j ⨁ 2 s 1 , j = (2*s_{0,j}) \bigoplus s_{1,j} \bigoplus s_{2,j} \bigoplus s_{3,j} \bigoplus 2s_{1,j} =(2∗s0,j)⨁s1,j⨁s2,j⨁s3,j⨁2s1,j
$= (2s_{0,j}) \bigoplus (3s_{1,j}) \bigoplus s_{2,j} \bigoplus s_{3,j} $
自然,
s
1
′
,
s
2
′
,
s
3
′
s_1',s_2',s_3'
s1′,s2′,s3′ 同理,可证 6.4 等同于 6.9
G F ( 2 8 ) GF(2^8) GF(28) 乘法实现
#include<iostream>
using namespace std;
/*思路
a * b = a * 2^i*b[i];
*/
//实现 x*2,若 x 的最高位是1,则异或 0x1b
unsigned char XTIME(unsigned char x) {
return ((x << 1) ^ ((x & 0x80) ? 0x1b : 0x00));
}
unsigned char multiply(unsigned char a, unsigned char b) {
unsigned char temp[8] = { a };
unsigned char res = 0x00;
int i = 0;
//temp 数组存储的是 a * 0x01, a*0x02, ... , a*0x80,遵循了 GF(2^8) 的乘法法则
for (int i = 1; i < 8; i++) {
temp[i] = XTIME(temp[i - 1]);
}
for (int i = 0; i < 8; i++) {
res ^= (((b >> i) & 0x01) * temp[i]);
}
return res;
}
int main() {
int a, b;
cin >> a >> b;
int res = (int)multiply((unsigned char)a, (unsigned char)b);
cout << res << endl;
return 0;
}
S 盒的实现
#include <cstdio>
unsigned char S_box[16][16];
void initialize(); //初始化 S-box[i][j] <- {ij}
unsigned char msb(unsigned short num); //找到非零最高位并返回
unsigned char divide(unsigned short a, unsigned char b, unsigned char &r); //双字节的多项式除法,返回a/b
unsigned char Mul(unsigned char a, unsigned char b); //GF(2^8)乘法,返回a * b
unsigned char inverse(unsigned char b); //扩展欧几里得算法求b在GF(2^8)的乘法逆元
unsigned char map(unsigned char a); //映射
void main()
{
initialize();
unsigned char i, j;
for(i = 0; i <= 0xF; i++)
{
printf("\n");
for(j = 0; j <= 0xF; j++)
{
S_box[i][j] = map(S_box[i][j]);
printf("%02X ",S_box[i][j]);
}
}
printf("\n");
}
void initialize()
{
unsigned char i, j;
for(i = 0; i <= 0xF; i++)
{
for(j = 0; j <= 0xF; j++)
{
S_box[i][j] = inverse((i << 4) + j); //使第i行第j列的元素为{xj}
}
}
}
unsigned char msb(unsigned short num)
{
unsigned char i;
for(i = 0; i <= 8; i++)
{
if(!(num >> (i + 1)))
{
return i;
}
}
}
// a/b
unsigned char divide(unsigned short a, unsigned char b, unsigned char &r)
{
unsigned char a_msb = msb(a);
unsigned char b_msb = msb(b);
if(a < b)
{
r = a;
return 0;
}
unsigned char bit = a_msb - b_msb;
unsigned short temp = b;
temp = temp << bit;
a = a ^ temp;
return (1 << bit) | divide(a, b, r);
}
unsigned char XTIME(unsigned char x) {
return ((x << 1) ^ ((x & 0x80) ? 0x1b : 0x00));
}
// a*b
unsigned char Mul(unsigned char a, unsigned char b) {
unsigned char temp[8] = { a };
unsigned char tempmultiply = 0x00;
int i = 0;
for (i = 1; i < 8; i++) {
temp[i] = XTIME(temp[i - 1]);
}
tempmultiply = (b & 0x01) * a;
for (i = 1; i <= 7; i++) {
tempmultiply ^= (((b >> i) & 0x01) * temp[i]);
}
return tempmultiply;
}
unsigned char inverse(unsigned char b)
{
if(b == 0)
return 0;
short r0 = 0x11B;
unsigned char r1 = b, r2, q;
unsigned char w0 = 0, w1 = 1, w2;
q = divide(r0, r1 , r2);
w2 = w0 ^ Mul(q, w1);
while(1)
{
if(r2 == 0)
break;
r0 = r1;
r1 = r2;
q = divide(r0, r1, r2);
w0 = w1;
w1 = w2;
w2 = w0 ^ Mul(q, w1);
}
return w1;
}
unsigned char map(unsigned char a)
{
unsigned char c = 0x63;
unsigned char res = 0x0;
unsigned char temp = 0x0;
unsigned char i;
for(i = 0; i < 8; i++)
{
temp = temp ^ ((a >> i) & 0x1) ^ ((a >> ((i + 4) % 8)) & 0x1);//优先级>> 高于 &
temp = temp ^ ((a >> ((i + 5) % 8)) & 0x1) ^ ((a >> ((i + 6) % 8)) & 0x1);
temp = temp ^ ((a >> ((i + 7) % 8)) & 0x1) ^ ((c >> i) & 0x1);
res = res | (temp << i);
temp = 0x0;
}
return res;
}