-1

This might seem like a strange question, but I have this idea that I want to make a python script that requires a pass login. The user should be able to type in the desired pass in the beginning of the program then the code will write that into the actual source code (so no extra files are generated).

I know that this is possible by doing something like this

with open('test.py','a') as f:
    f.write('\nprint "hello world"') 

Running this script 3 times will generate the following code

with open('test.py','a') as f:
    f.write('\nprint "hello world"')
print "hello world"
print "hello world"
print "hello world"

But I would like to make my python script work on every windows machine that doesn't have python installed. So i would have to use PyInstaller - but then how would I be able to write to the source code?

(Optional solution to my question would be an answer how to securely save then password without creating too many obscure files that frightens the end-user)

Norfeldt
  • 8,272
  • 23
  • 96
  • 152

3 Answers3

4

AFAIK there is no way to modify your code after it is an executable, but you can simply store the password as hash in one file (Method A) or better use a special module for it (Method B). You should never store passwords anywhere in plain text (even not in your executable)

Method A (only use this if you can't use other libraries)
The code could look like this:

# To create the password file (e.g. change password)
import hashlib
with open('password', 'wb') as f:
    p = 'new password'
    f.write(hashlib.sha512(p.encode('utf-8')).digest())  # hash and save password

# To check the password
import hashlib
with open('password', 'rb') as f:
    p_in = # your method to read get the password from the user
    p = hashlib.sha512(p_in.encode('utf-8')).digest()  # create hash
    if p == f.read():  # verify hash (password)
        # right password
    else:
        # wrong password

The content of the file is the binary form of the hash.
One important thing to note is, that you should use a secure hash function (look into the article linked above) or better use Method B.


Method B (you should use this)
Here is a way more secure and even simpler version (as pointed out by user9876) with the usage of the library passlib which is for such things.
This is an example copied from the passlib documentation:

# import the context under an app-specific name (so it can easily be replaced later)
from passlib.apps import custom_app_context as pwd_context

# encrypting a password...
hash = pwd_context.encrypt("somepass")

# verifying a password...
ok = pwd_context.verify("somepass", hash)

As you can see the hashing and verification is very simple and you can configure various parameters if you want.


There are a many ways to store the hash, which all have pros and cons so you have to carefully think about them.

  1. A simple File.
    • You could use the same file to store other settings of you program
    • If someone installs your program into C:\Program Files\ your program would probably not have the rights to store a file there (but you can use some standard directory like %APPDATA%)
    • You could hide the file (but if someone copies the program there is a high chance, that it will be lost)
  2. The Windows registry. You can use the standard python winreg module.
    • Hidden from the user
    • No extra files
    • Only on windows
    • Not portable (if you copy the program to another computer the password will be lost)
  3. Append it to the executable. This is an possibility, but it wouldn't work in your case, because you can't modify a running executable. That means you would need another program to change your main program and that would be another file. So it is the same number of files as if you use the first option, but more work.

Another think to note is, that you could have a master password or fallback password if someone (accidentally) deletes your saved password. But you should think about this, because someone who knows the master password can delete the old password and get into your program.

Community
  • 1
  • 1
TobiMarg
  • 3,667
  • 1
  • 20
  • 25
  • Please don't hash passwords like that. It's more secure than plaintext, but won't protect against a determined attacker. There are plenty of libraries around that will do proper salted hashes that are designed to be much slower than SHA512, so are much harder to brute-force. – user9876 Sep 18 '13 at 17:19
  • @user9876 your right! I simply wrote the simplest method. I now added a version using [passlib](http://code.google.com/p/passlib/) – TobiMarg Sep 18 '13 at 18:09
  • I really like this solution a lot and it is most likely going to run on a windows machine. But what if I want to make a portable .exe and don't want to create a lot of extra files? these files might not be copied if the user wants to make a duplicate. Sorry for the newbie questions - not used to working with passwords that much. – Norfeldt Sep 19 '13 at 07:36
  • @Norfeldt I added a section about saving the password. – TobiMarg Sep 19 '13 at 17:15
3

As you already noticed, storing data in code has more problems than it solves. The way to store "hidden" configuration would be to use _winreg (or winreg in py3) under Windows, and ConfigParser for a ~/.config/myapp.ini file under Linux and other POSIX systems. But then, most people use an .INI file in %APPDATA% under Windows too, that's hidden enough.

If you write a wrapper class that abstracts away the differences, your application code can use this uniformly as a small key/value store. More or less ready-to-use solutions are in this recipe and in kilnconfig.

Then when it comes to passwords, use py-bcrypt to securely persist them.

jhermann
  • 2,071
  • 13
  • 17
1

NEVER NEVER NEVER store passwords!!! It is just insecure! Use the following approach instead:

  1. make a file "passwords.pwd" (windows will not recognize the file type - good for dummy useres)
  2. Don't store the pssword but the hashing function of the password (you can use e.g. passlib or do your own approach):

    import hashlib
    password = "12345" #take user input here
    hashed_password = hashlib.sha512(password).hexdigest()
    print hashed_password
    

    Whenever you have to verify a password, just do the above calculation and compare the result to the strored hash value.

OBu
  • 4,977
  • 3
  • 29
  • 45