/****************************************************************/
/* 802.16e AES-CCM Vector Generator                             */
/* Copyright (c) 2003 David Johnston                            */
/*
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
/* Author: David Johnston                                       */
/* Email : david.johnston@ieee.org                              */
/* Version 0.1                                                  */
/*                                                              */
/* v0.1     First version                                       */
/*          CRC32 is questionable, need to verify against .3    */ 
/****************************************************************/
 
#include <stdlib.h>
#include <stdio.h>

/****************************************/
/* Text output options.                 */
/* Comment out to reduce text output    */
/****************************************/

/* Enable any selection of the following for extra diagnostic output

#define SHOW_PHASES      
#define SHOW_HEADER_FIELDS
#define SHOW_INIT_BLOCKS
#define SHOW_CTR_PRELOAD
#define SHOW_DEBUG

*/

/********************************************/
/* Test Cases                               */
/* An array of test cases, each containing  */
/* an MPDU.                                 */
/* A separate array gives the MPDU length.  */
/********************************************/

int num_test_cases; 
int enc_decn;

int test_case_length[100];  
int test_case_enc_decn[100];


unsigned long int test_case_pnl[100]; 



unsigned char keys[100*16];

unsigned char test_cases[16384];


/***************************************/
/********* Table for CRC 32 ************/
/***************************************/

 unsigned char lookahead_table[1024] =
 {
        0x00,0x00,0x00,0x00,0x96,0x30,0x07,0x77,0x2c,0x61,0x0e,0xee,0xba,0x51,0x09,0x99,
        0x19,0xc4,0x6d,0x07,0x8f,0xf4,0x6a,0x70,0x35,0xa5,0x63,0xe9,0xa3,0x95,0x64,0x9e,
        0x32,0x88,0xdb,0x0e,0xa4,0xb8,0xdc,0x79,0x1e,0xe9,0xd5,0xe0,0x88,0xd9,0xd2,0x97,
        0x2b,0x4c,0xb6,0x09,0xbd,0x7c,0xb1,0x7e,0x07,0x2d,0xb8,0xe7,0x91,0x1d,0xbf,0x90,
        0x64,0x10,0xb7,0x1d,0xf2,0x20,0xb0,0x6a,0x48,0x71,0xb9,0xf3,0xde,0x41,0xbe,0x84,
        0x7d,0xd4,0xda,0x1a,0xeb,0xe4,0xdd,0x6d,0x51,0xb5,0xd4,0xf4,0xc7,0x85,0xd3,0x83,
        0x56,0x98,0x6c,0x13,0xc0,0xa8,0x6b,0x64,0x7a,0xf9,0x62,0xfd,0xec,0xc9,0x65,0x8a,
        0x4f,0x5c,0x01,0x14,0xd9,0x6c,0x06,0x63,0x63,0x3d,0x0f,0xfa,0xf5,0x0d,0x08,0x8d,
        0xc8,0x20,0x6e,0x3b,0x5e,0x10,0x69,0x4c,0xe4,0x41,0x60,0xd5,0x72,0x71,0x67,0xa2,
        0xd1,0xe4,0x03,0x3c,0x47,0xd4,0x04,0x4b,0xfd,0x85,0x0d,0xd2,0x6b,0xb5,0x0a,0xa5,
        0xfa,0xa8,0xb5,0x35,0x6c,0x98,0xb2,0x42,0xd6,0xc9,0xbb,0xdb,0x40,0xf9,0xbc,0xac,
        0xe3,0x6c,0xd8,0x32,0x75,0x5c,0xdf,0x45,0xcf,0x0d,0xd6,0xdc,0x59,0x3d,0xd1,0xab,
        0xac,0x30,0xd9,0x26,0x3a,0x00,0xde,0x51,0x80,0x51,0xd7,0xc8,0x16,0x61,0xd0,0xbf,
        0xb5,0xf4,0xb4,0x21,0x23,0xc4,0xb3,0x56,0x99,0x95,0xba,0xcf,0x0f,0xa5,0xbd,0xb8,
        0x9e,0xb8,0x02,0x28,0x08,0x88,0x05,0x5f,0xb2,0xd9,0x0c,0xc6,0x24,0xe9,0x0b,0xb1,
        0x87,0x7c,0x6f,0x2f,0x11,0x4c,0x68,0x58,0xab,0x1d,0x61,0xc1,0x3d,0x2d,0x66,0xb6,
        0x90,0x41,0xdc,0x76,0x06,0x71,0xdb,0x01,0xbc,0x20,0xd2,0x98,0x2a,0x10,0xd5,0xef,
        0x89,0x85,0xb1,0x71,0x1f,0xb5,0xb6,0x06,0xa5,0xe4,0xbf,0x9f,0x33,0xd4,0xb8,0xe8,
        0xa2,0xc9,0x07,0x78,0x34,0xf9,0x00,0x0f,0x8e,0xa8,0x09,0x96,0x18,0x98,0x0e,0xe1,
        0xbb,0x0d,0x6a,0x7f,0x2d,0x3d,0x6d,0x08,0x97,0x6c,0x64,0x91,0x01,0x5c,0x63,0xe6,
        0xf4,0x51,0x6b,0x6b,0x62,0x61,0x6c,0x1c,0xd8,0x30,0x65,0x85,0x4e,0x00,0x62,0xf2,
        0xed,0x95,0x06,0x6c,0x7b,0xa5,0x01,0x1b,0xc1,0xf4,0x08,0x82,0x57,0xc4,0x0f,0xf5,
        0xc6,0xd9,0xb0,0x65,0x50,0xe9,0xb7,0x12,0xea,0xb8,0xbe,0x8b,0x7c,0x88,0xb9,0xfc,
        0xdf,0x1d,0xdd,0x62,0x49,0x2d,0xda,0x15,0xf3,0x7c,0xd3,0x8c,0x65,0x4c,0xd4,0xfb,
        0x58,0x61,0xb2,0x4d,0xce,0x51,0xb5,0x3a,0x74,0x00,0xbc,0xa3,0xe2,0x30,0xbb,0xd4,
        0x41,0xa5,0xdf,0x4a,0xd7,0x95,0xd8,0x3d,0x6d,0xc4,0xd1,0xa4,0xfb,0xf4,0xd6,0xd3,
        0x6a,0xe9,0x69,0x43,0xfc,0xd9,0x6e,0x34,0x46,0x88,0x67,0xad,0xd0,0xb8,0x60,0xda,
        0x73,0x2d,0x04,0x44,0xe5,0x1d,0x03,0x33,0x5f,0x4c,0x0a,0xaa,0xc9,0x7c,0x0d,0xdd,
        0x3c,0x71,0x05,0x50,0xaa,0x41,0x02,0x27,0x10,0x10,0x0b,0xbe,0x86,0x20,0x0c,0xc9,
        0x25,0xb5,0x68,0x57,0xb3,0x85,0x6f,0x20,0x09,0xd4,0x66,0xb9,0x9f,0xe4,0x61,0xce,
        0x0e,0xf9,0xde,0x5e,0x98,0xc9,0xd9,0x29,0x22,0x98,0xd0,0xb0,0xb4,0xa8,0xd7,0xc7,
        0x17,0x3d,0xb3,0x59,0x81,0x0d,0xb4,0x2e,0x3b,0x5c,0xbd,0xb7,0xad,0x6c,0xba,0xc0,
        0x20,0x83,0xb8,0xed,0xb6,0xb3,0xbf,0x9a,0x0c,0xe2,0xb6,0x03,0x9a,0xd2,0xb1,0x74,
        0x39,0x47,0xd5,0xea,0xaf,0x77,0xd2,0x9d,0x15,0x26,0xdb,0x04,0x83,0x16,0xdc,0x73,
        0x12,0x0b,0x63,0xe3,0x84,0x3b,0x64,0x94,0x3e,0x6a,0x6d,0x0d,0xa8,0x5a,0x6a,0x7a,
        0x0b,0xcf,0x0e,0xe4,0x9d,0xff,0x09,0x93,0x27,0xae,0x00,0x0a,0xb1,0x9e,0x07,0x7d,
        0x44,0x93,0x0f,0xf0,0xd2,0xa3,0x08,0x87,0x68,0xf2,0x01,0x1e,0xfe,0xc2,0x06,0x69,
        0x5d,0x57,0x62,0xf7,0xcb,0x67,0x65,0x80,0x71,0x36,0x6c,0x19,0xe7,0x06,0x6b,0x6e,
        0x76,0x1b,0xd4,0xfe,0xe0,0x2b,0xd3,0x89,0x5a,0x7a,0xda,0x10,0xcc,0x4a,0xdd,0x67,
        0x6f,0xdf,0xb9,0xf9,0xf9,0xef,0xbe,0x8e,0x43,0xbe,0xb7,0x17,0xd5,0x8e,0xb0,0x60,
        0xe8,0xa3,0xd6,0xd6,0x7e,0x93,0xd1,0xa1,0xc4,0xc2,0xd8,0x38,0x52,0xf2,0xdf,0x4f,
        0xf1,0x67,0xbb,0xd1,0x67,0x57,0xbc,0xa6,0xdd,0x06,0xb5,0x3f,0x4b,0x36,0xb2,0x48,
        0xda,0x2b,0x0d,0xd8,0x4c,0x1b,0x0a,0xaf,0xf6,0x4a,0x03,0x36,0x60,0x7a,0x04,0x41,
        0xc3,0xef,0x60,0xdf,0x55,0xdf,0x67,0xa8,0xef,0x8e,0x6e,0x31,0x79,0xbe,0x69,0x46,
        0x8c,0xb3,0x61,0xcb,0x1a,0x83,0x66,0xbc,0xa0,0xd2,0x6f,0x25,0x36,0xe2,0x68,0x52,
        0x95,0x77,0x0c,0xcc,0x03,0x47,0x0b,0xbb,0xb9,0x16,0x02,0x22,0x2f,0x26,0x05,0x55,
        0xbe,0x3b,0xba,0xc5,0x28,0x0b,0xbd,0xb2,0x92,0x5a,0xb4,0x2b,0x04,0x6a,0xb3,0x5c,
        0xa7,0xff,0xd7,0xc2,0x31,0xcf,0xd0,0xb5,0x8b,0x9e,0xd9,0x2c,0x1d,0xae,0xde,0x5b,
        0xb0,0xc2,0x64,0x9b,0x26,0xf2,0x63,0xec,0x9c,0xa3,0x6a,0x75,0x0a,0x93,0x6d,0x02,
        0xa9,0x06,0x09,0x9c,0x3f,0x36,0x0e,0xeb,0x85,0x67,0x07,0x72,0x13,0x57,0x00,0x05,
        0x82,0x4a,0xbf,0x95,0x14,0x7a,0xb8,0xe2,0xae,0x2b,0xb1,0x7b,0x38,0x1b,0xb6,0x0c,
        0x9b,0x8e,0xd2,0x92,0x0d,0xbe,0xd5,0xe5,0xb7,0xef,0xdc,0x7c,0x21,0xdf,0xdb,0x0b,
        0xd4,0xd2,0xd3,0x86,0x42,0xe2,0xd4,0xf1,0xf8,0xb3,0xdd,0x68,0x6e,0x83,0xda,0x1f,
        0xcd,0x16,0xbe,0x81,0x5b,0x26,0xb9,0xf6,0xe1,0x77,0xb0,0x6f,0x77,0x47,0xb7,0x18,
        0xe6,0x5a,0x08,0x88,0x70,0x6a,0x0f,0xff,0xca,0x3b,0x06,0x66,0x5c,0x0b,0x01,0x11,
        0xff,0x9e,0x65,0x8f,0x69,0xae,0x62,0xf8,0xd3,0xff,0x6b,0x61,0x45,0xcf,0x6c,0x16,
        0x78,0xe2,0x0a,0xa0,0xee,0xd2,0x0d,0xd7,0x54,0x83,0x04,0x4e,0xc2,0xb3,0x03,0x39,
        0x61,0x26,0x67,0xa7,0xf7,0x16,0x60,0xd0,0x4d,0x47,0x69,0x49,0xdb,0x77,0x6e,0x3e,
        0x4a,0x6a,0xd1,0xae,0xdc,0x5a,0xd6,0xd9,0x66,0x0b,0xdf,0x40,0xf0,0x3b,0xd8,0x37,
        0x53,0xae,0xbc,0xa9,0xc5,0x9e,0xbb,0xde,0x7f,0xcf,0xb2,0x47,0xe9,0xff,0xb5,0x30,
        0x1c,0xf2,0xbd,0xbd,0x8a,0xc2,0xba,0xca,0x30,0x93,0xb3,0x53,0xa6,0xa3,0xb4,0x24,
        0x05,0x36,0xd0,0xba,0x93,0x06,0xd7,0xcd,0x29,0x57,0xde,0x54,0xbf,0x67,0xd9,0x23,
        0x2e,0x7a,0x66,0xb3,0xb8,0x4a,0x61,0xc4,0x02,0x1b,0x68,0x5d,0x94,0x2b,0x6f,0x2a,
        0x37,0xbe,0x0b,0xb4,0xa1,0x8e,0x0c,0xc3,0x1b,0xdf,0x05,0x5a,0x8d,0xef,0x02,0x2d

  };

