/**

GALOIS BLOCK CIPHER (GBC) (Version 1)

SUBKEY GENERATION

Requires 33 subkeys: 2 per round (16 rounds) and 1 for final XOR

1. Initialize subkeys to the hex digits of PI

2. XOR first subkey with encryption key

3. Encrypt block containing all 0 bits

4. Replace the first subkey with the output

5. Encrypt the output

6. Replace the 2nd subkey with the output

7. Continue this for the rest of the subkeys

Notation:

SK_i = Subkey(i)

* = Multiplication in GF(2^128)

A^-1 = Multiplicative inverse in GF(2^128)

^ = XOR / GF(2^128) addition

S = Cipher state

ENCRYPTION

S = Plaintext

for i = 0 to 29, step 2

S = S ^ SK_i

S = SBOX(S)

S = S * SK_(i+1)

S = PBOX(S)

S = S ^ SK_30

S = SBOX(S)

S = S * SK_31

S = S ^ SK_32

Ciphertext = S

DECRYPTION

S = Ciphertext

S = S ^ SK_32

S = S * (SK_31)^-1

S = INV_SBOX(S)

S = S ^ SK_30

for i = 29 to 0, step -2

S = INV_PBOX(S)

S = S * (SK_i)^-1

S = INV_SBOX(S)

S = S ^ SK_(i-1)

Plaintext = S

Notes:

1. Uses Rijndael S-boxes

2. P-box was randomly generated using some heuristics. Can probably be improved.

3. Decryption performance can be improved by computing the multiplivative inverse of subkeys 1,3,7..31

during subkey generation instead of during the round function.

*/

#include<string.h> //For memset

#include"gbc.h"

/**

*Rijndael S-box

*/

static const unsigned char SBOX [ 256 ] = {

0x63 , 0x7C , 0x77 , 0x7B , 0xF2 , 0x6B , 0x6F , 0xC5 , 0x30 , 0x01 , 0x67 , 0x2B , 0xFE , 0xD7 , 0xAB , 0x76 ,

0xCA , 0x82 , 0xC9 , 0x7D , 0xFA , 0x59 , 0x47 , 0xF0 , 0xAD , 0xD4 , 0xA2 , 0xAF , 0x9C , 0xA4 , 0x72 , 0xC0 ,

0xB7 , 0xFD , 0x93 , 0x26 , 0x36 , 0x3F , 0xF7 , 0xCC , 0x34 , 0xA5 , 0xE5 , 0xF1 , 0x71 , 0xD8 , 0x31 , 0x15 ,

0x04 , 0xC7 , 0x23 , 0xC3 , 0x18 , 0x96 , 0x05 , 0x9A , 0x07 , 0x12 , 0x80 , 0xE2 , 0xEB , 0x27 , 0xB2 , 0x75 ,

0x09 , 0x83 , 0x2C , 0x1A , 0x1B , 0x6E , 0x5A , 0xA0 , 0x52 , 0x3B , 0xD6 , 0xB3 , 0x29 , 0xE3 , 0x2F , 0x84 ,

0x53 , 0xD1 , 0x00 , 0xED , 0x20 , 0xFC , 0xB1 , 0x5B , 0x6A , 0xCB , 0xBE , 0x39 , 0x4A , 0x4C , 0x58 , 0xCF ,

0xD0 , 0xEF , 0xAA , 0xFB , 0x43 , 0x4D , 0x33 , 0x85 , 0x45 , 0xF9 , 0x02 , 0x7F , 0x50 , 0x3C , 0x9F , 0xA8 ,

0x51 , 0xA3 , 0x40 , 0x8F , 0x92 , 0x9D , 0x38 , 0xF5 , 0xBC , 0xB6 , 0xDA , 0x21 , 0x10 , 0xFF , 0xF3 , 0xD2 ,

0xCD , 0x0C , 0x13 , 0xEC , 0x5F , 0x97 , 0x44 , 0x17 , 0xC4 , 0xA7 , 0x7E , 0x3D , 0x64 , 0x5D , 0x19 , 0x73 ,

0x60 , 0x81 , 0x4F , 0xDC , 0x22 , 0x2A , 0x90 , 0x88 , 0x46 , 0xEE , 0xB8 , 0x14 , 0xDE , 0x5E , 0x0B , 0xDB ,

0xE0 , 0x32 , 0x3A , 0x0A , 0x49 , 0x06 , 0x24 , 0x5C , 0xC2 , 0xD3 , 0xAC , 0x62 , 0x91 , 0x95 , 0xE4 , 0x79 ,

0xE7 , 0xC8 , 0x37 , 0x6D , 0x8D , 0xD5 , 0x4E , 0xA9 , 0x6C , 0x56 , 0xF4 , 0xEA , 0x65 , 0x7A , 0xAE , 0x08 ,

0xBA , 0x78 , 0x25 , 0x2E , 0x1C , 0xA6 , 0xB4 , 0xC6 , 0xE8 , 0xDD , 0x74 , 0x1F , 0x4B , 0xBD , 0x8B , 0x8A ,

0x70 , 0x3E , 0xB5 , 0x66 , 0x48 , 0x03 , 0xF6 , 0x0E , 0x61 , 0x35 , 0x57 , 0xB9 , 0x86 , 0xC1 , 0x1D , 0x9E ,

0xE1 , 0xF8 , 0x98 , 0x11 , 0x69 , 0xD9 , 0x8E , 0x94 , 0x9B , 0x1E , 0x87 , 0xE9 , 0xCE , 0x55 , 0x28 , 0xDF ,

0x8C , 0xA1 , 0x89 , 0x0D , 0xBF , 0xE6 , 0x42 , 0x68 , 0x41 , 0x99 , 0x2D , 0x0F , 0xB0 , 0x54 , 0xBB , 0x16

} ;

