为了能到远方,脚下的每一步都不能少.|

chchee

园龄:1年3个月粉丝:1关注:1

AES

AES

The Advanced Encryption Standard

On October 2, 2000, Rijndael was selected to be the Advanced Encryption Standard

image-20241030152452019

Mathematical Preliminaries


Finite Fields

All byte values in AES will be presented as the concatenation of its individual bit values(0 or 1) in order : {a7,a6,a5,a4,a3,a2,a1,a0}

The bytess in AES are interpreted as finite field elements using a polynomial representation:

{a7,a6,a5,a4,a3,a2,a1,a0}a7x7+a6x6+a5x5+a4x4+a3x3+a2x2+a1x1+a0x0=i=0i=7bixi


Addition

The addition of two elements in a finite field is achieved by adding the coefficients for the corresponding powers in the polynomials for the two elements.

The addition is performed with the XOR operation:

For two bytes : {a7,a6,a5,a4,a3,a2,a1,a0},{b7,b6,b5,b4,b3,b2,b1,b0} , the sum is {c7,c6,c5,c4,c3,c2,c1,c0} , where each ci=aibi

1 + 1 mod 2 = 0
1 + 0 mod 2 = 1
0 + 1 mod 2 = 1
0 + 0 mod 2 = 0

1 - 1 mod 2 = 0
1 - 0 mod 2 = 1
0 - 1 mod 2 = 1
0 - 0 mod 2 = 0

Subtraction of polynomials is identical to addition of polynomials.


Multiplication

In the polynomial representation, multiplication in GF(28) (denoted by ) corresponds with the multiplication of polynomials modulo an irreducible polynomial of degree 8

A polynomial is irreducible if its only divisors are one and itself. For AES, this irreducible polynomial is m(x)=x8+x4+x3+x+1

For any non-zero binary polynomial b(x) , the multiplicative inverse of b(x) , denoted b(x)1 can be found as:

The extended Euclidean algorithm is used to compute polynomials a(x) and c(x) such that: b(x)a(x)+m(x)c(x)=1 .

Hence b(x)1=a(x)mod m(x)


Multiplication by x

a(x)=a7x7+a6x6+a5x5+a4x4+a3x3+a2x2+a1x1+a0x0

a(x)xa7x8+a6x7+a5x6+a4x5+a3x4+a2x3+a1x2+a0x1

  • a(x)x is obtained by modulo m(x)

    • a7=0 : Done

    • a7=1 : a(x)x modulo m(x) i.e. XOR m(x)={01}{1b}

multiplication by x (i.e., {00000010} or {02}) can be implemented at the byte level as:

  • a left shift
  • a conditional bitwise XOR with {1b}

This operation on bytes is denoted by xtime() , Multiplication by higher power of x can be implemented by repeated application of xtime()

一定要注意数字是十进制还是十六进制还是二进制!!!!

5702=xtime(57)=xtime(0101 0111)=ae

5704=xtime(ae)=xtime(1010 1110)=0101110 000011011=01000111=4716

5708=xtime(01000111)=100011102=8e16

571016=0001110000011011=00000111=0716

57161316=5716(00010011)2=5716(011602161016)=570157025710=57ae07



Polynimials with Coefficients in GF( 28)

**Four term polynomials can be defined with coefficients that are finite field elements : ** a(x)=a3x3+a2x2+a1x+a0 , which will be denoted as a word in the form [a0,a1,a2,a3]

!!!! The coefficients here are finite field elements themselves, i.e. bytes, instead of bits


Addition

Addition is performed by adding the finite field coefficients of like power of x . This addition corresponds to an XOR operation between the corresponding bytes in each of the words.

a(x)+b(x)=(a3b3)x3+(a2b2)x2+(a1b1)x+(a0b0)


Multiplication

  1. c(x)=a(x)b(x) is algebraically expanded, and like powers are collected :

    c(x)=c6x6+c5x5+c4x4+c3x3+c2x2+c1x1+c0

    c0=a0b0,c4=a3b1a2b2a1b3c1=a1b0a0b1, c5=a3b2a2b3c2=a2b0a1b1a0b2, c6=a3b3c3=a3b0a2b1a1b2a0b3

  2. reduce c(x) to modulo a polynomial of degree 4

    xi mod (x4+1)=xi mod 4