/***************************************/
/********* Table for CRC 8  ************/
/***************************************/
                                                                                                                            
 unsigned char crc8_lookahead_table[256] =
 {
	0x00,0x89,0xc7,0x4e,0xe0,0x69,0x27,0xae,0x70,0xf9,0xb7,0x3e,0x90,0x19,0x57,0xde,
	0x38,0xb1,0xff,0x76,0xd8,0x51,0x1f,0x96,0x48,0xc1,0x8f,0x06,0xa8,0x21,0x6f,0xe6,
	0x1c,0x95,0xdb,0x52,0xfc,0x75,0x3b,0xb2,0x6c,0xe5,0xab,0x22,0x8c,0x05,0x4b,0xc2,
	0x24,0xad,0xe3,0x6a,0xc4,0x4d,0x03,0x8a,0x54,0xdd,0x93,0x1a,0xb4,0x3d,0x73,0xfa,
	0x0e,0x87,0xc9,0x40,0xee,0x67,0x29,0xa0,0x7e,0xf7,0xb9,0x30,0x9e,0x17,0x59,0xd0,
	0x36,0xbf,0xf1,0x78,0xd6,0x5f,0x11,0x98,0x46,0xcf,0x81,0x08,0xa6,0x2f,0x61,0xe8,
	0x12,0x9b,0xd5,0x5c,0xf2,0x7b,0x35,0xbc,0x62,0xeb,0xa5,0x2c,0x82,0x0b,0x45,0xcc,
	0x2a,0xa3,0xed,0x64,0xca,0x43,0x0d,0x84,0x5a,0xd3,0x9d,0x14,0xba,0x33,0x7d,0xf4,
	0x07,0x8e,0xc0,0x49,0xe7,0x6e,0x20,0xa9,0x77,0xfe,0xb0,0x39,0x97,0x1e,0x50,0xd9,
	0x3f,0xb6,0xf8,0x71,0xdf,0x56,0x18,0x91,0x4f,0xc6,0x88,0x01,0xaf,0x26,0x68,0xe1,
	0x1b,0x92,0xdc,0x55,0xfb,0x72,0x3c,0xb5,0x6b,0xe2,0xac,0x25,0x8b,0x02,0x4c,0xc5,
	0x23,0xaa,0xe4,0x6d,0xc3,0x4a,0x04,0x8d,0x53,0xda,0x94,0x1d,0xb3,0x3a,0x74,0xfd,
	0x09,0x80,0xce,0x47,0xe9,0x60,0x2e,0xa7,0x79,0xf0,0xbe,0x37,0x99,0x10,0x5e,0xd7,
	0x31,0xb8,0xf6,0x7f,0xd1,0x58,0x16,0x9f,0x41,0xc8,0x86,0x0f,0xa1,0x28,0x66,0xef,
	0x15,0x9c,0xd2,0x5b,0xf5,0x7c,0x32,0xbb,0x65,0xec,0xa2,0x2b,0x85,0x0c,0x42,0xcb,
	0x2d,0xa4,0xea,0x63,0xcd,0x44,0x0a,0x83,0x5d,0xd4,0x9a,0x13,0xbd,0x34,0x7a,0xf3
 };

