//
// Algoritmo códigos de liberación DCT4
// Algorithm unlock codes DCT4
//
// indear
//

#include <stdio.h>
#include <string.h>

unsigned char tabla_1[] = {  // 17 bytes
		0x00,0x03,0x06,0x01,0x04,0x07,0x02,0x05,0x00,0x03,0x06,0x01,0x04,0x07,0x02,0x05,0x00};

unsigned char tabla_2[] = {  // 136 bytes
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x16,0x73,0x3B,0x1E,0x8E,0x70,0xBD,0x86, \
		0x47,0x7E,0x24,0x56,0xF1,0x77,0x88,0x46,0xB1,0xBA,0xA3,0xB7,0x10,0x0A,0xC5,0x37, \
		0xC9,0x5A,0x28,0xAC,0x64,0xA5,0xEC,0xAB,0xC6,0x67,0x95,0x58,0x0D,0xF8,0x9A,0xF6, \
		0x66,0xDC,0x05,0x3D,0xD3,0x8A,0xC3,0xD8,0x6A,0xE9,0x36,0x49,0x43,0xBF,0xEB,0xD4, \
		0x9B,0x68,0xA0,0x65,0x5D,0x57,0x92,0x1F,0x71,0x5C,0xBB,0x22,0xC1,0xBE,0x7B,0xBC, \
		0x63,0x94,0x5F,0x2A,0x61,0xB8,0x34,0x32,0xFD,0xFB,0x17,0x40,0xE6,0x51,0x1D,0x41, \
		0x8F,0x29,0xDD,0x04,0x80,0xDE,0xE7,0x31,0x7F,0x01,0xA2,0xF7,0x39,0xDA,0x6F,0x23, \
		0xFE,0x3A,0xD0,0x1C,0xD1,0x30,0x3E,0x12,0xCD,0x0F,0xE0,0xA8,0xAF,0x82,0x59,0x2C, \
		0x7D,0xAD,0xB2,0xEF,0xC2,0x87,0xCE,0x75 };

unsigned char tabla_3[] = {  // 256 bytes
		0x01,0x2D,0xE2,0x93,0xBE,0x45,0x15,0xAE,0x78,0x03,0x87,0xA4,0xB8,0x38,0xCF,0x3F, \
		0x08,0x67,0x09,0x94,0xEB,0x26,0xA8,0x6B,0xBD,0x18,0x34,0x1B,0xBB,0xBF,0x72,0xF7, \
		0x40,0x35,0x48,0x9C,0x51,0x2F,0x3B,0x55,0xE3,0xC0,0x9F,0xD8,0xD3,0xF3,0x8D,0xB1, \
		0xFF,0xA7,0x3E,0xDC,0x86,0x77,0xD7,0xA6,0x11,0xFB,0xF4,0xBA,0x92,0x91,0x64,0x83, \
		0xF1,0x33,0xEF,0xDA,0x2C,0xB5,0xB2,0x2B,0x88,0xD1,0x99,0xCB,0x8C,0x84,0x1D,0x14, \
		0x81,0x97,0x71,0xCA,0x5F,0xA3,0x8B,0x57,0x3C,0x82,0xC4,0x52,0x5C,0x1C,0xE8,0xA0, \
		0x04,0xB4,0x85,0x4A,0xF6,0x13,0x54,0xB6,0xDF,0x0C,0x1A,0x8E,0xDE,0xE0,0x39,0xFC, \
		0x20,0x9B,0x24,0x4E,0xA9,0x98,0x9E,0xAB,0xF2,0x60,0xD0,0x6C,0xEA,0xFA,0xC7,0xD9, \
		0x00,0xD4,0x1F,0x6E,0x43,0xBC,0xEC,0x53,0x89,0xFE,0x7A,0x5D,0x49,0xC9,0x32,0xC2, \
		0xF9,0x9A,0xF8,0x6D,0x16,0xDB,0x59,0x96,0x44,0xE9,0xCD,0xE6,0x46,0x42,0x8F,0x0A, \
		0xC1,0xCC,0xB9,0x65,0xB0,0xD2,0xC6,0xAC,0x1E,0x41,0x62,0x29,0x2E,0x0E,0x74,0x50, \
		0x02,0x5A,0xC3,0x25,0x7B,0x8A,0x2A,0x5B,0xF0,0x06,0x0D,0x47,0x6F,0x70,0x9D,0x7E, \
		0x10,0xCE,0x12,0x27,0xD5,0x4C,0x4F,0xD6,0x79,0x30,0x68,0x36,0x75,0x7D,0xE4,0xED, \
		0x80,0x6A,0x90,0x37,0xA2,0x5E,0x76,0xAA,0xC5,0x7F,0x3D,0xAF,0xA5,0xE5,0x19,0x61, \
		0xFD,0x4D,0x7C,0xB7,0x0B,0xEE,0xAD,0x4B,0x22,0xF5,0xE7,0x73,0x23,0x21,0xC8,0x05, \
		0xE1,0x66,0xDD,0xB3,0x58,0x69,0x63,0x56,0x0F,0xA1,0x31,0x95,0x17,0x07,0x3A,0x28 };

