text:
/*
 * Derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm
 * and modified slightly to be functionally identical but condensed into control structures.
 */

#include "md5.h"

/*
 * Constants defined by the MD5 algorithm
 */
#define A 0x67452301
#define B 0xefcdab89
#define C 0x98badcfe
#define D 0x10325476

static uint32_t S[] = {7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
                       5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20,
                       4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
                       6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21};

static uint32_t K[] = {0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
                       0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
                       0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
                       0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
                       0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
                       0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
                       0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
                       0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
                       0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
                       0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
                       0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
                       0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
                       0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
                       0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
                       0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
                       0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391};

/*
 * Bit-manipulation functions defined by the MD5 algorithm
 */
#define F(X, Y, Z) ((X & Y) | (~X & Z))
#define G(X, Y, Z) ((X & Z) | (Y & ~Z))
#define H(X, Y, Z) (X ^ Y ^ Z)
#define I(X, Y, Z) (Y ^ (X | ~Z))

/*
 * Padding used to make the size (in bits) of the input congruent to 448 mod 512
 */
static uint8_t PADDING[] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

/*
 * Initialize a context
 */
void md5Init(MD5Context *ctx){
	ctx->size = (uint64_t)0;

	ctx->buffer[0] = (uint32_t)A;
	ctx->buffer[1] = (uint32_t)B;
	ctx->buffer[2] = (uint32_t)C;
	ctx->buffer[3] = (uint32_t)D;
}

/*
 * Add some amount of input to the context
 *
 * If the input fills out a block of 512 bits, apply the algorithm (md5Step)
 * and save the result in the buffer. Also updates the overall size.
 */
void md5Update(MD5Context *ctx, uint8_t *input_buffer, size_t input_len){
	uint32_t input[16];
	unsigned int offset = ctx->size % 64;
	ctx->size += (uint64_t)input_len;

	// Copy each byte in input_buffer into the next space in our context input
	for(unsigned int i = 0; i < input_len; ++i){
		ctx->input[offset++] = (uint8_t)*(input_buffer + i);

		// If we've filled our context input, copy it into our local array input
		// then reset the offset to 0 and fill in a new buffer.
		// Every time we fill out a chunk, we run it through the algorithm
		// to enable some back and forth between cpu and i/o
		if(offset % 64 == 0){
			for(unsigned int j = 0; j < 16; ++j){
				// Convert to little-endian
				// The local variable `input` our 512-bit chunk separated into 32-bit words
				// we can use in calculations
				input[j] = (uint32_t)(ctx->input[(j * 4) + 3]) << 24 |
						   (uint32_t)(ctx->input[(j * 4) + 2]) << 16 |
						   (uint32_t)(ctx->input[(j * 4) + 1]) <<  8 |
						   (uint32_t)(ctx->input[(j * 4)]);
			}
			md5Step(ctx->buffer, input);
			offset = 0;
		}
	}
}

/*
 * Pad the current input to get to 448 bytes, append the size in bits to the very end,
 * and save the result of the final iteration into digest.
 */
void md5Finalize(MD5Context *ctx){
	uint32_t input[16];
	unsigned int offset = ctx->size % 64;
	unsigned int padding_length = offset < 56 ? 56 - offset : (56 + 64) - offset;

	// Fill in the padding andndo the changes to size that resulted from the update
	md5Update(ctx, PADDING, padding_length);
	ctx->size -= (uint64_t)padding_length;

	// Do a final update (internal to this function)
	// Last two 32-bit words are the two halves of the size (converted from bytes to bits)
	for(unsigned int j = 0; j < 14; ++j){
		input[j] = (uint32_t)(ctx->input[(j * 4) + 3]) << 24 |
		           (uint32_t)(ctx->input[(j * 4) + 2]) << 16 |
		           (uint32_t)(ctx->input[(j * 4) + 1]) <<  8 |
		           (uint32_t)(ctx->input[(j * 4)]);
	}
	input[14] = (uint32_t)(ctx->size * 8);
	input[15] = (uint32_t)((ctx->size * 8) >> 32);

	md5Step(ctx->buffer, input);

	// Move the result into digest (convert from little-endian)
	for(unsigned int i = 0; i < 4; ++i){
		ctx->digest[(i * 4) + 0] = (uint8_t)((ctx->buffer[i] & 0x000000FF));
		ctx->digest[(i * 4) + 1] = (uint8_t)((ctx->buffer[i] & 0x0000FF00) >>  8);
		ctx->digest[(i * 4) + 2] = (uint8_t)((ctx->buffer[i] & 0x00FF0000) >> 16);
		ctx->digest[(i * 4) + 3] = (uint8_t)((ctx->buffer[i] & 0xFF000000) >> 24);
	}
}

/*
 * Step on 512 bits of input with the main MD5 algorithm.
 */
void md5Step(uint32_t *buffer, uint32_t *input){
	uint32_t AA = buffer[0];
	uint32_t BB = buffer[1];
	uint32_t CC = buffer[2];
	uint32_t DD = buffer[3];

	uint32_t E;

	unsigned int j;

	for(unsigned int i = 0; i < 64; ++i){
		switch(i / 16){
			case 0:
				E = F(BB, CC, DD);
				j = i;
				break;
			case 1:
				E = G(BB, CC, DD);
				j = ((i * 5) + 1) % 16;
				break;
			case 2:
				E = H(BB, CC, DD);
				j = ((i * 3) + 5) % 16;
				break;
			default:
				E = I(BB, CC, DD);
				j = (i * 7) % 16;
				break;
		}

		uint32_t temp = DD;
		DD = CC;
		CC = BB;
		BB = BB + rotateLeft(AA + E + K[i] + input[j], S[i]);
		AA = temp;
	}

	buffer[0] += AA;
	buffer[1] += BB;
	buffer[2] += CC;
	buffer[3] += DD;
}

/*
 * Functions that will return a pointer to the hash of the provided input
 */
uint8_t* md5String(char *input){
	MD5Context ctx;
	md5Init(&ctx);
	md5Update(&ctx, (uint8_t *)input, strlen(input));
	md5Finalize(&ctx);

	uint8_t *result = malloc(16);
	memcpy(result, ctx.digest, 16);
	return result;
}

uint8_t* md5File(FILE *file){
	char *input_buffer = malloc(1024);
	size_t input_size = 0;

	MD5Context ctx;
	md5Init(&ctx);

	while((input_size = fread(input_buffer, 1, 1024, file)) > 0){
		md5Update(&ctx, (uint8_t *)input_buffer, input_size);
	}

	md5Finalize(&ctx);

	free(input_buffer);

	uint8_t *result = malloc(16);
	memcpy(result, ctx.digest, 16);
	return result;
}

