文件清单:
AES算法实现:aes.c,aes.h
AES算法CBC模式加解密封装:aes_util.c,aes_util.h
BASE64编解码实现:base64.c,base64.h
AES算法测试:aes_util_test.c
aes.c:
/********************************************************************* * Filename: aes.c * Author: Brad Conte (brad AT bradconte.com) * Copyright: * Disclaimer: This code is presented "as is" without any guarantees. * Details: This code is the implementation of the AES algorithm and the CTR, CBC, and CCM modes of operation it can be used in. AES is, specified by the NIST in in publication FIPS PUB 197, availible at: * http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf . The CBC and CTR modes of operation are specified by NIST SP 800-38 A, available at: * http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf . The CCM mode of operation is specified by NIST SP80-38 C, available at: * http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf *********************************************************************/ /*************************** HEADER FILES ***************************/ #include <stdlib.h> #include <memory.h> #include "aes.h" #include <stdio.h> /****************************** MACROS ******************************/ // The least significant byte of the word is rotated to the end. #define KE_ROTWORD(x) (((x) << 8) | ((x) >> 24)) #define TRUE 1 #define FALSE 0 /**************************** DATA TYPES ****************************/ #define AES_128_ROUNDS 10 #define AES_192_ROUNDS 12 #define AES_256_ROUNDS 14 /*********************** FUNCTION DECLARATIONS **********************/ void ccm_prepare_first_ctr_blk(BYTE counter[], const BYTE nonce[], int nonce_len, int payload_len_store_size); void ccm_prepare_first_format_blk(BYTE buf[], int assoc_len, int payload_len, int payload_len_store_size, int mac_len, const BYTE nonce[], int nonce_len); void ccm_format_assoc_data(BYTE buf[], int *end_of_buf, const BYTE assoc[], int assoc_len); void ccm_format_payload_data(BYTE buf[], int *end_of_buf, const BYTE payload[], int payload_len); /**************************** VARIABLES *****************************/ // This is the specified AES SBox. To look up a substitution value, put the first // nibble in the first index (row) and the second nibble in the second index (column). static const BYTE aes_sbox[16][16] = { {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} }; static const BYTE aes_invsbox[16][16] = { {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} }; // This table stores pre-calculated values for all possible GF(2^8) calculations.This // table is only used by the (Inv)MixColumns steps. // USAGE: The second index (column) is the coefficient of multiplication. Only 7 different // coefficients are used: 0x01, 0x02, 0x03, 0x09, 0x0b, 0x0d, 0x0e, but multiplication by // 1 is negligible leaving only 6 coefficients. Each column of the table is devoted to one // of these coefficients, in the ascending order of value, from values 0x00 to 0xFF. static const BYTE gf_mul[256][6] = { {0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x03,0x09,0x0b,0x0d,0x0e}, {0x04,0x06,0x12,0x16,0x1a,0x1c},{0x06,0x05,0x1b,0x1d,0x17,0x12}, {0x08,0x0c,0x24,0x2c,0x34,0x38},{0x0a,0x0f,0x2d,0x27,0x39,0x36}, {0x0c,0x0a,0x36,0x3a,0x2e,0x24},{0x0e,0x09,0x3f,0x31,0x23,0x2a}, {0x10,0x18,0x48,0x58,0x68,0x70},{0x12,0x1b,0x41,0x53,0x65,0x7e}, {0x14,0x1e,0x5a,0x4e,0x72,0x6c},{0x16,0x1d,0x53,0x45,0x7f,0x62}, {0x18,0x14,0x6c,0x74,0x5c,0x48},{0x1a,0x17,0x65,0x7f,0x51,0x46}, {0x1c,0x12,0x7e,0x62,0x46,0x54},{0x1e,0x11,0x77,0x69,0x4b,0x5a}, {0x20,0x30,0x90,0xb0,0xd0,0xe0},{0x22,0x33,0x99,0xbb,0xdd,0xee}, {0x24,0x36,0x82,0xa6,0xca,0xfc},{0x26,0x35,0x8b,0xad,0xc7,0xf2}, {0x28,0x3c,0xb4,0x9c,0xe4,0xd8},{0x2a,0x3f,0xbd,0x97,0xe9,0xd6}, {0x2c,0x3a,0xa6,0x8a,0xfe,0xc4},{0x2e,0x39,0xaf,0x81,0xf3,0xca}, {0x30,0x28,0xd8,0xe8,0xb8,0x90},{0x32,0x2b,0xd1,0xe3,0xb5,0x9e}, {0x34,0x2e,0xca,0xfe,0xa2,0x8c},{0x36,0x2d,0xc3,0xf5,0xaf,0x82}, {0x38,0x24,0xfc,0xc4,0x8c,0xa8},{0x3a,0x27,0xf5,0xcf,0x81,0xa6}, {0x3c,0x22,0xee,0xd2,0x96,0xb4},{0x3e,0x21,0xe7,0xd9,0x9b,0xba}, {0x40,0x60,0x3b,0x7b,0xbb,0xdb},{0x42,0x63,0x32,0x70,0xb6,0xd5}, {0x44,0x66,0x29,0x6d,0xa1,0xc7},{0x46,0x65,0x20,0x66,0xac,0xc9}, {0x48,0x6c,0x1f,0x57,0x8f,0xe3},{0x4a,0x6f,0x16,0x5c,0x82,0xed}, {0x4c,0x6a,0x0d,0x41,0x95,0xff},{0x4e,0x69,0x04,0x4a,0x98,0xf1}, {0x50,0x78,0x73,0x23,0xd3,0xab},{0x52,0x7b,0x7a,0x28,0xde,0xa5}, {0x54,0x7e,0x61,0x35,0xc9,0xb7},{0x56,0x7d,0x68,0x3e,0xc4,0xb9}, {0x58,0x74,0x57,0x0f,0xe7,0x93},{0x5a,0x77,0x5e,0x04,0xea,0x9d}, {0x5c,0x72,0x45,0x19,0xfd,0x8f},{0x5e,0x71,0x4c,0x12,0xf0,0x81}, {0x60,0x50,0xab,0xcb,0x6b,0x3b},{0x62,0x53,0xa2,0xc0,0x66,0x35}, {0x64,0x56,0xb9,0xdd,0x71,0x27},{0x66,0x55,0xb0,0xd6,0x7c,0x29}, {0x68,0x5c,0x8f,0xe7,0x5f,0x03},{0x6a,0x5f,0x86,0xec,0x52,0x0d}, {0x6c,0x5a,0x9d,0xf1,0x45,0x1f},{0x6e,0x59,0x94,0xfa,0x48,0x11}, {0x70,0x48,0xe3,0x93,0x03,0x4b},{0x72,0x4b,0xea,0x98,0x0e,0x45}, {0x74,0x4e,0xf1,0x85,0x19,0x57},{0x76,0x4d,0xf8,0x8e,0x14,0x59}, {0x78,0x44,0xc7,0xbf,0x37,0x73},{0x7a,0x47,0xce,0xb4,0x3a,0x7d}, {0x7c,0x42,0xd5,0xa9,0x2d,0x6f},{0x7e,0x41,0xdc,0xa2,0x20,0x61}, {0x80,0xc0,0x76,0xf6,0x6d,0xad},{0x82,0xc3,0x7f,0xfd,0x60,0xa3}, {0x84,0xc6,0x64,0xe0,0x77,0xb1},{0x86,0xc5,0x6d,0xeb,0x7a,0xbf}, {0x88,0xcc,0x52,0xda,0x59,0x95},{0x8a,0xcf,0x5b,0xd1,0x54,0x9b}, {0x8c,0xca,0x40,0xcc,0x43,0x89},{0x8e,0xc9,0x49,0xc7,0x4e,0x87}, {0x90,0xd8,0x3e,0xae,0x05,0xdd},{0x92,0xdb,0x37,0xa5,0x08,0xd3}, {0x94,0xde,0x2c,0xb8,0x1f,0xc1},{0x96,0xdd,0x25,0xb3,0x12,0xcf}, {0x98,0xd4,0x1a,0x82,0x31,0xe5},{0x9a,0xd7,0x13,0x89,0x3c,0xeb}, {0x9c,0xd2,0x08,0x94,0x2b,0xf9},{0x9e,0xd1,0x01,0x9f,0x26,0xf7}, {0xa0,0xf0,0xe6,0x46,0xbd,0x4d},{0xa2,0xf3,0xef,0x4d,0xb0,0x43}, {0xa4,0xf6,0xf4,0x50,0xa7,0x51},{0xa6,0xf5,0xfd,0x5b,0xaa,0x5f}, {0xa8,0xfc,0xc2,0x6a,0x89,0x75},{0xaa,0xff,0xcb,0x61,0x84,0x7b}, {0xac,0xfa,0xd0,0x7c,0x93,0x69},{0xae,0xf9,0xd9,0x77,0x9e,0x67}, {0xb0,0xe8,0xae,0x1e,0xd5,0x3d},{0xb2,0xeb,0xa7,0x15,0xd8,0x33}, {0xb4,0xee,0xbc,0x08,0xcf,0x21},{0xb6,0xed,0xb5,0x03,0xc2,0x2f}, {0xb8,0xe4,0x8a,0x32,0xe1,0x05},{0xba,0xe7,0x83,0x39,0xec,0x0b}, {0xbc,0xe2,0x98,0x24,0xfb,0x19},{0xbe,0xe1,0x91,0x2f,0xf6,0x17}, {0xc0,0xa0,0x4d,0x8d,0xd6,0x76},{0xc2,0xa3,0x44,0x86,0xdb,0x78}, {0xc4,0xa6,0x5f,0x9b,0xcc,0x6a},{0xc6,0xa5,0x56,0x90,0xc1,0x64}, {0xc8,0xac,0x69,0xa1,0xe2,0x4e},{0xca,0xaf,0x60,0xaa,0xef,0x40}, {0xcc,0xaa,0x7b,0xb7,0xf8,0x52},{0xce,0xa9,0x72,0xbc,0xf5,0x5c}, {0xd0,0xb8,0x05,0xd5,0xbe,0x06},{0xd2,0xbb,0x0c,0xde,0xb3,0x08}, {0xd4,0xbe,0x17,0xc3,0xa4,0x1a},{0xd6,0xbd,0x1e,0xc8,0xa9,0x14}, {0xd8,0xb4,0x21,0xf9,0x8a,0x3e},{0xda,0xb7,0x28,0xf2,0x87,0x30}, {0xdc,0xb2,0x33,0xef,0x90,0x22},{0xde,0xb1,0x3a,0xe4,0x9d,0x2c}, {0xe0,0x90,0xdd,0x3d,0x06,0x96},{0xe2,0x93,0xd4,0x36,0x0b,0x98}, {0xe4,0x96,0xcf,0x2b,0x1c,0x8a},{0xe6,0x95,0xc6,0x20,0x11,0x84}, {0xe8,0x9c,0xf9,0x11,0x32,0xae},{0xea,0x9f,0xf0,0x1a,0x3f,0xa0}, {0xec,0x9a,0xeb,0x07,0x28,0xb2},{0xee,0x99,0xe2,0x0c,0x25,0xbc}, {0xf0,0x88,0x95,0x65,0x6e,0xe6},{0xf2,0x8b,0x9c,0x6e,0x63,0xe8}, {0xf4,0x8e,0x87,0x73,0x74,0xfa},{0xf6,0x8d,0x8e,0x78,0x79,0xf4}, {0xf8,0x84,0xb1,0x49,0x5a,0xde},{0xfa,0x87,0xb8,0x42,0x57,0xd0}, {0xfc,0x82,0xa3,0x5f,0x40,0xc2},{0xfe,0x81,0xaa,0x54,0x4d,0xcc}, {0x1b,0x9b,0xec,0xf7,0xda,0x41},{0x19,0x98,0xe5,0xfc,0xd7,0x4f}, {0x1f,0x9d,0xfe,0xe1,0xc0,0x5d},{0x1d,0x9e,0xf7,0xea,0xcd,0x53}, {0x13,0x97,0xc8,0xdb,0xee,0x79},{0x11,0x94,0xc1,0xd0,0xe3,0x77}, {0x17,0x91,0xda,0xcd,0xf4,0x65},{0x15,0x92,0xd3,0xc6,0xf9,0x6b}, {0x0b,0x83,0xa4,0xaf,0xb2,0x31},{0x09,0x80,0xad,0xa4,0xbf,0x3f}, {0x0f,0x85,0xb6,0xb9,0xa8,0x2d},{0x0d,0x86,0xbf,0xb2,0xa5,0x23}, {0x03,0x8f,0x80,0x83,0x86,0x09},{0x01,0x8c,0x89,0x88,0x8b,0x07}, {0x07,0x89,0x92,0x95,0x9c,0x15},{0x05,0x8a,0x9b,0x9e,0x91,0x1b}, {0x3b,0xab,0x7c,0x47,0x0a,0xa1},{0x39,0xa8,0x75,0x4c,0x07,0xaf}, {0x3f,0xad,0x6e,0x51,0x10,0xbd},{0x3d,0xae,0x67,0x5a,0x1d,0xb3}, {0x33,0xa7,0x58,0x6b,0x3e,0x99},{0x31,0xa4,0x51,0x60,0x33,0x97}, {0x37,0xa1,0x4a,0x7d,0x24,0x85},{0x35,0xa2,0x43,0x76,0x29,0x8b}, {0x2b,0xb3,0x34,0x1f,0x62,0xd1},{0x29,0xb0,0x3d,0x14,0x6f,0xdf}, {0x2f,0xb5,0x26,0x09,0x78,0xcd},{0x2d,0xb6,0x2f,0x02,0x75,0xc3}, {0x23,0xbf,0x10,0x33,0x56,0xe9},{0x21,0xbc,0x19,0x38,0x5b,0xe7}, {0x27,0xb9,0x02,0x25,0x4c,0xf5},{0x25,0xba,0x0b,0x2e,0x41,0xfb}, {0x5b,0xfb,0xd7,0x8c,0x61,0x9a},{0x59,0xf8,0xde,0x87,0x6c,0x94}, {0x5f,0xfd,0xc5,0x9a,0x7b,0x86},{0x5d,0xfe,0xcc,0x91,0x76,0x88}, {0x53,0xf7,0xf3,0xa0,0x55,0xa2},{0x51,0xf4,0xfa,0xab,0x58,0xac}, {0x57,0xf1,0xe1,0xb6,0x4f,0xbe},{0x55,0xf2,0xe8,0xbd,0x42,0xb0}, {0x4b,0xe3,0x9f,0xd4,0x09,0xea},{0x49,0xe0,0x96,0xdf,0x04,0xe4}, {0x4f,0xe5,0x8d,0xc2,0x13,0xf6},{0x4d,0xe6,0x84,0xc9,0x1e,0xf8}, {0x43,0xef,0xbb,0xf8,0x3d,0xd2},{0x41,0xec,0xb2,0xf3,0x30,0xdc}, {0x47,0xe9,0xa9,0xee,0x27,0xce},{0x45,0xea,0xa0,0xe5,0x2a,0xc0}, {0x7b,0xcb,0x47,0x3c,0xb1,0x7a},{0x79,0xc8,0x4e,0x37,0xbc,0x74}, {0x7f,0xcd,0x55,0x2a,0xab,0x66},{0x7d,0xce,0x5c,0x21,0xa6,0x68}, {0x73,0xc7,0x63,0x10,0x85,0x42},{0x71,0xc4,0x6a,0x1b,0x88,0x4c}, {0x77,0xc1,0x71,0x06,0x9f,0x5e},{0x75,0xc2,0x78,0x0d,0x92,0x50}, {0x6b,0xd3,0x0f,0x64,0xd9,0x0a},{0x69,0xd0,0x06,0x6f,0xd4,0x04}, {0x6f,0xd5,0x1d,0x72,0xc3,0x16},{0x6d,0xd6,0x14,0x79,0xce,0x18}, {0x63,0xdf,0x2b,0x48,0xed,0x32},{0x61,0xdc,0x22,0x43,0xe0,0x3c}, {0x67,0xd9,0x39,0x5e,0xf7,0x2e},{0x65,0xda,0x30,0x55,0xfa,0x20}, {0x9b,0x5b,0x9a,0x01,0xb7,0xec},{0x99,0x58,0x93,0x0a,0xba,0xe2}, {0x9f,0x5d,0x88,0x17,0xad,0xf0},{0x9d,0x5e,0x81,0x1c,0xa0,0xfe}, {0x93,0x57,0xbe,0x2d,0x83,0xd4},{0x91,0x54,0xb7,0x26,0x8e,0xda}, {0x97,0x51,0xac,0x3b,0x99,0xc8},{0x95,0x52,0xa5,0x30,0x94,0xc6}, {0x8b,0x43,0xd2,0x59,0xdf,0x9c},{0x89,0x40,0xdb,0x52,0xd2,0x92}, {0x8f,0x45,0xc0,0x4f,0xc5,0x80},{0x8d,0x46,0xc9,0x44,0xc8,0x8e}, {0x83,0x4f,0xf6,0x75,0xeb,0xa4},{0x81,0x4c,0xff,0x7e,0xe6,0xaa}, {0x87,0x49,0xe4,0x63,0xf1,0xb8},{0x85,0x4a,0xed,0x68,0xfc,0xb6}, {0xbb,0x6b,0x0a,0xb1,0x67,0x0c},{0xb9,0x68,0x03,0xba,0x6a,0x02}, {0xbf,0x6d,0x18,0xa7,0x7d,0x10},{0xbd,0x6e,0x11,0xac,0x70,0x1e}, {0xb3,0x67,0x2e,0x9d,0x53,0x34},{0xb1,0x64,0x27,0x96,0x5e,0x3a}, {0xb7,0x61,0x3c,0x8b,0x49,0x28},{0xb5,0x62,0x35,0x80,0x44,0x26}, {0xab,0x73,0x42,0xe9,0x0f,0x7c},{0xa9,0x70,0x4b,0xe2,0x02,0x72}, {0xaf,0x75,0x50,0xff,0x15,0x60},{0xad,0x76,0x59,0xf4,0x18,0x6e}, {0xa3,0x7f,0x66,0xc5,0x3b,0x44},{0xa1,0x7c,0x6f,0xce,0x36,0x4a}, {0xa7,0x79,0x74,0xd3,0x21,0x58},{0xa5,0x7a,0x7d,0xd8,0x2c,0x56}, {0xdb,0x3b,0xa1,0x7a,0x0c,0x37},{0xd9,0x38,0xa8,0x71,0x01,0x39}, {0xdf,0x3d,0xb3,0x6c,0x16,0x2b},{0xdd,0x3e,0xba,0x67,0x1b,0x25}, {0xd3,0x37,0x85,0x56,0x38,0x0f},{0xd1,0x34,0x8c,0x5d,0x35,0x01}, {0xd7,0x31,0x97,0x40,0x22,0x13},{0xd5,0x32,0x9e,0x4b,0x2f,0x1d}, {0xcb,0x23,0xe9,0x22,0x64,0x47},{0xc9,0x20,0xe0,0x29,0x69,0x49}, {0xcf,0x25,0xfb,0x34,0x7e,0x5b},{0xcd,0x26,0xf2,0x3f,0x73,0x55}, {0xc3,0x2f,0xcd,0x0e,0x50,0x7f},{0xc1,0x2c,0xc4,0x05,0x5d,0x71}, {0xc7,0x29,0xdf,0x18,0x4a,0x63},{0xc5,0x2a,0xd6,0x13,0x47,0x6d}, {0xfb,0x0b,0x31,0xca,0xdc,0xd7},{0xf9,0x08,0x38,0xc1,0xd1,0xd9}, {0xff,0x0d,0x23,0xdc,0xc6,0xcb},{0xfd,0x0e,0x2a,0xd7,0xcb,0xc5}, {0xf3,0x07,0x15,0xe6,0xe8,0xef},{0xf1,0x04,0x1c,0xed,0xe5,0xe1}, {0xf7,0x01,0x07,0xf0,0xf2,0xf3},{0xf5,0x02,0x0e,0xfb,0xff,0xfd}, {0xeb,0x13,0x79,0x92,0xb4,0xa7},{0xe9,0x10,0x70,0x99,0xb9,0xa9}, {0xef,0x15,0x6b,0x84,0xae,0xbb},{0xed,0x16,0x62,0x8f,0xa3,0xb5}, {0xe3,0x1f,0x5d,0xbe,0x80,0x9f},{0xe1,0x1c,0x54,0xb5,0x8d,0x91}, {0xe7,0x19,0x4f,0xa8,0x9a,0x83},{0xe5,0x1a,0x46,0xa3,0x97,0x8d} }; /*********************** FUNCTION DEFINITIONS ***********************/ // XORs the in and out buffers, storing the result in out. Length is in bytes. void xor_buf(const BYTE in[], BYTE out[], size_t len) { size_t idx; for (idx = 0; idx < len; idx++) out[idx] ^= in[idx]; } /******************* * AES - CBC *******************/ int aes_encrypt_cbc(const BYTE in[], size_t in_len, BYTE out[], const WORD key[], int keysize, const BYTE iv[]) { BYTE buf_in[AES_BLOCK_SIZE], buf_out[AES_BLOCK_SIZE], iv_buf[AES_BLOCK_SIZE]; int blocks, idx; if (in_len % AES_BLOCK_SIZE != 0) return(FALSE); blocks = in_len / AES_BLOCK_SIZE; memcpy(iv_buf, iv, AES_BLOCK_SIZE); for (idx = 0; idx < blocks; idx++) { memcpy(buf_in, &in[idx * AES_BLOCK_SIZE], AES_BLOCK_SIZE); xor_buf(iv_buf, buf_in, AES_BLOCK_SIZE); aes_encrypt(buf_in, buf_out, key, keysize); memcpy(&out[idx * AES_BLOCK_SIZE], buf_out, AES_BLOCK_SIZE); memcpy(iv_buf, buf_out, AES_BLOCK_SIZE); } return(TRUE); } int aes_encrypt_cbc_mac(const BYTE in[], size_t in_len, BYTE out[], const WORD key[], int keysize, const BYTE iv[]) { BYTE buf_in[AES_BLOCK_SIZE], buf_out[AES_BLOCK_SIZE], iv_buf[AES_BLOCK_SIZE]; int blocks, idx; if (in_len % AES_BLOCK_SIZE != 0) return(FALSE); blocks = in_len / AES_BLOCK_SIZE; memcpy(iv_buf, iv, AES_BLOCK_SIZE); for (idx = 0; idx < blocks; idx++) { memcpy(buf_in, &in[idx * AES_BLOCK_SIZE], AES_BLOCK_SIZE); xor_buf(iv_buf, buf_in, AES_BLOCK_SIZE); aes_encrypt(buf_in, buf_out, key, keysize); memcpy(iv_buf, buf_out, AES_BLOCK_SIZE); // Do not output all encrypted blocks. } memcpy(out, buf_out, AES_BLOCK_SIZE); // Only output the last block. return(TRUE); } int aes_decrypt_cbc(const BYTE in[], size_t in_len, BYTE out[], const WORD key[], int keysize, const BYTE iv[]) { BYTE buf_in[AES_BLOCK_SIZE], buf_out[AES_BLOCK_SIZE], iv_buf[AES_BLOCK_SIZE]; int blocks, idx; if (in_len % AES_BLOCK_SIZE != 0) return(FALSE); blocks = in_len / AES_BLOCK_SIZE; memcpy(iv_buf, iv, AES_BLOCK_SIZE); for (idx = 0; idx < blocks; idx++) { memcpy(buf_in, &in[idx * AES_BLOCK_SIZE], AES_BLOCK_SIZE); aes_decrypt(buf_in, buf_out, key, keysize); xor_buf(iv_buf, buf_out, AES_BLOCK_SIZE); memcpy(&out[idx * AES_BLOCK_SIZE], buf_out, AES_BLOCK_SIZE); memcpy(iv_buf, buf_in, AES_BLOCK_SIZE); } return(TRUE); } /******************* * AES - CTR *******************/ void increment_iv(BYTE iv[], int counter_size) { int idx; // Use counter_size bytes at the end of the IV as the big-endian integer to increment. for (idx = AES_BLOCK_SIZE - 1; idx >= AES_BLOCK_SIZE - counter_size; idx--) { iv[idx]++; if (iv[idx] != 0 || idx == AES_BLOCK_SIZE - counter_size) break; } } // Performs the encryption in-place, the input and output buffers may be the same. // Input may be an arbitrary length (in bytes). void aes_encrypt_ctr(const BYTE in[], size_t in_len, BYTE out[], const WORD key[], int keysize, const BYTE iv[]) { size_t idx = 0, last_block_length; BYTE iv_buf[AES_BLOCK_SIZE], out_buf[AES_BLOCK_SIZE]; if (in != out) memcpy(out, in, in_len); memcpy(iv_buf, iv, AES_BLOCK_SIZE); last_block_length = in_len - AES_BLOCK_SIZE; if (in_len > AES_BLOCK_SIZE) { for (idx = 0; idx < last_block_length; idx += AES_BLOCK_SIZE) { aes_encrypt(iv_buf, out_buf, key, keysize); xor_buf(out_buf, &out[idx], AES_BLOCK_SIZE); increment_iv(iv_buf, AES_BLOCK_SIZE); } } aes_encrypt(iv_buf, out_buf, key, keysize); xor_buf(out_buf, &out[idx], in_len - idx); // Use the Most Significant bytes. } void aes_decrypt_ctr(const BYTE in[], size_t in_len, BYTE out[], const WORD key[], int keysize, const BYTE iv[]) { // CTR encryption is its own inverse function. aes_encrypt_ctr(in, in_len, out, key, keysize, iv); } /******************* * AES - CCM *******************/ // out_len = payload_len + assoc_len int aes_encrypt_ccm(const BYTE payload[], WORD payload_len, const BYTE assoc[], unsigned short assoc_len, const BYTE nonce[], unsigned short nonce_len, BYTE out[], WORD *out_len, WORD mac_len, const BYTE key_str[], int keysize) { BYTE temp_iv[AES_BLOCK_SIZE], counter[AES_BLOCK_SIZE], mac[16], *buf; int end_of_buf, payload_len_store_size; WORD key[60]; if (mac_len != 4 && mac_len != 6 && mac_len != 8 && mac_len != 10 && mac_len != 12 && mac_len != 14 && mac_len != 16) return(FALSE); if (nonce_len < 7 || nonce_len > 13) return(FALSE); if (assoc_len > 32768 /* = 2^15 */) return(FALSE); buf = (BYTE*)malloc(payload_len + assoc_len + 48 /*Round both payload and associated data up a block size and add an extra block.*/); if (! buf) return(FALSE); // Prepare the key for usage. aes_key_setup(key_str, key, keysize); // Format the first block of the formatted data. payload_len_store_size = AES_BLOCK_SIZE - 1 - nonce_len; ccm_prepare_first_format_blk(buf, assoc_len, payload_len, payload_len_store_size, mac_len, nonce, nonce_len); end_of_buf = AES_BLOCK_SIZE; // Format the Associated Data, aka, assoc[]. ccm_format_assoc_data(buf, &end_of_buf, assoc, assoc_len); // Format the Payload, aka payload[]. ccm_format_payload_data(buf, &end_of_buf, payload, payload_len); // Create the first counter block. ccm_prepare_first_ctr_blk(counter, nonce, nonce_len, payload_len_store_size); // Perform the CBC operation with an IV of zeros on the formatted buffer to calculate the MAC. memset(temp_iv, 0, AES_BLOCK_SIZE); aes_encrypt_cbc_mac(buf, end_of_buf, mac, key, keysize, temp_iv); // Copy the Payload and MAC to the output buffer. memcpy(out, payload, payload_len); memcpy(&out[payload_len], mac, mac_len); // Encrypt the Payload with CTR mode with a counter starting at 1. memcpy(temp_iv, counter, AES_BLOCK_SIZE); increment_iv(temp_iv, AES_BLOCK_SIZE - 1 - mac_len); // Last argument is the byte size of the counting portion of the counter block. /*BUG?*/ aes_encrypt_ctr(out, payload_len, out, key, keysize, temp_iv); // Encrypt the MAC with CTR mode with a counter starting at 0. aes_encrypt_ctr(&out[payload_len], mac_len, &out[payload_len], key, keysize, counter); free(buf); *out_len = payload_len + mac_len; return(TRUE); } // plaintext_len = ciphertext_len - mac_len // Needs a flag for whether the MAC matches. int aes_decrypt_ccm(const BYTE ciphertext[], WORD ciphertext_len, const BYTE assoc[], unsigned short assoc_len, const BYTE nonce[], unsigned short nonce_len, BYTE plaintext[], WORD *plaintext_len, WORD mac_len, int *mac_auth, const BYTE key_str[], int keysize) { BYTE temp_iv[AES_BLOCK_SIZE], counter[AES_BLOCK_SIZE], mac[16], mac_buf[16], *buf; int end_of_buf, plaintext_len_store_size; WORD key[60]; if (ciphertext_len <= mac_len) return(FALSE); buf = (BYTE*)malloc(assoc_len + ciphertext_len /*ciphertext_len = plaintext_len + mac_len*/ + 48); if (! buf) return(FALSE); // Prepare the key for usage. aes_key_setup(key_str, key, keysize); // Copy the plaintext and MAC to the output buffers. *plaintext_len = ciphertext_len - mac_len; plaintext_len_store_size = AES_BLOCK_SIZE - 1 - nonce_len; memcpy(plaintext, ciphertext, *plaintext_len); memcpy(mac, &ciphertext[*plaintext_len], mac_len); // Prepare the first counter block for use in decryption. ccm_prepare_first_ctr_blk(counter, nonce, nonce_len, plaintext_len_store_size); // Decrypt the Payload with CTR mode with a counter starting at 1. memcpy(temp_iv, counter, AES_BLOCK_SIZE); increment_iv(temp_iv, AES_BLOCK_SIZE - 1 - mac_len); // (AES_BLOCK_SIZE - 1 - mac_len) is the byte size of the counting portion of the counter block. aes_decrypt_ctr(plaintext, *plaintext_len, plaintext, key, keysize, temp_iv); // Setting mac_auth to NULL disables the authentication check. if (mac_auth != NULL) { // Decrypt the MAC with CTR mode with a counter starting at 0. aes_decrypt_ctr(mac, mac_len, mac, key, keysize, counter); // Format the first block of the formatted data. plaintext_len_store_size = AES_BLOCK_SIZE - 1 - nonce_len; ccm_prepare_first_format_blk(buf, assoc_len, *plaintext_len, plaintext_len_store_size, mac_len, nonce, nonce_len); end_of_buf = AES_BLOCK_SIZE; // Format the Associated Data into the authentication buffer. ccm_format_assoc_data(buf, &end_of_buf, assoc, assoc_len); // Format the Payload into the authentication buffer. ccm_format_payload_data(buf, &end_of_buf, plaintext, *plaintext_len); // Perform the CBC operation with an IV of zeros on the formatted buffer to calculate the MAC. memset(temp_iv, 0, AES_BLOCK_SIZE); aes_encrypt_cbc_mac(buf, end_of_buf, mac_buf, key, keysize, temp_iv); // Compare the calculated MAC against the MAC embedded in the ciphertext to see if they are the same. if (! memcmp(mac, mac_buf, mac_len)) { *mac_auth = TRUE; } else { *mac_auth = FALSE; memset(plaintext, 0, *plaintext_len); } } free(buf); return(TRUE); } // Creates the first counter block. First byte is flags, then the nonce, then the incremented part. void ccm_prepare_first_ctr_blk(BYTE counter[], const BYTE nonce[], int nonce_len, int payload_len_store_size) { memset(counter, 0, AES_BLOCK_SIZE); counter[0] = (payload_len_store_size - 1) & 0x07; memcpy(&counter[1], nonce, nonce_len); } void ccm_prepare_first_format_blk(BYTE buf[], int assoc_len, int payload_len, int payload_len_store_size, int mac_len, const BYTE nonce[], int nonce_len) { // Set the flags for the first byte of the first block. buf[0] = ((((mac_len - 2) / 2) & 0x07) << 3) | ((payload_len_store_size - 1) & 0x07); if (assoc_len > 0) buf[0] += 0x40; // Format the rest of the first block, storing the nonce and the size of the payload. memcpy(&buf[1], nonce, nonce_len); memset(&buf[1 + nonce_len], 0, AES_BLOCK_SIZE - 1 - nonce_len); buf[15] = payload_len & 0x000000FF; buf[14] = (payload_len >> 8) & 0x000000FF; } void ccm_format_assoc_data(BYTE buf[], int *end_of_buf, const BYTE assoc[], int assoc_len) { int pad; buf[*end_of_buf + 1] = assoc_len & 0x00FF; buf[*end_of_buf] = (assoc_len >> 8) & 0x00FF; *end_of_buf += 2; memcpy(&buf[*end_of_buf], assoc, assoc_len); *end_of_buf += assoc_len; pad = AES_BLOCK_SIZE - (*end_of_buf % AES_BLOCK_SIZE); /*BUG?*/ memset(&buf[*end_of_buf], 0, pad); *end_of_buf += pad; } void ccm_format_payload_data(BYTE buf[], int *end_of_buf, const BYTE payload[], int payload_len) { int pad; memcpy(&buf[*end_of_buf], payload, payload_len); *end_of_buf += payload_len; pad = *end_of_buf % AES_BLOCK_SIZE; if (pad != 0) pad = AES_BLOCK_SIZE - pad; memset(&buf[*end_of_buf], 0, pad); *end_of_buf += pad; } /******************* * AES *******************/ ///////////////// // KEY EXPANSION ///////////////// // Substitutes a word using the AES S-Box. WORD SubWord(WORD word) { unsigned int result; result = (int)aes_sbox[(word >> 4) & 0x0000000F][word & 0x0000000F]; result += (int)aes_sbox[(word >> 12) & 0x0000000F][(word >> 8) & 0x0000000F] << 8; result += (int)aes_sbox[(word >> 20) & 0x0000000F][(word >> 16) & 0x0000000F] << 16; result += (int)aes_sbox[(word >> 28) & 0x0000000F][(word >> 24) & 0x0000000F] << 24; return(result); } // Performs the action of generating the keys that will be used in every round of // encryption. "key" is the user-supplied input key, "w" is the output key schedule, // "keysize" is the length in bits of "key", must be 128, 192, or 256. void aes_key_setup(const BYTE key[], WORD w[], int keysize) { int Nb=4,Nr,Nk,idx; WORD temp,Rcon[]={0x01000000,0x02000000,0x04000000,0x08000000,0x10000000,0x20000000, 0x40000000,0x80000000,0x1b000000,0x36000000,0x6c000000,0xd8000000, 0xab000000,0x4d000000,0x9a000000}; switch (keysize) { case 128: Nr = 10; Nk = 4; break; case 192: Nr = 12; Nk = 6; break; case 256: Nr = 14; Nk = 8; break; default: return; } for (idx=0; idx < Nk; ++idx) { w[idx] = ((key[4 * idx]) << 24) | ((key[4 * idx + 1]) << 16) | ((key[4 * idx + 2]) << 8) | ((key[4 * idx + 3])); } for (idx = Nk; idx < Nb * (Nr+1); ++idx) { temp = w[idx - 1]; if ((idx % Nk) == 0) temp = SubWord(KE_ROTWORD(temp)) ^ Rcon[(idx-1)/Nk]; else if (Nk > 6 && (idx % Nk) == 4) temp = SubWord(temp); w[idx] = w[idx-Nk] ^ temp; } } ///////////////// // ADD ROUND KEY ///////////////// // Performs the AddRoundKey step. Each round has its own pre-generated 16-byte key in the // form of 4 integers (the "w" array). Each integer is XOR'd by one column of the state. // Also performs the job of InvAddRoundKey(); since the function is a simple XOR process, // it is its own inverse. void AddRoundKey(BYTE state[][4], const WORD w[]) { BYTE subkey[4]; // memcpy(subkey,&w[idx],4); // Not accurate for big endian machines // Subkey 1 subkey[0] = w[0] >> 24; subkey[1] = w[0] >> 16; subkey[2] = w[0] >> 8; subkey[3] = w[0]; state[0][0] ^= subkey[0]; state[1][0] ^= subkey[1]; state[2][0] ^= subkey[2]; state[3][0] ^= subkey[3]; // Subkey 2 subkey[0] = w[1] >> 24; subkey[1] = w[1] >> 16; subkey[2] = w[1] >> 8; subkey[3] = w[1]; state[0][1] ^= subkey[0]; state[1][1] ^= subkey[1]; state[2][1] ^= subkey[2]; state[3][1] ^= subkey[3]; // Subkey 3 subkey[0] = w[2] >> 24; subkey[1] = w[2] >> 16; subkey[2] = w[2] >> 8; subkey[3] = w[2]; state[0][2] ^= subkey[0]; state[1][2] ^= subkey[1]; state[2][2] ^= subkey[2]; state[3][2] ^= subkey[3]; // Subkey 4 subkey[0] = w[3] >> 24; subkey[1] = w[3] >> 16; subkey[2] = w[3] >> 8; subkey[3] = w[3]; state[0][3] ^= subkey[0]; state[1][3] ^= subkey[1]; state[2][3] ^= subkey[2]; state[3][3] ^= subkey[3]; } ///////////////// // (Inv)SubBytes ///////////////// // Performs the SubBytes step. All bytes in the state are substituted with a // pre-calculated value from a lookup table. void SubBytes(BYTE state[][4]) { state[0][0] = aes_sbox[state[0][0] >> 4][state[0][0] & 0x0F]; state[0][1] = aes_sbox[state[0][1] >> 4][state[0][1] & 0x0F]; state[0][2] = aes_sbox[state[0][2] >> 4][state[0][2] & 0x0F]; state[0][3] = aes_sbox[state[0][3] >> 4][state[0][3] & 0x0F]; state[1][0] = aes_sbox[state[1][0] >> 4][state[1][0] & 0x0F]; state[1][1] = aes_sbox[state[1][1] >> 4][state[1][1] & 0x0F]; state[1][2] = aes_sbox[state[1][2] >> 4][state[1][2] & 0x0F]; state[1][3] = aes_sbox[state[1][3] >> 4][state[1][3] & 0x0F]; state[2][0] = aes_sbox[state[2][0] >> 4][state[2][0] & 0x0F]; state[2][1] = aes_sbox[state[2][1] >> 4][state[2][1] & 0x0F]; state[2][2] = aes_sbox[state[2][2] >> 4][state[2][2] & 0x0F]; state[2][3] = aes_sbox[state[2][3] >> 4][state[2][3] & 0x0F]; state[3][0] = aes_sbox[state[3][0] >> 4][state[3][0] & 0x0F]; state[3][1] = aes_sbox[state[3][1] >> 4][state[3][1] & 0x0F]; state[3][2] = aes_sbox[state[3][2] >> 4][state[3][2] & 0x0F]; state[3][3] = aes_sbox[state[3][3] >> 4][state[3][3] & 0x0F]; } void InvSubBytes(BYTE state[][4]) { state[0][0] = aes_invsbox[state[0][0] >> 4][state[0][0] & 0x0F]; state[0][1] = aes_invsbox[state[0][1] >> 4][state[0][1] & 0x0F]; state[0][2] = aes_invsbox[state[0][2] >> 4][state[0][2] & 0x0F]; state[0][3] = aes_invsbox[state[0][3] >> 4][state[0][3] & 0x0F]; state[1][0] = aes_invsbox[state[1][0] >> 4][state[1][0] & 0x0F]; state[1][1] = aes_invsbox[state[1][1] >> 4][state[1][1] & 0x0F]; state[1][2] = aes_invsbox[state[1][2] >> 4][state[1][2] & 0x0F]; state[1][3] = aes_invsbox[state[1][3] >> 4][state[1][3] & 0x0F]; state[2][0] = aes_invsbox[state[2][0] >> 4][state[2][0] & 0x0F]; state[2][1] = aes_invsbox[state[2][1] >> 4][state[2][1] & 0x0F]; state[2][2] = aes_invsbox[state[2][2] >> 4][state[2][2] & 0x0F]; state[2][3] = aes_invsbox[state[2][3] >> 4][state[2][3] & 0x0F]; state[3][0] = aes_invsbox[state[3][0] >> 4][state[3][0] & 0x0F]; state[3][1] = aes_invsbox[state[3][1] >> 4][state[3][1] & 0x0F]; state[3][2] = aes_invsbox[state[3][2] >> 4][state[3][2] & 0x0F]; state[3][3] = aes_invsbox[state[3][3] >> 4][state[3][3] & 0x0F]; } ///////////////// // (Inv)ShiftRows ///////////////// // Performs the ShiftRows step. All rows are shifted cylindrically to the left. void ShiftRows(BYTE state[][4]) { int t; // Shift left by 1 t = state[1][0]; state[1][0] = state[1][1]; state[1][1] = state[1][2]; state[1][2] = state[1][3]; state[1][3] = t; // Shift left by 2 t = state[2][0]; state[2][0] = state[2][2]; state[2][2] = t; t = state[2][1]; state[2][1] = state[2][3]; state[2][3] = t; // Shift left by 3 t = state[3][0]; state[3][0] = state[3][3]; state[3][3] = state[3][2]; state[3][2] = state[3][1]; state[3][1] = t; } // All rows are shifted cylindrically to the right. void InvShiftRows(BYTE state[][4]) { int t; // Shift right by 1 t = state[1][3]; state[1][3] = state[1][2]; state[1][2] = state[1][1]; state[1][1] = state[1][0]; state[1][0] = t; // Shift right by 2 t = state[2][3]; state[2][3] = state[2][1]; state[2][1] = t; t = state[2][2]; state[2][2] = state[2][0]; state[2][0] = t; // Shift right by 3 t = state[3][3]; state[3][3] = state[3][0]; state[3][0] = state[3][1]; state[3][1] = state[3][2]; state[3][2] = t; } ///////////////// // (Inv)MixColumns ///////////////// // Performs the MixColums step. The state is multiplied by itself using matrix // multiplication in a Galios Field 2^8. All multiplication is pre-computed in a table. // Addition is equivilent to XOR. (Must always make a copy of the column as the original // values will be destoyed.) void MixColumns(BYTE state[][4]) { BYTE col[4]; // Column 1 col[0] = state[0][0]; col[1] = state[1][0]; col[2] = state[2][0]; col[3] = state[3][0]; state[0][0] = gf_mul[col[0]][0]; state[0][0] ^= gf_mul[col[1]][1]; state[0][0] ^= col[2]; state[0][0] ^= col[3]; state[1][0] = col[0]; state[1][0] ^= gf_mul[col[1]][0]; state[1][0] ^= gf_mul[col[2]][1]; state[1][0] ^= col[3]; state[2][0] = col[0]; state[2][0] ^= col[1]; state[2][0] ^= gf_mul[col[2]][0]; state[2][0] ^= gf_mul[col[3]][1]; state[3][0] = gf_mul[col[0]][1]; state[3][0] ^= col[1]; state[3][0] ^= col[2]; state[3][0] ^= gf_mul[col[3]][0]; // Column 2 col[0] = state[0][1]; col[1] = state[1][1]; col[2] = state[2][1]; col[3] = state[3][1]; state[0][1] = gf_mul[col[0]][0]; state[0][1] ^= gf_mul[col[1]][1]; state[0][1] ^= col[2]; state[0][1] ^= col[3]; state[1][1] = col[0]; state[1][1] ^= gf_mul[col[1]][0]; state[1][1] ^= gf_mul[col[2]][1]; state[1][1] ^= col[3]; state[2][1] = col[0]; state[2][1] ^= col[1]; state[2][1] ^= gf_mul[col[2]][0]; state[2][1] ^= gf_mul[col[3]][1]; state[3][1] = gf_mul[col[0]][1]; state[3][1] ^= col[1]; state[3][1] ^= col[2]; state[3][1] ^= gf_mul[col[3]][0]; // Column 3 col[0] = state[0][2]; col[1] = state[1][2]; col[2] = state[2][2]; col[3] = state[3][2]; state[0][2] = gf_mul[col[0]][0]; state[0][2] ^= gf_mul[col[1]][1]; state[0][2] ^= col[2]; state[0][2] ^= col[3]; state[1][2] = col[0]; state[1][2] ^= gf_mul[col[1]][0]; state[1][2] ^= gf_mul[col[2]][1]; state[1][2] ^= col[3]; state[2][2] = col[0]; state[2][2] ^= col[1]; state[2][2] ^= gf_mul[col[2]][0]; state[2][2] ^= gf_mul[col[3]][1]; state[3][2] = gf_mul[col[0]][1]; state[3][2] ^= col[1]; state[3][2] ^= col[2]; state[3][2] ^= gf_mul[col[3]][0]; // Column 4 col[0] = state[0][3]; col[1] = state[1][3]; col[2] = state[2][3]; col[3] = state[3][3]; state[0][3] = gf_mul[col[0]][0]; state[0][3] ^= gf_mul[col[1]][1]; state[0][3] ^= col[2]; state[0][3] ^= col[3]; state[1][3] = col[0]; state[1][3] ^= gf_mul[col[1]][0]; state[1][3] ^= gf_mul[col[2]][1]; state[1][3] ^= col[3]; state[2][3] = col[0]; state[2][3] ^= col[1]; state[2][3] ^= gf_mul[col[2]][0]; state[2][3] ^= gf_mul[col[3]][1]; state[3][3] = gf_mul[col[0]][1]; state[3][3] ^= col[1]; state[3][3] ^= col[2]; state[3][3] ^= gf_mul[col[3]][0]; } void InvMixColumns(BYTE state[][4]) { BYTE col[4]; // Column 1 col[0] = state[0][0]; col[1] = state[1][0]; col[2] = state[2][0]; col[3] = state[3][0]; state[0][0] = gf_mul[col[0]][5]; state[0][0] ^= gf_mul[col[1]][3]; state[0][0] ^= gf_mul[col[2]][4]; state[0][0] ^= gf_mul[col[3]][2]; state[1][0] = gf_mul[col[0]][2]; state[1][0] ^= gf_mul[col[1]][5]; state[1][0] ^= gf_mul[col[2]][3]; state[1][0] ^= gf_mul[col[3]][4]; state[2][0] = gf_mul[col[0]][4]; state[2][0] ^= gf_mul[col[1]][2]; state[2][0] ^= gf_mul[col[2]][5]; state[2][0] ^= gf_mul[col[3]][3]; state[3][0] = gf_mul[col[0]][3]; state[3][0] ^= gf_mul[col[1]][4]; state[3][0] ^= gf_mul[col[2]][2]; state[3][0] ^= gf_mul[col[3]][5]; // Column 2 col[0] = state[0][1]; col[1] = state[1][1]; col[2] = state[2][1]; col[3] = state[3][1]; state[0][1] = gf_mul[col[0]][5]; state[0][1] ^= gf_mul[col[1]][3]; state[0][1] ^= gf_mul[col[2]][4]; state[0][1] ^= gf_mul[col[3]][2]; state[1][1] = gf_mul[col[0]][2]; state[1][1] ^= gf_mul[col[1]][5]; state[1][1] ^= gf_mul[col[2]][3]; state[1][1] ^= gf_mul[col[3]][4]; state[2][1] = gf_mul[col[0]][4]; state[2][1] ^= gf_mul[col[1]][2]; state[2][1] ^= gf_mul[col[2]][5]; state[2][1] ^= gf_mul[col[3]][3]; state[3][1] = gf_mul[col[0]][3]; state[3][1] ^= gf_mul[col[1]][4]; state[3][1] ^= gf_mul[col[2]][2]; state[3][1] ^= gf_mul[col[3]][5]; // Column 3 col[0] = state[0][2]; col[1] = state[1][2]; col[2] = state[2][2]; col[3] = state[3][2]; state[0][2] = gf_mul[col[0]][5]; state[0][2] ^= gf_mul[col[1]][3]; state[0][2] ^= gf_mul[col[2]][4]; state[0][2] ^= gf_mul[col[3]][2]; state[1][2] = gf_mul[col[0]][2]; state[1][2] ^= gf_mul[col[1]][5]; state[1][2] ^= gf_mul[col[2]][3]; state[1][2] ^= gf_mul[col[3]][4]; state[2][2] = gf_mul[col[0]][4]; state[2][2] ^= gf_mul[col[1]][2]; state[2][2] ^= gf_mul[col[2]][5]; state[2][2] ^= gf_mul[col[3]][3]; state[3][2] = gf_mul[col[0]][3]; state[3][2] ^= gf_mul[col[1]][4]; state[3][2] ^= gf_mul[col[2]][2]; state[3][2] ^= gf_mul[col[3]][5]; // Column 4 col[0] = state[0][3]; col[1] = state[1][3]; col[2] = state[2][3]; col[3] = state[3][3]; state[0][3] = gf_mul[col[0]][5]; state[0][3] ^= gf_mul[col[1]][3]; state[0][3] ^= gf_mul[col[2]][4]; state[0][3] ^= gf_mul[col[3]][2]; state[1][3] = gf_mul[col[0]][2]; state[1][3] ^= gf_mul[col[1]][5]; state[1][3] ^= gf_mul[col[2]][3]; state[1][3] ^= gf_mul[col[3]][4]; state[2][3] = gf_mul[col[0]][4]; state[2][3] ^= gf_mul[col[1]][2]; state[2][3] ^= gf_mul[col[2]][5]; state[2][3] ^= gf_mul[col[3]][3]; state[3][3] = gf_mul[col[0]][3]; state[3][3] ^= gf_mul[col[1]][4]; state[3][3] ^= gf_mul[col[2]][2]; state[3][3] ^= gf_mul[col[3]][5]; } ///////////////// // (En/De)Crypt ///////////////// void aes_encrypt(const BYTE in[], BYTE out[], const WORD key[], int keysize) { BYTE state[4][4]; // Copy input array (should be 16 bytes long) to a matrix (sequential bytes are ordered // by row, not col) called "state" for processing. // *** Implementation note: The official AES documentation references the state by // column, then row. Accessing an element in C requires row then column. Thus, all state // references in AES must have the column and row indexes reversed for C implementation. state[0][0] = in[0]; state[1][0] = in[1]; state[2][0] = in[2]; state[3][0] = in[3]; state[0][1] = in[4]; state[1][1] = in[5]; state[2][1] = in[6]; state[3][1] = in[7]; state[0][2] = in[8]; state[1][2] = in[9]; state[2][2] = in[10]; state[3][2] = in[11]; state[0][3] = in[12]; state[1][3] = in[13]; state[2][3] = in[14]; state[3][3] = in[15]; // Perform the necessary number of rounds. The round key is added first. // The last round does not perform the MixColumns step. AddRoundKey(state,&key[0]); SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[4]); SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[8]); SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[12]); SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[16]); SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[20]); SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[24]); SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[28]); SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[32]); SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[36]); if (keysize != 128) { SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[40]); SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[44]); if (keysize != 192) { SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[48]); SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[52]); SubBytes(state); ShiftRows(state); AddRoundKey(state,&key[56]); } else { SubBytes(state); ShiftRows(state); AddRoundKey(state,&key[48]); } } else { SubBytes(state); ShiftRows(state); AddRoundKey(state,&key[40]); } // Copy the state to the output array. out[0] = state[0][0]; out[1] = state[1][0]; out[2] = state[2][0]; out[3] = state[3][0]; out[4] = state[0][1]; out[5] = state[1][1]; out[6] = state[2][1]; out[7] = state[3][1]; out[8] = state[0][2]; out[9] = state[1][2]; out[10] = state[2][2]; out[11] = state[3][2]; out[12] = state[0][3]; out[13] = state[1][3]; out[14] = state[2][3]; out[15] = state[3][3]; } void aes_decrypt(const BYTE in[], BYTE out[], const WORD key[], int keysize) { BYTE state[4][4]; // Copy the input to the state. state[0][0] = in[0]; state[1][0] = in[1]; state[2][0] = in[2]; state[3][0] = in[3]; state[0][1] = in[4]; state[1][1] = in[5]; state[2][1] = in[6]; state[3][1] = in[7]; state[0][2] = in[8]; state[1][2] = in[9]; state[2][2] = in[10]; state[3][2] = in[11]; state[0][3] = in[12]; state[1][3] = in[13]; state[2][3] = in[14]; state[3][3] = in[15]; // Perform the necessary number of rounds. The round key is added first. // The last round does not perform the MixColumns step. if (keysize > 128) { if (keysize > 192) { AddRoundKey(state,&key[56]); InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[52]);InvMixColumns(state); InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[48]);InvMixColumns(state); } else { AddRoundKey(state,&key[48]); } InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[44]);InvMixColumns(state); InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[40]);InvMixColumns(state); } else { AddRoundKey(state,&key[40]); } InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[36]);InvMixColumns(state); InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[32]);InvMixColumns(state); InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[28]);InvMixColumns(state); InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[24]);InvMixColumns(state); InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[20]);InvMixColumns(state); InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[16]);InvMixColumns(state); InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[12]);InvMixColumns(state); InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[8]);InvMixColumns(state); InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[4]);InvMixColumns(state); InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[0]); // Copy the state to the output array. out[0] = state[0][0]; out[1] = state[1][0]; out[2] = state[2][0]; out[3] = state[3][0]; out[4] = state[0][1]; out[5] = state[1][1]; out[6] = state[2][1]; out[7] = state[3][1]; out[8] = state[0][2]; out[9] = state[1][2]; out[10] = state[2][2]; out[11] = state[3][2]; out[12] = state[0][3]; out[13] = state[1][3]; out[14] = state[2][3]; out[15] = state[3][3]; }
aes.h:
/********************************************************************* * Filename: aes.h * Author: Brad Conte (brad AT bradconte.com) * Copyright: * Disclaimer: This code is presented "as is" without any guarantees. * Details: Defines the API for the corresponding AES implementation. *********************************************************************/ #ifndef AES_H #define AES_H /*************************** HEADER FILES ***************************/ #include <stddef.h> /****************************** MACROS ******************************/ #define AES_BLOCK_SIZE 16 // AES operates on 16 bytes at a time /**************************** DATA TYPES ****************************/ typedef unsigned char BYTE; // 8-bit byte typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines /*********************** FUNCTION DECLARATIONS **********************/ /////////////////// // AES /////////////////// // Key setup must be done before any AES en/de-cryption functions can be used. void aes_key_setup(const BYTE key[], // The key, must be 128, 192, or 256 bits WORD w[], // Output key schedule to be used later int keysize); // Bit length of the key, 128, 192, or 256 void aes_encrypt(const BYTE in[], // 16 bytes of plaintext BYTE out[], // 16 bytes of ciphertext const WORD key[], // From the key setup int keysize); // Bit length of the key, 128, 192, or 256 void aes_decrypt(const BYTE in[], // 16 bytes of ciphertext BYTE out[], // 16 bytes of plaintext const WORD key[], // From the key setup int keysize); // Bit length of the key, 128, 192, or 256 /////////////////// // AES - CBC /////////////////// int aes_encrypt_cbc(const BYTE in[], // Plaintext size_t in_len, // Must be a multiple of AES_BLOCK_SIZE BYTE out[], // Ciphertext, same length as plaintext const WORD key[], // From the key setup int keysize, // Bit length of the key, 128, 192, or 256 const BYTE iv[]); // IV, must be AES_BLOCK_SIZE bytes long int aes_decrypt_cbc(const BYTE in[], size_t in_len, BYTE out[], const WORD key[], int keysize, const BYTE iv[]); // Only output the CBC-MAC of the input. int aes_encrypt_cbc_mac(const BYTE in[], // plaintext size_t in_len, // Must be a multiple of AES_BLOCK_SIZE BYTE out[], // Output MAC const WORD key[], // From the key setup int keysize, // Bit length of the key, 128, 192, or 256 const BYTE iv[]); // IV, must be AES_BLOCK_SIZE bytes long /////////////////// // AES - CTR /////////////////// void increment_iv(BYTE iv[], // Must be a multiple of AES_BLOCK_SIZE int counter_size); // Bytes of the IV used for counting (low end) void aes_encrypt_ctr(const BYTE in[], // Plaintext size_t in_len, // Any byte length BYTE out[], // Ciphertext, same length as plaintext const WORD key[], // From the key setup int keysize, // Bit length of the key, 128, 192, or 256 const BYTE iv[]); // IV, must be AES_BLOCK_SIZE bytes long void aes_decrypt_ctr(const BYTE in[], // Ciphertext size_t in_len, // Any byte length BYTE out[], // Plaintext, same length as ciphertext const WORD key[], // From the key setup int keysize, // Bit length of the key, 128, 192, or 256 const BYTE iv[]); // IV, must be AES_BLOCK_SIZE bytes long /////////////////// // AES - CCM /////////////////// // Returns True if the input parameters do not violate any constraint. int aes_encrypt_ccm(const BYTE plaintext[], // IN - Plaintext. WORD plaintext_len, // IN - Plaintext length. const BYTE associated_data[], // IN - Associated Data included in authentication, but not encryption. unsigned short associated_data_len, // IN - Associated Data length in bytes. const BYTE nonce[], // IN - The Nonce to be used for encryption. unsigned short nonce_len, // IN - Nonce length in bytes. BYTE ciphertext[], // OUT - Ciphertext, a concatination of the plaintext and the MAC. WORD *ciphertext_len, // OUT - The length of the ciphertext, always plaintext_len + mac_len. WORD mac_len, // IN - The desired length of the MAC, must be 4, 6, 8, 10, 12, 14, or 16. const BYTE key[], // IN - The AES key for encryption. int keysize); // IN - The length of the key in bits. Valid values are 128, 192, 256. // Returns True if the input parameters do not violate any constraint. // Use mac_auth to ensure decryption/validation was preformed correctly. // If authentication does not succeed, the plaintext is zeroed out. To overwride // this, call with mac_auth = NULL. The proper proceedure is to decrypt with // authentication enabled (mac_auth != NULL) and make a second call to that // ignores authentication explicitly if the first call failes. int aes_decrypt_ccm(const BYTE ciphertext[], // IN - Ciphertext, the concatination of encrypted plaintext and MAC. WORD ciphertext_len, // IN - Ciphertext length in bytes. const BYTE assoc[], // IN - The Associated Data, required for authentication. unsigned short assoc_len, // IN - Associated Data length in bytes. const BYTE nonce[], // IN - The Nonce to use for decryption, same one as for encryption. unsigned short nonce_len, // IN - Nonce length in bytes. BYTE plaintext[], // OUT - The plaintext that was decrypted. Will need to be large enough to hold ciphertext_len - mac_len. WORD *plaintext_len, // OUT - Length in bytes of the output plaintext, always ciphertext_len - mac_len . WORD mac_len, // IN - The length of the MAC that was calculated. int *mac_auth, // OUT - TRUE if authentication succeeded, FALSE if it did not. NULL pointer will ignore the authentication. const BYTE key[], // IN - The AES key for decryption. int keysize); // IN - The length of the key in BITS. Valid values are 128, 192, 256. #endif // AES_H
aes_util.c:
// // Created by gj21798 on 2019/10/31. // #include <stddef.h> #include <stdlib.h> #include <string.h> #include "aes.h" #include "aes_util.h" unsigned char * encrypt(const unsigned char *data, int in_len, unsigned int *out_len, const unsigned char *key, const unsigned char *iv) { if (in_len <= 0 || in_len >= MAX_LEN) { return NULL; } if (!data) { return NULL; } unsigned int rest_len = in_len % AES_BLOCK_SIZE; unsigned int padding_len = AES_BLOCK_SIZE - rest_len; unsigned int src_len = in_len + padding_len; unsigned char *input = (unsigned char *) calloc(1, src_len); memcpy(input, data, in_len); if (padding_len > 0) { // memset(input + in_len, (unsigned char) padding_len, padding_len); for (unsigned int i = 0; i < padding_len; i++) { *(input + in_len + i) = (unsigned char) padding_len; } } unsigned char *buff = (unsigned char *) calloc(1, src_len); if (!buff) { free(input); return NULL; } unsigned int key_schedule[AES_BLOCK_SIZE * 4] = {0}; aes_key_setup(key, key_schedule, AES_KEY_SIZE); aes_encrypt_cbc(input, src_len, buff, key_schedule, AES_KEY_SIZE, iv); *out_len = src_len; //内存释放 free(input); return buff; } unsigned char *decrypt(const unsigned char *data, int in_len, unsigned int *out_len, const unsigned char *key, const unsigned char *iv) { if (in_len <= 0 || in_len >= MAX_LEN) { return NULL; } if (!data) { return NULL; } unsigned int padding_len = 0; unsigned int src_len = in_len + padding_len; unsigned char *input = (unsigned char *) calloc(1, src_len); memcpy(input, data, in_len); if (padding_len > 0) { // memset(input + in_len, (unsigned char) padding_len, padding_len); for (unsigned int i = 0; i < padding_len; i++) { *(input + in_len + i) = (unsigned char) padding_len; } } unsigned char *buff = (unsigned char *) calloc(1, src_len); if (!buff) { free(input); return NULL; } unsigned int key_schedule[AES_BLOCK_SIZE * 4] = {0}; aes_key_setup(key, key_schedule, AES_KEY_SIZE); aes_decrypt_cbc(input, src_len, buff, key_schedule, AES_KEY_SIZE, iv); unsigned char *ptr = buff; ptr += (src_len - 1); padding_len = (unsigned int) *ptr; if (padding_len > 0 && padding_len <= AES_BLOCK_SIZE) { src_len -= padding_len; } *out_len = src_len; //内存释放 free(input); return buff; }
aes_util.h:
// // Created by gj21798 on 2019/10/31. // #ifndef AESWITHPUREC_AES_UTIL_H #define AESWITHPUREC_AES_UTIL_H #define MAX_LEN (2*1024*1024) #define AES_KEY_SIZE 128 unsigned char *encrypt(const unsigned char *in, int in_len, unsigned int *out_len, const unsigned char *key, const unsigned char *iv); unsigned char *decrypt(const unsigned char *in, int in_len, unsigned int *out_len, const unsigned char *key, const unsigned char *iv); #endif //AESWITHPUREC_AES_UTIL_H
aes_util_test.c:
// // Created by gj on 2019/10/31. // #include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "aes_util.h" #include "base64.h" const unsigned char KEY[16] = "0123456789ABCDEF"; const unsigned char IV[16] = { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0 }; void printBuf(const unsigned char *buf, unsigned int len) { printf("buf len :%d\n", len); for (unsigned int i = 0; i < len; i++) { printf("%02x, ", *(buf + i)); } printf("\n"); } int main(int argc, char **argv) { unsigned char in[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, }; //orig int in_len = sizeof(in); printBuf(in, in_len); //encrypt unsigned int out_len = 0; unsigned char *out = encrypt(in, in_len, &out_len, KEY, IV); printBuf(out, out_len); //base64 encode const char *b64_cipher_text = b64_encode(out, out_len); printf("base64 result:\t%s\n", b64_cipher_text); //base64 decode size_t de_size = 0; unsigned char *deb64_orig_data = b64_decode_ex(b64_cipher_text, strlen(b64_cipher_text), &de_size); //decrypt unsigned int out_len2 = 0; unsigned char *out_decrypted = decrypt(deb64_orig_data, de_size, &out_len2, KEY, IV); printBuf(out_decrypted, out_len2); free(out); free(b64_cipher_text); free(deb64_orig_data); free(out_decrypted); return EXIT_SUCCESS; }
base64.c:
// // Created by gj21798 on 2019/10/11. // #include<stdlib.h> #include <ctype.h> #include "base64.h" char *b64_encode(const unsigned char *src, size_t len) { int i = 0; int j = 0; char *enc = NULL; size_t size = 0; unsigned char buf[4]; unsigned char tmp[3]; // alloc enc = (char *) malloc(0); if (NULL == enc) { return NULL; } // parse until end of source while (len--) { // read up to 3 bytes at a time into `tmp' tmp[i++] = *(src++); // if 3 bytes read then encode into `buf' if (3 == i) { buf[0] = (tmp[0] & 0xfc) >> 2; buf[1] = ((tmp[0] & 0x03) << 4) + ((tmp[1] & 0xf0) >> 4); buf[2] = ((tmp[1] & 0x0f) << 2) + ((tmp[2] & 0xc0) >> 6); buf[3] = tmp[2] & 0x3f; // allocate 4 new byts for `enc` and // then translate each encoded buffer // part by index from the base 64 index table // into `enc' unsigned char array enc = (char *) realloc(enc, size + 4); for (i = 0; i < 4; ++i) { enc[size++] = b64_table[buf[i]]; } // reset index i = 0; } } // remainder if (i > 0) { // fill `tmp' with `\0' at most 3 times for (j = i; j < 3; ++j) { tmp[j] = '\0'; } // perform same codec as above buf[0] = (tmp[0] & 0xfc) >> 2; buf[1] = ((tmp[0] & 0x03) << 4) + ((tmp[1] & 0xf0) >> 4); buf[2] = ((tmp[1] & 0x0f) << 2) + ((tmp[2] & 0xc0) >> 6); buf[3] = tmp[2] & 0x3f; // perform same write to `enc` with new allocation for (j = 0; (j < i + 1); ++j) { enc = (char *) realloc(enc, size + 1); enc[size++] = b64_table[buf[j]]; } // while there is still a remainder // append `=' to `enc' while ((i++ < 3)) { enc = (char *) realloc(enc, size + 1); enc[size++] = '='; } } // Make sure we have enough space to add '\0' character at end. enc = (char *) realloc(enc, size + 1); enc[size] = '\0'; return enc; } unsigned char *b64_decode(const char *src, size_t len) { return b64_decode_ex(src, len, NULL); } unsigned char *b64_decode_ex(const char *src, size_t len, size_t *decsize) { int i = 0; int j = 0; int l = 0; size_t size = 0; unsigned char *dec = NULL; unsigned char buf[3]; unsigned char tmp[4]; // alloc dec = (unsigned char *) malloc(0); if (NULL == dec) { return NULL; } // parse until end of source while (len--) { // break if char is `=' or not base64 char if ('=' == src[j]) { break; } if (!(isalnum(src[j]) || '+' == src[j] || '/' == src[j])) { break; } // read up to 4 bytes at a time into `tmp' tmp[i++] = src[j++]; // if 4 bytes read then decode into `buf' if (4 == i) { // translate values in `tmp' from table for (i = 0; i < 4; ++i) { // find translation char in `b64_table' for (l = 0; l < 64; ++l) { if (tmp[i] == b64_table[l]) { tmp[i] = l; break; } } } // decode buf[0] = (tmp[0] << 2) + ((tmp[1] & 0x30) >> 4); buf[1] = ((tmp[1] & 0xf) << 4) + ((tmp[2] & 0x3c) >> 2); buf[2] = ((tmp[2] & 0x3) << 6) + tmp[3]; // write decoded buffer to `dec' dec = (unsigned char *) realloc(dec, size + 3); for (i = 0; i < 3; ++i) { dec[size++] = buf[i]; } // reset i = 0; } } // remainder if (i > 0) { // fill `tmp' with `\0' at most 4 times for (j = i; j < 4; ++j) { tmp[j] = '\0'; } // translate remainder for (j = 0; j < 4; ++j) { // find translation char in `b64_table' for (l = 0; l < 64; ++l) { if (tmp[j] == b64_table[l]) { tmp[j] = l; break; } } } // decode remainder buf[0] = (tmp[0] << 2) + ((tmp[1] & 0x30) >> 4); buf[1] = ((tmp[1] & 0xf) << 4) + ((tmp[2] & 0x3c) >> 2); buf[2] = ((tmp[2] & 0x3) << 6) + tmp[3]; // write remainer decoded buffer to `dec' dec = (unsigned char *) realloc(dec, size + (i - 1)); for (j = 0; (j < i - 1); ++j) { dec[size++] = buf[j]; } } // Make sure we have enough space to add '\0' character at end. dec = (unsigned char *) realloc(dec, size + 1); dec[size] = '\0'; // Return back the size of decoded string if demanded. if (decsize != NULL) *decsize = size; return dec; }
base64.h:
// // Created by gj21798 on 2019/10/11. // #ifndef AESWITHPUREC_BASE64_H #define AESWITHPUREC_BASE64_H #include <stdint.h> static const char b64_table[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' }; #ifdef __cplusplus extern "C" { #endif /** * Encode `unsigned char *' source with `size_t' size. * Returns a `char *' base64 encoded string. */ char * b64_encode(const unsigned char *, size_t); /** * Dencode `char *' source with `size_t' size. * Returns a `unsigned char *' base64 decoded string. */ unsigned char * b64_decode(const char *, size_t); /** * Dencode `char *' source with `size_t' size. * Returns a `unsigned char *' base64 decoded string + size of decoded string. */ unsigned char * b64_decode_ex(const char *, size_t, size_t *); #ifdef __cplusplus } #endif #endif //AESWITHPUREC_BASE64_H