/*****************************/
/******** SBOX Table *********/
/*****************************/

    unsigned char sbox_table[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
    };


    FILE *input_file;
    FILE *output_file;

/*****************************/
/**** Function Prototypes ****/
/*****************************/

void bitwise_xor(unsigned char *ina, unsigned char *inb, unsigned char *out);
void construct_mic_iv(
                        unsigned char *mic_header1,
                        unsigned char *mpdu,
                        unsigned int payload_length,
                        unsigned char * pn_vector
                        );
void construct_ctr_preload(
                        unsigned char *ctr_preload,
                        unsigned char *mpdu,
                        unsigned char *pn_vector,
                        int c
                        );
void get_mpdu(      int test_case,
                    unsigned char *plaintext);

int encrypt_mpdu(   unsigned char *key,
                    unsigned char *morphed_mpdu,
                    int length,
                    unsigned char *ciphertext,
                    int test_case);

void xor_128(unsigned char *a, unsigned char *b, unsigned char *out);
void xor_32(unsigned char *a, unsigned char *b, unsigned char *out);
unsigned char sbox(unsigned char a);
void next_key(unsigned char *key, int round);
void byte_sub(unsigned char *in, unsigned char *out);
void shift_row(unsigned char *in, unsigned char *out);
void mix_column(unsigned char *in, unsigned char *out);
void add_round_key( unsigned char *shiftrow_in,
                    unsigned char *mcol_in,
                    unsigned char *block_in,
                    int round,
                    unsigned char *out);
void aes128k128d(unsigned char *key, unsigned char *data, unsigned char *ciphertext);

void blockprint(unsigned char *str, unsigned char* block)
{
	printf("%s = (lsb) %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x (msb)\n", str,
		block[0], block[1], block[2], block[3],
		block[4], block[5], block[6], block[7],
		block[8], block[9], block[10], block[11],
		block[12], block[13], block[14], block[15]);
}

void blockprint_gmh(unsigned char *str, unsigned char *gmh)
{
	printf("%s = %02x %02x %02x %02x %02x %02x\n", str,
		gmh[0], gmh[1], gmh[2], gmh[3], gmh[4], gmh[5]);
}

void blockprint_payload(unsigned char *str, unsigned char *payload, int length)
{
	int blocks;
	int residue;
	int i;
	int j;
	unsigned char *ptr;

	ptr = payload;
	blocks = length/16;
	residue = length % 16;

	printf("%s",str);
	if (blocks > 0)
	{
		printf ("\t");
		for (j=0;j<15;j++)
		{
			printf("%02x ",*ptr++);
		}
		printf("%02x\n",*ptr++);
	}

	for (i=1;i<blocks;i++)
	{
		printf("\t\t\t");
		for (j=0;j<15;j++)
		{
			printf("%02x ",*ptr++);
		}
		printf("%02x\n",*ptr++);
	}

	if (residue > 0)
	{
		if (blocks != 0)
		{
			printf("\t\t\t");
		}
		else printf("\t");
		for(i=0;i<(residue-1);i++)
		{
			printf("%02x ",*ptr++);
		}
		printf("%02x\n",*ptr++);
	}
}


void testvector_print(unsigned char *str, unsigned char* block)
{
	fprintf(input_file,"%s%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", str,
		block[0], block[1], block[2], block[3],
		block[4], block[5], block[6], block[7],
		block[8], block[9], block[10], block[11],
		block[12], block[13], block[14], block[15]);
}

void testvector_print_be(unsigned char *str, unsigned char* block)
{
	printf("%s%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", str,
		block[15], block[14], block[13], block[12],
		block[11], block[10], block[9], block[8],
		block[7], block[6], block[5], block[4],
		block[3], block[2], block[1], block[0]);
}

/****************************************/
/* aes128k128d()                        */
/* Performs a 128 bit AES encrypt with  */
/* 128 bit data.                        */
/****************************************/
void xor_128(unsigned char *a, unsigned char *b, unsigned char *out)
{
    int i;
    for (i=0;i<16; i++)
    {
        out[i] = a[i] ^ b[i];
    }
}

