1

I've been working on converting a C++ crypting method to C#. The problem is, I cant get it to encrypt/decrypt the way I want it to.

The idea is simple, I capture a packet, and decrypt it. The output will be: Packet Size - Command/Action - Null (End)

(The decryptor cuts off the first and last 2 bytes)

The C++ code is this:

// Crypt the packet with Xor operator
void cryptPacket(char *packet)
{
    unsigned short paksize=(*((unsigned short*)&packet[0])) - 2;

    for(int i=2; i<paksize; i++)
    {
         packet[i] = 0x61 ^ packet[i];
    }
}

So I thought this would work in C# if I didn't want to use pointers:

public static char[] CryptPacket(char[] packet)
{
    ushort paksize = (ushort) (packet.Length - 2);

    for(int i=2; i<paksize; i++)
    {
        packet[i] = (char) (0x61 ^ packet[i]);
    }

    return packet;
}

-but it isn't, the value returned is just another line of rubish instead of the decrypted value. The output given is: ..O♦&/OOOe.

Well.. atleast the '/' is in the right place for some reason.

Some more information:

  • The test packet I'm using is this:

Hex value: 0C 00 E2 66 65 47 4E 09 04 13 65 00

Plain text: ...feGN...e.

Decrypted: XX/hereXX

X = Unknown value, I cant really remember, but it doesn't matter.

  • Using Hex Workshop you can decrypt the packet this way:
    1. Special Paste the hex value as CF_TEXT, make sure the 'treat as hexidecimal value' box is checked.
    2. Afterwards, select everything from the hexidecimal value you just pasted, except the first and last 2 bytes.
    3. Go to Tools>Operations>Xor.
    4. Select 'Treat data as 8 bit data' and set value to '61'.
    5. Press 'OK', and you'r done.

That's all the information I can give at the moment, because I'm writing this off the top of my head.

Thank you for your time.

In case you don't see a question in this:

It would be great if someone could take a look at the code to see what's wrong with it, or if there's another way to do it. I'm converting this code because I'm horrible with C++, and want to create a C# application with that code.

Ps: The code tags and such were a pain, so I'm sorry if the spacing etc. is a little messed up.

vgru
  • 49,838
  • 16
  • 120
  • 201
Nick
  • 1,082
  • 1
  • 15
  • 27
  • You just indent everything by 4 spaces to instruct markdown that it should be formatted as code. You can also select an entire code block, and click the "code" button (the one with curly braces) in the toolbar. It shouldn't be as difficult as it seemed to be for you. – Cody Gray - on strike Jan 27 '11 at 12:00
  • This isn't a terribly sophisticated encryption (XORing each byte with a fixed constant). In fact, it's basically no different to e.g. ROT13! It should be pretty simple to step through and see why it's not working, using an ASCII chart (e.g. http://www.asciitable.com/) as a reference. What have you learnt already with the debugger and trace statements? – Oliver Charlesworth Jan 27 '11 at 12:02
  • @Cody That's what I did, but the tags showed up at different places, so I tried to cut/paste the tags, but then they messed up some of the lines. *sigh* @Oli I've learned that it's working as instructed, but not as intended.. – Nick Jan 27 '11 at 12:04
  • 1
    @Nick: As you step through the loop, is each value of `packet[i]` what you expect? Is the result of each XOR operation what you expect? – Oliver Charlesworth Jan 27 '11 at 12:05
  • As Massif said below, use `byte` instead of `char`. Also, there is not much benefit in using `ushort` instead of `int` for `paksize`. – vgru Jan 27 '11 at 12:07
  • Alright, I see here that the GetBytes methods turns '...' (Hex: 09 04 13) into '46 46 46'. I'm guessing I'm supposed to convert the string to Hex before I decrypt it so it will get the proper value? – Nick Jan 27 '11 at 12:24
  • I wouldn't call this encryption, but just obfuscation. – CodesInChaos Jan 27 '11 at 12:36
  • @Code: You're not wrong. I'd charitably call this "light encryption". – Steven Sudit Feb 06 '11 at 00:18
  • I'm just glad I didn't make the system. – Nick Feb 07 '11 at 15:52