/*
 * Rotates a 32-bit word left by n bits
 */
uint32_t rotateLeft(uint32_t x, uint32_t n){
	return (x << n) | (x >> (32 - n));
}


text:
/*********************************************************************
* 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 DEBUGGING FUNCTIONS
*******************/
/*
// This prints the "state" grid as a linear hex string.
void print_state(BYTE state[][4])
{
	int idx,idx2;

	for (idx=0; idx < 4; idx++)
		for (idx2=0; idx2 < 4; idx2++)
			printf("%02x",state[idx2][idx]);
	printf("\n");
}

// This prints the key (4 consecutive ints) used for a given round as a linear hex string.
void print_rnd_key(WORD key[])
{
	int idx;

	for (idx=0; idx < 4; idx++)
		printf("%08x",key[idx]);
	printf("\n");
}
*/

repo_name: LiEnby/psse-decrypt

repo_language: C

mime_type: text/x-c


text:
/*********************************************************************
* 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

// 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.

///////////////////
// Test functions
///////////////////
int aes_test();
int aes_ecb_test();
int aes_cbc_test();
int aes_ctr_test();
int aes_ccm_test();

#include "aes.c"

#endif   // AES_H


text:
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>

#include "aes.h"
#include "md5.c"

#ifdef MAX_PATH
#ifndef PATH_MAX
#define PATH_MAX MAX_PATH
#endif
#else
#ifndef PATH_MAX
#define PATH_MAX (0x7FFF)
#endif
#endif

#define DEBUG 1

#define PSSE_BLOCK_SIZE (0x8000)
#define PSSE_SIG_BLOCK_SIZE (0x80000)
#define PSSE_SIG_SIZE (0x400)

#define AES_KEY_SIZE (0x10)
#define AES_IV_SIZE (0x10)

const uint8_t header_iv[AES_IV_SIZE]			=	{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}; // IV for the encrypted PSSE Header
const uint8_t header_key[AES_KEY_SIZE]			=	{0x4E, 0x29, 0x8B, 0x40, 0xF5, 0x31, 0xF4, 0x69, 0xD2, 0x1F, 0x75, 0xB1, 0x33, 0xC3, 0x07, 0xBE}; // Key used to decrypt the encrypted PSSE Header

const uint8_t runtime_title_key[AES_KEY_SIZE]	=	{0xA8, 0x69, 0x3C, 0x4D, 0xF0, 0xAE, 0xED, 0xBC, 0x9A, 0xBF, 0xD8, 0x21, 0x36, 0x92, 0x91, 0x2D}; // Header used to decrypt runtime libaries, eg. Sce.PlayStation.Core.dll.
const uint8_t header_key_psmdev[AES_KEY_SIZE]	=	{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}; // Key used to decrypt the encrypted PSSE Header in PSM dev,

const char* runtime_content_id			=	"IP9100-NPXS10074_00-0000000000000000";

static char title_content_id[0x30];
static uint8_t title_iv[AES_IV_SIZE];
static uint8_t title_key[AES_KEY_SIZE];

// psse header
typedef struct psse_header{
	char     magic[0x4];
	uint32_t version;
	uint64_t file_size;
	uint32_t psse_type;
	char     content_id[0x2C];
	uint8_t  md5_hash[0x10];
	uint8_t  file_name[0x20];
	uint8_t  file_iv[0x10];
	uint8_t  unk[0x600];
} psse_header;

// rif header
typedef struct ScePsmDrmLicense {
  char magic[0x8];
  uint32_t unk1;
  uint32_t unk2;
  uint64_t account_id;
  uint32_t unk3;
  uint32_t unk4;
  uint64_t start_time;
  uint64_t expiration_time;
  uint8_t activation_checksum[0x20];
  char content_id[0x30];
  uint8_t unk5[0x80];
  uint8_t unk6[0x20];
  uint8_t key[0x10];
  uint8_t signature[0x1D0];
  uint8_t rsa_signature[0x100];
} ScePsmDrmLicense;

// psse_block_ref struct
typedef struct psse_block_ref{
	uint8_t block_data[PSSE_BLOCK_SIZE];
	size_t block_size;
} psse_block_ref;

typedef struct decrypted_file{
	uint8_t* data;
	size_t file_size;
} decrypted_file;

// Debug print buffer contents
void print_buffer(char* buffer_title, uint8_t* buffer, size_t buffer_sz){
	printf("[*] %s: ", buffer_title);
	for(int i = 0; i < buffer_sz; i++) {
		printf("%02X", buffer[i]);
	}
	printf("\n");
}

// Convert a path to one for whatever OS your using.
void fix_paths(char* path){
	size_t sz = strlen(path);
	for(int i = 0; i < sz; i++){
		#ifdef _WIN32
		if(path[i] == '/')
		#else
		if(path[i] == '\\')
		#endif
		{
			#ifdef _WIN32
			path[i] = '\\';
			#else
			path[i] = '/';
			#endif
		}
	}
}

// Convert a path to one for whatever OS your using.
int is_dir(char* path){
	size_t sz = strlen(path);
	if(path[sz] == '/' || path[sz] == '\\')
		return 1;
	return 0;
}

// Reads title key and content id from a rif
// returns <0 on fail, 0 on success.
int read_rif(char* rif_path){
	ScePsmDrmLicense rif;

	FILE* rif_fd = fopen(rif_path, "rb");
	if(rif_fd == NULL){
		return -1;
	}
	fread(&rif, sizeof(ScePsmDrmLicense), 1, rif_fd);
	fclose(rif_fd);

	// Read important stuff.
	strncpy(title_content_id, rif.content_id, sizeof(title_content_id));
	memcpy(title_key, rif.key, sizeof(title_key));

	if(strlen(title_content_id) != 0x24){
		return -2;
	}

	return 0x0;
}

// Returns the total filesize of a file.
size_t get_file_size(char* file_path){
	FILE* get_size_fd = fopen(file_path, "rb");
	fseek(get_size_fd, 0, SEEK_END);
	size_t size = ftell(get_size_fd);
	fclose(get_size_fd);
	return size;
}

// Calculate IV for this block.
uint8_t* roll_iv(uint64_t block_id) {
	uint8_t* new_iv = (uint8_t*)malloc(sizeof(title_iv));

	memset(new_iv,0x00, sizeof(title_iv));
	memcpy(new_iv, &block_id, sizeof(uint64_t));
	for(int i = 0; i < sizeof(title_iv); i++){
		new_iv[i] = new_iv[i] ^ title_iv[i];
	}
	return new_iv;
}

// Decrypts a specific block inside a PSSE file.
psse_block_ref decrypt_block(FILE* psse_file, uint64_t block_id, uint64_t total_blocks, uint32_t file_size){
	psse_block_ref ref;
	memset(&ref, 0x00, sizeof(psse_block_ref));

	uint8_t* new_iv = roll_iv(block_id);
	uint64_t block_loc = block_id * PSSE_BLOCK_SIZE;
    size_t total_read = PSSE_BLOCK_SIZE;
    uint64_t trim_to = total_read;

    if(block_id == 0){  // Skip to filedata
        block_loc = sizeof(psse_header);
        total_read -= sizeof(psse_header);
        trim_to = total_read;
	}
    else if(block_loc % PSSE_SIG_BLOCK_SIZE == 0){ // Skip signature block
        block_loc += PSSE_SIG_SIZE;
        total_read -= PSSE_SIG_SIZE;
        trim_to = total_read;
	}

    uint64_t rd_amt = ((block_loc - sizeof(psse_header)) - (PSSE_SIG_SIZE*(block_loc / PSSE_SIG_BLOCK_SIZE))); // Total amount of bytes read so far.

    if (block_id >= total_blocks) { // Is this the last block?
        total_read = file_size - rd_amt;
        trim_to = total_read;
        total_read += ((AES_BLOCK_SIZE) - (total_read % (AES_BLOCK_SIZE)));
	}

	uint8_t* block_data = malloc(total_read);

    fseek(psse_file, block_loc, SEEK_SET);
	fread(block_data, total_read, 0x1, psse_file);
	ref.block_size = trim_to;

	// Decrypt block
	uint32_t aes_game_ctx[0x3C];
	aes_key_setup(title_key, aes_game_ctx, 0x80);
	aes_decrypt_cbc(block_data, total_read, ref.block_data, aes_game_ctx, 0x80, new_iv);

	free(block_data);
	free(new_iv);
	return ref;
}

// returns decrypted data on success, empty filesize on error
decrypted_file decrypt_file(char* psse_file){
	size_t total_filesize = get_file_size(psse_file);
	uint64_t total_blocks = (total_filesize / 0x8000);

	uint8_t title_key_copy[sizeof(title_key)];

	uint32_t aes_header_ctx[0x3C];

	FILE* psse_file_fd = fopen(psse_file, "rb");

	decrypted_file plaintext_file;
	memset(&plaintext_file, 0x00, sizeof(decrypted_file));

	psse_header file_psse_header;
	memset(&file_psse_header, 0x00, sizeof(psse_header));
	fread(&file_psse_header, sizeof(psse_header), 0x1, psse_file_fd);

	#ifdef DEBUG
		printf("[*] Decrypting: %s\n", psse_file);
	#endif

	// Check magic number
	if(!((strncmp(file_psse_header.magic, "PSSE", 0x4) == 0) || (strncmp(file_psse_header.magic, "PSME", 0x4) == 0))){
		#ifdef DEBUG
				printf("[*] %s Is not a valid PSSE file.\n", psse_file);
		#endif
		return plaintext_file;
	}

	// Chceck version
	if(file_psse_header.version != 0x01){
		#ifdef DEBUG
				printf("[*] %s has unknown PSSE version %i.\n", psse_file, file_psse_header.version);
		#endif
		return plaintext_file;
	}

	// Check psse type
	if(file_psse_header.psse_type != 0x01){
		#ifdef DEBUG
				printf("[*] %s has unknown PSSE type %i.\n", psse_file, file_psse_header.version);
		#endif
		return plaintext_file;
	}

	int psm_dev = 0;

	// Check content id
	if(strlen(file_psse_header.content_id) == 0x24) {
		if(strcmp(file_psse_header.content_id, title_content_id) == 0){ // Retail PSM
			aes_key_setup(header_key, aes_header_ctx, 0x80);
		}
		else if(strcmp(file_psse_header.content_id, runtime_content_id)){ // Runtime Libary
			memcpy(title_key_copy, title_key, sizeof(title_key));
			memcpy(title_key, runtime_title_key, sizeof(title_key));
			aes_key_setup(header_key, aes_header_ctx, 0x80);
			psm_dev = 1;
		}
		else{
			return plaintext_file;
		}
	}
	else { // Debug PSM
		aes_key_setup(header_key_psmdev, aes_header_ctx, 0x80);
	}

	aes_decrypt_cbc(file_psse_header.file_iv, sizeof(title_iv), title_iv, aes_header_ctx, 0x80, header_iv);

	char* plaintext = malloc(file_psse_header.file_size);
	uintptr_t plaintext_ptr = 0;

	MD5Context md5_ctx;
	md5Init(&md5_ctx);

	for(int i = 0; i <= total_blocks; i++){
		psse_block_ref block_ref = decrypt_block(psse_file_fd, i, total_blocks, file_psse_header.file_size);

		md5Update(&md5_ctx, block_ref.block_data, block_ref.block_size);

		memcpy(plaintext+plaintext_ptr, block_ref.block_data, block_ref.block_size);
		plaintext_ptr += block_ref.block_size;
	}

	md5Finalize(&md5_ctx);

	if(memcmp(file_psse_header.md5_hash, md5_ctx.digest, 0x10) != 0){
		#ifdef DEBUG
			printf("[*] MD5 Hash did not match expected.\n");
			print_buffer("Got MD5", md5_ctx.digest, 0x10);
			print_buffer("Expected MD5", file_psse_header.md5_hash, 0x10);
		#endif
		return plaintext_file;
	}

	fclose(psse_file_fd);

	plaintext_file.data = plaintext;
	plaintext_file.file_size = file_psse_header.file_size;

	if(psm_dev){
		memcpy(title_key, title_key_copy, sizeof(title_key));
	}

	return plaintext_file;
}

int decrypt_all_files(char* application_folder, char* psse_list, size_t psse_list_sz){
	uint64_t start_point = 0;
	size_t sz = 0;

	char rel_path[PATH_MAX];
	for(uint64_t i = 0; i < psse_list_sz; i++){

		if(psse_list[i] == '\r' || psse_list[i] == '\n') {

			if (sz == 0){
				goto next;
			}

			char* cur_filename = (char*)malloc(sz+1);
			memset(cur_filename, 0x00, sz+1);
			strncpy(cur_filename, (psse_list+start_point), sz);

			memset(rel_path, 0x00, sizeof(rel_path));
			snprintf(rel_path, sizeof(rel_path), "%s\\%s", application_folder, cur_filename);
			free(cur_filename);

			fix_paths(rel_path);

			if(is_dir(rel_path)){
				goto next;
			}

			decrypted_file dec_file = decrypt_file(rel_path);

			if(dec_file.data == NULL){
				#ifdef DEBUG
					printf("[*] Decryption failed.\n");
				#endif
				return -3;
			}

			// Write decrypted file to disk.
			FILE* dec_file_fd = fopen(rel_path, "wb");
			if(dec_file_fd == NULL){
				#ifdef DEBUG
					printf("[*] Failed to open %s for writing.\n", rel_path);
				#endif
				return -4;
			}
			fwrite(dec_file.data, dec_file.file_size, 0x1, dec_file_fd);
			fclose(dec_file_fd);

			free(dec_file.data);

			next:
			start_point = i+1;
			sz = 0;
			continue;
		}
		sz++;
	}
}

int main(int argc, char** argv)
{
	memset(title_content_id, 0x00, sizeof(title_content_id));
	memset(title_iv, 0x00, sizeof(title_iv));
	memset(title_key, 0x00, sizeof(title_key));

	if(argc <= 1){
		printf("PSSE Decryptor.\n");
		printf("Created by Li / SilicaAndPina ..\n");
		printf("Usage: %s <PSM_FOLDER>\n",argv[0]);
		return 0;
	}

	char* psm_folder = argv[1];

	char application_folder[PATH_MAX];
	char psse_list[PATH_MAX];
	char rif_file[PATH_MAX];

	snprintf(application_folder, (PATH_MAX-1), "%s\\RO\\Application", psm_folder);
	snprintf(psse_list, (PATH_MAX-1), "%s\\psse.list", application_folder);
	snprintf(rif_file, (PATH_MAX-1), "%s\\RO\\License\\FAKE.rif", psm_folder);

	fix_paths(application_folder);
	fix_paths(psse_list);
	fix_paths(rif_file);

	if(read_rif(rif_file) < 0){
		printf("[*] Unable to read RIF: %s\n", rif_file);
		return -1;
	}
	#ifdef DEBUG
		print_buffer("[*] Title Key", title_key, sizeof(title_key));
	#endif

	decrypted_file plaintext_psse_list = decrypt_file(psse_list);
	if(plaintext_psse_list.data == NULL){
		printf("[*] Decryption failed.\n");
		return -2;
	}

	// Write decrypted psse.list.
	FILE* psse_list_fd = fopen(psse_list, "wb");
	fwrite(plaintext_psse_list.data, plaintext_psse_list.file_size, 0x1, psse_list_fd);
	fclose(psse_list_fd);

	int res = decrypt_all_files(application_folder, plaintext_psse_list.data, plaintext_psse_list.file_size);
	if (res < 0){
		return res;
	}
	free(plaintext_psse_list.data);
}


text:
A simple statistical profiler which outputs in format suitable for FlameGraph_.

INSTALL:
--------

Simply run::

  pip install git+https://github.com/evanhempel/python-flamegraph.git

USAGE:
------

Run your script under the profiler::

  python -m flamegraph -o perf.log myscript.py --your-script args here

Or, run the profiler from your script::

  flamegraph.start_profile_thread(fd=open("./perf.log", "w"))

Run Brendan Gregg's FlameGraph_ tool against the output::

  flamegraph.pl --title "MyScript CPU" perf.log > perf.svg

Enjoy the output:

.. image:: docs/attic-create.png
  :alt: Attic create flame graph
  :width: 679
  :height: 781
  :align: center

**Filtering**

Sometimes you may want to exclude a method
(for example in a server the method that waits for a new request)
or you may want to profile only a subset of your code
(a particular method and its children which are performance critical).

Filtering can be done by passing a python regular expression to the
``-f`` or ``--filter`` command line option
which will restrict output to only those lines which match.
Filtering is done against the entire line so you can filter by
function name, thread name, both, or even by
more complex filters such as function ABC calls DEF (``ABC.*DEF``).

Alternatively since the output is stackframes each on a line by itself,
this can simply be done with a simple grep filter.::

    Exclude:

      grep -v waiting_method perf.log > removed_waiting.log

    Include:

      grep function_name perf.log > filtered.log

Then run the flamegraph.pl script against the filtered file.

.. figure:: docs/ycanta-full.png
  :alt: yCanta webapp full profile of PDF export
  :align: center

  Full profile output of yCanta_ webapp PDF export.  Most time is
  spent in wait state and graph is not very helpful.

.. figure:: docs/ycanta-pdf.png
  :alt: yCanta webapp filtered for PDF export format function.
  :align: center

  Filtered profile output of yCanta_ webapp PDF export.  Filtering was on the
  pdf format function so time spent in wait state has been excluded and the
  graph is now helpful.

.. _FlameGraph: http://www.brendangregg.com/flamegraphs.html

.. _yCanta: https://github.com/yCanta/yCanta

repo_name: evanhempel/python-flamegraph

repo_language: Python

mime_type: text/plain


text:
"""
Example usage of flamegraph.

To view a flamegraph run these commands:
$ python example.py
$ flamegraph.pl perf.log > perf.svg
$ inkview perf.svg
"""

import time
import sys
import flamegraph

def foo():
    time.sleep(.1)
    bar()

def bar():
    time.sleep(.05)

if __name__ == "__main__":
    flamegraph.start_profile_thread(fd=open("./perf.log", "w"))

    N = 10
    for x in xrange(N):
        print "{}/{}".format(x, N)
        foo()


text:
from setuptools import setup
setup(
    name = "flamegraph",
    version = "0.1",
    packages = ['flamegraph'],

    author = 'Evan Hempel',
    author_email = 'evanhempel@evanhempel.com',
    description = 'Statistical profiler which outputs in format suitable for FlameGraph',
    long_description = open('README.rst').read(),
    license = 'UNLICENSE',
    keywords = 'profiler flamegraph',
    url = 'https://github.com/evanhempel/python-flamegraph',
    classifiers=[
      'Development Status :: 3 - Alpha',
      'Environment :: Console',
      'Intended Audience :: Developers',
      'License :: Public Domain',
      'Programming Language :: Python',
      'Topic :: Software Development :: Debuggers',
      ]
    )


text: from .flamegraph import start_profile_thread, ProfileThread


text:
import re
import sys
import time
import os.path
import argparse
import threading
import traceback
import collections
import atexit
import functools

def get_thread_name(ident):
  for th in threading.enumerate():
    if th.ident == ident:
      return th.getName()
  return str(ident) # couldn't find, return something useful anyways

def default_format_entry(threadname, fname, line, fun, fmt='%(threadname)s`%(fun)s'):
  return fmt % locals()

def create_flamegraph_entry(thread_id, frame, format_entry, collapse_recursion=False):
  threadname = get_thread_name(thread_id)

  # [1:] to skip first frame which is in this program
  if collapse_recursion:
    ret = []
    last = None
    for fn, ln, fun, text in traceback.extract_stack(frame)[1:]:
      if last != fun:
        ret.append(format_entry(threadname, fn, ln, fun))
      last = fun
    return ';'.join(ret)

  return ';'.join(format_entry(threadname, fn, ln, fun)
      for fn, ln, fun, text in traceback.extract_stack(frame)[1:])

class ProfileThread(threading.Thread):
  def __init__(self, fd, interval, filter, format_entry, collapse_recursion=False):
    threading.Thread.__init__(self, name="FlameGraph Thread")
    self.daemon = True

    self._lock = threading.Lock()
    self._fd = fd
    self._written = False
    self._interval = interval
    self._format_entry = format_entry
    self._collapse_recursion = collapse_recursion
    if filter is not None:
      self._filter = re.compile(filter)
    else:
      self._filter = None

    self._stats = collections.defaultdict(int)

    self._keeprunning = True
    self._stopevent = threading.Event()

    atexit.register(self.stop)

  def run(self):
    my_thread = threading.current_thread().ident
    while self._keeprunning:
      for thread_id, frame in sys._current_frames().items():
        if thread_id == my_thread:
          continue

        entry = create_flamegraph_entry(thread_id, frame, self._format_entry, self._collapse_recursion)
        if self._filter is None or self._filter.search(entry):
          with self._lock:
            self._stats[entry] += 1

        self._stopevent.wait(self._interval)  # basically a sleep for x seconds unless someone asked to stop

    self._write_results()

  def _write_results(self):
    with self._lock:
      if self._written:
        return
      self._written = True
      for key in sorted(self._stats.keys()):
        self._fd.write('%s %d\n' % (key, self._stats[key]))
      self._fd.close()

  def num_frames(self, unique=False):
    if unique:
      return len(self._stats)
    else:
      return sum(self._stats.values())

  def stop(self):
    self._keeprunning = False
    self._stopevent.set()
    self._write_results()
    # Wait for the thread to actually stop.
    # Using atexit without this line can result in the interpreter shutting
    # down while the thread is alive, raising an exception.
    self.join()

def start_profile_thread(fd, interval=0.001, filter=None, format_entry=default_format_entry, collapse_recursion=False):
  """Start a profiler thread."""
  profile_thread = ProfileThread(
    fd=fd,
    interval=interval,
    filter=filter,
    format_entry=format_entry,
    collapse_recursion=collapse_recursion)
  profile_thread.start()
  return profile_thread

def main():
  parser = argparse.ArgumentParser(prog='python -m flamegraph', description="Sample python stack frames for use with FlameGraph")
  parser.add_argument('script_file', metavar='script.py', type=str,
      help='Script to profile')
  parser.add_argument('script_args', metavar='[arguments...]', type=str, nargs=argparse.REMAINDER,
      help='Arguments for script')
  parser.add_argument('-o', '--output', nargs='?', type=argparse.FileType('w'), default=sys.stderr,
      help='Save stats to file. If not specified default is to stderr')
  parser.add_argument('-i', '--interval', type=float, nargs='?', default=0.001,
      help='Interval in seconds for collection of stackframes (default: %(default)ss)')
  parser.add_argument('-c', '--collapse-recursion', action='store_true',
      help='Collapse simple recursion (function calls itself) into one stack frame in output')
  parser.add_argument('-f', '--filter', type=str, nargs='?', default=None,
      help='Regular expression to filter which stack frames are profiled.  The '
      'regular expression is run against each entire line of output so you can '
      'filter by function or thread or both.')
  parser.add_argument('-F', '--format', type=str, nargs='?', default='%(threadname)s`%(fun)s',
      help='Format-string (old-style) for encoding each stack frame into text.'
      ' May include: "threadname", "fname", "fun" and "line"')

  args = parser.parse_args()
  print(args)

  format_entry = functools.partial(default_format_entry, fmt=args.format)
  thread = ProfileThread(args.output, args.interval, args.filter, format_entry, args.collapse_recursion)

  if not os.path.isfile(args.script_file):
    parser.error('Script file does not exist: ' + args.script_file)

  sys.argv = [args.script_file] + args.script_args
  sys.path.insert(0, os.path.dirname(args.script_file))
  script_compiled = compile(open(args.script_file, 'rb').read(), args.script_file, 'exec')
  script_globals = {'__name__': '__main__', '__file__': args.script_file, '__package__': None}

  start_time = time.clock()
  thread.start()

  try:
    # exec docs say globals and locals should be same dictionary else treated as class context
    exec(script_compiled, script_globals, script_globals)
  finally:
    thread.stop()
    thread.join()
    print('Elapsed Time: %2.2f seconds.  Collected %d stack frames (%d unique)'
        % (time.clock() - start_time, thread.num_frames(), thread.num_frames(unique=True)))

if __name__ == '__main__':
  main()


text:
from __future__ import absolute_import
from flamegraph import flamegraph
if __name__ == '__main__':
  flamegraph.main()


text:
# .NET 3.5 Feature Installer for Windows 10 x86/x64

* Standalone Offline Installer to enable (install .NET Framework 3.5 feature for Windows 10

* Windows 10 images already contain language resources for .NET 3.5
this is basically an AIO for microsoft-windows-netfx3-ondemand-package.cab for both architectures.

* Important: only/best workable on a freshly installed system with no updates applied.

* Usage:
- Run as administrator
- Click Next to begin the process
- Wait for the extraction process to complete
- Wait for the installation/adding process to complete

* Command line switches:
```
/ai
Passive mode, shows operation progress but requires no user interaction.

/ais
Quiet mode, no user input required, only extraction dialog is shown.

/ais /gm2
Silent mode, no user input required or any output shown.
```

* Note: NET35.cmd needs to be updated for each new Windows 10 build.

* Credits for the GUI module by [ricktendo64](https://forums.mydigitallife.net/members/28038/).

* Older releases:

- [Windows 10 builds 18362/17763/17134](https://github.com/abbodi1406/dotNetFx35W10/releases/tag/v0.19.03)

- Windows 10 builds 17134/16299/15063/14393
```
   File: dotNetFx35_WX_6_x86_x64.exe
  SHA-1: f52a6aee447d39f35dace3d15f76d39019c65bec
SHA-256: 3960b5cdcca5fb378bd3616170ced0f0dd39707513f2fa8e82e9c71b62002d8d
```

(https://drive.google.com/open?id=13udwgPrbRSsiZKfrdXddTmeMhJG7bcgL)
(https://mega.nz/#!H403xDqb!CHdgLmDI5zVJywIKRjlZMvRVowYsZkMzoO-sdFe2sW0)

switches:
```
Automatically install the package and display progress:
dotNetFx35_WX_6_x86_x64.exe /SILENT /NORESTART

Silently install the package and display no progress:
dotNetFx35_WX_6_x86_x64.exe /VERYSILENT /NORESTART
```

repo_language: Batchfile


text:
@echo off
set "SysPath=%Windir%\System32"
if exist "%Windir%\Sysnative\reg.exe" set "SysPath=%Windir%\Sysnative"
set "Path=%SysPath%;%Windir%;%SysPath%\Wbem"
for /f "tokens=6 delims=[]. " %%G in ('ver') do set winbuild=%%G
if %winbuild% LSS 10240 (
  if not "%1"=="" goto :eof
  echo ==== ERROR ====
  echo This package is only for Windows 10
  echo Press any Key to Exit.
  pause >nul
  goto :eof
)
set arch=x64
if /i "%PROCESSOR_ARCHITECTURE%"=="x86" (
if "%PROCESSOR_ARCHITEW6432%"=="" set arch=x86
)
cd /d "%~dp0"
if %winbuild% LSS 17763 (
set "source=%arch%\17763\update.mum"
)
if %winbuild% GEQ 17763 (
set "source=%arch%\17763\update.mum"
)
if %winbuild% GEQ 18362 (
set "source=%arch%\18362\update.mum"
)
if %winbuild% GEQ 19041 (
set "source=%arch%\19041\update.mum"
)
echo.
DISM.exe /Online /NoRestart /Add-Package /PackagePath:"%source%"
echo.
echo ============================================================
echo.
if not "%1"=="" goto :eof
echo Press any Key to Exit.
pause >nul
goto :eof


text:
;!@Install@!UTF-8!
GUIMode="0"
GUIFlags="2+4+8+16+32+2048+4096"
MiscFlags="4"

SetEnvironment="product=.NET Framework 3.5"
Title="Microsoft %product% Setup"
InstallPath="%SystemDrive%\\NET35WX5"
Delete="%SystemDrive%\\NET35WX5"

;Default Full with install prompt
RunProgram="NET35.cmd"

;[/ai | SHIFT] Passive
AutoInstall="NET35.cmd u"

;[/ais] Silent
AutoInstalls="hidcon:NET35.cmd s"

;Setup dialogs
BeginPrompt="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs30\lang9 %product% Setup\par\fs16\par\par\par
This will install %product% (includes .NET 2.0 and 3.0) feature for Windows 10.\par\par
Supports Windows 10 version 1809 and later.\par}"

CancelPrompt="Are you sure you want to cancel?"

ExtractTitle="Extracting files"
ExtractDialogText="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs18\lang9 Preparing:\par}"

FinishMessage="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs30\lang9 Setup Is Complete\par\fs16\par\par\par
%product% has been processed.\par}"

HelpText="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs18\lang9 Usage:\tab %%M [switches]\par
\tab All switches are optional.\par\par
/ai - Passive mode, shows operation progress but requires no user interaction.\par\par
/ais - Quiet mode, no user input required, only extraction dialog is shown.\par\par
/ais /gm2 - Silent mode, no user input required or any output shown.\par\par
/h | /? - Display this help.\par\par
Examples:\par\par
Automatically install the package and display progress:\par
%%M /ai\par\par
Silently install the package and display no progress:\par
%%M /ais /gm2\par\par
(c) Microsoft Corporation. All Rights Reserved.\par}"
;!@InstallEnd@!

;!@Install@!UTF-8:Language:1025!
CancelPrompt="هل تريد بالتأكيد الإلغاء؟"
ExtractTitle="يتم الآن استخراج الملفات"
ExtractDialogText="{\rtf1\fbidis\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset178 Tahoma;}{\f1\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\ltrpar\sl240\slmult1\f0\rtlch\fs18\lang1025 يتم الآن التحضير\f1\ltrch\lang1033 :\lang9\par}"
FinishMessage="{\rtf1\fbidis\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset178 Tahoma;}{\f1\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\ltrpar\sl240\slmult1\f0\rtlch\fs30\lang1025 اكتمل التثبيت\par\fs16\par\par\par
تم تثبيت\f1\ltrch\lang1033  %product%\lang9\par}"
;!@InstallEnd@:Language:1025!

;!@Install@!UTF-8:Language:1028!
CancelPrompt="您確定要取消嗎?"
ExtractTitle="正在解壓縮檔案"
ExtractDialogText="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\froman\fprq2\fcharset136 PMingLiU;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs18\lang1028 正在準備:\par}"
FinishMessage="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\froman\fprq2\fcharset136 PMingLiU;}{\f1\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs30\lang1028 安裝完成\par\fs16\par\par\par
\f1 %product%\f0  安裝完成。\par}"
;!@InstallEnd@:Language:1028!

;!@Install@!UTF-8:Language:1029!
CancelPrompt="Opravdu chcete akci zrušit?"
ExtractTitle="Extrahování souborů"
ExtractDialogText="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}{\f1\fnil\fcharset238 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs18\lang9 P\f1 ř\f0 íprava:\par}"
FinishMessage="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}{\f1\fnil\fcharset238 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs30\lang9 Instalace byla dokon\f1 č\f0 ena\par\fs16\par\par\par
Produkt %product% byl nainstalován.\par}"
;!@InstallEnd@:Language:1029!

;!@Install@!UTF-8:Language:1030!
CancelPrompt="Er du sikker på, at du vil annullere?"
ExtractTitle="Udpakker filer"
ExtractDialogText="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs18\lang9 Forbereder:\par}"
FinishMessage="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs30\lang9 Installationen er fuldført\par\fs16\par\par\par
%product% er installeret.\par}"
;!@InstallEnd@:Language:1030!

;!@Install@!UTF-8:Language:1031!
CancelPrompt="Möchten Sie den Vorgang wirklich abbrechen?"
ExtractTitle="Dateien werden extrahiert..."
ExtractDialogText="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs18\lang9 Vorgang wird vorbereitet:\par}"
FinishMessage="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs30\lang9 Die Installation ist abgeschlossen.\par\fs16\par\par\par
%product% wurde installiert.\par}"
;!@InstallEnd@:Language:1031!

;!@Install@!UTF-8:Language:1032!
CancelPrompt="Είστε βέβαιοι ότι θέλετε να ακυρώσετε;"
ExtractTitle="Εξαγωγή αρχείων"
ExtractDialogText="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset161 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs18\lang1032 Προετοιμασία:\par}"
FinishMessage="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset161 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs30\lang1032 Η εγκατάσταση ολοκληρώθηκε\par\fs16\par\par\par
Η εγκατάσταση του %product% ολοκληρώθηκε.\par}"
;!@InstallEnd@:Language:1032!

;!@Install@!UTF-8:Language:1033!
;!@InstallEnd@:Language:1033!

;!@Install@!UTF-8:Language:1035!
CancelPrompt="Haluatko varmasti peruuttaa?"
ExtractTitle="Puretaan tiedostoja"
ExtractDialogText="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs18\lang9 Valmistellaan:\par}"
FinishMessage="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs30\lang9 Asennus on valmis\par\fs16\par\par\par
%product% on asennettu.\par}"
;!@InstallEnd@:Language:1035!

;!@Install@!UTF-8:Language:1036!
CancelPrompt="Voulez-vous vraiment annuler ?"
ExtractTitle="Extraction des fichiers"
ExtractDialogText="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs18\lang9 En cours de préparation :\par}"
FinishMessage="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs30\lang9 Installation terminée\par\fs16\par\par\par
%product% a été installé.\par}"
;!@InstallEnd@:Language:1036!

;!@Install@!UTF-8:Language:1037!
CancelPrompt="האם אתה בטוח שברצונך לבטל?"
ExtractTitle="מחלץ קבצים"
ExtractDialogText="{\rtf1\fbidis\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset177 Tahoma;}{\f1\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\ltrpar\sl240\slmult1\f0\rtlch\fs18\lang1037 מתכונן\f1\ltrch\lang1033 :\lang9\par}"
FinishMessage="{\rtf1\fbidis\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset177 Tahoma;}{\f1\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\ltrpar\sl240\slmult1\f0\rtlch\fs30\lang1037 ההתקנה הושלמה\par\fs16\par\par\par
\f1\ltrch\lang1033 %product% \f0\rtlch\lang1037 הותקן\f1\ltrch\lang1033 .\f0\rtlch\lang1037\par}"
;!@InstallEnd@:Language:1037!

;!@Install@!UTF-8:Language:1038!
CancelPrompt="Biztosan megszakítja a műveletet?"
ExtractTitle="Fájlok kibontása"
ExtractDialogText="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}{\f1\fnil\fcharset238 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs18\lang9 El\f1 ők\f0 észítés:\par}"
FinishMessage="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}{\f1\fnil\fcharset238 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs30\lang9 A telepítés befejez\f1 őd\f0 ött.\par\fs16\par\par\par
A %product% telepítése megtörtént.\par}"
;!@InstallEnd@:Language:1038!

;!@Install@!UTF-8:Language:1040!
CancelPrompt="Annullare?"
ExtractTitle="Estrazione file"
ExtractDialogText="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs18\lang9 Preparazione:\par}"
FinishMessage="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs30\lang9 Installazione completata\par\fs16\par\par\par
Installazione di %product% completata.\par}"
;!@InstallEnd@:Language:1040!

;!@Install@!UTF-8:Language:1041!
CancelPrompt="本当にキャンセルしてもよろしいですか?"
ExtractTitle="ファイルを抽出しています"
ExtractDialogText="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fswiss\fprq2\fcharset128 MS PGothic;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs18\lang1041 準備中:\par}"
FinishMessage="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fswiss\fprq2\fcharset128 MS PGothic;}{\f1\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs30\lang1041 インストールが完了しました\par\fs16\par\par\par
\f1 %product%\f0  がインストールされました。\par}"
;!@InstallEnd@:Language:1041!

;!@Install@!UTF-8:Language:1042!
CancelPrompt="취소하시겠습니까?"
ExtractTitle="파일 압축을 푸는 중"
ExtractDialogText="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fswiss\fprq2\fcharset129 Gulim;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs18\lang1042 준비 중:\par}"
FinishMessage="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fswiss\fprq2\fcharset129 Gulim;}{\f1\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs30\lang1042 설치 완료\par\fs16\par\par\par
\f1 %product%\f0 이(가) 설치되었습니다.\par}"
;!@InstallEnd@:Language:1042!

;!@Install@!UTF-8:Language:1043!
CancelPrompt="Weet u zeker dat u wilt annuleren?"
ExtractTitle="Bestanden uitpakken"
ExtractDialogText="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs18\lang9 Voorbereiden:\par}"
FinishMessage="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs30\lang9 Installatie voltooid\par\fs16\par\par\par
%product% is geïnstalleerd.\par}"
;!@InstallEnd@:Language:1043!

;!@Install@!UTF-8:Language:1044!
CancelPrompt="Er du sikker på at du vil avbryte?"
ExtractTitle="Pakke ut filer"
ExtractDialogText="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs18\lang9 Forbereder:\par}"
FinishMessage="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs30\lang9 Installasjonen er fullført\par\fs16\par\par\par
%product% har blitt installert.\par}"
;!@InstallEnd@:Language:1044!

;!@Install@!UTF-8:Language:1045!
CancelPrompt="Czy na pewno chcesz anulować?"
ExtractTitle="Wyodrębnianie plików"
ExtractDialogText="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs18\lang9 Przygotowywanie:\par}"
FinishMessage="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}{\f1\fnil\fcharset238 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs30\lang9 Instalacja zako\f1 ń\f0 czona\par\fs16\par\par\par
Program %product% zosta\f1 ł\f0 zainstalowany.\par}"
;!@InstallEnd@:Language:1045!

;!@Install@!UTF-8:Language:1046!
CancelPrompt="Tem certeza de que deseja cancelar?"
ExtractTitle="Extraindo arquivos"
ExtractDialogText="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs18\lang9 Preparando:\par}"
FinishMessage="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs30\lang9 Instalação Concluída\par\fs16\par\par\par
O %product% foi instalado.\par}"
;!@InstallEnd@:Language:1046!

;!@Install@!UTF-8:Language:1049!
CancelPrompt="Вы действительно хотите выполнить отмену?"
ExtractTitle="Извлечение файлов"
ExtractDialogText="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset204 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs18\lang1049 Подготовка:\lang9\par}"
FinishMessage="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset204 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs30\lang1049 Установка завершена\par\fs16\par\par\par
Установка %product% завершена.\par}"
;!@InstallEnd@:Language:1049!

;!@Install@!UTF-8:Language:1053!
CancelPrompt="Vill du avbryta?"
ExtractTitle="Filer extraheras"
ExtractDialogText="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs18\lang9 Förbereder:\par}"
FinishMessage="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs30\lang9 Installationen har slutförts\par\fs16\par\par\par
%product% har installerats.\par}"
;!@InstallEnd@:Language:1053!

;!@Install@!UTF-8:Language:1055!
CancelPrompt="İptal etmek istediğinizden emin misiniz?"
ExtractTitle="Dosyalar ayıklanıyor"
ExtractDialogText="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}{\f1\fnil\fcharset238 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs18\lang9 Haz\f1 ı\f0 rlan\f1 ı\f0 yor:\par}"
FinishMessage="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}{\f1\fnil\fcharset238 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs30\lang9 Yükleme Tamamland\f1 ı\par\fs16\par\par\par
\f0 %product% yüklendi.\par}"
;!@InstallEnd@:Language:1055!

;!@Install@!UTF-8:Language:2052!
CancelPrompt="是否确实要取消?"
ExtractTitle="正在提取文件"
ExtractDialogText="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fprq2\fcharset134 SimSun;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs18\lang2052 正在准备:\par}"
FinishMessage="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fprq2\fcharset134 SimSun;}{\f1\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs30\lang2052 安装完毕\par\fs16\par\par\par
已安装 \f1 %product%\f0 。\par}"
;!@InstallEnd@:Language:2052!

;!@Install@!UTF-8:Language:2070!
CancelPrompt="Tem a certeza de que pretende cancelar?"
ExtractTitle="A extrair ficheiros"
ExtractDialogText="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs18\lang9 A Preparar:\par}"
FinishMessage="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs30\lang9 Instalação está Concluída\par\fs16\par\par\par
O %product% foi instalado.\par}"
;!@InstallEnd@:Language:2070!

;!@Install@!UTF-8:Language:3082!
CancelPrompt="¿Está seguro de que desea cancelar la operación?"
ExtractTitle="Extrayendo archivos"
ExtractDialogText="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs18\lang9 Preparando:\par}"
FinishMessage="{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\sl240\slmult1\f0\fs30\lang9 Se completó la instalación\par\fs16\par\par\par
Se instaló %product%.\par}"
;!@InstallEnd@:Language:3082!


text:
@echo off
if exist "%Windir%\Sysnative\reg.exe" (set "SysPath=%Windir%\Sysnative") else (set "SysPath=%Windir%\System32")
set "Path=%SysPath%;%Windir%;%SysPath%\Wbem"
for /f "tokens=6 delims=[]. " %%G in ('ver') do set winbuild=%%G
if %winbuild% LSS 10240 (
  if not "%1"=="" goto :eof
  echo ==== ERROR ====
  echo This package is only for Windows 10
  echo Press any Key to Exit.
  pause >nul
  goto :eof
)
set arch=x64
if /i "%PROCESSOR_ARCHITECTURE%"=="x86" (
if "%PROCESSOR_ARCHITEW6432%"=="" set arch=x86
)
cd /d "%~dp0"
if %winbuild% LSS 16299 (
set "source=%arch%\16299\update.mum"
)
if %winbuild% GEQ 16299 (
set "source=%arch%\16299\update.mum"
)
if %winbuild% GEQ 17134 (
set "source=%arch%\17134\update.mum"
)
if %winbuild% GEQ 17763 (
set "source=%arch%\17763\update.mum"
)
echo.
DISM.exe /Online /NoRestart /Add-Package /PackagePath:"%source%"
echo.
echo ============================================================
echo.
if not "%1"=="" goto :eof
echo Press any Key to Exit.
pause >nul
goto :eof


text:
#define MyAppName "Microsoft .NET Framework 3.5"
#define MyAppNameS "Microsoft .NET Framework 3.5 Setup"
#define MyAppProduct "Microsoft® .NET Framework"
#define MyAppVersion "3.5.30729.8833"
#define MyAppCompany "Microsoft Corporation"
#define MyAppCopyright "© Microsoft Corporation. All rights reserved."
#define MyAppExeName "dotnetfx35.exe"

[Setup]
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppCopyright={#MyAppCopyright}
VersionInfoDescription={#MyAppNameS}
VersionInfoProductName={#MyAppProduct}
VersionInfoCompany={#MyAppCompany}
VersionInfoVersion={#MyAppVersion}
CreateAppDir=no
OutputDir=.
OutputBaseFilename=dotNetFx35_WX_4_x86_x64
Compression=zip/1
InternalCompressLevel=ultra
SolidCompression=yes
PrivilegesRequired=admin
ArchitecturesAllowed=x86 x64
ArchitecturesInstallIn64BitMode=x64
Uninstallable=false
SetupIconFile=3000.ico
WizardImageFile=3001.bmp
WizardSmallImageFile=3002.bmp

[Files]
Source: "7za32.exe"; DestDir: "{tmp}"; Flags: ignoreversion deleteafterinstall
Source: "7za64.exe"; DestDir: "{tmp}"; Flags: ignoreversion deleteafterinstall
Source: "NET35.cmd"; DestDir: "{tmp}"; Flags: ignoreversion deleteafterinstall
Source: "dotNetFx35.7z"; DestDir: "{tmp}"; Flags: ignoreversion deleteafterinstall

[Run]
Filename: "{tmp}\7za32.exe"; Parameters: "x ""{tmp}\dotNetFx35.7z"" -o""{tmp}\"" x86\* -r -aoa"; Check: not IsWin64; StatusMsg: "Extracting files..."; Flags: runhidden
Filename: "{tmp}\7za64.exe"; Parameters: "x ""{tmp}\dotNetFx35.7z"" -o""{tmp}\"" x64\* -r -aoa"; Check: IsWin64; StatusMsg: "Extracting files..."; Flags: runhidden
Filename: "{tmp}\NET35.cmd"; StatusMsg: "Processing installation..."; Flags: skipifsilent
Filename: "{tmp}\NET35.cmd"; Parameters: "/s"; StatusMsg: "Processing installation..."; Flags: runhidden skipifnotsilent

[Languages]
Name: "default"; MessagesFile: "compiler:Default.isl"