unsigned char tabla_4[] = {  // 256 bytes
		0x80,0x00,0xB0,0x09,0x60,0xEF,0xB9,0xFD,0x10,0x12,0x9F,0xE4,0x69,0xBA,0xAD,0xF8, \
		0xC0,0x38,0xC2,0x65,0x4F,0x06,0x94,0xFC,0x19,0xDE,0x6A,0x1B,0x5D,0x4E,0xA8,0x82, \
		0x70,0xED,0xE8,0xEC,0x72,0xB3,0x15,0xC3,0xFF,0xAB,0xB6,0x47,0x44,0x01,0xAC,0x25, \
		0xC9,0xFA,0x8E,0x41,0x1A,0x21,0xCB,0xD3,0x0D,0x6E,0xFE,0x26,0x58,0xDA,0x32,0x0F, \
		0x20,0xA9,0x9D,0x84,0x98,0x05,0x9C,0xBB,0x22,0x8C,0x63,0xE7,0xC5,0xE1,0x73,0xC6, \
		0xAF,0x24,0x5B,0x87,0x66,0x27,0xF7,0x57,0xF4,0x96,0xB1,0xB7,0x5C,0x8B,0xD5,0x54, \
		0x79,0xDF,0xAA,0xF6,0x3E,0xA3,0xF1,0x11,0xCA,0xF5,0xD1,0x17,0x7B,0x93,0x83,0xBC, \
		0xBD,0x52,0x1E,0xEB,0xAE,0xCC,0xD6,0x35,0x08,0xC8,0x8A,0xB4,0xE2,0xCD,0xBF,0xD9, \
		0xD0,0x50,0x59,0x3F,0x4D,0x62,0x34,0x0A,0x48,0x88,0xB5,0x56,0x4C,0x2E,0x6B,0x9E, \
		0xD2,0x3D,0x3C,0x03,0x13,0xFB,0x97,0x51,0x75,0x4A,0x91,0x71,0x23,0xBE,0x76,0x2A, \
		0x5F,0xF9,0xD4,0x55,0x0B,0xDC,0x37,0x31,0x16,0x74,0xD7,0x77,0xA7,0xE6,0x07,0xDB, \
		0xA4,0x2F,0x46,0xF3,0x61,0x45,0x67,0xE3,0x0C,0xA2,0x3B,0x1C,0x85,0x18,0x04,0x1D, \
		0x29,0xA0,0x8F,0xB2,0x5A,0xD8,0xA6,0x7E,0xEE,0x8D,0x53,0x4B,0xA1,0x9A,0xC1,0x0E, \
		0x7A,0x49,0xA5,0x2C,0x81,0xC4,0xC7,0x36,0x2B,0x7F,0x43,0x95,0x33,0xF2,0x6C,0x68, \
		0x6D,0xF0,0x02,0x28,0xCE,0xDD,0x9B,0xEA,0x5E,0x99,0x7C,0x14,0x86,0xCF,0xE5,0x42, \
		0xB8,0x40,0x78,0x2D,0x3A,0xE9,0x64,0x1F,0x92,0x90,0x7D,0x39,0x6F,0xE0,0x89,0x30 };


unsigned char tabla_asic2[]  = {0x4a,0x33,0x78,0x90,0x11,0xaf,0xf2,0x3c};
unsigned char tabla_asic2a[] = {0x30,0x49,0x02,0xea,0x6b,0xd5,0x88,0x46}; //xor con 0x7A
unsigned char tabla_asic5[]  = {0x54,0xa1,0x3b,0x22,0x9d,0xa8,0x11,0x77};
unsigned char tabla_asic5a[] = {0xc5,0x30,0xaa,0xb3,0x0c,0x39,0x80,0xe6}; //xor con 0x91
unsigned char tabla_asic6[] = {0x56,0xD4,0xD2,0x9F,0x9D,0xDC,0xEE,0x3D};
unsigned char tabla_asic6a[] = {0xD5,0x57,0x51,0x1C,0x1E,0x5F,0x6D,0xBE}; //xor con 0x83
unsigned char tabla_asic7[]  = {0x9c,0xd7,0xe4,0xa9,0xa4,0x36,0x72,0x92};
unsigned char tabla_asic7a[] = {0xfd,0xb6,0x85,0xc8,0xc5,0x57,0x13,0xf3}; //xor con 0x61