void xor_32(unsigned char *a, unsigned char *b, unsigned char *out)
{
    int i;
    for (i=0;i<4; i++)
    {
        out[i] = a[i] ^ b[i];
    }
}
unsigned char sbox(unsigned char a)
{
    return sbox_table[(int)a];
}

void next_key(unsigned char *key, int round)
{
    unsigned char rcon;
    unsigned char sbox_key[4];
    unsigned char rcon_table[12] =
    {
        0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
        0x1b, 0x36, 0x36, 0x36
    };

    sbox_key[0] = sbox(key[13]);
    sbox_key[1] = sbox(key[14]);
    sbox_key[2] = sbox(key[15]);
    sbox_key[3] = sbox(key[12]);

    rcon = rcon_table[round];

    xor_32(&key[0], sbox_key, &key[0]);
    key[0] = key[0] ^ rcon;

    xor_32(&key[4], &key[0], &key[4]);
    xor_32(&key[8], &key[4], &key[8]);
    xor_32(&key[12], &key[8], &key[12]);
}

void byte_sub(unsigned char *in, unsigned char *out)
{
    int i;
    for (i=0; i< 16; i++)
    {
        out[i] = sbox(in[i]);
    }
}

void shift_row(unsigned char *in, unsigned char *out)
{
    out[0] =  in[0];
    out[1] =  in[5];
    out[2] =  in[10];
    out[3] =  in[15];
    out[4] =  in[4];
    out[5] =  in[9];
    out[6] =  in[14];
    out[7] =  in[3];
    out[8] =  in[8];
    out[9] =  in[13];
    out[10] = in[2];
    out[11] = in[7];
    out[12] = in[12];
    out[13] = in[1];
    out[14] = in[6];
    out[15] = in[11];
}

void mix_column(unsigned char *in, unsigned char *out)
{
    int i;
    unsigned char add1b[4];
    unsigned char add1bf7[4];
    unsigned char rotl[4];
    unsigned char swap_halfs[4];
    unsigned char andf7[4];
    unsigned char rotr[4];
    unsigned char temp[4];
    unsigned char tempb[4];

    for (i=0 ; i<4; i++)
    {
        if ((in[i] & 0x80)== 0x80)
            add1b[i] = 0x1b;
        else
            add1b[i] = 0x00;
    }

    swap_halfs[0] = in[2];    /* Swap halfs */
    swap_halfs[1] = in[3];
    swap_halfs[2] = in[0];
    swap_halfs[3] = in[1];

    rotl[0] = in[3];        /* Rotate left 8 bits */
    rotl[1] = in[0];
    rotl[2] = in[1];
    rotl[3] = in[2];

    andf7[0] = in[0] & 0x7f;
    andf7[1] = in[1] & 0x7f;
    andf7[2] = in[2] & 0x7f;
    andf7[3] = in[3] & 0x7f;

    for (i = 3; i>0; i--)    /* logical shift left 1 bit */
    {
        andf7[i] = andf7[i] << 1;
        if ((andf7[i-1] & 0x80) == 0x80)
        {
            andf7[i] = (andf7[i] | 0x01);
        }
    }
    andf7[0] = andf7[0] << 1;
    andf7[0] = andf7[0] & 0xfe;

    xor_32(add1b, andf7, add1bf7);

    xor_32(in, add1bf7, rotr);

    temp[0] = rotr[0];         /* Rotate right 8 bits */
    rotr[0] = rotr[1];
    rotr[1] = rotr[2];
    rotr[2] = rotr[3];
    rotr[3] = temp[0];

    xor_32(add1bf7, rotr, temp);
    xor_32(swap_halfs, rotl,tempb);
    xor_32(temp, tempb, out);
}

void aes128k128d(unsigned char *key, unsigned char *data, unsigned char *ciphertext)
{
    int round;
    int i;
    unsigned char intermediatea[16];
    unsigned char intermediateb[16];
    unsigned char round_key[16];

    for(i=0; i<16; i++) round_key[i] = key[i];

    for (round = 0; round < 11; round++)
    {
        if (round == 0)
        {
            xor_128(round_key, data, ciphertext);
            next_key(round_key, round);         
        }
        else if (round == 10)
        {
            byte_sub(ciphertext, intermediatea);
            shift_row(intermediatea, intermediateb);
            xor_128(intermediateb, round_key, ciphertext);          
        }
        else    /* 1 - 9 */
        {
            byte_sub(ciphertext, intermediatea);
            shift_row(intermediatea, intermediateb);
            mix_column(&intermediateb[0], &intermediatea[0]);
            mix_column(&intermediateb[4], &intermediatea[4]);
            mix_column(&intermediateb[8], &intermediatea[8]);
            mix_column(&intermediateb[12], &intermediatea[12]);
            xor_128(intermediatea, round_key, ciphertext);
            next_key(round_key, round);
        }
    }

}

/****************************************/
/* CRC8()                               */
/* Calculates the CRC32 of a sequence   */
/* of octets.                           */
/****************************************/
                                                                                                                            
void crc8(unsigned char *crc, unsigned char *data, int length)
{
                                                                                                                            
    int i;
    int index;
    unsigned char ch;
    unsigned char table_entry;
                                                                                                                            
    *crc = 0x00;
                                                                                                                            
    for (i=0; i<length; i++)
    {
        ch = data[i];
        index = (((int)((*crc) ^ ch)) & 0xff);
        table_entry = lookahead_table[index];
        *crc = *crc ^ table_entry;
    }
                                                                                                                            
    /* *crc = *crc ^ 0xff; */
}

/****************************************/
/* CRC32()                              */
/* Calculates the CRC32 of a sequence   */
/* of octets.                           */
/****************************************/

void crc32(unsigned char *crc, unsigned char *data, int length)
{

    int i;
    int index;
    unsigned char ch;
    unsigned char table_entry[4];

    crc[3] = 0xff;
    crc[2] = 0xff;
    crc[1] = 0xff;
    crc[0] = 0xff;

    for (i=0; i<length; i++)
    {
        ch = data[i];

        index = (((int)(crc[0] ^ ch)) & 0xff) * 4;

        table_entry[0] = lookahead_table[index];
        table_entry[1] = lookahead_table[index+1];
        table_entry[2] = lookahead_table[index+2];
        table_entry[3] = lookahead_table[index+3];

        crc[0] = crc[1] ^ table_entry[0];
        crc[1] = crc[2] ^ table_entry[1];
        crc[2] = crc[3] ^ table_entry[2];
        crc[3] = table_entry[3];

    }

    crc[0] = crc[0] ^ 0xff;
    crc[1] = crc[1] ^ 0xff;
    crc[2] = crc[2] ^ 0xff;
    crc[3] = crc[3] ^ 0xff;
}