image-20241030222033408

image-20241030222221226

description


参数

Parameters & Functions

  • K : Cipher key

  • Nb : Number of columns (32-bit words) comprising the State. For AES, Nb = 4

  • Nk : Number of 32-bit words comprising the Cipher Key. For AES, Nk = 4, 6, 8

  • Nr : Number of rounds Nr = 10, 12, 14

  • Block length : 128

    Block : Sequence of binary bits that comprise the input, output, State and Round Key. The length of a sequence is the number of bits it contains. Blocks are also interpreted as arrays of bytes.

  • Key length : 128, 192, 256 bits

  • Nr : Nr = 10 if key length is 128 bits, Nr = 12 if key length is 192 bits, Nr = 14 if key length is 256 bits.


流程:

  1. Initialize State to be plaintext x , then perform ADD-ROUNDKEY (x-ors the RoundKey with State)
  2. For each of the first Nr1 rounds:
    1. Perform a substitution operation : SUB-BYTES on State using a S-box.
    2. Perform a permutation SHIF-TROWS on State
    3. Perform a permutation MIX-COLUMNS on State
    4. Perform ADD-ROUNDKEY
  3. Perform SUB-TYPES, SHIFT-ROWS, ADD-ROUNDKEY
  4. Define the ciphertext y to be State



State(s 数组)

image-20241030155309684

The State consists of four rows of bytes, each containing Nb bytes, where Nb is the block length divided by 32.

In the State array denoted by the symbol s, each individual byte has two indices(索引), with its row number r : 0r4, and its column number c : 0cNb

Hence, at the beginning of the Cipher or Inverse Cipher, the input array, in , is copied to the State array according to the scheme:

s[r][c]=in[r+4c],

out[r+4c]=s[r][c],for 0r3,0cNb1

The four bytes in each column of the State array form 32-bit words, where the row number r provides an index for the four bytes within each word. The state can hence be interpreted as a one-dimensional array of 32 bit words: w0,w1,w2,w3

w0=s0,0,s1,0,s2,0,s3,0

w1=s0,1,s1,1,s2,1,s3,1

w2=s0,2,s1,2,s2,2,s3,2

w3=s0,3,s1,3,s2,3,s3,3



Key Expansion

The Key Expansion generates a total of Nb(Nr+1) words( Require an initial set of Nb words).

The resulting key schedule consists of a linear array of 4-byte words, denoted [wi] , with i in range 0iNb(Nr+1)

KeyExpansion(byte key[4*Nk], word x[Nb*(Nr+1)], Nk)
begin 
	word temp
	i = 0
	
	while(i < Nk)
		w[i] = word(key[4*i], key[4*i+1], key[4*i+2], key[4*i+3])
		i = i+1
	end while
	
	while(i < Nb * (Nr + 1))
		temp = w[i-1]
		if (i mod Nk == 0)
			temp = SubWord(RotWord(temp)) xor Rcon[i/Nk]
		else if (Nk > 6 and i mod Nk = 4)
			temp = SubWord(temp)
		end if
		w[i] = w[i-Nk] xor temp
		i = i + 1
	end while
end
  • The first Nk words of the expanded key are filled with the Cipher Key
  • Following word : w[i]
    • If : i0modNk , SubWord(RotWord(w[i1]))Rcon[i/Nk]
    • else : w[i]=w[i1]w[iNk]



ROTWORD

ROTWORD(B0,B1,B2,B3) , performs a cyclic shift of the four bytes : ROTWORD(B0,B1,B2,B3)=(B1,B2,B3,B0)


SUBWORD

Apply the S-box to each of the four bytes : SUBWORD(B0,B1,B2,B3)=(B0,B1,B2,B3)

where Bi=SUBBYTES(Bi)


RCon