unsigned char tp1[] = {0x3F,0x00,0x7F,0x20,0x6F,0x07,0xFF,0xFF};
unsigned char tp2[] = {0x3F,0x00,0x7F,0x20,0x6F,0x3E,0xFF,0xFF};
unsigned char tp3[] = {0x3F,0x00,0x7F,0x20,0x6F,0x3F,0xFF,0xFF};
unsigned char tp4[] = {0x3F,0x00,0x7F,0x20,0x6F,0x07,0xFF,0xFF};
unsigned char tp5[] = {0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA};
unsigned char tp6[] = {0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA};
unsigned char tp7[] = {0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA};

unsigned char tp_a1[] = {0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x01};
unsigned char tp_a2[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01};
unsigned char tp_a3[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01};
unsigned char tp_a4[] = {0x03,0xFF,0x00,0x00,0x00,0x00,0x00,0x01};
unsigned char tp_a5[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02};
unsigned char tp_a6[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03};
unsigned char tp_a7[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};

int tabla_operaciones[] = {1,0,0,1,1,0,0,1};
int tabla_cambio[] = {1,0,3,2,5,4,7,6,2,0,6,4,3,1,7,5,4,0,5,1,6,2,7,3};
int tabla_cambio2[] = {0,1,2,3,4,5,6,7,0,2,4,6,1,3,5,7,0,4,1,5,2,6,3,7};

void obtener_codigo_liberacion(unsigned char codigo_a_sacar, unsigned char asic, char *IMEI_ASCII,
							   char *network_code_ASCII, char *box_serial,
							   char *destino_codigo_liberacion);
void ASCII2HEX (unsigned char *origen, unsigned char *destino, int caracteres);
void xor_de_8_bytes (unsigned char *cadena1, unsigned char *cadena2, unsigned char *destino);
unsigned char convertir_byte_a_hex (unsigned char byte);
void permutacion(unsigned char *cadena1, unsigned char *cadena2);
unsigned char calculo (char *cadena1, char *cadena2);
unsigned char movimiento_bytes (unsigned char byte1, unsigned char byte2);
unsigned char movimiento2_bytes (unsigned char byte1, unsigned char byte2);