/************************************************/
/* construct_mic_iv()                           */
/* Builds the MIC IV from header fields and PN  */
/************************************************/

void construct_mic_iv(
                        unsigned char *mic_iv,
                        unsigned char *mpdu,
                        unsigned int payload_length,
                        unsigned char *pn_vector
                        )
{
    int i;

    mic_iv[0] = 0x19;

    for (i = 1; i < 6; i++)
        mic_iv[i] = mpdu[i-1];                    /* mic_iv[1:5] = GMH[0:4] = mpdu[0:4] */

    for (i = 6; i < 14; i++)
        mic_iv[i] = pn_vector[i-6];          /* mic_iv[6:13] = PN[0:7] */

	mic_iv[10] = 0x00;
	mic_iv[11] = 0x00;
	mic_iv[12] = 0x00;
	mic_iv[13] = 0x00;

    mic_iv[14] = (unsigned char) (payload_length / 256);
    mic_iv[15] = (unsigned char) (payload_length % 256);
}

/************************************************/
/* construct_ctr_preload()                      */
/* Builds the ctr preload block                 */
/************************************************/


void construct_ctr_preload(
                        unsigned char *ctr_preload,
                        unsigned char *mpdu,
                        unsigned char *pn_vector,
                        int c
                        )
{
    int i = 0;
    for (i=0; i<16; i++) ctr_preload[i] = 0x00;
    i = 0;

    ctr_preload[0] = 0x01;                                  /* flag */

    for (i = 1; i < 6; i++)
        ctr_preload[i] = mpdu[i-1];                    /* mic_iv[1:5] = GMH[0:4] = mpdu[0:4] */
                                                                                                                                                                                 
    for (i = 6; i < 14; i++)
        ctr_preload[i] = pn_vector[i-6];          /* mic_iv[6:13] = PN[0:7] */
        ctr_preload[10] = 0x00;
        ctr_preload[11] = 0x00; 
	ctr_preload[12] = 0x00;
	ctr_preload[13] = 0x00;                                                                                                                                                                         
    ctr_preload[14] =  (unsigned char) (c / 256); /* Ctr */
    ctr_preload[15] =  (unsigned char) (c % 256);
}


/************************************/
/* bitwise_xor()                    */
/* A 128 bit, bitwise exclusive or  */
/************************************/

void bitwise_xor(unsigned char *ina, unsigned char *inb, unsigned char *out)
{
    int i;
    for (i=0; i<16; i++)
    {
        out[i] = ina[i] ^ inb[i];
    }
}


/********************************************************/
/* int encrypt_mpdu()                                   */
/* Encrypts a plaintext mpdu in accordance with         */
/* the proposed 802.16e ccm specification. PN and MIC   */
/* insertion takes place.                               */
/* Returns the resulting length of the packet.          */
/********************************************************/
int encrypt_mpdu(   unsigned char *key,
                    unsigned char *morphed_mpdu,
                    int length,
                    unsigned char *ciphertext,
		    int test_case)
{
    /* PN */
    unsigned char pn_vector[4];
    unsigned char pn_byte;
    /* MIC working variables */
    int i;
    int j;
    int payload_length;
    int num_blocks;
    int payload_remainder;
    int payload_index;
    /* Initialization Blocks */
    unsigned char mic_iv[16];
    unsigned char ctr_preload[16];

    /* Length adjustment on header */
    unsigned char lengthlsb;
    unsigned char lengthmsb;

    /* Intermediate Buffers */
    unsigned char chain_buffer[16];
    unsigned char aes_out[16];
    unsigned char padded_buffer[16];

    /* MIC */
    unsigned char mic[8];

    for (i=0;i<16;i++)             /* Reset the buffers to zero */
    {
        mic_iv[i] = 0x00;
        ctr_preload[i] = 0x00;
        chain_buffer[i] = 0x00;
        aes_out[i] = 0x00;
        padded_buffer[i] = 0x00;
    }

    #ifdef SHOW_PHASES
    printf("--ENCRYPTING...\n");
    #endif

    #ifdef SHOW_HEADER_FIELDS
    printf("---- Key =            (lsb) %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x (msb)\n",
                        key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7],
                        key[8], key[9], key[10], key[11], key[12], key[13], key[14], key[15]  );
    #endif


    for (i=0; i<4; i++)
    {
	pn_vector[i] = morphed_mpdu[6+i]; 
    }

    /* Copy plaintext to ciphertext */
    for (i=0; i<length; i++)
    {
        ciphertext[i] = morphed_mpdu[i];
    };


    /* Turn the PN into a vector of bytes, taking care  */
    /* not to be dependent on the endianess of the      */
    /* architecture we are running on                   */

    #ifdef SHOW_HEADER_FIELDS
    printf("---- PN =             0x%08lx\n", pnl );
    #endif

    /* Calculate MIC */
    payload_length = length - 10; /* subtract header and pn length */
    construct_mic_iv(
                        mic_iv,
                        morphed_mpdu,
                        payload_length,
                        pn_vector
                        );

    #ifdef SHOW_INIT_BLOCKS
    printf("---- MIC_IV =         (lsb) ");
    for (i=0;i<16;i++) printf("%02x ", mic_iv[i]);
    printf(" (msb)\n");

    #endif

    /* Calculate number of 16 byte blocks in MPDU */

    payload_remainder = (payload_length) % 16;
    num_blocks = (payload_length) / 16;

    /* Find start of payload */
    payload_index = 10;

    /* Calculate MIC */
    aes128k128d(key, mic_iv, aes_out);
    #ifdef SHOW_DEBUG
	blockprint("  ---- First MIC (lsb)", aes_out);
    #endif

    /* iterate through each 16 byte payload block */
    for (i = 0; i < num_blocks; i++)     
    {
        bitwise_xor(aes_out, &morphed_mpdu[payload_index], chain_buffer);
	#ifdef SHOW_DEBUG
	blockprint("  ---- Subsequent MIC input (lsb)", chain_buffer);
	#endif
        payload_index += 16;
        aes128k128d(key, chain_buffer, aes_out);
	#ifdef SHOW_DEBUG
	blockprint("  ---- Subsequent MIC (lsb)", aes_out);
	#endif
    }

    /* Add on the final payload block if it needs padding */
    if (payload_remainder > 0)
    {
        for (j = 0; j < 16; j++) padded_buffer[j] = 0x00;
        for (j = 0; j < payload_remainder; j++)
        {
            padded_buffer[j] = morphed_mpdu[payload_index++];
        }
	#ifdef SHOW_DEBUG
	blockprint("  ---- padded mic input ", padded_buffer);
	#endif
        bitwise_xor(aes_out, padded_buffer, chain_buffer);
	#ifdef SHOW_DEBUG
	blockprint("  ---- final MIC input", chain_buffer);
	#endif
        aes128k128d(key, chain_buffer, aes_out);
	#ifdef SHOW_DEBUG
	blockprint("  ---- final PT MIC   ", aes_out);
	#endif
    }

    /* aes_out contains padded mic, discard most significant    */
    /* 8 bytes to generate 64 bit MIC                           */

    for (j = 0 ; j < 8; j++) mic[j] = aes_out[j];

    /* Insert MIC into payload */
    for (j = 0; j < 8; j++)
    {
        //printf(" mic putting index %d, value = 0x%02x\n",(payload_index + j), mic[j]);
        ciphertext[payload_index + j] = mic[j];
    }
    length += 8;
    payload_length += 8;

    /**** Encrypt the payload and MIC ****/

    payload_index = 10; /* header + PN header */
    for (i=0; i< num_blocks; i++)
    {
        construct_ctr_preload(
                                ctr_preload,
                                morphed_mpdu,
                                pn_vector,
                                i+1
                            );
        #ifdef SHOW_CTR_PRELOAD
        printf("---- CTR_PRELOAD(%i) = (lsb) %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x  (msb)\n",
                            i+1, ctr_preload[0],ctr_preload[1],ctr_preload[2],ctr_preload[3],
                            ctr_preload[4],ctr_preload[5],ctr_preload[6],ctr_preload[7],
                            ctr_preload[8],ctr_preload[9],ctr_preload[10],ctr_preload[11],
                            ctr_preload[12],ctr_preload[13],ctr_preload[14],ctr_preload[15]);
        #endif

        aes128k128d(key, ctr_preload, aes_out);
	bitwise_xor(aes_out, &ciphertext[payload_index], chain_buffer);
	#ifdef SHOW_DEBUG
	blockprint("  ---- Cipherstream = ", aes_out);
	blockprint("  ---- Plaintext    = ", &ciphertext[payload_index]);
	blockprint("  ---- Ciphertext   = ", chain_buffer);
	#endif
        for (j=0; j<16;j++) ciphertext[payload_index++] = chain_buffer[j];
    }

    if (payload_remainder > 0)          /* If there is a short final block, then pad it,*/
    {                                   /* encrypt it and copy the unpadded part back   */
        construct_ctr_preload(
                                ctr_preload,
                                morphed_mpdu,
                                pn_vector,
                                num_blocks+1         
                            );

        for (j = 0; j < 16; j++) padded_buffer[j] = 0x00;
        for (j = 0; j < payload_remainder; j++)
        {
            padded_buffer[j] = ciphertext[payload_index+j];
        }
        aes128k128d(key, ctr_preload, aes_out);
	#ifdef SHOW_DEBUG
	blockprint(" ---- final CTR_PRELOAD ", ctr_preload);	
	blockprint(" ---- final cipherstream ", aes_out);
	blockprint(" ---- final plaintest    ", padded_buffer);
	#endif
        bitwise_xor(aes_out, padded_buffer, chain_buffer);
        for (j=0; j<payload_remainder;j++) ciphertext[payload_index++] = chain_buffer[j];
    }

    /* Encrypt the MIC */
    construct_ctr_preload(
                        ctr_preload,
                        morphed_mpdu,
                        pn_vector,
                        0
                        );
	#ifdef SHOW_DEBUG
	blockprint("  ---- CTR_PRELOAD(0) ", ctr_preload);
	#endif
    for (j = 0; j < 16; j++) padded_buffer[j] = 0x00;
    for (j = 0; j < 8; j++)
    {
	padded_buffer[j] = ciphertext[j+length-8];
    }
    aes128k128d(key, ctr_preload, aes_out);
    bitwise_xor(aes_out, padded_buffer, chain_buffer);
    #ifdef SHOW_DEBUG
    blockprint(" ---- CTR_PRELOAD(0) cipherstream ", aes_out);
    blockprint(" ---- Plaintext MIC ", padded_buffer);
    blockprint(" ---- Ciphertext MIC ", chain_buffer);
    #endif
    for (j=0; j<8;j++) ciphertext[payload_index++] = chain_buffer[j];

    if ((ciphertext[1] & 0x40)==0x40) /* if CRC, compute it */
	{
		crc32(&ciphertext[length], ciphertext, length);
		length=length+4;
	}

    return length;
}