an array of 10 words. Constants given by [xi1,00,00,00] , (xi1 is the powers of x , x is denoted as {02} in the field GF(28))

RCon[1]01000000

RCon[2]02000000

RCon[3]04000000

RCon[4]08000000

RCon[5]10000000

RCon[6]20000000

RCon[7]40000000

RCon[8]80000000

RCon[9]1B000000

RCon[10]36000000



代码实现

u8** KeyExpansion(u8* k) {

    // Round Constant
    u8** RCon = CalRoundConstant();
    u8** w = (u8**)malloc(sizeof(u8*) * Nb * (Nr + 1));
    for(int i = 0; i < 4; i++) {
        w[i] = (u8*)malloc(sizeof(u8) * 4);
    }

    int i = 0;
    u8* tmp;

    // w[i] = word(key[4*i], key[4*i+1], key[4*i+2], key[4*i+3]), i < Nk
    for(; i < Nk; i++) {
        for(int j = 0; j < 4; j++) {
            w[i][j] = k[i + 4 * j];
        }
    }

    while(i < Nb * (Nr + 1)) {
        tmp = Byte2Word(w, i - 1);
        if(!(i % Nk)) {
            // temp = SubWord(RotWord(temp)) xor Rcon[i/Nk]
            RotWord(tmp);
            SubWord(tmp);
            for(int j = 0; j < 4; j++) {
                tmp[j] = GFAdd(tmp[j], RCon[j][i/Nk]) ;
            }
        } else if ((Nk > 6) && (i % Nk == 4)){
            SubWord(tmp);
        }

        // w[i] = w[i-Nk] xor temp
        for(int j = 0; j < 4 ; j++) {
            w[j][i] = w[j][i - Nk] ^ tmp[j];
        }
        i++;
    }
    return w;
}



cipher


流程分析

image-20241103093812442

Cipher(byte in[4*Nb], type out[4*Nb], word w[Nb*(Nr + 1)]) // w[] contains the key schedule
begin
	byte state[4][Nb]
	
	state = in
	
	AddRoundKey(state, w[0, Nb - 1])
	
	for round = 1 step 1 to Nr - 1
        SubBytes(state) // substitute bytes
        ShiftRows(state)
        MixColumns(state)
        AddRoundKey(state, w[round*Nb, (round+1)*Nb - 1])
	end for
	
	SubBytes(state)
	ShiftRows(state)
	AddRoundKey(state, w[Nr*Nb, (Nr+1)*Nb-1])
	
	out = state
end

SubBytes

Non-linear byte substitution that operates independently on each byte of the State using a substitution table(S-box) , which is a permutation of {0,1}8

In contrast to the S-boxes in DES, which are apparently "random" substitutions, the AES S-box can be defined algebraically.


πS操作:

the permutation πS incorporates operations in the finite field : F28=Z2[x]/(x8+x4+x3+x+1)(主要是求逆元操作 : a(x)b(x)1modm(x))

  1. Take the multiplicative inverse in the finite field GF(28)( 把字节看做有限域 28 上的元素)

  2. Affine transformation(over GF(2)): bi=bib(i+4)mod 8b(i+5)mod 8b(i+6)mod 8b(i+7)mod 8ci

image-20241031093559358



伪代码:

SUBTYPES(a7a6a5a4a3a2a1a0)

external FIELDINV, BINARYTOFIELD, FIELDTOBINARY

zBINARYTOFIELD(a7a6a5a4a3a2a1a0)

if z0

​ then zFIELDINV(z)

(a7a6a5a4a3a2a1a0)FIELDTOBINARY(z)

(c7c6c5c4c3c2c1c0)(01100011)

/// All subscripts are to be reduced modulo 8 in the following loop

for i0 to 7 :

​ DO bi(ai+ai+4+ai+5+ai+7+ci) mod 2

return (b7b6b5b4b3b2b1b0)


由于对每个已知输入,经过 S 盒的输出都是固定的,可以直接将 S 盒写成替代表的形式来减少计算开销。

image-20241030180130227

