views:

627

answers:

4

I have an XOR encypted file by a VB.net program using this function to scramble:

Public Class Crypter
    ...
    'This Will convert String to bytes, then call the other function.
    Public Function Crypt(ByVal Data As String) As String
        Return Encoding.Default.GetString(Crypt(Encoding.Default.GetBytes(Data)))
    End Function

    'This calls XorCrypt giving Key converted to bytes
    Public Function Crypt(ByVal Data() As Byte) As Byte()
        Return XorCrypt(Data, Encoding.Default.GetBytes(Me.Key))
    End Function

    'Xor Encryption.
    Private Function XorCrypt(ByVal Data() As Byte, ByVal Key() As Byte) As Byte()
        Dim i As Integer
        If Key.Length <> 0 Then
            For i = 0 To Data.Length - 1
                Data(i) = Data(i) Xor Key(i Mod Key.Length)
            Next
        End If
        Return Data
    End Function
End Class

and saved this way:

Dim Crypter As New Cryptic(Key)
'open destination file
Dim objWriter As New StreamWriter(fileName)
'write crypted content
objWriter.Write(Crypter.Crypt(data))

Now I have to reopen the file with Python but I have troubles getting single bytes, this is the XOR function in python:

def crypto(self, data):
    'crypto(self, data) -> str'
    return ''.join(chr((ord(x) ^ ord(y)) % 256) \
        for (x, y) in izip(data.decode('utf-8'), cycle(self.key))

I had to add the % 256 since sometimes x is > 256 i.e. not a single byte.

This thing of two bytes being passed does not break the decryption because the key keeps "paired" with the following data.

The problem is some decrypted character in the conversion is wrong. These chars are all accented letters like à, è, ì but just a few of the overall accented letters. The others are all correctly restored.

I guess it could be due to the 256 mod but without it I of course get a chr exception...

Thanks for your support

+3  A: 

Your decoded data appears to contain unicode characters with values above 256. In Python 2.x chr can only handle values below 256. Use unichr instead of chr and it should work:

return ''.join(unichr((ord(x) ^ ord(y))) \
    for (x, y) in izip(data.decode('utf-8'), cycle(self.key))
Mark Byers
I have no more exceptions but data is not correct.I have a lot of "m²" in the document and the most are restored as "m\xc2\xb2" but some as "m\xe2\x80\xaa".I'd think data is corrupted but using VB.net all "m²" are correctly restored. (this involves accented letters too of course: most are correct, some not)
neurino
+1  A: 

If you're opening the file in text mode, it might be interpreted as Unicode text. Try opening it in binary mode to make all characters into bytes. That should avoid your issues with chr. If you're using Python 3.x, do remember that when working in binary mode you should be using bytes literals rather than string literals, the latter of which are Unicode strings by design.

Dustin
I'm opening file in 'rb' mode in python 2.5 but had to add data.decode('utf-8')anyway and even with that it seems I still can't get bytes one by one
neurino
+2  A: 

is it correct to save scrambled data as string (i.e. re-encoded with default encoding) with StreamWriter? Wouldn't be correct to save bytes directly? Or is it the same thing?

Dim objWriter As New StreamWriter(fileName)
objWriter.Write(Crypter.Crypt(data))

Which Crypter.Crypt is called by StreamWriter.Write?

This

Public Function Crypt(ByVal Data() As Byte) As Byte()

or this?

Public Function Crypt(ByVal Data As String) As String

I'm not handy with Vb.net...


I've run this to get what chars are involved in the right/wrong "²" conversion

for (x, y) in izip(data.decode('utf-8'), cycle(self.key.decode('utf-8'))):
    if (ord(x) ^ ord(y)) > 255 or chr(ord(x) ^ ord(y)) == '\xb2':
        print (x, y, chr((ord(x) ^ ord(y)) % 256),
               unichr(ord(x) ^ ord(y)), ord(x), ord(y))

I got this:

ù K ² ² 249 75
 p ² ² 194 112
Æ t ² ² 198 116
‚ 0 * ‪ 8218 48

the last one is wrong because a double byte is used... but if just one would be passed probably the rest of the decryption would result outh of phase

neurino
if data is of type string, then the first overload of Crypt is used (and it's implementation is incorrect, as I've answered). If data is of type Byte(), then the second overload. If it's of some other type, then it depends on whether data is implicitly convertable to either String or Byte()
Damien_The_Unbeliever
+1  A: 

Indeed, the following line is wrong:

Return Encoding.Default.GetString(Crypt(Encoding.Default.GetBytes(Data)))

There's no general guarantee that the bytes being returned from Crypt are valid to decode as a string. You'd be better using Convert.ToBase64String, and then passing that string to your Python code (where obviously, you'd need to be able to Base-64 decode the bytes.

And as others have pointed out, the level of security XORing provides is adequate to protect your data from, maybe, your little sister.

Damien_The_Unbeliever
thank you, you were almost right, the VB.net function was not exactly the one I posted, it used a function to make a "Positive 256 module" to "prevent a non byte value. the result is always >= 0 and <= 255" well removing all back-to-string conversions in vb.net code and saving to file Byte directly I'm having python reading chars properly. I'm near to the solution.As I already answered it's not mine the XOR crypting idea and I'd be grateful if someone would break it and make some hurt since I'm telling it but nobody cares... <_<
neurino