0

I have a highscore system in my game that I made in Pygame, it saves name and score in text files name.txt and score.txt but the problem is that anyone can edit that text files.So could i hide them in exe file.
python version 2.7
setup script: pygame2exe

And if it's possible could I do it without extra modules. UPDATE:I'll obviously need to encrypt text somehow.Can you suggest some simple encryption alghoritham? Note that I use numbers and newlines.

I would still want to put file in exe.

NetSec
  • 85
  • 1
  • 1
  • 12
  • 1
    py2exe exe files are in fact zipped files. So even if you save your file inside the exe, anyone could open it – joaquin Sep 27 '14 at 19:14
  • 1
    Properly "hiding" files requires encryption, which is a __huge__ topic. – matsjoyce Sep 27 '14 at 19:19
  • So what module should I have for encryption.I don't believe that someone will really try so hard just to earn more points – NetSec Sep 27 '14 at 19:24
  • @joaquin you mean he could just open it in notepad? – NetSec Sep 27 '14 at 19:45
  • 1
    If you believe that no one will really try so hard to earn points, try `rot13` algorithm which is a very simple encryption scheme – nu11p01n73R Sep 27 '14 at 19:48
  • @nu11p01n73R is there rot13 for numbers????????? – NetSec Sep 27 '14 at 19:50
  • you can extract the files and folder inside the exe and read them in any text editor – joaquin Sep 27 '14 at 19:50
  • @user3841722 yeah, it can also be used for numbers as well. The generated string depends entirly on your key – nu11p01n73R Sep 27 '14 at 19:58
  • 1
    As a rule, you can't assume that the current user can write to the current executable that you're running. It just happens to be that Windows didn't have basic security until Vista so a lot of people learned bad habits. Instead you always have to write to a file in a per-user location (APPDATA on Windows, XDG_DATA_HOME everywhere else) – o11c Sep 27 '14 at 23:09
  • @nu11p01n73R : Standard rot13 doesn't use a key - it's a fixed encoding method. OTOH, it _is_ a variety of [Caesar cipher](http://en.wikipedia.org/wiki/Caesar_cipher), which _does_ take a key. Note that standard rot13 _only_ works on letters. Eg, `str.encode('rot_13')` will operate on ASCII chars (i.e in the range \x00 to \x7f) but it only changes the letters. You _could_ use another Caesar cipher variant, but XOR is simpler and faster. – PM 2Ring Sep 28 '14 at 00:20
  • @PM2Ring you can apply `rot13` for each digit in the number, not to the whole number as such. If we use a base string `str=[a-zA-Z0-9]` we can encode all ASCII values – nu11p01n73R Sep 28 '14 at 06:55
  • @nu11p01n73R : Sure, but that's a Caesar cipher variant, not standard rot13, and so calling it rot13 can be confusing. – PM 2Ring Sep 29 '14 at 07:12

1 Answers1

1

There's not much point using strong encryption for this algorithm because your program needs to access the decryption key, so if a determined user looks at your program's code they can figure out where your program stores the key and what it does with it. True, reading & understanding the code in a .pyc is somewhat more difficult than reading a .py, but it's still a lot easier than breaking good encryption.

Anyway, here's some code that does simple encryption / decryption of an arbitrary string. It works best if the string isn't very random, and it works better on long strings than short ones.

To encrypt, it first compresses the data using gzip, which not only can make the data smaller, it reduces the amount of pattern in the data, which improves the quality of the encryption. It then XORs the integer value of each byte (in the zipped data) with a series of random integers in the range(256) to produce the encoded version.

The XOR operation is symmetrical in this sense: if a = b ^ c, then b = a ^ c (and also c = a ^ b). So to undo XORing, we just have to apply it again.

So to decrypt, we simply reverse the encryption process. First we XOR the encoded version with the same series of random integers we used to encode it and then we unzip it.

If the amount of data you want to hide is fairly small or highly random you can skip the zipping / unzipping steps, since XORing with a series of random bytes from a good pseudo-random number generator (like the Mersenne Twister that Python uses by default) is actually quite a good form of encryption, assuming that the attacker doesn't know both the algorithm that generates your random numbers and the seed for the random sequence. (Note that Python's random.seed() accepts any hashable object as the seed: eg an int, a string, or even a tuple).

The code below uses a calendar of the year as test data to make it easy to see that the process works.

gzipcrypt.py

#! /usr/bin/env python

''' Simple encryption
    Encode by gziping then XORing bytes with a pseudorandom stream
    Decode by XORing and then unziping with the same pseudorandom stream

    Written by PM 2Ring 2014.09.28
'''

import random

import sys
from calendar import calendar  


def randoms(seed):
    random.seed(seed)
    while True:
        yield random.randint(0, 255)


def xorcrypt(data, key):
    return str(bytearray(d ^ k for d, k in 
        zip(bytearray(data), randoms(key))))


def zipcrypt(data, key):
    return xorcrypt(data.encode('zlib_codec'), key)


def decryptzip(data, key):
    return xorcrypt(data, key).decode('zlib_codec')


def main():
    #Test encryption & decryption
    key = sys.argv[1] if len(sys.argv) > 1 else 42
    data = calendar(2014)

    print data
    print 'Length:', len(data), '\n'

    #code = xorcrypt(data, key)
    code = zipcrypt(data, key)
    print `code` 
    print 'Length:', len(code), '\n'

    #newd = xorcrypt(code, key)
    newd = decryptzip(code, key)
    print newd
    print newd == data


if __name__ == '__main__':
    main()

Edit

Here's a simpler version of xorcrypt() that doesn't use a generator function, bytearray(), or list comprehensions that's hopefully more comprehensible.

def xorcrypt1(data, key):
    random.seed(key)
    code = []
    for ch in data:
        n = ord(ch)
        n = n ^ random.randint(0, 255)
        code.append(chr(n))
    return ''.join(code)
PM 2Ring
  • 54,345
  • 6
  • 82
  • 182
  • thanks I may try something like that when I learn python and cryptography better but I think i'll go with some ascii values encryption.I searched for simple encryption and found **Base64** can i keep newline character when encrypting with that?? – NetSec Sep 28 '14 at 12:20
  • Sure, Base64 can encode any ASCII character. But it's just a simple encoding, I wouldn't call it an encryption method, per se. It's useful when you want to encode arbitrary binary data into safe printable characters. I guess it may be adequate for your purpose, but it's not hard to use my `xorcrypt()`. Just `import random` into your script and paste in my `xorcrypt()` and `randoms()` functions and you're good to go. :) – PM 2Ring Sep 29 '14 at 07:10
  • sure I could do that but I like when I understand what I am doing – NetSec Sep 29 '14 at 14:37
  • does someone know how could i hide it in exe aniway???i just remembered that my game is open source(facepalm) – NetSec Sep 29 '14 at 14:45
  • Is this running in Windows? As o11c said above, the OS might not let a .exe modify its file on disk. – PM 2Ring Sep 29 '14 at 14:48
  • What part of my code don't you understand? I'm happy to try to explain it. But in the mean time, I'll show you a version of `xorcrypt()` that may be easier to understand. – PM 2Ring Sep 29 '14 at 14:50
  • yes it's run on windows(at first i didn't understand o11c comment) about code there's a lot of things that i don't understand but i think the google may solve it(things like yield keyword,random.seed etc) – NetSec Sep 29 '14 at 14:55