0

I´m learning my way thru data types in Python, and it´s being not so easy :)

I´m trying to setup a very simple save/restore XOR´ed data sample script, but I can´t retrieve the original data. I saved it as string, once "encrypted", for easy of reading.

I´ve tried decoding the result of the retrieve function, but a str variable can´t be decoded.

This is my sample code:

mykey = 'SOME%$(=084RANDOM'

# generates encrypted value. s1 is target, s2 is key
def save_xor(s1, s2):
 j = "".join([chr(ord(c1) ^ ord(c2)) for (c1,c2) in zip(s1,s2)])
 return str(j.encode())                     # returns in readable format
 
# recovers clean value from encryted and key
def retrieve_xor(s1, s2):
 j = "".join([chr(ord(c1) ^ ord(c2)) for (c1,c2) in zip(s1,s2)])
 return j           

myVal = "aBcD123"

toSave = save_xor(myVal,mykey)
print("Saving value",myVal," as ",toSave)
f = open("data.ini","w")
f.write(toSave)
f.close()

r = open("data.ini","r")
toRead = r.read()
r.close()
sameVal = retrieve_xor(toRead,mykey)
print("Retrieving value saved as ",toRead," and now is ",sameVal)

and this is my output:

Saving value aBcD123 as b'2\r.\x01\x14\x16\x1b'

Retrieving value saved as b'2\r.\x01\x14\x16\x1b' and now is 1W tE h*pz7|

What´s the wrong part of it? Yes, I know it´s a very basic security scheme. It´s just the base of it :)

Thanks!

PiBer2
  • 159
  • 10
  • Welcome to SO, you do not need `str(j.encode())` checkout https://stackoverflow.com/a/20558041/3210415 – Nicolae Oct 13 '20 at 15:41
  • Yes, thanks. I couldn´t remember where I´ve got the original code, to quote it. I´m converting var j to string so I can save it in the file in readable format. Is that ok? Keeping all in variables works ok. Saving to file and restoring is the tricky part (for me!) – PiBer2 Oct 13 '20 at 15:47
  • https://stackoverflow.com/a/17615424/3210415 encode and decode from `ascii` – Nicolae Oct 13 '20 at 16:22
  • @Bertu The var `j` is *already* a string. Doing `j.encode()` will convert it to bytes, So `str(j.encode())` will return a stringified version of the bytes, which is literally this: `b'2\\r.\\x01\\x14\\x16\\x1b'`. That obviously messes up the xor-encoding, so don't do that - just do `return j` instead. To get readable strings, you should use string formatting in the print statements, like this: `print("Saving value %r as %r" % (myVal, toSave))`. Also, to avoid problems with automatic newline conversions, add the argument `newlines=''` when opening the files. – ekhumoro Oct 13 '20 at 16:31
  • @Nicolae: I´m sorry, I don´t understand your idea. From function save_xor a receive a string with the format "b'(some bytes)'". Please note that the string begins with b' and ends with ' . This is a string easily saved to a text file. When I read that string back from the file and decrypt it back, as it is a string, I can´t decode it with sameVal.decode(). – PiBer2 Oct 13 '20 at 16:35
  • @PiBer2 Yes - as I just explained, it messes up the xor-encoding, because it adds three extra characters: `b`, `'` and `'`. – ekhumoro Oct 13 '20 at 16:45
  • @ekhumoro -- Thanks! I´ve already tried that. I need the content of the file to be readable (txt format). The encryption+saving, sending, opening+decrypting are different actions, in different times, different systems. Think of it as a config file where one of the items has this basic encryption. One system encrypts+saves the file that the other system receives, opens and decrytps. – PiBer2 Oct 13 '20 at 16:48
  • @PiBer2 The xor-encoding function shouldn't do any output formatting because it won't round-trip. To get readable content in the config file, the additional encoding/decoding should be done when reading/writing the file. One simple way to do that is to use hex format, like this: encode => `f.write(toSave.encode().hex())`; decode => `toRead = bytes.fromhex(r.read()).decode()`. – ekhumoro Oct 13 '20 at 17:21
  • @ekhumoro -- I like it! But I get a "TypeError: unsupported operand type(s) for ^: 'str' and 'int'" on the call to retrieve_xor(). The key is string and the value is array of int now? I keep getting confused by datatypes in Python. :( – PiBer2 Oct 13 '20 at 18:09
  • @PiBer2 It works perfectly fine for me using the example code in your question. The only other change needed is to use `return j` in `save_xor`. My guess is that you didn't copy the exact code given in my previous comment. (PS: The output in the file should be this: `320d2e0114161b`). – ekhumoro Oct 13 '20 at 18:51
  • @ekhumoro: done! works like a charm. I appreciate your support! – PiBer2 Oct 13 '20 at 21:28

1 Answers1

0

Save it as byte and then for retrieving u need to use it as a byte.

( if you have a problem with saving it as a byte check the edited part )

In this part, you don't need to str(j.encode()) just j.encode() is enough.

mykey = 'SOME%$(=084RANDOM'
# generates encrypted value. s1 is target, s2 is key
def save_xor(s1, s2):
    j = "".join([chr(ord(c1) ^ ord(c2)) for (c1, c2) in zip(s1, s2)])
    return j.encode()  # returns in readable format

This Part also because now s1 is a byte you don't use ord(c1)

# recovers clean value from encryted and key
def retrieve_xor(s1, s2):
    j = "".join([chr(c1 ^ ord(c2)) for (c1, c2) in zip(s1, s2)])
    return j

This part also you have to save it as a byte.

myVal = "aBcD123"

toSave = save_xor(myVal, mykey)
print("Saving value", myVal, " as ", toSave)
with open("data.ini", "wb") as f :
    f.write(toSave)


with open("data.ini", "rb") as r :
    toRead = r.read()

sameVal = retrieve_xor(toRead, mykey)
print("Retrieving value saved as ", toRead, " and now is ", sameVal)

edited

I have checked all the encode and decoding stuff but the thing is if you save as string and then load and encode it again you may lose some information. check this example :

use return j.encode().decode('utf-8') for save_xor and then you use toRead = toRead.encode() and keep the rest. this time the result will be "aEcD123" but we expected "aBcD123"

I suggest that you save it byte by byte like this :

toSave = ','.join([str(x) for x in toSave])
print("Saving value", myVal, " as ", toSave)
with open("data.ini", "w") as f :
    f.write(toSave)

and load it like this :

with open("data.ini", "r") as r :
    toRead = r.read()
toRead = [int(i)for i in toRead.split(',')]
toRead = bytearray(toRead)

and the rest of the code is the same as above.

Pouria Nikvand
  • 362
  • 2
  • 13
  • 1
    Thanks! Works great as save & retrieve. The only issue is that the file is not readable. I mean is not a txt file. I need to combine some other text values in the same file (sort of a config file), so being able to copy/paste to it is a plus. – PiBer2 Oct 13 '20 at 16:42
  • 1
    Great! I´ll work in the saving/restoring from file so it´s not that clear that it´s comma-separated bytes. Thanks a lot, it gets the job done! – PiBer2 Oct 13 '20 at 18:18