代码实现
void SubBytes(u8** a) {
    for(int j = 0; j < Nb; j++) {
        for(int i = 0; i < 4; i++) {
            a[i][j] = s_box[a[i][j] >> 4][a[i][j] & 0x0f];
        }
    }
}

ShiftRows()

Sr,c=Sr,(c+shift(r,Nb)) mod Nb, 0<r<4 and 0c<Nb

shift(1,4)=1;shift(2,4)=2.;shift(3,4)=3

image-20241031094504365

代码实现
void ShiftRows(u8** a) {
    u8* tmp = (u8*)malloc(sizeof(u8)* Nb);

    for(int i = 1; i < 4; i++) {
        for(int j = 0; j < Nb; j++) {
            tmp[j] = a[i][j];
        }
        for(int j = 0; j < Nb; j++) {
            a[i][j] = tmp[(j + i) % Nb];
        }
    }

    free(tmp);
}



MixColumns()

MixColumns operates in the State column-by-column, treating each column as a four-term polynomial over GF(28) and multiplied modulo x4+1 with a fixed polynomial a(x)={03}x3+{01}x2+{01}x+{02}

image-20241031095209819

image-20241031095259727

image-20241031095417297

乘法操作可以通过 x 乘实现

代码实现:
void MixColumns(u8** a) {
    u8 tmp[4];
    for(int j = 0; j < Nb; j++) {
        tmp[0] = a[0][j];
        tmp[1] = a[1][j];
        tmp[2] = a[2][j];
        tmp[3] = a[3][j];
        a[0][j] = xtime(tmp[0]) ^ xtime(tmp[1]) ^ tmp[1] ^ tmp[2] ^ tmp[3];
        a[1][j] = tmp[0] ^ xtime(tmp[1]) ^ xtime(tmp[2]) ^ tmp[2] ^ tmp[3];
        a[2][j] = tmp[0] ^ tmp[1] ^ xtime(tmp[2]) ^ xtime(tmp[3]) ^ tmp[3];
        a[3][j] = xtime(tmp[0]) ^ tmp[0] ^ tmp[1] ^ tmp[2] ^ xtime(tmp[3]);
    }
}



AddRoundKey()

image-20241101200202948

[s0,c,s1,c,s2,c,s3,c]=[s0,c,s1,c,s2,c,s3,c][wroundNb,c]

image-20241102153519636
代码实现
u8* AddRoundKey(u8** state, u8** w, int round) {
    for(int j = 0; j < Nb; j++){
        for(int i = 0; i < 4; i++) {
            state[i][j] = GFAdd(state[i][j], w[i][round * 4 + j]) ;
        }
    }
}

解密


直接反向解密

image-20241103153514987

  • Inv_ShiftRows: 反向右移

  • Inv_S-box : S 先逆仿射变换再求逆

  • Inv_MixColumns : 乘以矩阵的乘法逆元

    image-20241103170747937
  • AddRoundKey : 逆变换即为自身

Pseudo Code

InvCipher(byte in[4*Nb], byte out[4*Nb], word w[Nb*(Nr+1)])
begin
	byte state[4,Nb]
	
	state = in
	
	AddRoundKey(state, w[Nr*Nb, (Nr+1)*Nb-1])
	
	for round = Nr-1 setp -1 to 1
		InvShiftRows(state)
		InvSubBytes(state)
		AddRoundKey(state, w[round*Nb, (round+1)*Nb-1])
		InvMixColumns(state)
	end for
	
	InvShiftRows(state)
	InvSubBytes(state)
	AddRoundKey(state, w[0, Nb-1])
	
	out = state
end



完整代码:

#include<stdio.h>
#include<stdlib.h>
#include<stdint.h>
#include<string.h>
#define u8 uint8_t
#define u32 uint32_t

const int Nb = 4; // 分组字块数
int Nr;
int Nk;