/********************************************************/
/* int decrypt_mpdu()                                   */
/* Decrypts a ciphertext mpdu in accordance with        */
/* the proposed 802.16 ccm specification.               */
/* Returns the resulting length of the packet.          */
/********************************************************/
int decrypt_mpdu(   unsigned char *key,
                    unsigned char *ciphertext_mpdu,
                    int length,
                    unsigned char *plaintext,
		    int test_case)
{
    /* PN */
    unsigned char pn_vector[4];
    unsigned char pn_byte;
    /* MIC working variables */
    int i;
    int j;
    int trailer_length;
    int payload_length;
    int num_blocks;
    int payload_remainder;
    int payload_index;
    int crc_ind;
    /* Initialization Blocks */
    unsigned char mic_iv[16];
    unsigned char ctr_preload[16];

    /* Length adjustment on header */
    unsigned char lengthlsb;
    unsigned char lengthmsb;

    /* Intermediate Buffers */
    unsigned char chain_buffer[16];
    unsigned char aes_out[16];
    unsigned char padded_buffer[16];

    /* MIC */
    unsigned char mic[8];

    /* detect CRC */
    crc_ind=0;
    if ((ciphertext_mpdu[1] & 0x40)==0x40) crc_ind=1;

    for (i=0;i<16;i++)             /* Reset the buffers to zero */
    {
        mic_iv[i] = 0x00;
        ctr_preload[i] = 0x00;
        chain_buffer[i] = 0x00;
        aes_out[i] = 0x00;
        padded_buffer[i] = 0x00;
    }

    #ifdef SHOW_PHASES
    printf("--DECRYPTING...\n");
    #endif

    #ifdef SHOW_HEADER_FIELDS
    printf("---- Key =            (lsb) %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x (msb)\n",
                        key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7],
                        key[8], key[9], key[10], key[11], key[12], key[13], key[14], key[15]  );
    #endif


    for (i=0; i<4; i++)
    {
	pn_vector[i] = ciphertext_mpdu[6+i]; 
    }

    /* Copy ciphertext to plaintext */
    for (i=0; i<length; i++)
    {
        plaintext[i] = ciphertext_mpdu[i];
    };

    /* Turn the PN into a vector of bytes, taking care  */
    /* not to be dependent on the endianess of the      */
    /* architecture we are running on                   */

    #ifdef SHOW_HEADER_FIELDS
    printf("---- PN =             0x%08lx\n", pnl );
    #endif

    payload_length = length - 18;
    if (crc_ind) payload_length = length - 22; /* subtract header, pn, mic and crc length */

    /* Calculate number of 16 byte blocks in MPDU */

    payload_remainder = (payload_length) % 16;
    num_blocks = (payload_length) / 16;


    /**** Decrypt the payload and MIC ****/

    payload_index = 10; /* header + PN header */
    for (i=0; i< num_blocks; i++)
    {
        construct_ctr_preload(
                                ctr_preload,
                                ciphertext_mpdu,
                                pn_vector,
                                i+1
                            );
        #ifdef SHOW_CTR_PRELOAD
        printf("---- CTR_PRELOAD(%i) = (lsb) %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x  (msb)\n",
                            i+1, ctr_preload[0],ctr_preload[1],ctr_preload[2],ctr_preload[3],
                            ctr_preload[4],ctr_preload[5],ctr_preload[6],ctr_preload[7],
                            ctr_preload[8],ctr_preload[9],ctr_preload[10],ctr_preload[11],
                            ctr_preload[12],ctr_preload[13],ctr_preload[14],ctr_preload[15]);
        #endif

        aes128k128d(key, ctr_preload, aes_out);
	bitwise_xor(aes_out, &ciphertext_mpdu[payload_index], chain_buffer);
	#ifdef SHOW_DEBUG
	blockprint("  ---- Cipherstream = ", aes_out);
	blockprint("  ---- Plaintext    = ", &ciphertext[payload_index]);
	blockprint("  ---- Ciphertext   = ", chain_buffer);
	#endif
        for (j=0; j<16;j++) plaintext[payload_index++] = chain_buffer[j];
    }

    if (payload_remainder > 0)          /* If there is a short final block, then pad it,*/
    {                                   /* encrypt it and copy the unpadded part back   */
        construct_ctr_preload(
                                ctr_preload,
                                ciphertext_mpdu,
                                pn_vector,
                                num_blocks+1         
                            );

        for (j = 0; j < 16; j++) padded_buffer[j] = 0x00;
        for (j = 0; j < payload_remainder; j++)
        {
            padded_buffer[j] = ciphertext_mpdu[payload_index+j];
        }
        aes128k128d(key, ctr_preload, aes_out);
	#ifdef SHOW_DEBUG
	blockprint(" ---- final CTR_PRELOAD ", ctr_preload);	
	blockprint(" ---- final cipherstream ", aes_out);
	blockprint(" ---- final plaintest    ", padded_buffer);
	#endif
        bitwise_xor(aes_out, padded_buffer, chain_buffer);
        for (j=0; j<payload_remainder;j++) plaintext[payload_index++] = chain_buffer[j];
    }

    /* Decrypt the MIC */
    construct_ctr_preload(
                        ctr_preload,
                        ciphertext_mpdu,
                        pn_vector,
                        0
                        );
	#ifdef SHOW_DEBUG
	blockprint("  ---- CTR_PRELOAD(0) ", ctr_preload);
	#endif
    for (j = 0; j < 16; j++) padded_buffer[j] = 0x00;
    if (crc_ind)
    {
    	for (j = 0; j < 8; j++) padded_buffer[j] = ciphertext_mpdu[j+length-12];
    }
    else
    {
	for (j = 0; j < 8; j++) padded_buffer[j] = ciphertext_mpdu[j+length-8];
    }


    aes128k128d(key, ctr_preload, aes_out);
    bitwise_xor(aes_out, padded_buffer, chain_buffer);
    #ifdef SHOW_DEBUG
    blockprint(" ---- CTR_PRELOAD(0) cipherstream ", aes_out);
    blockprint(" ---- Plaintext MIC ", padded_buffer);
    blockprint(" ---- Ciphertext MIC ", chain_buffer);
    #endif
    for (j=0; j<8;j++) plaintext[payload_index++] = chain_buffer[j];


    /* Calculate MIC */
    payload_length = length - 18;
    if (crc_ind) payload_length = length - 22; /* subtract header, pn, mic and crc length */

    construct_mic_iv(
                        mic_iv,
                        plaintext,
                        payload_length,
                        pn_vector
                        );

    payload_index = 10;

    /* Calculate MIC */
    aes128k128d(key, mic_iv, aes_out);
    #ifdef SHOW_DEBUG
	blockprint("  ---- First MIC (lsb)", aes_out);
    #endif

    /* iterate through each 16 byte payload block */
    for (i = 0; i < num_blocks; i++)     
    {
        bitwise_xor(aes_out, &plaintext[payload_index], chain_buffer);
	#ifdef SHOW_DEBUG
	blockprint("  ---- Subsequent MIC input (lsb)", chain_buffer);
	#endif
        payload_index += 16;
        aes128k128d(key, chain_buffer, aes_out);
	#ifdef SHOW_DEBUG
	blockprint("  ---- Subsequent MIC (lsb)", aes_out);
	#endif
    }

    /* Add on the final payload block if it needs padding */
    if (payload_remainder > 0)
    {
        for (j = 0; j < 16; j++) padded_buffer[j] = 0x00;
        for (j = 0; j < payload_remainder; j++)
        {
            padded_buffer[j] = plaintext[payload_index++];
        }
	#ifdef SHOW_DEBUG
	blockprint("  ---- padded mic input ", padded_buffer);
	#endif
        bitwise_xor(aes_out, padded_buffer, chain_buffer);
	#ifdef SHOW_DEBUG
	blockprint("  ---- final MIC input", chain_buffer);
	#endif
        aes128k128d(key, chain_buffer, aes_out);
	#ifdef SHOW_DEBUG
	blockprint("  ---- final PT MIC   ", aes_out);
	#endif
    }

    /* aes_out contains padded mic, discard most significant    */
    /* 8 bytes to generate 64 bit MIC                           */

    for (j = 0 ; j < 8; j++) mic[j] = aes_out[j];

    return(length);
}