/**

*Inverse Rijandael S-box

*/

static const unsigned char INV_SBOX [ 256 ] = {

0x52 , 0x09 , 0x6A , 0xD5 , 0x30 , 0x36 , 0xA5 , 0x38 , 0xBF , 0x40 , 0xA3 , 0x9E , 0x81 , 0xF3 , 0xD7 , 0xFB ,

0x7C , 0xE3 , 0x39 , 0x82 , 0x9B , 0x2F , 0xFF , 0x87 , 0x34 , 0x8E , 0x43 , 0x44 , 0xC4 , 0xDE , 0xE9 , 0xCB ,

0x54 , 0x7B , 0x94 , 0x32 , 0xA6 , 0xC2 , 0x23 , 0x3D , 0xEE , 0x4C , 0x95 , 0x0B , 0x42 , 0xFA , 0xC3 , 0x4E ,

0x08 , 0x2E , 0xA1 , 0x66 , 0x28 , 0xD9 , 0x24 , 0xB2 , 0x76 , 0x5B , 0xA2 , 0x49 , 0x6D , 0x8B , 0xD1 , 0x25 ,

0x72 , 0xF8 , 0xF6 , 0x64 , 0x86 , 0x68 , 0x98 , 0x16 , 0xD4 , 0xA4 , 0x5C , 0xCC , 0x5D , 0x65 , 0xB6 , 0x92 ,

0x6C , 0x70 , 0x48 , 0x50 , 0xFD , 0xED , 0xB9 , 0xDA , 0x5E , 0x15 , 0x46 , 0x57 , 0xA7 , 0x8D , 0x9D , 0x84 ,

0x90 , 0xD8 , 0xAB , 0x00 , 0x8C , 0xBC , 0xD3 , 0x0A , 0xF7 , 0xE4 , 0x58 , 0x05 , 0xB8 , 0xB3 , 0x45 , 0x06 ,

0xD0 , 0x2C , 0x1E , 0x8F , 0xCA , 0x3F , 0x0F , 0x02 , 0xC1 , 0xAF , 0xBD , 0x03 , 0x01 , 0x13 , 0x8A , 0x6B ,

0x3A , 0x91 , 0x11 , 0x41 , 0x4F , 0x67 , 0xDC , 0xEA , 0x97 , 0xF2 , 0xCF , 0xCE , 0xF0 , 0xB4 , 0xE6 , 0x73 ,

0x96 , 0xAC , 0x74 , 0x22 , 0xE7 , 0xAD , 0x35 , 0x85 , 0xE2 , 0xF9 , 0x37 , 0xE8 , 0x1C , 0x75 , 0xDF , 0x6E ,

0x47 , 0xF1 , 0x1A , 0x71 , 0x1D , 0x29 , 0xC5 , 0x89 , 0x6F , 0xB7 , 0x62 , 0x0E , 0xAA , 0x18 , 0xBE , 0x1B ,

0xFC , 0x56 , 0x3E , 0x4B , 0xC6 , 0xD2 , 0x79 , 0x20 , 0x9A , 0xDB , 0xC0 , 0xFE , 0x78 , 0xCD , 0x5A , 0xF4 ,

0x1F , 0xDD , 0xA8 , 0x33 , 0x88 , 0x07 , 0xC7 , 0x31 , 0xB1 , 0x12 , 0x10 , 0x59 , 0x27 , 0x80 , 0xEC , 0x5F ,

0x60 , 0x51 , 0x7F , 0xA9 , 0x19 , 0xB5 , 0x4A , 0x0D , 0x2D , 0xE5 , 0x7A , 0x9F , 0x93 , 0xC9 , 0x9C , 0xEF ,

0xA0 , 0xE0 , 0x3B , 0x4D , 0xAE , 0x2A , 0xF5 , 0xB0 , 0xC8 , 0xEB , 0xBB , 0x3C , 0x83 , 0x53 , 0x99 , 0x61 ,

0x17 , 0x2B , 0x04 , 0x7E , 0xBA , 0x77 , 0xD6 , 0x26 , 0xE1 , 0x69 , 0x14 , 0x63 , 0x55 , 0x21 , 0x0C , 0x7D

} ;