static u8 s_box[16][16] = {
	// 0     1     2     3     4     5     6     7     8     9     a     b     c     d     e     f
	{0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76}, // 0
	{0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0}, // 1
	{0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15}, // 2
	{0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75}, // 3
	{0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84}, // 4
	{0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf}, // 5
	{0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8}, // 6
	{0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2}, // 7
	{0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73}, // 8
	{0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb}, // 9
	{0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79}, // a
	{0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08}, // b
	{0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a}, // c
	{0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e}, // d
	{0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf}, // e
	{0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16}};// f

static u8 inv_s_box[16][16] = {
	// 0     1     2     3     4     5     6     7     8     9     a     b     c     d     e     f
	{0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb},	 // 0
	{0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb},	 // 1
	{0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e},	 // 2
	{0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25},	 // 3
	{0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92},	 // 4
	{0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84},	 // 5
	{0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06},	 // 6
	{0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b},	 // 7
	{0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73},	 // 8
	{0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e},	 // 9
	{0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b},	 // a
	{0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4},	 // b
	{0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f},	 // c
	{0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef},	 // d
	{0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61},	 // e
	{0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d}}; // f

u8 GFAdd(u8 a, u8 b) {
    return a ^ b;
}

u8 GFSub(u8 a, u8 b) {
    return a ^ b;
}

u8 xtime(u8 a) {
    u8 msb = a & 0x80;
    a = a << 1;
    if(msb) {   
        return GFSub(a, 0x1b);
    } else {
        return a;
    }
} 

u8 GFMul(u8 a, u8 b) {
    u8 ans = 0;

    while(b) {
        if(b & 0x1) {
            ans = GFAdd(ans, a);
        }
        a = xtime(a);
        b = b >> 1;
    }
    return ans;
}


void RotWord(u8* a) {
    u8 tmp = a[0];
    a[0] = a[1];
    a[1] = a[2];
    a[2] = a[3];
    a[3] = tmp;
}

u8* Byte2Word(u8**a, int i) {
    u8* b = (u8*)malloc(sizeof(u8) * 4);
    b[0] = a[0][i];
    b[1] = a[1][i];
    b[2] = a[2][i];
    b[3] = a[3][i];
    return b;
}

void test_array(const char* str, u8** arr, int size) {
    printf("%s: ", str);
    for(int j = 0; j < size; j++) {
        for(int i = 0; i < 4; i++) {
            printf("%02x", arr[i][j]);
        }
        printf(" ");
    }
    printf("\n");
}



u8** CalRoundConstant() {
    u8** RCon = (u8**)malloc(sizeof(u8*)* 11);
    for(int i = 0; i < 11; i++) {
        RCon[i] = (u8*)malloc(sizeof(u8)*4);
    }
    for(int i = 1; i < 4; i++) {
        for(int j = 0; j < 11; j++) {
            RCon[i][j] = 0;
        }
    }
    RCon[0][1] = 0x01; 

    for(int i = 2; i <= 10; i++) {
        RCon[0][i] = xtime(RCon[0][i - 1]);
    }
    // test_array("RCon", RCon, 11);
    return RCon;
}

void ShiftRows(u8** a) {
    u8* tmp = (u8*)malloc(sizeof(u8)* Nb);

    for(int i = 1; i < 4; i++) {
        for(int j = 0; j < Nb; j++) {
            tmp[j] = a[i][j];
        }
        for(int j = 0; j < Nb; j++) {
            a[i][j] = tmp[(j + i) % Nb];
        }
    }

    free(tmp);
}

void InvShiftRows(u8** a) {
    u8* tmp = (u8*)malloc(sizeof(u8)* Nb);

    for(int i = 1; i < 4; i++) {
        for(int j = 0; j < Nb; j++) {
            tmp[j] = a[i][j];
        }
        for(int j = 0; j < Nb; j++) {
            a[i][j] = tmp[(j - i + Nb) % Nb];
        }
    }

    free(tmp);
}


