PDA

Просмотр полной версии : Проблема с BlowFish


noklin
15.03.2015, 21:41
Получаю от сервера Init пакет 186 байт:

ba 00 8c 22 e3 95 ee 6e b5 71 57 80 e3 c9 b8 cf
44 23 41 39 19 c4 35 36 11 3a 87 12 6d ac 22 14
92 4d d3 04 6e 91 32 aa 44 cb 17 69 8f 65 48 0b
f8 6d dc c7 d8 09 9d 07 da fd 50 66 da 97 05 24
e5 ee ef 3b da cd 6f 82 a3 a3 73 64 6b b2 01 92
39 2e 0d b4 f1 16 03 e0 aa db ab 0a b4 af 05 9a
c0 01 a9 59 40 cb 49 10 e6 b7 c9 15 3a c5 b2 b0
2a 68 cc 00 6a 2c ad 7a d2 3d 4f 9d 76 8b ad 71
cd 7b 31 59 7f 24 c8 1d 09 16 b1 12 c0 8b 9b 35
6b 21 86 d0 8b 54 39 0b 31 46 e6 36 75 fc 62 b2
17 40 99 c6 8b cb 72 78 4f b4 6b 77 d5 5a ba ea
14 65 9f 5c 4c a0 6c 01 d9 e7

Затем пытаюсь расшифровывать:
1. Беру первые 8 байт начиная с 3-его (8c 22 e3 95 ee 6e b5 71)
2. Делю их на подблоки. L = 8c 22 e3 95; R = ee 6e b5 71;
и так далее по алгоритму расшифровки.


Вопросы:
1. Размер блока и в правду должен быть 8 байт?
2. Нужно ли делать еще какие нибудь манипуляции с байтами до расшифровки?

ScythLab
16.03.2015, 15:29
Ты сам пишешь алгоритм blowfish? Если брать готовые модули, то они как правило работают с потоком данных, а внутри сами разделяют по блокам.
До расшифровки ничего с данными делать не нужно, а вот после для некоторых пакетов (возможно как раз для Init) требуется дексорирование.

noklin
16.03.2015, 17:42
Ты сам пишешь алгоритм blowfish?
Да. Точнее писал, пока не наткнулся на готовое решение в сорцах сборки l2jskyline.ru.
Так вот там, там есть метод:

private void decryptBlock(byte[] src, int srcIndex, byte[] dst, int dstIndex){

int xl = BytesTo32bits(src, srcIndex);
int xr = BytesTo32bits(src, srcIndex + 4);

xl ^= P[ROUNDS + 1];

for (int i = ROUNDS; i > 0; i -= 2){
xr ^= F(xl) ^ P[i];
xl ^= F(xr) ^ P[i - 1];
}

xr ^= P[0];

Bits32ToBytes(xr, dst, dstIndex);
Bits32ToBytes(xl, dst, dstIndex + 4);
}

Он работает с массивами байт из одного читает->расшифровывает а в другой записывает и главное что есть индекс начального байта с которого начинают работу как для массива из которого читают , так и для массива в который пишут. Из этого складывается мысль что для конкретного пакета существует свой алгоритм или такая архитектура связана с механизмом формирования пакета.

Я ваще думаю что байты инвертировать надо в пакете.
Всем известный факт: 2 первых байта это размер пакета. Так? Да окей берем 2 байта BA00 читаем как в школе учили слева на право: 1011101000000000 а это у нас ваще -17920(в десятичной системе) Отсюда мысль про ивертирование. По моей гипотезе нужно брать по порядку значимые байты и их инвертировать. То есть зная что 2 байта есть размер пакета, мы берем и инвертируем это 2 байта получаем 00BA. Следующий байт 8С тип пакета его не трогаем. Следующие 4 байта ID сессии его тоже инвертируем и так далее. А потом применить мой BlowFish без первых 2х байт конечно же.

Копался в исходниках но нечего похожего на это не нашел.

ScythLab
16.03.2015, 22:42
Не нужно ничего инвертировать, инвертирование тебе нужно только чтобы число (размером более 1 байта), которое ты видишь в потоке, например корректно вбить его в калькулятор.
Тебе нужно раскодировать пакет с помощью BlowFish (с блоками сам определяйся), потом по какому-то принципу провести дексорирование (если нужно) и получишь готовый пакет.
Если готовый пакет не получается, то возможно 3 варианта:
1) ошибка в BlowFish
2) ошибка в дексорировании
3) на сервере установлена нестандартная защита

noklin
17.03.2015, 03:30
Алилуя! Проблема решена!
Покопался поглубже в исходниках. Нашел класс LoginCrypt в нем метод ecrypt(массив, смещение, и размер) который обращался к методу decrypt(массив, смещение, и размер) Объекта NewCrypt

public void decrypt(byte raw[], int offset, int size) throws IOException
{
byte result[] = new byte[size];
int count = size / 8;
for(int i = 0; i < count; i++)
_decrypt.processBlock(raw, offset + i * 8, result, i * 8);

System.arraycopy(result, 0, raw, offset, size);
}
Видно, что тут блоки явно по 8 байт.
Берем 8 байт кидаем их в processBlock он в свою очередь вызывает метод decryptBlock(in, inOff, out, outOff);

private void decryptBlock(byte[] src, int srcIndex, byte[] dst, int dstIndex)
{
int xl = bytesTo32bits(src, srcIndex);
int xr = bytesTo32bits(src, srcIndex + 4);
xl ^= P[ROUNDS + 1];
for (int i = ROUNDS; i > 0; i -= 2)
{
xr ^= func(xl) ^ P[i];
xl ^= func(xr) ^ P[i - 1];
}
xr ^= P[0];
bits32ToBytes(xr, dst, dstIndex);
bits32ToBytes(xl, dst, dstIndex + 4);
}

А вот и метод где байты инвертируются

private int bytesTo32bits(byte[] b, int i)
{
return ((b[i + 3] & 0xff) << 24) | ((b[i + 2] & 0xff) << 16) | ((b[i + 1] & 0xff) << 8)
| ((b[i] & 0xff));
}
На выходе инвертируются обратно:

private void bits32ToBytes(int in, byte[] b, int offset)
{
b[offset] = (byte) in;
b[offset + 1] = (byte) (in >> 8);
b[offset + 2] = (byte) (in >> 16);
b[offset + 3] = (byte) (in >> 24);
}

Проблемы была в том что я на входе ничего не инвертировал.
Пользовался вместо вышеуказанного метода bytesTo32bits
таким:

private int BytesTo32bits(byte[] b, int i)
{
return ((b[i] & 0xff) << 24) | ((b[i + 1] & 0xff) << 16) | ((b[i + 2] & 0xff) << 8) | ((b[i + 3] & 0xff));
}