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?
2 Answers 2
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.
-
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\$Hackworth– Hackworth2014年03月26日 08:46:43 +00:00Commented Mar 26, 2014 at 8:46
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();
-
\$\begingroup\$ I don't think
(char)
is doing the truncating(byte)
was. \$\endgroup\$James Khoury– James Khoury2014年03月26日 23:13:01 +00:00Commented 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\$ChrisW– ChrisW2014年03月26日 23:34:59 +00:00Commented 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\$James Khoury– James Khoury2014年03月27日 01:48:30 +00:00Commented Mar 27, 2014 at 1:48
os.path.basename(path_and_filename)
is"c28556fb686c8d07066419601a2bdd83"
? \$\endgroup\$