/************************************************/
/* get_mpdu()                                   */
/* Copies an mpdu from the test case data       */
/************************************************/
void get_mpdu(      int test_case,
                    unsigned char *plaintext)
{
    int i;
    unsigned char *ptr;

    ptr = test_cases;
    for (i=0; i< (test_case-1); i++)    /* Iterate through test cases */
    {
        ptr = ptr + test_case_length[i];
    }

    for (i=0; i< test_case_length[test_case-1]; i++)
    {
        plaintext[i] = *ptr++;
    }

    crc8(&plaintext[5],plaintext,5);  /* Calculate the HCS */
}

/********************************************************/
/* morph_mpdu()                                         */
/* Turns a plaintext mpdu into one ready for encryption */
/* by adjusting the length to include the PN, by        */
/* extending the payload and moving the plaintext to    */
/* make space for the PN, setting the EC bit on and     */
/* recomputing the resulting HCS.                       */
/********************************************************/

int morph_mpdu (
	unsigned char *plaintext_mpdu,
	int length,
	unsigned char *morphed_mpdu,
	int testcase)
{
	/* prepare packet for entry into crypto block  */
	/* So add a PN, adjust length field for the PN */
	/* the crc (if there) and the mic. recomputie  */
	/* the HCS.                                    */  
	int i;
	int morphed_length;
	int gmh_length;
	unsigned long int pn;

	/* copy header */
	for (i=0; i<6; i++) morphed_mpdu[i] = plaintext_mpdu[i];
	/* Shift payload right by 4 bytes to make room for the PN */
	for (i=length-1; i>5;i--) morphed_mpdu[i+4]=plaintext_mpdu[i];

	/* insert the PN */
	pn = test_case_pnl[testcase-1];
	morphed_mpdu[6]=pn % 256;
	morphed_mpdu[7]=(pn/256) % 256;
	morphed_mpdu[8]=(pn/(256*256)) % 256;
	morphed_mpdu[9]=(pn/(256*256*256)) % 256;

	morphed_length = length+4;

	/* compute the length field in the GMH            */
	/* = header + payload + pn + mic + crc if present */

	gmh_length = length + 4 + 8;
	if ((plaintext_mpdu[1]&0x40)==0x40) gmh_length+=4; /* add 4 for crc */

	morphed_mpdu[2] = gmh_length % 256;
	morphed_mpdu[1] = plaintext_mpdu[1] & 0xf8; /* clear lower 3 bits */
	morphed_mpdu[1] = morphed_mpdu[1] | (((gmh_length/256) % 256) & 0x7);

	/* set the encryption bit on */
	morphed_mpdu[0] = morphed_mpdu[0] | 0x40;
 
	/* compute the HCS */
	crc8(&morphed_mpdu[5],morphed_mpdu,5);

	return (morphed_length);
}


