C#: Blowfish Encipher a single dword

心不动则不痛 提交于 2020-01-06 03:22:07

问题


I'm translating a C++ TCP Client into C#.The client is used to encode 4 bytes of an array using blowfish.

C++ Blowfish

C# Blowfish(C# NET)

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!


回答1:


Blowfish works on eight byte blocks. The only way to encrypt data that falls short of eight bytes (or a multiple of eight) is to pad it out (in this case with zeroes).

You need to pass an eight byte buffer into your C++ function, since you are encrypting in place. The code you posted will actually encrypt four additional bytes of adjacent memory ((DWORD *)(pInput + 4)), which is obviously not what you want. Furthermore, all eight output bytes are required in order to decrypt - so, unfortunately, you can't just pass four of the encrypted bytes and expect them to be decrypted successfully at the other end.

I know this doesn't solve your problem - I don't see any way to solve it, since you want to send only four bytes of encrypted data and Blowfish always produces a minimum of eight!



来源:https://stackoverflow.com/questions/705596/c-blowfish-encipher-a-single-dword

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!