C#: Blowfish Зашифровать один меч
Я перевожу C++ TCP-клиент на C#. Клиент используется для кодирования 4 байтов массива с использованием blowfish.
C++
BYTE response[6] =
{
0x00, 0x80, 0x01, 0x61, 0xF8, 0x17
};
// Encrypt the last 4 bytes of the packet only(0x01,0x061,0xF8,0x17)
blowfish.Encode(responce + 2, responce + 2, 4);
// Send the packet
send(s, (char*)sendPtr, sendSize, 0);
C#
responce = new byte[6] { 0x00, 0x80, 0x01, 0x61, 0xF8, 0x17};
// Encrypt the last 4 bytes of the packet only(0x01,0x061,0xF8,0x17)
Handshake.blowfish.Encrypt(responce, 2, responce, 2, 4);
// Send the packet
WS.sock.Send(encrypted);
В коде C++, когда строка "Blowfish.Encode" вызывается с этими параметрами, она входит в функцию cBlowfish.Encrypt
DWORD cBlowFish::Encode(BYTE * pInput, BYTE * pOutput, DWORD lSize)
{
DWORD lCount, lOutSize, lGoodBytes;
BYTE *pi, *po;
int i, j;
int SameDest =(pInput == pOutput ? 1 : 0);
lOutSize = GetOutputLength(lSize);
for(lCount = 0; lCount < lOutSize; lCount += 8)
{
if(SameDest) // if encoded data is being written into input buffer
{
if(lCount < lSize - 7) // if not dealing with uneven bytes at end
{
Blowfish_encipher((DWORD *) pInput, (DWORD *)(pInput + 4));
}
else // pad end of data with null bytes to complete encryption
{
po = pInput + lSize; // point at byte past the end of actual data
j =(int)(lOutSize - lSize); // number of bytes to set to null
for(i = 0; i < j; i++)
*po++ = 0;
Blowfish_encipher((DWORD *) pInput, (DWORD *)(pInput + 4));
}
pInput += 8;
}
else // output buffer not equal to input buffer, so must copy
{ // input to output buffer prior to encrypting
if(lCount < lSize - 7) // if not dealing with uneven bytes at end
{
pi = pInput;
po = pOutput;
for(i = 0; i < 8; i++)
// copy bytes to output
*po++ = *pi++;
// now encrypt them
Blowfish_encipher((DWORD *) pOutput, (DWORD *)(pOutput + 4));
}
else // pad end of data with null bytes to complete encryption
{
lGoodBytes = lSize - lCount; // number of remaining data bytes
po = pOutput;
for(i = 0; i <(int) lGoodBytes; i++)
*po++ = *pInput++;
for(j = i; j < 8; j++)
*po++ = 0;
Blowfish_encipher((DWORD *) pOutput, (DWORD *)(pOutput + 4));
}
pInput += 8;
pOutput += 8;
}
}
return lOutSize;
}
Чтобы было ясно, цикл выполняется только один раз из-за короткой длины пропущенных байтов (4).
Из этого огромного кода выполняется только один вызов (только один раз), вызов:
Blowfish_encipher((DWORD *) pInput, (DWORD *)(pInput + 4));
// означает, что код передает первые два оператора if, а затем покидает цикл и функцию.
С моей точки зрения, решение скрыто где-то внутри функции шифрования:
void cBlowFish::Blowfish_encipher(DWORD *xl, DWORD *xr)
{
union aword Xl, Xr;
Xl.dword = *xl;
Xr.dword = *xr;
Xl.dword ^= PArray [0];
ROUND(Xr, Xl, 1);
ROUND(Xl, Xr, 2);
ROUND(Xr, Xl, 3);
ROUND(Xl, Xr, 4);
ROUND(Xr, Xl, 5);
ROUND(Xl, Xr, 6);
ROUND(Xr, Xl, 7);
ROUND(Xl, Xr, 8);
ROUND(Xr, Xl, 9);
ROUND(Xl, Xr, 10);
ROUND(Xr, Xl, 11);
ROUND(Xl, Xr, 12);
ROUND(Xr, Xl, 13);
ROUND(Xl, Xr, 14);
ROUND(Xr, Xl, 15);
ROUND(Xl, Xr, 16);
Xr.dword ^= PArray [17];
*xr = Xl.dword;
*xl = Xr.dword;
}
Определения:
#define S(x,i) (SBoxes[i][x.w.byte##i])
#define bf_F(x) (((S(x,0) + S(x,1)) ^ S(x,2)) + S(x,3))
#define ROUND(a,b,n) (a.dword ^= bf_F(b) ^ PArray[n])
Проблема в том, что функция Blowfish_Encipher в C++ имеет два параметра:Input(xl) как dword и Output(xr) как dword.
Функция Clow Blowfish Encrypt_Block имеет четыре параметра, почему?
public void EncryptBlock(uint hi,uint lo,out uint outHi,out uint outLo)
В отличие от C++ blowfish,EncryptBlock вызывает Encrypt вместо Encrypt для вызова EncryptBlock. Может быть EncryptBlock НЕ является C++ Blowfish_Encipher?
В любом случае, моя проблема заключается в том, что когда я вызываю код C++ с этим массивом из 6 байтов, запрашивая Blowfish для кодирования только последних 4 байтов, он делает это.
Хотя если я вызываю функцию шифрования в C# с этими 4 байтами, она возвращает 0x00 (если вы хотите увидеть Blowfish C#, проверьте мои первые строки - я добавил там гиперссылку).
Заметьте, я не могу изменить структуру пакета, она должна быть такой, но зашифрованной.
Я также попробовал это:
Зная, что функции C++ Encrpypt выполняют только один вызов - blowfish Encipher. Я пытался вызвать EncryptBlock в C# напрямую, но есть Hi Uint32 и Low Uint32 в качестве входных и выходных данных, как их распространить в HI или LO? Будет ли это работать, если Encrypt_Block вызывает Blowfish Encrypt в C#? Я совсем не уверен.
Заранее спасибо!
1 ответ
Blowfish работает на восьмибайтовых блоках. Единственный способ зашифровать данные, длина которых не превышает восьми байтов (или кратно восьми), - это заполнить их (в данном случае нулями).
Вам нужно передать 8-байтовый буфер в вашу функцию C++, так как вы шифруете на месте. Размещенный вами код фактически зашифрует четыре дополнительных байта смежной памяти ((DWORD *)(pInput + 4)
), что явно не то, что вы хотите. Кроме того, для расшифровки требуются все восемь выходных байтов, поэтому, к сожалению, вы не можете просто передать четыре зашифрованных байта и ожидать, что они будут успешно расшифрованы на другом конце.
Я знаю, что это не решит вашу проблему - я не вижу способа решить ее, так как вы хотите отправить только четыре байта зашифрованных данных, а Blowfish всегда выдает минимум восемь!