//
// Algoritmo códigos de liberación DCT2
// Algorithm unlock codes DCT2
//
// indear
//
// NOTE: this code is port of the pascal code
// that was published in the forum, but includes
// two differences that splnokia.exe has.
// (search "original:" in order to see them)
//

#include <stdio.h>

unsigned char Sl_F0[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
unsigned char S_Sub[] = { 0x17,0x2D,0x25,0x29,0x17,0x15,0x23,0x13,0x2B,0x19,0x20,0x16,0x29,0x1F,0x1C };
unsigned char S_Xor[] = { 0x02,0x0B,0x07,0x04,0x01,0x19,0x11,0x09,0x10,0x1E };
unsigned char S_Add[] = { 0x01,0x05,0x07,0x06,0x03,0x02,0x03,0x05,0x09,0x01 };
unsigned char C_112[] = { 0x17,0x2C,0x43,0x0E,0x22,0x13,0x43,0x4D,0x59,0x16,0x22,0x4E,0x37,0x58,
						  0x5C,0x0C,0x23,0x1D,0x4E,0x5C,0x22,0x2D,0x15,0x44,0x30,0x34,0x3B,0x0D,
						  0x4B,0x2D,0x5A,0x12,0x24,0x43,0x35,0x4A,0x47,0x36,0x13,0x17,0x53,0x24,
						  0x13,0x1B,0x1F,0x62,0x38,0x4D,0x54,0x2A,0x38,0x15,0x1D,0x0D,0x0B,0x41,
						  0x22,0x47,0x1D,0x4E,0x62,0x22,0x41,0x17,0x26,0x30,0x2C,0x57,0x38,0x36,
						  0x12,0x40,0x20,0x59,0x23,0x21,0x36,0x32,0x48,0x52,0x62,0x3F,0x13,0x0D,
						  0x42,0x2E,0x18,0x2D,0x4E,0x20,0x0E,0x23,0x4A,0x60,0x47,0x25,0x30,0x39,
						  0x3F,0x52,0x48,0x3B,0x1A,0x26,0x5D,0x2D,0x2C,0x57,0x45,0x11,0x20,0x30 };
unsigned char C_1C[] = { 0x01,0x05,0x07,0x06,0x03,0x02,0x03,0x05,
						 0x09,0x01,0x00,0x02,0x05,0x06,0x02,0x08,
						 0x05,0x06,0x07,0x09,0x02,0x03,0x05,0x08,
						 0x03,0x05,0x04,0x01 };

char convertir_byte_a_hex (char byte)
{
	if ((byte > 57) || (byte < 48))  // '0' a '9'
		return (byte-55);
	else
		return (byte-48);			 // 'A' a 'F' o otro caracter
}

void calcular_codigo (int CodeNR, char *IMEI, char *network_code, char *GID1, char *GID2, char *MSIN, char *codigo_liberacion )
{
	unsigned char Summ;
	unsigned char Imei[15];
	unsigned char SL[10];
	unsigned char T28[28];
	unsigned char Sl_Temp[3];
	unsigned char SP[5];
	unsigned char Buff[0x1b];
	unsigned char Long[0x10e];
	int i, I, O, L, C;
	unsigned char NSL_Result;
	unsigned char Gid1_1, Gid1_2, Gid2_1, Gid2_2;
	unsigned char Sl_F1[2];
	unsigned char Sl_F2[2];
	
	unsigned char Secr=0;   //Always 0  (Siempre 0)
	unsigned char IMSI[10];

	unsigned char A_3[3];
	unsigned char A_1C[0x1c];

	unsigned char Fix, Fux;
	unsigned short W1, W2, W3;

	for (i=0; i<5; i++)
		SP[i]=convertir_byte_a_hex(network_code[i]);

	for (i=0; i<15; i++)
		Imei[i]=IMEI[i];
	
	Gid1_1=convertir_byte_a_hex(GID1[0]) << 4;
	Gid1_1|=convertir_byte_a_hex(GID1[1]);
	Gid1_2=convertir_byte_a_hex(GID1[2]) << 4;
	Gid1_2|=convertir_byte_a_hex(GID1[3]);
	
	Gid2_1=convertir_byte_a_hex(GID2[0]) << 4;
	Gid2_1|=convertir_byte_a_hex(GID2[1]);
	Gid2_2=convertir_byte_a_hex(GID2[2]) << 4;
	Gid2_2|=convertir_byte_a_hex(GID2[3]);

	for (i=0; i<10; i++)
		IMSI[i]=convertir_byte_a_hex(MSIN[i]);

	if (CodeNR == 4)
	{
		Sl_F0[0]=(SP[0] << 4);		 // original: Sl_F0[0]=9 | (SP[0] << 4);
		Sl_F0[1]=SP[1] | (SP[2] << 4);
		Sl_F0[2]=SP[3] | (SP[4] << 4);
		Sl_F0[3]=IMSI[0] | (IMSI[1] << 4);
		Sl_F0[4]=IMSI[2] | (IMSI[3] << 4);
		Sl_F0[5]=IMSI[5] | (IMSI[4] << 4);   // original: Sl_F0[5]=IMSI[4] | (IMSI[5] << 4);
		Sl_F0[6]=IMSI[6] | (IMSI[7] << 4);
		Sl_F0[7]=IMSI[8] | (IMSI[9] << 4);
	}

	Sl_F1[0]=Gid1_1;
	Sl_F1[1]=Gid1_2;

	Sl_F2[0]=Gid2_1;
	Sl_F2[1]=Gid2_2;


	Sl_Temp[0]=SP[0] << 4;
	Sl_Temp[1]=SP[1] | (SP[2] << 4);
	Sl_Temp[2]=SP[3] | (SP[4] << 4);

	//Inicio Calc_28;
	Fux=(((Sl_Temp[0] & 0xF0) + Sl_Temp[1]) % 0x08);
	Fix=Sl_Temp[2] % 0x0E;
	O=Fix + (Fux * 0x0E);
	A_3[0]=(Sl_Temp[0] & 0xF0) - C_112[O];

	for (I=1; I<=2; I++)
	{
		O=((Fix + I) % 0x0E) + (Fux * 0x0E);
		A_3[I]=Sl_Temp[I] - C_112[O];
	}

	NSL_Result=0;
	C=0;
	do
	{
	NSL_Result= NSL_Result + (A_3[2] >> C) + (A_3[1] >> C);
	C=C+2;
	} while (C<=6);
	NSL_Result=NSL_Result & 0x07;

	for (I=0; I<=0x1b; I++)
	{
		O=(((NSL_Result+I) % 0x08) * 0x0E)+((I+Secr) % 0x0E);
		A_1C[I]= (A_3[I % 0x03] + Secr + C_1C[I]) ^ C_112[O];
	}

	NSL_Result=0;
	C=0;
	do
	{
	NSL_Result= NSL_Result ^ (A_3[2] >> C) ^ (A_3[0] >> C);
	C=C+2;
	} while (C<=6);
	NSL_Result=NSL_Result & 0x07;

	for (I=0; I<=0x1b; I++)
	{
		O=(((NSL_Result-I+0x1C) % 0x08) * 0x0E)+((I+Secr) % 0x0E);
		W1=C_112[O] & 0x00FF;
		W2=A_1C[I] & 0x00FF;
		W3=(W1 * W2) % 0x0100;
		W1=C_1C[I] & 0x00FF;
		W2=W3+W1;
		T28[I]=(W2 % 0x0A)+0x30;
	}
	
	//Fin Calc_28

	Summ=0;
	for (I=0x08; I<=0x0d; I++)
		Summ= Summ+ Imei[I];

	for (I=0; I<=7; I++)
	{
		O=(I+Summ) % 0x0F;
		Buff[I]=Sl_F0[I]-S_Sub[O];
	}


	for (I=8; I<=9; I++)
	{
		O=(I+Summ) % 0x0F;
		Buff[I]=Sl_F1[I-0x08]-S_Sub[O];
	}

	for (I=0x0A; I<=0x0B; I++)
	{
		O=(I+Summ) % 0x0F;
		Buff[I]=Sl_F2[I-0x0A]-S_Sub[O];
	}

	for (I=0x0C; I<=0x1A; I++)
	{
		O=(I-0x0c+Summ) % 0x0F;
		Buff[I]=Imei[I-0x0C]-S_Sub[O];
	}

	for (L=0; L<=0x09; L++)
		for (I=0; I<=0x1A; I++)
		{
			O=(S_Xor[L]+I) % 0x1B;
			Long[L * 0x1B + I]= Buff[O] ^ Buff[I];
		}

	for (L=0; L<=0x09; L++)
	{
		NSL_Result=0;
		for (I=0; I<=0x1a; I++)
		{
			O=(5*I+L) % 0x1C;
			NSL_Result= NSL_Result + (T28[O] * Long[L * 0x1B + I]);
		}
		SL[L]=(NSL_Result+S_Add[L]) % 0x0A;
	}

	// resultado SL
	for (i=0; i<10; i++)
		codigo_liberacion[i]=SL[i] + 0x30;
	codigo_liberacion[i]=0;
}

void main ()
{
	char resultado[20];

	// Unlock code 1 set GID1 and GID2 to "FFFF"
	// Unlock code 2 set GID2 to "FFFF"
	// Unlock code 3 set GID1 to "FFFF"
	// Unlock code 4 set GID1 and GID2 to "FFFF"
	// in the original "splnokia.exe" GID1/2 is FF + two bytes that you introduce in the program
	calcular_codigo(1, "111111111111119", "22222", "FFFF", "FFFF", "1234567890", resultado);
	printf("%s\n", resultado);
	calcular_codigo(2, "111111111111119", "22222", "AAFF", "FFFF", "1234567890", resultado);
	printf("%s\n", resultado);
	calcular_codigo(3, "111111111111119", "22222", "FFFF", "AAFF", "1234657890", resultado);
	printf("%s\n", resultado);
	calcular_codigo(4, "111111111111119", "22222", "FFFF", "FFFF", "1234657890", resultado);
	printf("%s\n", resultado);

}