/***********************************************************/
/* create_test_case()                                      */
/* Generates a test case, of the specified payload length  */
/* with the CRC bit, key and pn as specified.              */
/* The test_case_num should increment.                     */  
/* The returned pointer should be passed into *index so    */
/* it knows where in the test case array the next test     */
/* case should be placed.                                  */
/* inc_rndn controls whether the payload is random or      */
/* incrementing.                                           */
/***********************************************************/

unsigned int create_test_case(
			int test_case_num,
			unsigned int index,
			int length,
			int crc,
			int enc_decn,
			int inc_rndn
		)
{
	int i;

	test_case_length[test_case_num-1] = length+6; /* add GMH length */
	test_case_enc_decn[test_case_num-1] = enc_decn;
	
	
	test_case_pnl[test_case_num-1]=random();

	for(i=0;i<16;i++)
	{
		keys[(16*(test_case_num-1))+i]=(unsigned char)(random() % 256);
	}

	/* Fill the header */
	test_cases[index]=0x00;
	if (crc) {
		test_cases[index+1] = 0x40;
	} else {
		test_cases[index+1] = 0x00;
	}

	test_cases[index+2] = (length+6) % 256;
	test_cases[index+1] |= (((length+6) / 256) % 256) & 0x7;

	test_cases[index+3] = (unsigned char)random();
	test_cases[index+4] = (unsigned char)random();
	test_cases[index+5] = 0x00;

	/* Fill the payload with random or sequential data */
	if (inc_rndn)
	{
		for (i=0;i<length;i++)
		{
			test_cases[6+(index++)]=((unsigned char)i) % 256;
		}
	}
	else
	{
		for (i=0;i<length;i++)
		{
			test_cases[6+(index++)]=((unsigned char)random()) % 256;
		}
	}

return(index+6);
	
}

/***************************************************/
/* Iterate around and make some test cases         */
/***************************************************/

void make_test_cases()
{
	int crc;
	int i;
	int enc_decn;
	int length;
	int index;
	int test_case_num;

	num_test_cases = 0;
	index = 0;
	test_case_num=1;

	for (i=0;i<21;i++)
	{
		if (i==0) length=1;
		if (i==1) length=2;
		if (i==2) length=3;
		if (i==3) length=4;
		if (i==4) length=5;
		if (i==5) length=6;
		if (i==6) length=7;
		if (i==7) length=8;
		if (i==8) length=9;
		if (i==9) length=10;
		if (i==10) length=11;
		if (i==11) length=12;
		if (i==12) length=13;
		if (i==13) length=14;
		if (i==14) length=15;
		if (i==15) length=16;
		if (i==16) length=17;
		if (i==17) length=23;
		if (i==18) length=31;
		if (i==19) length=32;
		if (i==20) length=33;

		for (crc=0;crc<2;crc++)
		{
			for (enc_decn=0;enc_decn<2;enc_decn++)
			{
				num_test_cases++;
				index = create_test_case(
						test_case_num++,
						index,
						length,
						crc,
						enc_decn,
						1	
					);
			}
		}
	}	
}

/****************************************************/
/* main()                                           */
/* Iterate through the test cases, passing them     */
/* through the ccm algorithm to produce test        */
/* vectors                                          */
/****************************************************/

int main()
{
    int draft_output_length;
    int length;
    int plaintext_length;
    int test_case;
    int header_length;
    int payload_length;
    int num_blocks;
    int block_remainder;
    int i;
    int j;
    int trailer_length;
    unsigned char crc[4];
    unsigned char plaintext_mpdu[3000];
    unsigned char morphed_mpdu[3000];
    unsigned char ciphertext_mpdu[3000];
    unsigned char decrypted_mpdu[3000];
    unsigned char *key;
    unsigned int pn;

    make_test_cases();

    for (test_case = 1; test_case < (num_test_cases+1); test_case++)
    {
        key = keys + (16 * (test_case-1));
        get_mpdu(test_case, plaintext_mpdu);

	enc_decn = test_case_enc_decn[test_case-1];
	plaintext_length = test_case_length[test_case-1];
        length = morph_mpdu( plaintext_mpdu,     /* Perform frame expansion and change GMH */
                    plaintext_length,
		    morphed_mpdu,
                    test_case);

	printf("EXAMPLE #%d\n", test_case);
	blockprint_payload("\tPlaintext MPDU",plaintext_mpdu,plaintext_length);
	blockprint("\tAES Key",key);
	pn = morphed_mpdu[6];		/* extract the pn */
	pn += 256*morphed_mpdu[7];
	pn += 256*256*morphed_mpdu[8];
	pn += 256*256*256*morphed_mpdu[9];
	printf("\tPacket Number = %08x\n",pn);
 
        length = encrypt_mpdu( 
                        key,
                        morphed_mpdu,
			length,
                        ciphertext_mpdu,
			test_case);

	blockprint_payload("\tCiphertext mpdu",ciphertext_mpdu,length);
	
	length = decrypt_mpdu(
			key,
			ciphertext_mpdu,
			length,
			decrypted_mpdu,
			test_case);

	blockprint_payload("\tDecrypted MPDU",decrypted_mpdu,length);
    }
    return 0;
}
