11
\$\begingroup\$

I have a bit of Python source code that I want to recreate in C#. The code is about reading and decrypting a binary file. I have tested the function on an existing file and it runs without errors; while the resulting string is not garbled or anything, it does not appear to be useful to me.

But that is outside the scope of this question. I only want to know if I have translated the function correctly to C# so it does the same as in Python.

The Python code:

 filename = os.path.basename(path_and_filename)
 key = 0
 for char in filename:
 key = key + ord(char)
 f = open(path_and_filename, 'rb')
 results = ''
 tick = 1
 while True:
 byte = f.read(2)
 if byte:
 if tick:
 key = key + 2
 else:
 key = key - 2
 tick = not tick
 res = struct.unpack('h', byte)[0] ^ key
 results = results + chr(res)
 continue
 break
 f.close()
 return results

path_and_filename is an absolute path to the encrypted file.

Here is the C# code I wrote:

 string path = _path;
 string fileName = _fileName;
 char[] chars = fileName.ToCharArray();
 int key = 0;
 foreach (char c in chars)
 {
 key += c;
 }
 StringBuilder builder = new StringBuilder();
 using (FileStream file = new FileStream(path, FileMode.Open))
 {
 bool tick = true;
 while (true)
 {
 int i = file.ReadByte();
 if (i == -1)
 break;
 if (tick)
 key += 2;
 else
 key -= 2;
 tick = !tick;
 //The next 2 lines are for parsing the short, equivalent(?) to struct.unpack('h', byte)
 i <<= 8;
 i += file.ReadByte();
 i ^= key;
 byte b = (byte)i;
 char c = (char)b;
 builder.Append(c);
 }
 }
 string result = builder.ToString();

Never mind the dirtiness of the code. Will those 2 snippets give the same output to a certain input?

asked Mar 25, 2014 at 23:12
\$\endgroup\$
5
  • 3
    \$\begingroup\$ This is an interesting question, because unlike most translation questions (which are bad), you've actually tried to do it. This comment is designed to guard against thoughtless downvotes. I can in no way protect you from thoughtful ones. \$\endgroup\$ Commented Mar 25, 2014 at 23:17
  • \$\begingroup\$ Re. "certain input", we're supposed to assume but are you sure that os.path.basename(path_and_filename) is "c28556fb686c8d07066419601a2bdd83"? \$\endgroup\$ Commented Mar 26, 2014 at 0:15
  • \$\begingroup\$ @ChrisW I go by the official documentation here: docs.python.org/2/library/os.path.html The specification says that the last folder name is the return value of that basename method. Besides, that folder name is the key for the decryption operation, so it does make sense that it would be the input for the key. \$\endgroup\$ Commented Mar 26, 2014 at 0:48
  • \$\begingroup\$ I fear that "path" includes the filename as well as the folder: see stackoverflow.com/q/1112545/49942 for example, and this which says it returns the filename. \$\endgroup\$ Commented Mar 26, 2014 at 0:54
  • \$\begingroup\$ @ChrisW Thank you, that was indeed part of the problem. basename does return "Game_Keywords.dat". There were other msitakes as well. \$\endgroup\$ Commented Mar 26, 2014 at 8:21

2 Answers 2

4
\$\begingroup\$

This section seems wrong:

//The next 2 lines are for parsing the short, equivalent(?) to struct.unpack('h', byte)
i <<= 8;
i += file.ReadByte();

you're shifting the value in i 8 bits left and then reading another byte. I'm guessing because the original code read it in 2 bytes at a time. If your file isn't the right length then this will break it here. what about:

i <<= 8;
int secondByte = file.ReadByte()
if(secondByte != -1)
{
 i += secondByte ;
}

Whats with this? It is casting an int to a byte to a char and it is truncating.

byte b = (byte)i;
char c = (char)b;

so you're better off ignoring the first byte and instead everything after tick = !tick; could be:

i = file.ReadByte();
char c = (char)(i ^ (key & 255));
builder.Append(c);

In Python chr() will throw an exception if the value is greater than 255 anyway.

And IMHO it is a bad idea to roll your own encryption/decryption like this. Use a trusted known solution instead.

Question: I only want to know if I have translated the function correctly to C# so it does the same as in Python

Answer Its more of a transliteration rather than a translation but they should give the same output. If I were to re-write the python into c# it would look different as it seems inefficient to me.

answered Mar 26, 2014 at 2:16
\$\endgroup\$
1
  • 1
    \$\begingroup\$ I know about the dangers of rolling my own encryption. The python is not mine, however, I'm just trying to translate/transliterate it. \$\endgroup\$ Commented Mar 26, 2014 at 8:46
4
\$\begingroup\$

After a half-nighter, I finally found the solution. Running the code via Iron Python told me that os.path.basename(path_and_filename) in my case does return the file name, as pointed out in the comments, not the name of the last folder. That was the first problem, so I've been working with the wrong key.

The second issue was how I read the bytes to XOR with the key. Apparently, unpacking the two bytes read reverses their order in python, so in C# I have to read them in reverse order as well.

So my code would actually look something like this:

 string path = _path;
 string filename = _fileName;
 //python os.path.basename()
 char[] chars = filename.ToCharArray();
 int key = 0;
 foreach (char c in chars)
 {
 key += c;
 }
 StringBuilder builder = new StringBuilder();
 using (FileStream file = new FileStream(path + filename, FileMode.Open))
 {
 bool tick = true;
 while (true)
 {
 int i = file.ReadByte();
 //it's ok to break here because if the first byte is present, then the second byte will also be present, because the data files are well formed.
 if (i == -1)
 break;
 //we can skip the 2nd byte because the algorithm ignores it anyway
 file.ReadByte();
 if (tick)
 key += 2;
 else
 key -= 2;
 tick = !tick;
 i ^= key;
 char c = (char)(i & 255);
 builder.Append(c);
 }
 }
 string result = builder.ToString();
answered Mar 26, 2014 at 8:39
\$\endgroup\$
3
  • \$\begingroup\$ I don't think (char) is doing the truncating (byte) was. \$\endgroup\$ Commented Mar 26, 2014 at 23:13
  • \$\begingroup\$ @JamesKhoury I don't see why you made that edit; it doesn't look good to me. Note the @" at the start of the string. \$\endgroup\$ Commented Mar 26, 2014 at 23:34
  • \$\begingroup\$ Sorry I should have mentioned it. The StackExchange syntax highlighter doesn't handle @" properly. Atleast on my machine. By putting the extra space it shows the syntax for future viewers.The other alternative is use an extra \ instead. \$\endgroup\$ Commented Mar 27, 2014 at 1:48

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.