//
// 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[] = "3F007F206F07FFFF\0";
unsigned char tp2[] = "3F007F206F3EFFFF\0";
unsigned char tp3[] = "3F007F206F3FFFFF\0";
unsigned char tp4[] = "3F007F206F07FFFF\0";
unsigned char tp5[] = "AAAAAAAAAAAAAAAA\0";
unsigned char tp6[] = "AAAAAAAAAAAAAAAA\0";
unsigned char tp7[] = "AAAAAAAAAAAAAAAA\0";

unsigned char tp_a1[] = "FC00010000000000\0";
unsigned char tp_a2[] = "0000010000000000\0";
unsigned char tp_a3[] = "0000010000000000\0";
unsigned char tp_a4[] = "03FF010000000000\0";
unsigned char tp_a5[] = "0000020000000000\0";
unsigned char tp_a6[] = "0000030000000000\0";
unsigned char tp_a7[] = "0000000000000000\0";

void obtener_codigo_liberacion(unsigned char codigo_a_sacar, unsigned char asic, unsigned char *IMEI_ASCII,
                                                           unsigned char *network_code_ASCII, unsigned char *box_serial,
                                                           unsigned 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 (unsigned char *cadena1, unsigned 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, unsigned char *IMEI_ASCII,
                                                           unsigned char *network_code_ASCII, unsigned char *box_serial,
                                                           unsigned char *destino_codigo_liberacion)
{
        unsigned char network_code[17];
        unsigned char *tabla_asic, *tabla_asic_a;
        unsigned char *tabla_permutacion1, *tabla_permutacion2;
        unsigned char permu1[9], permu2[9], permu3[9], permu4[9], permu5[9], permu6[9];
        unsigned char tabla_permutacion1_HEX[9], tabla_permutacion2_HEX[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, j;
        
        memset(network_code, 48, sizeof(network_code));   // '0'
        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=tp1;
                        break;
                case 2:
            tabla_permutacion1=tp2;
                        break;
                case 3:
                        tabla_permutacion1=tp3;
                        break;
                case 4:
            tabla_permutacion1=tp4;
                        break;
                case 5:
                        tabla_permutacion1=tp5;
                        break;
                case 6:
            tabla_permutacion1=tp6;
                        break;
                case 7:
            tabla_permutacion1=tp7;
                        break;
        }

        switch (codigo_a_sacar)
        {
                case 1:
            tabla_permutacion2=tp_a1;
                        break;
                case 2:
            tabla_permutacion2=tp_a2;
                        break;
                case 3:
                        tabla_permutacion2=tp_a3;
                        break;
                case 4:
            tabla_permutacion2=tp_a4;
                        break;
                case 5:
                        tabla_permutacion2=tp_a5;
                        break;
                case 6:
            tabla_permutacion2=tp_a6;
                        break;
                case 7:
            tabla_permutacion2=tp_a7;
                        break;
        }

        ASCII2HEX(IMEI_ASCII, IMEI_HEX, 14);
        IMEI_HEX[7]=0;
        ASCII2HEX(network_code, network_code_HEX, 16);
        ASCII2HEX(tabla_permutacion1, tabla_permutacion1_HEX, 16);
        ASCII2HEX(tabla_permutacion2, tabla_permutacion2_HEX, 16);
        ASCII2HEX(box_serial, box_serial_HEX, 6);

        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];

        destino_codigo_liberacion[0]=(codigo_liberacion_HEX[0] & 0x0F) + 0x30;
	j=1;
	for (i=1; i<=7; i++) {
		destino_codigo_liberacion[j]=(codigo_liberacion_HEX[i] >> 4) + 0x30;
		j++;
		destino_codigo_liberacion[j]=(codigo_liberacion_HEX[i] & 0x0F) + 0x30;
		j++;
	}
	destino_codigo_liberacion[j]=0;
}

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 > 57) || (byte < 48))  // '0' a '9'
                return (byte-55);
        else
                return (byte-48);        // 'A' a 'F' o otro caracter
}

