Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Porting code containing unsigned char pointer in C to C#

Tags:

c

c#

encryption

I have this code in C that I need to port to C#:

void CryptoBuffer(unsigned char *Buffer, unsigned short length)
{
    unsigned short i;
    for(i=0; i < length; i++)
    {
        *Buffer ^= 0xAA;
        *Buffer++ += 0xC9;
    }
}

I tried this:

public void CryptoBuffer(byte[] buffer, int length)
{
    for(int i = 0; i < length; i++)
    {
        buffer[i] ^= 0xAA;
        buffer[i] += 0xC9;
    }
}

But the outcome doesn't match the one expected.

According to the example, this:

A5 03 18 01...

should become this:

A5 6F 93 8B...

It also says the first byte is not encrypted, so that's why A5 stays the same.

EDIT for clarification: The specification just says you should skip the first byte, it doesn't go into details, so I'm guessing you just pass the sequence from position 1 until the last position to skip the first byte.

But my outcome with that C# port is:

A5 72 7B 74...

Is this port correct or am I missing something?

EDIT 2: For further clarification, this is a closed protocol, so I can't go into details, that's why I provided just enough information to help me port the code, that C code was the one that was given to me, and that's what the specification said it would do. The real problem was that the "0xAA" was wrong in the specification, that's why the output wasn't the expected one. The C# code provided here and by the accepted answer are correct after all.

like image 704
Mahmoud Avatar asked Mar 04 '13 21:03

Mahmoud


2 Answers

Let's break it down shall we, one step at a time.

void CryptoBuffer(unsigned char *Buffer, unsigned short length)
{
    unsigned short i;
    for(i=0; i < length; i++)
    {
        *Buffer ^= 0xAA;
        *Buffer++ += 0xC9;
    }
}

Regardless of some other remarks, this is how you normally do these things in C/C++. There's nothing fancy about this code, and it isn't overly complicated, but I think it is good to break it down to show you what happens.

Things to note:

  1. unsigned char is basically the same as byte in c#
  2. unsigned length has a value between 0-65536. Int should do the trick.
  3. Buffer has a post-increment
  4. The byte assignment (+= 0xC9) will overflow. If it overflows it's truncated to 8 bits in this case.
  5. The buffer is passed by ptr, so the pointer in the calling method will stay the same.
  6. This is just basic C code, no C++. It's quite safe to assume people don't use operator overloading here.

The only "difficult" thing here is the Buffer++. Details can be read in the book "Exceptional C++" from Sutter, but a small example explains this as well. And fortunately we have a perfect example at our disposal. A literal translation of the above code is:

void CryptoBuffer(unsigned char *Buffer, unsigned short length)
{
    unsigned short i;
    for(i=0; i < length; i++)
    {
        *Buffer ^= 0xAA;
        unsigned char *tmp = Buffer;
        *tmp += 0xC9;
        Buffer = tmp + 1;
    }
}

In this case the temp variable can be solved trivially, which leads us to:

void CryptoBuffer(unsigned char *Buffer, unsigned short length)
{
    unsigned short i;
    for(i=0; i < length; i++)
    {
        *Buffer ^= 0xAA;
        *Buffer += 0xC9;
        ++Buffer;
    }
}

Changing this code to C# now is pretty easy:

private void CryptoBuffer(byte[] Buffer, int length)
{
    for (int i=0; i<length; ++i) 
    {
        Buffer[i] = (byte)((Buffer[i] ^ 0xAA) + 0xC9);
    }
}

This is basically the same as your ported code. This means that somewhere down the road something else went wrong... So let's hack the cryptobuffer shall we? :-)

If we assume that the first byte isn't used (as you stated) and that the '0xAA' and/or the '0xC9' are wrong, we can simply try all combinations:

static void Main(string[] args)
{
    byte[] orig = new byte[] { 0x03, 0x18, 0x01 };
    byte[] target = new byte[] { 0x6F, 0x93, 0x8b };

    for (int i = 0; i < 256; ++i)
    {
        for (int j = 0; j < 256; ++j)
        {
            bool okay = true;
            for (int k = 0; okay && k < 3; ++k)
            {
                byte tmp = (byte)((orig[k] ^ i) + j);
                if (tmp != target[k]) { okay = false; break; }
            }
            if (okay)
            {
                Console.WriteLine("Solution for i={0} and j={1}", i, j);
            }
        }
    }
    Console.ReadLine();
}

There we go: oops there are no solutions. That means that the cryptobuffer is not doing what you think it's doing, or part of the C code is missing here. F.ex. do they really pass 'Buffer' to the CryptoBuffer method or did they change the pointer before?

Concluding, I think the only good answer here is that critical information for solving this question is missing.

like image 168
atlaste Avatar answered Oct 14 '22 16:10

atlaste


The example you were provided with is inconsistent with the code in the C sample, and the C and C# code produce identical results.

like image 41
Kobo Avatar answered Oct 14 '22 17:10

Kobo