3 Answers3

2

Your problem might be that as .NET's char is unicode, some characters are going to be using more than one byte, and your bitmask is only one byte long. So the most significant byte will be left unaltered.

Massif
  • 4,327
  • 23
  • 25
  • 2
    +1 That's correct, replacing `char` with `byte` should do the trick. – vgru Jan 27 '11 at 12:05
  • Tried it, but the result was: '..O♦&/OOOe.' I do see however, that the / ánd the 'e' are on the right spot, so we're getting closer. =P Thank you for responding, I hope you can think of something else. – Nick Jan 27 '11 at 12:07
1

I just tried your function and it seems ok:

class Program
{
    // OP's method: http://stackoverflow.com/questions/4815959
    public static byte[] CryptPacket(byte[] packet)
    {
        int paksize = packet.Length - 2;
        for (int i = 2; i < paksize; i++)
        {
            packet[i] = (byte)(0x61 ^ packet[i]);
        }
        return packet;
    }

    // http://stackoverflow.com/questions/321370 :)
    public static byte[] StringToByteArray(string hex)
    {
        return Enumerable.Range(0, hex.Length).
               Where(x => 0 == x % 2).
               Select(x => Convert.ToByte(hex.Substring(x, 2), 16)).
               ToArray();
    }

    static void Main(string[] args)
    {
        string hex = "0C 00 E2 66 65 47 4E 09 04 13 65 00".Replace(" ", "");
        byte[] input = StringToByteArray(hex);
        Console.WriteLine("Input: " + ASCIIEncoding.ASCII.GetString(input));
        byte[] output = CryptPacket(input);
        Console.WriteLine("Output: " + ASCIIEncoding.ASCII.GetString(output));
        Console.ReadLine();
    }
}

Console output:

Input: ...feGN.....
Output: ...../here..
(where '.' represents funny ascii characters)

It seems a bit smelly that your CryptPacket method is overwriting the initial array with the output values. And that irrelevant characters are not trimmed. But if you are trying to port something, I guess you should know what you are doing.

You could also consider trimming the input array, to remove the unwanted characters first, and then use a generic ROT13 method (like this one). This way you have your own "specialized" version with 2-byte offsets inside the crypt function itself, instead of something like:

public static byte[] CryptPacket(byte[] packet)
{
    // create a new instance
    byte[] output = new byte[packet.Length];

    // process ALL array items
    for (int i = 0; i < packet.Length; i++)
    {
        output[i] = (byte)(0x61 ^ packet[i]);
    }

    return output;
}
vgru
  • 49,838
  • 16
  • 120
  • 201
  • More correct way for conversion from unicode string to byte array: System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding(); byte[] byteArray = encoding.GetBytes("sample string"); – rkellerm Jan 27 '11 at 12:28
  • Thank you for the code, it works like a charm! The irrelevant data could be decrypted properly as well, but there's no need for me to put in the extra efford because I only need to extract strings starting with '/', untill the end of that string. Thanks again! – Nick Jan 27 '11 at 12:47
1

Here's an almost literal translation from C++ to C#, and it seems to work:

var packet = new byte[] {
                            0x0C, 0x00, 0xE2, 0x66, 0x65, 0x47,
                            0x4E, 0x09, 0x04, 0x13, 0x65, 0x00
                        };

CryptPacket(packet);

// displays "....../here." where "." represents an unprintable character
Console.WriteLine(Encoding.ASCII.GetString(packet));

// ...

void CryptPacket(byte[] packet)
{
    int paksize = (packet[0] | (packet[1] << 8)) - 2;

    for (int i = 2; i < paksize; i++)
    {
        packet[i] ^= 0x61;
    }
}
LukeH
  • 263,068
  • 57
  • 365
  • 409
  • Thank you for your time, I already received a working code but this version will help me alot in another project I'm working on! – Nick Jan 27 '11 at 12:46