void MixColumns(u8** a) {
    u8 tmp[4];
    for(int j = 0; j < Nb; j++) {
        tmp[0] = a[0][j];
        tmp[1] = a[1][j];
        tmp[2] = a[2][j];
        tmp[3] = a[3][j];
        a[0][j] = GFMul(tmp[0], 0x02) ^ GFMul(tmp[1], 0x03) ^ GFMul(tmp[2], 0x01) ^GFMul(tmp[3], 0x01);
        a[1][j] = GFMul(tmp[0], 0x01) ^ GFMul(tmp[1], 0x02) ^ GFMul(tmp[2], 0x03) ^GFMul(tmp[3], 0x01);
        a[2][j] = GFMul(tmp[0], 0x01) ^ GFMul(tmp[1], 0x01) ^ GFMul(tmp[2], 0x02) ^GFMul(tmp[3], 0x03);
        a[3][j] = GFMul(tmp[0], 0x03) ^ GFMul(tmp[1], 0x01) ^ GFMul(tmp[2], 0x01) ^GFMul(tmp[3], 0x02);
    }
}

void InvMixColumns(u8** a) {
    u8 tmp[4];
    for(int j = 0; j < Nb; j++) {
        tmp[0] = a[0][j];
        tmp[1] = a[1][j];
        tmp[2] = a[2][j];
        tmp[3] = a[3][j];
        a[0][j] = GFMul(tmp[0], 0x0e) ^ GFMul(tmp[1], 0x0b) ^ GFMul(tmp[2], 0x0d) ^GFMul(tmp[3], 0x09);
        a[1][j] = GFMul(tmp[0], 0x09) ^ GFMul(tmp[1], 0x0e) ^ GFMul(tmp[2], 0x0b) ^GFMul(tmp[3], 0x0d);
        a[2][j] = GFMul(tmp[0], 0x0d) ^ GFMul(tmp[1], 0x09) ^ GFMul(tmp[2], 0x0e) ^GFMul(tmp[3], 0x0b);
        a[3][j] = GFMul(tmp[0], 0x0b) ^ GFMul(tmp[1], 0x0d) ^ GFMul(tmp[2], 0x09) ^GFMul(tmp[3], 0x0e);
    }
}

u8* AddRoundKey(u8** state, u8** w, int round) {
    for(int j = 0; j < Nb; j++){
        for(int i = 0; i < 4; i++) {
            state[i][j] = GFAdd(state[i][j], w[i][round * 4 + j]) ;
        }
    }
}



void SubBytes(u8** a) {
    for(int j = 0; j < Nb; j++) {
        for(int i = 0; i < 4; i++) {
            a[i][j] = s_box[a[i][j] >> 4][a[i][j] & 0x0f];
        }
    }
}

void InvSubBytes(u8** a) {
    for(int j = 0; j < Nb; j++) {
        for(int i = 0; i < 4; i++) {
            a[i][j] = inv_s_box[a[i][j] >> 4][a[i][j] & 0x0f];
        }
    }
}


void SubWord(u8* a) {
    for(int i = 0; i < 4; i++) {
        a[i] = s_box[a[i] >> 4][a[i] & 0x0f];
    }
}




u8** KeyExpansion(u8* k) {

    // Round Constant
    u8** RCon = CalRoundConstant();
    u8** w = (u8**)malloc(sizeof(u8*) * Nb * (Nr + 1));
    for(int i = 0; i < 4; i++) {
        w[i] = (u8*)malloc(sizeof(u8) * 4);
    }

    int j = 0;
    u8* tmp;

    // w[i] = word(key[4*i], key[4*i+1], key[4*i+2], key[4*i+3]), i < Nk
    for(; j < Nk; j++) {
        for(int i = 0; i < 4; i++) {
            w[i][j] = k[i + 4 * j];
        }
    }

    while(j < Nb * (Nr + 1)) {
        tmp = Byte2Word(w, j - 1);
        if(!(j % Nk)) {
            // temp = SubWord(RotWord(temp)) xor Rcon[i/Nk]
            RotWord(tmp);
            SubWord(tmp);
            for(int i = 0; i < 4; i++) {
                tmp[i] = GFAdd(tmp[i], RCon[i][j/Nk]) ;
            }
        } else if ((Nk > 6) && (j % Nk == 4)){
            SubWord(tmp);
        }

        // w[i] = w[i-Nk] xor temp
        for(int i = 0; i < 4 ; i++) {
            w[i][j] = w[i][j - Nk] ^ tmp[i];
        }
        j++;
    }
    return w;
}


