Hello,
I'm translating a C++ TCP Client into C#.The client is used to encode 4 bytes of an array using 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);
In the C++ code,when the line "Blowfish.Encode" is called with these parameters,it goes into the cBlowfish.Encrypt function
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;
}
To make it clear,the loop is executed only one time due to the short length of the bytes passed(4).
Only one call is executed from this huge code(only once),the call is:
Blowfish_encipher((DWORD *) pInput, (DWORD *)(pInput + 4));
//meaning the code is passing the first two if statements and then leaves the loop and the function.
From my point of view,the solution is hidden somewhere inside the encipher function:
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;
}
The definitions:
#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])
The problem is that the Blowfish_Encipher function in C++ has two parameters:Input(xl) as dword and Output(xr) as dword.
The C# Blowfish Encrypt_Block function has four parameters,why?
public void EncryptBlock(uint hi,uint lo,out uint outHi,out uint outLo)
Unlike the C++ blowfish,EncryptBlock calls Encrypt instead Encrypt to call EncryptBlock.Maybe EncryptBlock is NOT the C++ Blowfish_Encipher?
Anyway,my problem is that when I call the C++ code with that array of 6 bytes requesting the blowfish to encode only the last 4 bytes,it does it.
While If I call the encrypt function in C# with those 4 bytes,it returns 0x00.(If you'd like to see the C# Blowfish,check my first lines - I have added a hyperlink there).
Note I can't change the packet structure,it should be just like that,but encrypted.
I also tried this:
Knowing the C++ Encrpypt functions executes only one call - blowfish Encipher.I tried to call EncryptBlock in C# directly,but there are Hi Uint32 and Low Uint32 as input and output,how to spread them into HI or LO? Will this work if the Encrypt_Block calls blowfish Encrypt in C#? I'm quite not sure.
Thank you in advance!