/**

* Hex digits of PI

*/

static const unsigned char SUBKEYS [ 33 ] [ 16 ] = {

{ 0x24 , 0x3f , 0x6a , 0x88 , 0x85 , 0xa3 , 0x08 , 0xd3 , 0x13 , 0x19 , 0x8a , 0x2e , 0x03 , 0x70 , 0x73 , 0x44 } ,

{ 0xa4 , 0x09 , 0x38 , 0x22 , 0x29 , 0x9f , 0x31 , 0xd0 , 0x08 , 0x2e , 0xfa , 0x98 , 0xec , 0x4e , 0x6c , 0x89 } ,

{ 0x45 , 0x28 , 0x21 , 0xe6 , 0x38 , 0xd0 , 0x13 , 0x77 , 0xbe , 0x54 , 0x66 , 0xcf , 0x34 , 0xe9 , 0x0c , 0x6c } ,

{ 0xc0 , 0xac , 0x29 , 0xb7 , 0xc9 , 0x7c , 0x50 , 0xdd , 0x3f , 0x84 , 0xd5 , 0xb5 , 0xb5 , 0x47 , 0x09 , 0x17 } ,

{ 0x92 , 0x16 , 0xd5 , 0xd9 , 0x89 , 0x79 , 0xfb , 0x1b , 0xd1 , 0x31 , 0x0b , 0xa6 , 0x98 , 0xdf , 0xb5 , 0xac } ,

{ 0x2f , 0xfd , 0x72 , 0xdb , 0xd0 , 0x1a , 0xdf , 0xb7 , 0xb8 , 0xe1 , 0xaf , 0xed , 0x6a , 0x26 , 0x7e , 0x96 } ,

{ 0xba , 0x7c , 0x90 , 0x45 , 0xf1 , 0x2c , 0x7f , 0x99 , 0x24 , 0xa1 , 0x99 , 0x47 , 0xb3 , 0x91 , 0x6c , 0xf7 } ,

{ 0x08 , 0x01 , 0xf2 , 0xe2 , 0x85 , 0x8e , 0xfc , 0x16 , 0x63 , 0x69 , 0x20 , 0xd8 , 0x71 , 0x57 , 0x4e , 0x69 } ,

{ 0xa4 , 0x58 , 0xfe , 0xa3 , 0xf4 , 0x93 , 0x3d , 0x7e , 0x0d , 0x95 , 0x74 , 0x8f , 0x72 , 0x8e , 0xb6 , 0x58 } ,

{ 0x71 , 0x8b , 0xcd , 0x58 , 0x82 , 0x15 , 0x4a , 0xee , 0x7b , 0x54 , 0xa4 , 0x1d , 0xc2 , 0x5a , 0x59 , 0xb5 } ,

{ 0x9c , 0x30 , 0xd5 , 0x39 , 0x2a , 0xf2 , 0x60 , 0x13 , 0xc5 , 0xd1 , 0xb0 , 0x23 , 0x28 , 0x60 , 0x85 , 0xf0 } ,

{ 0xca , 0x41 , 0x79 , 0x18 , 0xb8 , 0xdb , 0x38 , 0xef , 0x8e , 0x79 , 0xdc , 0xb0 , 0x60 , 0x3a , 0x18 , 0x0e } ,

{ 0x6c , 0x9e , 0x0e , 0x8b , 0xb0 , 0x1e , 0x8a , 0x3e , 0xd7 , 0x15 , 0x77 , 0xc1 , 0xbd , 0x31 , 0x4b , 0x27 } ,

{ 0x78 , 0xaf , 0x2f , 0xda , 0x55 , 0x60 , 0x5c , 0x60 , 0xe6 , 0x55 , 0x25 , 0xf3 , 0xaa , 0x55 , 0xab , 0x94 } ,

{ 0x57 , 0x48 , 0x98 , 0x62 , 0x63 , 0xe8 , 0x14 , 0x40 , 0x55 , 0xca , 0x39 , 0x6a , 0x2a , 0xab , 0x10 , 0xb6 } ,

{ 0xb4 , 0xcc , 0x5c , 0x34 , 0x11 , 0x41 , 0xe8 , 0xce , 0xa1 , 0x54 , 0x86 , 0xaf , 0x7c , 0x72 , 0xe9 , 0x93 } ,

{ 0xb3 , 0xee , 0x14 , 0x11 , 0x63 , 0x6f , 0xbc , 0x2a , 0x2b , 0xa9 , 0xc5 , 0x5d , 0x74 , 0x18 , 0x31 , 0xf6 } ,

{ 0xce , 0x5c , 0x3e , 0x16 , 0x9b , 0x87 , 0x93 , 0x1e , 0xaf , 0xd6 , 0xba , 0x33 , 0x6c , 0x24 , 0xcf , 0x5c } ,

{ 0x7a , 0x32 , 0x53 , 0x81 , 0x28 , 0x95 , 0x86 , 0x77 , 0x3b , 0x8f , 0x48 , 0x98 , 0x6b , 0x4b , 0xb9 , 0xaf } ,

{ 0xc4 , 0xbf , 0xe8 , 0x1b , 0x66 , 0x28 , 0x21 , 0x93 , 0x61 , 0xd8 , 0x09 , 0xcc , 0xfb , 0x21 , 0xa9 , 0x91 } ,

{ 0x48 , 0x7c , 0xac , 0x60 , 0x5d , 0xec , 0x80 , 0x32 , 0xef , 0x84 , 0x5d , 0x5d , 0xe9 , 0x85 , 0x75 , 0xb1 } ,

{ 0xdc , 0x26 , 0x23 , 0x02 , 0xeb , 0x65 , 0x1b , 0x88 , 0x23 , 0x89 , 0x3e , 0x81 , 0xd3 , 0x96 , 0xac , 0xc5 } ,

{ 0x0f , 0x6d , 0x6f , 0xf3 , 0x83 , 0xf4 , 0x42 , 0x39 , 0x2e , 0x0b , 0x44 , 0x82 , 0xa4 , 0x84 , 0x20 , 0x04 } ,

{ 0x69 , 0xc8 , 0xf0 , 0x4a , 0x9e , 0x1f , 0x9b , 0x5e , 0x21 , 0xc6 , 0x68 , 0x42 , 0xf6 , 0xe9 , 0x6c , 0x9a } ,

{ 0x67 , 0x0c , 0x9c , 0x61 , 0xab , 0xd3 , 0x88 , 0xf0 , 0x6a , 0x51 , 0xa0 , 0xd2 , 0xd8 , 0x54 , 0x2f , 0x68 } ,

{ 0x96 , 0x0f , 0xa7 , 0x28 , 0xab , 0x51 , 0x33 , 0xa3 , 0x6e , 0xef , 0x0b , 0x6c , 0x13 , 0x7a , 0x3b , 0xe4 } ,

{ 0xba , 0x3b , 0xf0 , 0x50 , 0x7e , 0xfb , 0x2a , 0x98 , 0xa1 , 0xf1 , 0x65 , 0x1d , 0x39 , 0xaf , 0x01 , 0x76 } ,

{ 0x66 , 0xca , 0x59 , 0x3e , 0x82 , 0x43 , 0x0e , 0x88 , 0x8c , 0xee , 0x86 , 0x19 , 0x45 , 0x6f , 0x9f , 0xb4 } ,

{ 0x7d , 0x84 , 0xa5 , 0xc3 , 0x3b , 0x8b , 0x5e , 0xbe , 0xe0 , 0x6f , 0x75 , 0xd8 , 0x85 , 0xc1 , 0x20 , 0x73 } ,

{ 0x40 , 0x1a , 0x44 , 0x9f , 0x56 , 0xc1 , 0x6a , 0xa6 , 0x4e , 0xd3 , 0xaa , 0x62 , 0x36 , 0x3f , 0x77 , 0x06 } ,

{ 0x1b , 0xfe , 0xdf , 0x72 , 0x42 , 0x9b , 0x02 , 0x3d , 0x37 , 0xd0 , 0xd7 , 0x24 , 0xd0 , 0x0a , 0x12 , 0x48 } ,

{ 0xdb , 0x0f , 0xea , 0xd3 , 0x49 , 0xf1 , 0xc0 , 0x9b , 0x07 , 0x53 , 0x72 , 0xc9 , 0x80 , 0x99 , 0x1b , 0x7b } ,

{ 0x25 , 0xd4 , 0x79 , 0xd8 , 0xf6 , 0xe8 , 0xde , 0xf7 , 0xe3 , 0xfe , 0x50 , 0x1a , 0xb6 , 0x79 , 0x4c , 0x3b }

} ;

