//
// Algoritmo códigos de liberación DCT3
// Algorithm unlock codes DCT3
//
// indear
//

#include <stdio.h>
#include <string.h>

void ASCII2HEX (unsigned char *origen, unsigned char *destino, int caracteres);
unsigned char convertir_byte_a_hex (unsigned char byte);
unsigned char calculo4_a (char caracter);
void calculo4 (unsigned char *cadena);
void calculo3 (unsigned char *cadena);
void calculo2_a (unsigned char *cadena, unsigned char byte, unsigned char byte2);
void calculo2 (unsigned char *cadena, unsigned char byte, unsigned char byte2);
void calculo1 (unsigned char byte, unsigned char *network_code_h, unsigned char *imei_h);
void calculo1_a (unsigned char *cadena);
void calcular_dct3 (unsigned char *imei, unsigned char *network_code, unsigned char *destino);

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++;
        }
}

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
}

unsigned char calculo4_a (char caracter)
{
        unsigned char aux1, aux2, aux3, temp;
        int i;

        aux1=0;
        aux2=7;
        temp=0;
        
        for (i=0; i<8; i++)
        {
                aux3=caracter;
                aux3=aux3>>aux2;
                aux3&=1;
                aux3=aux3<<aux1;
                temp|=aux3;
                aux1++;
                aux2--;
        }
        return temp;
}

void calculo4 (unsigned char *cadena)
{
        char temp[12];
        int i;

        memcpy(temp, cadena, 12);
        
        for (i=0; i<12; i++)
        {
                cadena[11-i]=calculo4_a(temp[i]);
        }

}
void permu1(unsigned char *network_code_hex, unsigned char *tabla, unsigned char *imei_hex)
{       
        unsigned char *puntero;
        int i;

        puntero=tabla;

        for (i=0; i<11; i++) {
                calculo1(*puntero, network_code_hex, imei_hex);
                calculo2(network_code_hex, 0, 8);
                calculo3(network_code_hex);
                calculo2(network_code_hex, 8, 0);
                puntero++;
        }

        calculo1(tabla[11], network_code_hex, imei_hex);
        calculo4(network_code_hex);
}
void calculo3 (unsigned char *cadena)
{
        unsigned char aux1, aux2, aux3, temp1, temp2;
        char temp[12];
        int i;
    
        memcpy(temp, cadena, 12);
        temp2=12;
        temp1=7;
        aux1=3;

        for(i=0; i<12; i++)
        {
                aux2=temp1;
                aux3=aux1;
                aux2=temp[aux2];
                aux2^=0xFF;
                aux2|=temp[aux3];
                temp2--;

                if (temp1==0)
                        temp1=12;

                temp1--;

                if (aux1==0)
                        aux1+=12;

                aux3=temp2;
                cadena[aux3]^=aux2;

                aux1--;
        }
}

void calculo2_a (unsigned char *cadena, unsigned char byte, unsigned char byte2)
{
        unsigned char aux1, aux2, aux3;
        unsigned char *puntero;
        int i,j;
        
        if (byte==0)
                return;

        for (i=0; i<byte; i++) 
        {
                aux1=cadena[byte2+3];
                aux1&=1;
                puntero=cadena+byte2;

                for (j=0; j<4; j++)
                {
                        aux2=*puntero;
                        aux3=aux2;
                        aux2=aux2>>1;
                        aux1=aux1<<7;
                        aux2|=aux1;
                        aux3&=1;
                        *puntero=aux2;
                        aux1=aux3;
                        puntero++;
                }
        }
}

void calculo2 (unsigned char *cadena, unsigned char byte, unsigned char byte2)
{
    calculo2_a(cadena, 10, byte);
        calculo2_a(cadena, 31, byte2);
}

void calculo1 (unsigned char byte, unsigned char *network_code_h, unsigned char *imei_h)
{
        unsigned char aux1, aux2;
        int contador;
        unsigned char *puntero, *puntero2;

        puntero=network_code_h;
        puntero2=imei_h;
        contador=0;
        aux1=0;
        
        while (contador < 12)
        {
                aux2=aux1;
                aux2=(aux2>>1) % 3;
                aux2&=1;
                aux2*=byte;
                aux2^=(*puntero2);
                (*puntero)^=aux2;
                aux1++;
                puntero++;
                puntero2++;
                
                contador++;
        }
        calculo1_a(network_code_h);
}