void obtener_codigo_liberacion(unsigned char codigo_a_sacar, unsigned char asic, char *IMEI_ASCII,
							   char *network_code_ASCII, char *box_serial,
							   char *destino_codigo_liberacion)
{
	unsigned char network_code[17];
	char *tabla_asic, *tabla_asic_a;
	char *tabla_permutacion1_HEX, *tabla_permutacion2_HEX;
	unsigned char permu1[9], permu2[9], permu3[9], permu4[9], permu5[9], permu6[9];
	unsigned char network_code_HEX[17];
	unsigned char codigo_liberacion_HEX[27];
	unsigned char IMEI_HEX[17];
	unsigned char box_serial_HEX[4];
	unsigned char aux[6];
	int i;
	
	memset(network_code, 48, sizeof(network_code));
	strcpy(network_code, network_code_ASCII);
	network_code[strlen(network_code_ASCII)]='0';

	destino_codigo_liberacion[0]=0;
	if ((codigo_a_sacar<1) & (codigo_a_sacar>8))
		return;

	switch (asic)
	{
		case 2:
			tabla_asic=tabla_asic2;
			tabla_asic_a=tabla_asic2a;
			break;
		case 5:
			tabla_asic=tabla_asic5;
			tabla_asic_a=tabla_asic5a;
			break;
		case 6:
			tabla_asic=tabla_asic6;
			tabla_asic_a=tabla_asic6a;
			break;
		case 7:
			tabla_asic=tabla_asic7;
			tabla_asic_a=tabla_asic7a;
			break;
	}

	switch (codigo_a_sacar)
	{
		case 1:
            		tabla_permutacion1_HEX=tp1;
            		tabla_permutacion2_HEX=tp_a1;
			break;
		case 2:
            		tabla_permutacion1_HEX=tp2;
            		tabla_permutacion2_HEX=tp_a2;
			break;
		case 3:
			tabla_permutacion1_HEX=tp3;
            		tabla_permutacion2_HEX=tp_a3;
			break;
		case 4:
            		tabla_permutacion1_HEX=tp4;
			tabla_permutacion2_HEX=tp_a4;
			break;
		case 5:
			tabla_permutacion1_HEX=tp5;
			tabla_permutacion2_HEX=tp_a5;
			break;
		case 6:
            		tabla_permutacion1_HEX=tp6;
			tabla_permutacion2_HEX=tp_a6;
			break;
		case 7:
            		tabla_permutacion1_HEX=tp7;
			tabla_permutacion2_HEX=tp_a7;
			break;
	}

	ASCII2HEX(IMEI_ASCII, IMEI_HEX, 14);
	IMEI_HEX[7]=0;
	ASCII2HEX(network_code, network_code_HEX, 16);
	ASCII2HEX(box_serial, box_serial_HEX, 6);

	// mejor cambiamos la tabla de permutacion y no tenemos q hacer esto :)
	//tabla_permutacion2_HEX[7]=tabla_permutacion2_HEX[2];
	//tabla_permutacion2_HEX[2]=0;

	xor_de_8_bytes (tabla_asic_a, IMEI_HEX, permu1);

	memcpy(permu2, tabla_permutacion1_HEX, 8);

	permutacion(permu1, permu2);

	memcpy(permu3, permu2, 8);

	xor_de_8_bytes(tabla_asic, IMEI_HEX, permu1);

	memcpy(permu2, tabla_permutacion2_HEX, 8);

	permutacion(permu1, permu2);

	memcpy(permu4, permu2, 8);

	xor_de_8_bytes (permu3, permu4, permu5);
	
	xor_de_8_bytes (tabla_asic, network_code_HEX, permu1);
	
	memcpy(permu2, permu5, 8);

	permutacion(permu1, permu2);

	memcpy(permu6, permu2, 8);

	codigo_liberacion_HEX[0] = box_serial_HEX[0];

	codigo_liberacion_HEX[1] = box_serial_HEX[1];

	codigo_liberacion_HEX[2] = box_serial_HEX[2];

	codigo_liberacion_HEX[3] = (permu6[5] & 0x77);

	codigo_liberacion_HEX[4] = (permu6[1] & 0x77);

	codigo_liberacion_HEX[5] = (permu6[6] & 0x77);

	codigo_liberacion_HEX[6] = (permu6[3] & 0x77);
	
	codigo_liberacion_HEX[7] = (permu6[7] & 0x77);

	// --------
	
	for (i=3; i<8; i++)
		codigo_liberacion_HEX[5+i] = ((codigo_liberacion_HEX[i] & 0xF0) >> 4);

	aux[0] = codigo_liberacion_HEX[0] & 0x0F;
	aux[1] = (codigo_liberacion_HEX[1] & 0xF0) >> 4;
	aux[2] = codigo_liberacion_HEX[1] & 0x0F;
	aux[3] = (codigo_liberacion_HEX[2] & 0xF0) >> 4;
	aux[4] = codigo_liberacion_HEX[2] & 0x0F;

	for (i=0; i<5; i++) {
		if (aux[i] <= codigo_liberacion_HEX[8+i])
			codigo_liberacion_HEX[8+i]=codigo_liberacion_HEX[8+i]-aux[i];
		else
			codigo_liberacion_HEX[8+i]=(10-aux[i])+codigo_liberacion_HEX[8+i];
	}
	codigo_liberacion_HEX[0]=(codigo_liberacion_HEX[0] & 0xF0) | codigo_liberacion_HEX[8];
	codigo_liberacion_HEX[1]=(codigo_liberacion_HEX[9] << 4) | codigo_liberacion_HEX[10];
	codigo_liberacion_HEX[2]=(codigo_liberacion_HEX[11] << 4) | codigo_liberacion_HEX[12];

	memset(destino_codigo_liberacion, 0, 16);

	destino_codigo_liberacion[0]=(codigo_liberacion_HEX[0] & 0x0F) + 0x30;
	for (i=1; i<8; i++)
	{
		sprintf(destino_codigo_liberacion,"%s%.2X", destino_codigo_liberacion,
				codigo_liberacion_HEX[i]);
	}
}

void ASCII2HEX (unsigned char *origen, unsigned char *destino, int caracteres)
{
	int i, j;
	unsigned char aux1, aux2;

	j=0;
	for(i=0; i<caracteres; i+=2)
	{
		aux1 = convertir_byte_a_hex(origen[i])<<4;
		if (i+1 < caracteres)
           		aux2 = convertir_byte_a_hex(origen[i+1]);
		else
			aux2 = 0;
		destino[j] = aux1 | aux2;
		j++;
	}
}