/**

* P-box

*/

static const unsigned char PBOX [ 16 ] = {

12 , 8 , 5 , 1 , 14 , 11 , 2 , 4 , 9 , 15 , 6 , 3 , 7 , 10 , 13 , 0

} ;

/**

* 128-bit XOR / Addition in GF(2^128)

*/

static void gf128_add ( const unsigned char * a, const unsigned char * b, unsigned char * s )

{

for ( int i = 0 ; i < 16 ; i ++ ) {

s [ i ] = a [ i ] ^ b [ i ] ;

}

}

/**

* Shift 128-bit value left

*/

static void shift_left ( const unsigned char * x, unsigned char * s )

{

unsigned char c_in = 0 ;

unsigned char c_out = 0 ;

for ( int i = 15 ; i >= 0 ; i -- ) {

c_out = x [ i ] >> 7 ;

s [ i ] = x [ i ] << 1 ;

s [ i ] | = c_in ;

c_in = c_out ;

}

}

/**

* Shift 128-bit value right

*/

static void shift_right ( const unsigned char * x, unsigned char * s )

{

unsigned char c_in = 0 ;

unsigned char c_out = 0 ;

for ( int i = 0 ; i < 16 ; i ++ ) {

c_out = ( x [ i ] & 0x01 ) << 7 ;

s [ i ] = x [ i ] >> 1 ;

s [ i ] | = c_in ;

c_in = c_out ;

}

}