void calculo1_a (unsigned char *cadena)
{
        // 60 bytes
        char tabla1[] = {0x01,0x09,0x04,0x08,0x0B,0x05,0x09,0x08,0x06,0x0A, \
                         0x01,0x03,0x0B,0x06,0x0A,0x00,0x08,0x07,0x0B,0x0A, \
                         0x01,0x05,0x00,0x08,0x03,0x01,0x09,0x00,0x02,0x0A, \
                         0x05,0x03,0x07,0x02,0x0A,0x00,0x04,0x03,0x0B,0x02, \
                         0x05,0x09,0x00,0x04,0x07,0x01,0x05,0x04,0x02,0x06, \
                         0x09,0x07,0x0B,0x02,0x06,0x04,0x08,0x03,0x07,0x06};

        // 60 bytes
        char tabla2[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x00,0x00, \
                         0x01,0x00,0x01,0x01,0x01,0x00,0x01,0x00,0x01,0x01, \
                         0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x01, \
                         0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, \
                         0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, \
                         0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01};
        
        unsigned char *puntero=cadena;
        unsigned char aux1, aux2;
        int contador1, contador2, contador3;
        char variable_8c[12];

        contador1=0;
        aux1=0;
        aux2=0;
        
        while (contador1<12) {
                contador2=5;
                aux2^=*puntero;

                while (contador2>0) {
                        if ((tabla2[aux1] == 0) && (contador1 <6)) {
                                variable_8c[tabla1[aux1]]=*puntero;
                        }
                        else {
                                variable_8c[tabla1[aux1]]^=*puntero;
                        }
                        aux1++;
                        contador2--;
                }
                contador1++;
                puntero++;
        }
        
        for (contador3=0; contador3<12; contador3++)
                variable_8c[contador3]^=aux2;
    
        memcpy(cadena, variable_8c, 12);        
}

void calcular_dct3 (unsigned char *imei, unsigned char *network_code, unsigned char *destino)
{
        char tabla[] = {0xb1,0x73,0xe6,0x5a,0xab,0x47,0x8e,0x0d,0x1a,0x34,0x68,0x0b}; //12 bytes
        char network_code_h[12], imei_h[12];
        int i, j;
        unsigned char aux1;

        memset(network_code_h, 0, sizeof(network_code_h));
        memset(imei_h, 0, sizeof(imei_h));
        ASCII2HEX(network_code, network_code_h, (int)strlen(network_code));
        ASCII2HEX(imei, imei_h+2, 14);
        
        for (i=2; i<12; i++)
                imei_h[i]^=0xa5;
        
        permu1(network_code_h, tabla, imei_h);
        
	j=0;
        for (i=0; i<5; i++)
        {
                aux1=network_code_h[i];
                if ((aux1&0x80) == 0x80)
                        aux1+=0xa0;
                if ((aux1&0x08) == 0x08)
            		aux1+=0xfa;

		destino[j]=(aux1 >> 4) + 0x30;
		j++;
		destino[j]=(aux1 & 0x0F) + 0x30;
		j++;
        }
        destino[j]=0;
}
void main() 
{
        // examples - ejemplos
        
        char destino[11];
        
        calcular_dct3 ( "111111111111119", "22222", destino);  // Code1 use network code
        printf("#pw+%s+1#\n", destino);                        // Codigo1 usar el codigo de operador
        
        calcular_dct3 ( "111111111111119", "FFFF", destino);   // Code2 use GID1
        printf("#pw+%s+2#\n", destino);                        // Codigo2 usar el GID1

	calcular_dct3 ( "111111111111119", "1234", destino); // Code3 use GID2
	printf("#pw+%s+3#\n", destino); // Codigo3 usar el GID2

	calcular_dct3 ( "111111111111119", "222221234567890", destino); // Code4 concatenate MCC+MNC+MSIN (15 digits)
	printf("#pw+%s+4#\n", destino); // Codigo4 concatenar MCC+MNC+MSIN (15 dígitos)
}