void xor_de_8_bytes (unsigned char *cadena1, unsigned char *cadena2, unsigned char *destino)
{
	int i;
	
	for(i=0; i<8; i++)
		destino[i]=cadena1[i] ^ cadena2[i];
}

unsigned char convertir_byte_a_hex (unsigned char byte)
{
	if ((byte > 47) && (byte < 58))  // '0' a '9'
		return (byte-48);
	else if ((byte > 64) && (byte < 71))  // 'A' a 'F' o otro caracter
		return (byte-55);
	else
		return byte;
}

void permutacion(unsigned char *cadena1, unsigned char *cadena2)
{
	unsigned char valor1, valor2, valor3;
	unsigned char aux1;
	int i, j;
	
	aux1=0;
	i=0;

	while (i < 8) {
		for (j = 0; j < 8; j++) {
			if (tabla_operaciones[j] == 1)
				cadena2[j] = cadena2[j] ^ calculo (&aux1, cadena1);  // xor
			else
				cadena2[j] = cadena2[j] + calculo (&aux1, cadena1);  // suma
		}

		for (j = 0; j < 8; j++) {
			if (tabla_operaciones[j] == 1)
				cadena2[j] = tabla_3[cadena2[j]] + calculo (&aux1, cadena1);  // suma
			else
				cadena2[j] = tabla_4[cadena2[j]] ^ calculo (&aux1, cadena1);  // xor
		}

		// ******************************************************** //

		for (j = 0; j < 24; j++)
            		cadena2[tabla_cambio[j]] = cadena2[tabla_cambio2[j]] + cadena2[tabla_cambio[j]];
		
		valor1=cadena2[1];
		valor2=cadena2[2];
		valor3=cadena2[4];
		cadena2[1]=valor3;
		cadena2[2]=valor1;
		cadena2[4]=valor2;

		valor1=cadena2[3];
		valor2=cadena2[5];
		valor3=cadena2[6];
		cadena2[3]=valor2;
		cadena2[5]=valor3;
		cadena2[6]=valor1;
		
		i++;
	}

	valor1=calculo (&aux1, cadena1);
	cadena2[0]=cadena2[0] ^ valor1;

	valor1=calculo (&aux1, cadena1);
	cadena2[1]=cadena2[1] + valor1;

	valor1=calculo (&aux1, cadena1);
	cadena2[2]=cadena2[2] + valor1;

	valor1=calculo (&aux1, cadena1);
	cadena2[3]=cadena2[3] ^ valor1;

	valor1=calculo (&aux1, cadena1);
	cadena2[4]=cadena2[4] ^ valor1;

	valor1=calculo (&aux1, cadena1);
	cadena2[5]=cadena2[5] + valor1;

	valor1=calculo (&aux1, cadena1);
	cadena2[6]=cadena2[6] + valor1;

	valor1=calculo (&aux1, cadena1);
	cadena2[7]=cadena2[7] ^ valor1;

}

unsigned char calculo (char *cadena1, char *cadena2)
{
	unsigned char temp1, temp2, temp3;
	unsigned char valor1, valor2;
	int i;

	if (cadena1[0] < 0x88) {
		temp2=cadena1[0];
		(*cadena1)++;
		temp3=cadena2[temp2&0x07];
		valor1=movimiento_bytes(temp2, 3);
		temp1=tabla_1[valor1&0x1F];
		valor2=temp3;
		
		for (i=0; i<temp1; i++)
			valor2 = movimiento2_bytes (valor2, 1);
		temp3=valor2;
		temp3=temp3+tabla_2[temp2];

		return temp3;
	}
	else {
		return 0;
	}
}

unsigned char movimiento_bytes (unsigned char byte1, unsigned char byte2)
{
	unsigned char temp1, temp2;

	temp1 = (byte1 << (8-byte2));
	temp2 = (byte1 >> byte2);
	return (temp1 | temp2);
}

unsigned char movimiento2_bytes (unsigned char byte1, unsigned char byte2)
{
	unsigned char temp1, temp2;

	temp1 = (byte1 >> (8-byte2));
	temp2 = (byte1 << byte2);
	return (temp1 | temp2);
}

void main()
{
	char destino[20];
	int i;
 
	for (i=1; i<8; i++)
	{
		obtener_codigo_liberacion (i, 2, "111111111111119", "22222", "034144", destino);
		printf("#pw+%s+%u#\n", destino, i);
	}
}