void permutacion(unsigned char *cadena1, unsigned char *cadena2)
{
        unsigned char valor1, valor2, valor3;
        unsigned char aux1;
        int i;
        
        aux1=0;
        i=0;

        while (i < 8) {
                cadena2[0] = cadena2[0] ^ calculo (&aux1, cadena1);  // xor
                cadena2[1] = cadena2[1] + calculo (&aux1, cadena1);  // suma
                cadena2[2] = cadena2[2] + calculo (&aux1, cadena1);  // suma
                cadena2[3] = cadena2[3] ^ calculo (&aux1, cadena1);  // xor
                cadena2[4] = cadena2[4] ^ calculo (&aux1, cadena1);  // xor
                cadena2[5] = cadena2[5] + calculo (&aux1, cadena1);  // suma
                cadena2[6] = cadena2[6] + calculo (&aux1, cadena1);  // suma
                cadena2[7] = cadena2[7] ^ calculo (&aux1, cadena1);  // xor

                cadena2[0] = tabla_3[cadena2[0]] + calculo (&aux1, cadena1);  // suma
                cadena2[1] = tabla_4[cadena2[1]] ^ calculo (&aux1, cadena1);  // xor
                cadena2[2] = tabla_4[cadena2[2]] ^ calculo (&aux1, cadena1);  // xor
                cadena2[3] = tabla_3[cadena2[3]] + calculo (&aux1, cadena1);  // suma
                cadena2[4] = tabla_3[cadena2[4]] + calculo (&aux1, cadena1);  // suma
                cadena2[5] = tabla_4[cadena2[5]] ^ calculo (&aux1, cadena1);  // xor
                cadena2[6] = tabla_4[cadena2[6]] ^ calculo (&aux1, cadena1);  // xor
                cadena2[7] = tabla_3[cadena2[7]] + calculo (&aux1, cadena1);  // suma

                // ******************************************************** //

                cadena2[1]=cadena2[0]+cadena2[1];
                cadena2[0]=cadena2[1]+cadena2[0];
        
                cadena2[3]=cadena2[2]+cadena2[3];
                cadena2[2]=cadena2[3]+cadena2[2];

                cadena2[5]=cadena2[4]+cadena2[5];
                cadena2[4]=cadena2[5]+cadena2[4];

                cadena2[7]=cadena2[6]+cadena2[7];
                cadena2[6]=cadena2[7]+cadena2[6];

                // ******************************************************** //

                cadena2[2]=cadena2[0]+cadena2[2];
                cadena2[0]=cadena2[2]+cadena2[0];

                cadena2[6]=cadena2[4]+cadena2[6];
                cadena2[4]=cadena2[6]+cadena2[4];

                cadena2[3]=cadena2[1]+cadena2[3];
                cadena2[1]=cadena2[3]+cadena2[1];

                cadena2[7]=cadena2[5]+cadena2[7];
                cadena2[5]=cadena2[7]+cadena2[5];

                // ******************************************************** //

                cadena2[4]=cadena2[0]+cadena2[4];
                cadena2[0]=cadena2[4]+cadena2[0];

                cadena2[5]=cadena2[1]+cadena2[5];
                cadena2[1]=cadena2[5]+cadena2[1];

                cadena2[6]=cadena2[2]+cadena2[6];
                cadena2[2]=cadena2[6]+cadena2[2];

                cadena2[7]=cadena2[3]+cadena2[7];
                cadena2[3]=cadena2[7]+cadena2[3];

                // ******************************************************** //
                
                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 (unsigned char *cadena1, unsigned 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()
{
        // examples - ejemplos
        
        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);
        }

        printf("\n\n");

        for (i=1; i<8; i++)
        {
                obtener_codigo_liberacion (i, 7, "111111111111119", "22222", "034144", destino);
                printf("#pw+%s+%u#\n", destino, i);
        }
}