u8** init(int key_size, u8* k, u8** state, u8* in) {
    switch (key_size) { // 128/192/256bits
        case 16: Nk = 4; Nr = 10; break;
        case 24: Nk = 6; Nr = 12; break;
        case 32: Nk = 8; Nr = 14; break;
    }
    u8** w = KeyExpansion(k);

    for(int j = 0; j < Nb; j++) {
        for(int i = 0; i < 4; i++) {
            state[i][j] = in[i + 4 * j];
        }
    }
    return w;
}

void AesEncrypt(int key_size, u8* k, u8* in, u8*out) {

    u8** state = (u8**)malloc(sizeof(u8*) * Nb);
    for(int i = 0; i < 4; i++) {
        state[i] = (u8*)malloc(sizeof(u8) * 4);
    }

    u8** w = init(key_size, k, state, in);
    
    AddRoundKey(state, w, 0);
    for(int round = 1; round < Nr; round++) {
        SubBytes(state); 
        ShiftRows(state); 
        MixColumns(state); 
        AddRoundKey(state, w, round); 
    }

    // last round
    SubBytes(state);
    ShiftRows(state);
    AddRoundKey(state, w, Nr);

    for(int j = 0; j < Nb; j++) {
        for(int i = 0; i < 4; i++) {
            out[i + 4 * j] = state[i][j];
        }
    }
    free(w);
    free(state);
}





u8* AesDecrypt(int key_size, u8* k, u8* in, u8*out) {
    /*in: encrypt_text, out : decrypt_text*/

    u8** state = (u8**)malloc(sizeof(u8*) * Nb);
    for(int i = 0; i < 4; i++) {
        state[i] = (u8*)malloc(sizeof(u8) * 4);
    }
    u8** w = init(key_size, k, state, in); // w stores the expanded key
    AddRoundKey(state, w, Nr);
    for(int round = Nr - 1; round > 0; round--) {
        InvShiftRows(state);
        InvSubBytes(state);
        AddRoundKey(state, w, round);
        InvMixColumns(state);
    }

    InvShiftRows(state);
    InvSubBytes(state);
    AddRoundKey(state, w, 0);

    for(int j = 0; j < Nb; j++) {
        for(int i = 0; i < 4; i++) {
            out[i + 4 * j] = state[i][j];
        }
    }
    free(w);
    free(state);
}

void display(u8* a) {
    for(int i = 0; i < Nb * 4; i++)
    printf("%02x", a[i]);
    printf("\n");
}

int main() {
    u8* encrypt_text = (u8*)malloc(sizeof(u8) * (4 * Nb));
    u8* decrypt_text = (u8*)malloc(sizeof(u8) * (4 * Nb));
    unsigned char plain_text[16] = "zzzzyyyyxxxxwwww";

    unsigned char key_16[16] = "abcdefghijklmnop";
    unsigned char key_24[24] = "abcdefghijklmnopqrstuvwx";
    unsigned char key_32[32] = "abcdefghijklmnopqrstuvwxyyyyzzzz";

    // keysize = 128 bits
    AesEncrypt(16, key_16, plain_text, encrypt_text);
    display(encrypt_text);

    AesDecrypt(16, key_16, encrypt_text, decrypt_text);
    display(decrypt_text);


    // keysize = 192 bits
    AesEncrypt(24, key_24, plain_text, encrypt_text);
    display(encrypt_text);

    AesDecrypt(24, key_24, encrypt_text, decrypt_text);
    display(decrypt_text);

    //keysize = 256 bits
    AesEncrypt(32, key_32, plain_text, encrypt_text);
    display(encrypt_text);

    AesDecrypt(32, key_32, encrypt_text, decrypt_text);
    display(decrypt_text);
    
}

本文作者:chchee

本文链接:https://www.cnblogs.com/chchee-blog/p/18528788

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   chchee  阅读(23)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起