/**

* Multiplication in GF(2^128) mod x^128 + x^7 + x^2 + x + 1

* p = a * b

*/

static void gf128_mult ( const unsigned char * a, const unsigned char * b, unsigned char * p )

{

unsigned char x [ 16 ] ;

unsigned char y [ 16 ] ;

unsigned char z [ 16 ] ;

memset ( z, 0 , 16 ) ;

memcpy ( x, a, 16 ) ;

memcpy ( y, b, 16 ) ;

unsigned char bit_set = 0 ;

for ( int i = 0 ; i < 128 ; i ++ ) {

if ( y [ 15 ] & 0x01 ) {

gf128_add ( z, x, z ) ;

}

bit_set = x [ 0 ] & 0x80 ;

shift_left ( x, x ) ;

if ( bit_set ) {

x [ 15 ] ^ = 0x87 ;

}

shift_right ( y,y ) ;

}

memcpy ( p, z, 16 ) ;

}

/**

* Multiplicative inverse in GF(2^128) mod x^128 + x^7 + x^2 + x + 1

* p = a^-1

*/

static void gf128_imult ( const unsigned char * a, unsigned char * p )

{

unsigned char x [ 16 ] ;

unsigned char y [ 16 ] ;

memcpy ( x, a, 16 ) ;

memcpy ( y, a, 16 ) ;

// Compute a^ (2^n-1) using squaring method

for ( int i = 0 ; i < 127 ; i ++ ) {

gf128_mult ( x, x, x ) ;

}

// compute a^2

gf128_mult ( y, y, y ) ;

// Compute a^(2^n-1 -2) by computing

// a^(2^n-2 + 2^1 + 2^2 + 2^3 + 2^4..)

for ( int i = 1 ; i < 127 ; i ++ ) {

gf128_mult ( x, y, x ) ;

gf128_mult ( y, y, y ) ;

}

// copy result

memcpy ( p, x, 16 ) ;

}

