uint32* blowfish_init(int8 key[], int16 keybytes, uint32* P, uint32* S) { int16 i; int16 j; int16 k; uint32 data; uint32 datal; uint32 datar; const uint32 N = 16; memcpy(P, subkey, 72); memcpy(S, subkey+72, 4096); j = 0; for (i = 0; i < N + 2; ++i) { data = 0; for (k = 0; k < 4; ++k) { data = (data << 8) | key[j]; j = j + 1; if (j >= keybytes) { j = 0; } } P[i] = P[i] ^ data; } datal = 0; datar = 0; for (i = 0; i < N + 2; i += 2) { blowfish_encipher(&datal, &datar, P, S); P[i] = datal; P[i + 1] = datar; } for (i = 0; i < 4; ++i) { for (j = 0; j < 256; j += 2) { blowfish_encipher(&datal, &datar, P, S); S[i*256+j] = datal; S[i*256+j + 1] = datar; } } return P; }
int32 CTCPRequestPacket::SendToSocket(uint8* data, uint32 length) { int32 iResult; WBUFW(data,(0x00)) = length; // packet size WBUFL(data,(0x04)) = 0x46465849; // "XIFF" md5((uint8*)(key), blowfish.hash, 24); blowfish_init((int8*)blowfish.hash,16, blowfish.P, blowfish.S[0]); md5(data+8, data+length-0x18+0x04, length-0x18-0x04); uint8 tmp = (length-12)/4; tmp -= tmp%2; for(uint8 i = 0; i < tmp; i += 2) { blowfish_encipher((uint32*)data+i+2, (uint32*)data+i+3, blowfish.P, blowfish.S[0]); } memcpy(&data[length]-0x04, key+16, 4); iResult = send(*m_socket, (const int8*)data, length, 0); if (iResult == SOCKET_ERROR) { #ifdef WIN32 ShowError("send failed with error: %d\n", WSAGetLastError()); #else ShowError("send failed with error: %d\n", errno); #endif return 0; } return ReceiveFromSocket(); }
int32 send_parse(int8 *buff, size_t* buffsize, sockaddr_in* from, map_session_data_t* map_session_data) { // Модификация заголовка исходящего пакета // Суть преобразований: // - отправить клиенту номер последнего полученного от него пакета // - присвоить исходящему пакету номер последнего отправленного клиенту пакета +1 // - записать текущее время отправки пакета WBUFW(buff,0) = map_session_data->server_packet_id; WBUFW(buff,2) = map_session_data->client_packet_id; // сохранение текущего времени (32 BIT!) WBUFL(buff,8) = (uint32)time(NULL); //Сжимаем данные без учета заголовка //Возвращаемый размер в 8 раз больше реальных данных uint32 PacketSize = zlib_compress(buff+FFXI_HEADER_SIZE, *buffsize-FFXI_HEADER_SIZE, PTempBuff, *buffsize, zlib_compress_table); //Запись размера данных без учета заголовка WBUFL(PTempBuff,(PacketSize+7)/8) = PacketSize; //Расчет hash'a также без учета заголовка, но с учетом записанного выше размера данных PacketSize = (PacketSize+7)/8+4; uint8 hash[16]; md5((uint8*)PTempBuff, hash, PacketSize); memcpy(PTempBuff+PacketSize, hash, 16); PacketSize += 16; if (PacketSize > map_config.buffer_size + 20) { ShowFatalError(CL_RED"%Memory manager: PTempBuff is overflowed (%u)\n" CL_RESET, PacketSize); } //making total packet memcpy(buff+FFXI_HEADER_SIZE, PTempBuff, PacketSize); uint32 CypherSize = (PacketSize/4)&-2; blowfish_t* pbfkey = &map_session_data->blowfish; for(uint32 j = 0; j < CypherSize; j += 2) { blowfish_encipher((uint32*)(buff)+j+7, (uint32*)(buff)+j+8, pbfkey->P, pbfkey->S[0]); } // контролируем размер отправляемого пакета. в случае, // если его размер превышает 1400 байт (размер данных + 42 байта IP заголовок), // то клиент игнорирует пакет и возвращает сообщение о его потере // в случае возникновения подобной ситуации выводим предупреждующее сообщение и // уменьшаем размер BuffMaxSize с шагом в 4 байта до ее устранения (вручную) *buffsize = PacketSize+FFXI_HEADER_SIZE; if (*buffsize > 1350) { ShowWarning(CL_YELLOW"send_parse: packet is very big <%u>\n" CL_RESET,*buffsize); } return 0; }
int32 send_parse(int8 *buff, size_t* buffsize, sockaddr_in* from, map_session_data_t* map_session_data) { // Модификация заголовка исходящего пакета // Суть преобразований: // - отправить клиенту номер последнего полученного от него пакета // - присвоить исходящему пакету номер последнего отправленного клиенту пакета +1 // - записать текущее время отправки пакета WBUFW(buff, 0) = map_session_data->server_packet_id; WBUFW(buff, 2) = map_session_data->client_packet_id; // сохранение текущего времени (32 BIT!) WBUFL(buff, 8) = (uint32)time(nullptr); // собираем большой пакет, состоящий из нескольких маленьких CCharEntity *PChar = map_session_data->PChar; CBasicPacket* PSmallPacket; uint32 PacketSize = UINT32_MAX; uint32 PacketCount = PChar->getPacketCount(); uint8 packets = 0; while (PacketSize > 1300 - FFXI_HEADER_SIZE - 16) //max size for client to accept { *buffsize = FFXI_HEADER_SIZE; PacketList_t packetList = PChar->getPacketList(); packets = 0; while (!packetList.empty() && *buffsize + packetList.front()->length() < map_config.buffer_size && packets < PacketCount) { PSmallPacket = packetList.front(); PSmallPacket->sequence(map_session_data->server_packet_id); memcpy(buff + *buffsize, *PSmallPacket, PSmallPacket->length()); *buffsize += PSmallPacket->length(); packetList.pop_front(); packets++; } //Сжимаем данные без учета заголовка //Возвращаемый размер в 8 раз больше реальных данных PacketSize = zlib_compress(buff + FFXI_HEADER_SIZE, *buffsize - FFXI_HEADER_SIZE, PTempBuff, *buffsize, zlib_compress_table); WBUFL(PTempBuff, (PacketSize + 7) / 8) = PacketSize; PacketSize = (PacketSize + 7) / 8 + 4; PacketCount /= 2; } PChar->erasePackets(packets); //Запись размера данных без учета заголовка uint8 hash[16]; md5((uint8*)PTempBuff, hash, PacketSize); memcpy(PTempBuff + PacketSize, hash, 16); PacketSize += 16; if (PacketSize > map_config.buffer_size + 20) { ShowFatalError(CL_RED"%Memory manager: PTempBuff is overflowed (%u)\n" CL_RESET, PacketSize); } //making total packet memcpy(buff + FFXI_HEADER_SIZE, PTempBuff, PacketSize); uint32 CypherSize = (PacketSize / 4)&-2; blowfish_t* pbfkey = &map_session_data->blowfish; for (uint32 j = 0; j < CypherSize; j += 2) { blowfish_encipher((uint32*)(buff)+j + 7, (uint32*)(buff)+j + 8, pbfkey->P, pbfkey->S[0]); } // контролируем размер отправляемого пакета. в случае, // если его размер превышает 1400 байт (размер данных + 42 байта IP заголовок), // то клиент игнорирует пакет и возвращает сообщение о его потере // в случае возникновения подобной ситуации выводим предупреждующее сообщение и // уменьшаем размер BuffMaxSize с шагом в 4 байта до ее устранения (вручную) *buffsize = PacketSize + FFXI_HEADER_SIZE; return 0; }
static void blowfish_init(u_8bit_t * key, int keybytes) { int i, j, bx; time_t lowest; u_32bit_t data; u_32bit_t datal; u_32bit_t datar; union aword temp; /* drummer: Fixes crash if key is longer than 80 char. This may cause the key * to not end with \00 but that's no problem. */ if (keybytes > 80) keybytes = 80; /* Is buffer already allocated for this? */ for (i = 0; i < BOXES; i++) if (box[i].P != NULL) { if ((box[i].keybytes == keybytes) && (!strncmp((char *) (box[i].key), (char *) key, keybytes))) { /* Match! */ box[i].lastuse = now; bf_P = box[i].P; bf_S = box[i].S; return; } } /* No pre-allocated buffer: make new one */ /* Set 'bx' to empty buffer */ bx = (-1); for (i = 0; i < BOXES; i++) { if (box[i].P == NULL) { bx = i; i = BOXES + 1; } } if (bx < 0) { /* Find oldest */ lowest = now; for (i = 0; i < BOXES; i++) if (box[i].lastuse <= lowest) { lowest = box[i].lastuse; bx = i; } nfree(box[bx].P); for (i = 0; i < 4; i++) nfree(box[bx].S[i]); nfree(box[bx].S); } /* Initialize new buffer */ /* uh... this is over 4k */ box[bx].P = (u_32bit_t *) nmalloc((bf_N + 2) * sizeof(u_32bit_t)); box[bx].S = (u_32bit_t **) nmalloc(4 * sizeof(u_32bit_t *)); for (i = 0; i < 4; i++) box[bx].S[i] = (u_32bit_t *) nmalloc(256 * sizeof(u_32bit_t)); bf_P = box[bx].P; bf_S = box[bx].S; box[bx].keybytes = keybytes; strncpy(box[bx].key, key, keybytes); box[bx].key[keybytes] = 0; box[bx].lastuse = now; /* Robey: Reset blowfish boxes to initial state * (I guess normally it just keeps scrambling them, but here it's * important to get the same encrypted result each time) */ for (i = 0; i < bf_N + 2; i++) bf_P[i] = initbf_P[i]; for (i = 0; i < 4; i++) for (j = 0; j < 256; j++) bf_S[i][j] = initbf_S[i][j]; j = 0; if (keybytes > 0) { /* drummer: fixes crash if key=="" */ for (i = 0; i < bf_N + 2; ++i) { temp.word = 0; temp.w.byte0 = key[j]; temp.w.byte1 = key[(j + 1) % keybytes]; temp.w.byte2 = key[(j + 2) % keybytes]; temp.w.byte3 = key[(j + 3) % keybytes]; data = temp.word; bf_P[i] = bf_P[i] ^ data; j = (j + 4) % keybytes; } } datal = 0x00000000; datar = 0x00000000; for (i = 0; i < bf_N + 2; i += 2) { blowfish_encipher(&datal, &datar); bf_P[i] = datal; bf_P[i + 1] = datar; } for (i = 0; i < 4; ++i) { for (j = 0; j < 256; j += 2) { blowfish_encipher(&datal, &datar); bf_S[i][j] = datal; bf_S[i][j + 1] = datar; } } }
void blowfish_init(UBYTE_08bits *key, short keybytes) { int i, j, bx; time_t lowest; UWORD_32bits data; UWORD_32bits datal; UWORD_32bits datar; union aword temp; /* is buffer already allocated for this? */ for(i=0; i<BOXES; i++) { if(box[i].P != NULL) { if((box[i].keybytes == keybytes) && (strncmp(box[i].key,key,keybytes) == 0)) { /* match! */ box[i].lastuse = time(NULL); bf_P = box[i].P; bf_S = box[i].S; return; } } } /* no pre-allocated buffer: make new one */ /* set 'bx' to empty buffer */ bx = (-1); for(i=0; i<BOXES; i++) { if(box[i].P == NULL) { bx = i; i = BOXES + 1; } } if(bx < 0) { /* find oldest */ lowest = time(NULL); for(i=0; i<BOXES; i++) { if(box[i].lastuse <= lowest) { lowest = box[i].lastuse; bx = i; } } mfree(box[bx].P); for(i=0; i<4; i++) mfree(box[bx].S[i]); mfree(box[bx].S); } /* initialize new buffer */ /* uh... this is over 4k */ box[bx].P = (UWORD_32bits *)nmalloc((bf_N+2)*sizeof(UWORD_32bits)); box[bx].S = (UWORD_32bits **)nmalloc(4*sizeof(UWORD_32bits *)); for(i=0; i<4; i++) box[bx].S[i] = (UWORD_32bits *)nmalloc(256*sizeof(UWORD_32bits)); bf_P = box[bx].P; bf_S = box[bx].S; box[bx].keybytes = keybytes; strncpy(box[bx].key,key,keybytes); box[bx].lastuse = time(NULL); /* robey: reset blowfish boxes to initial state */ /* (i guess normally it just keeps scrambling them, but here it's */ /* important to get the same encrypted result each time) */ for(i=0; i<bf_N+2; i++) bf_P[i] = initbf_P[i]; for(i=0; i<4; i++) for(j=0; j<256; j++) bf_S[i][j] = initbf_S[i][j]; j = 0; for(i=0; i<bf_N+2; ++i) { temp.word = 0; temp.w.byte0 = key[j]; temp.w.byte1 = key[(j+1) % keybytes]; temp.w.byte2 = key[(j+2) % keybytes]; temp.w.byte3 = key[(j+3) % keybytes]; data = temp.word; bf_P[i] = bf_P[i] ^ data; j = (j+4) % keybytes; } datal = 0x00000000; datar = 0x00000000; for(i=0; i<bf_N+2; i+=2) { blowfish_encipher(&datal,&datar); bf_P[i] = datal; bf_P[i+1] = datar; } for(i=0; i<4; ++i) { for(j=0; j<256; j+=2) { blowfish_encipher(&datal, &datar); bf_S[i][j] = datal; bf_S[i][j+1] = datar; } } }
static void blowfish_init(UBYTE_08bits * key, short keybytes) { int i, j; UWORD_32bits data; UWORD_32bits datal; UWORD_32bits datar; union aword temp; /* is buffer already allocated for this? */ if (box.P != NULL) { if ((box.keybytes == keybytes) && (!strncmp((char *) (box.key), (char *) key, keybytes))) { /* match! */ bf_P = box.P; bf_S = box.S; return; } free(box.P); for (i = 0; i < 4; i++) free(box.S[i]); free(box.S); } /* initialize new buffer */ /* uh... this is over 4k */ box.P = (UWORD_32bits *) malloc((bf_N + 2) * sizeof(UWORD_32bits)); box.S = (UWORD_32bits **) malloc(4 * sizeof(UWORD_32bits *)); for (i = 0; i < 4; i++) box.S[i] = (UWORD_32bits *) malloc(256 * sizeof(UWORD_32bits)); bf_P = box.P; bf_S = box.S; box.keybytes = keybytes; strncpy(box.key, key, keybytes); /* robey: reset blowfish boxes to initial state */ /* (i guess normally it just keeps scrambling them, but here it's * important to get the same encrypted result each time) */ for (i = 0; i < bf_N + 2; i++) bf_P[i] = initbf_P[i]; for (i = 0; i < 4; i++) for (j = 0; j < 256; j++) bf_S[i][j] = initbf_S[i][j]; j = 0; for (i = 0; i < bf_N + 2; ++i) { temp.word = 0; temp.w.byte0 = key[j]; temp.w.byte1 = key[(j + 1) % keybytes]; temp.w.byte2 = key[(j + 2) % keybytes]; temp.w.byte3 = key[(j + 3) % keybytes]; data = temp.word; bf_P[i] = bf_P[i] ^ data; j = (j + 4) % keybytes; } datal = 0x00000000; datar = 0x00000000; for (i = 0; i < bf_N + 2; i += 2) { blowfish_encipher(&datal, &datar); bf_P[i] = datal; bf_P[i + 1] = datar; } for (i = 0; i < 4; ++i) { for (j = 0; j < 256; j += 2) { blowfish_encipher(&datal, &datar); bf_S[i][j] = datal; bf_S[i][j + 1] = datar; } } }