/**

* P-BOX

*/

static void pbox ( unsigned char * x )

{

unsigned char tmp [ 16 ] ;

memcpy ( tmp, x, 16 ) ;

for ( int i = 0 ; i < 16 ; i ++ ) {

x [ i ] = tmp [ PBOX [ i ] ] ;

}

}

/**

* Inverse P-BOX

*/

static void inv_pbox ( unsigned char * x )

{

unsigned char tmp [ 16 ] ;

memcpy ( tmp, x, 16 ) ;

for ( int i = 0 ; i < 16 ; i ++ ) {

x [ PBOX [ i ] ] = tmp [ i ] ;

}

}

/**

* S-BOX

*/

static void sbox ( unsigned char * x )

{

for ( int i = 0 ; i < 16 ; i ++ ) {

x [ i ] = SBOX [ x [ i ] ] ;

}

}

/**

* Inverse S-BOX

*/

static void inv_sbox ( unsigned char * x )

{

for ( int i = 0 ; i < 16 ; i ++ ) {

x [ i ] = INV_SBOX [ x [ i ] ] ;

}

}

/**

* Generates encryption subkeys

*/

void gbc_gen_subkeys ( bool encrypt, const unsigned char * key, unsigned char subkeys [ ] [ 16 ] )

{

unsigned char s [ 16 ] = { 0 } ;

for ( int i = 0 ; i < 33 ; i ++ ) {

memcpy ( subkeys [ i ] , SUBKEYS [ i ] , 16 ) ;

}

// XOR first subkey with key

for ( int i = 0 ; i < 16 ; i ++ ) {

subkeys [ 0 ] [ i ] ^ = key [ i ] ;

}

// Encrypt empty string.

// Replace first subkey with ciphertext.

// Encrypt again. Replace 2nd subkey

// Repeat for all subkeys

for ( int i = 0 ; i < 33 ; i ++ ) {

gbc_encrypt ( s, s, subkeys ) ;

memcpy ( subkeys [ i ] , s, 16 ) ;

}

if ( encrypt ) {

for ( int i = 1 ; i < 32 ; i + = 2 ) {

gf128_imult ( subkeys [ i ] , subkeys [ i ] ) ;

}

}

}

/**

* Encrypts 128-bit block

*/

void gbc_encrypt ( const unsigned char * plaintext, unsigned char * ciphertext, const unsigned char subkeys [ ] [ 16 ] )

{

unsigned char s [ 16 ] ;

memcpy ( s, plaintext, 16 ) ;

// Round 1 to 15

for ( int i = 0 ; i < 30 ; i + = 2 ) {

gf128_add ( s, subkeys [ i ] , s ) ;

sbox ( s ) ;

gf128_mult ( s, subkeys [ i + 1 ] , s ) ;

pbox ( s ) ;

}

// Last round, no permutation

gf128_add ( s, subkeys [ 30 ] , s ) ;

sbox ( s ) ;

gf128_mult ( s, subkeys [ 31 ] , s ) ;

// XOR with final subkey

gf128_add ( s, subkeys [ 32 ] , s ) ;

memcpy ( ciphertext, s, 16 ) ;

}

/**

* Decrypts 128-bit block

*/

void gbc_decrypt ( const unsigned char * ciphertext, unsigned char * plaintext, const unsigned char subkeys [ ] [ 16 ] )

{

unsigned char s [ 16 ] ;

memcpy ( s, ciphertext, 16 ) ;

// XOR with final subkey

gf128_add ( s, subkeys [ 32 ] , s ) ;

// Undo round 16

gf128_mult ( s, subkeys [ 31 ] , s ) ;

inv_sbox ( s ) ;

gf128_add ( s, subkeys [ 30 ] , s ) ;

// Undo rounds 1 to 15

for ( int i = 29 ; i >= 1 ; i - = 2 ) {

inv_pbox ( s ) ;

gf128_mult ( s, subkeys [ i ] , s ) ;

inv_sbox ( s ) ;

gf128_add ( s, subkeys [ i - 1 ] , s ) ;

}

memcpy ( plaintext, s, 16 ) ;