How to do Passwords Right
NotTani (46)


If you've ever made a text-based RPG, chat application, or easter-egg filled number guessing game, you've probably collected a password or some kind of secret passphrase from your user, keeping it away from potential prying eyes. So I bring you a couple tips from my experience building console programs.
Quick note: I will be using Python and its standard libraries for this tutorial. If you are using Node or Scheme or Assembly or BrainF, this should be fairly easy to adapt. Other note: This tutorial is mainly geared to beginners, so I simplied some things. If you are a more advanced user, please bear with me.

Let's get started! Here is how you are likely getting password from a user:

password = input("Please enter your password > ")

if password == "my_secret_password":
    print("Many secrets are revealed!")

Works fine, but there are actually two issues with this.
First, here's what it looks like when the user enters their password:

Please enter your password > my_secret_password
Many secrets are revealed!

Let's imagine that a malicious user (let's call him Brian) is trying to steal your password. If he is looking over the users shoulder, he can see the users password plain as bun without a vegetarian patty and a slice of cheddar cheese! And if your user and Brian both have to enter their passwords in the same program, Brian can simply scroll up and read the user's password.

Fortunately for us, this is a simple problem to fix. In Python, there is a built-in module called getpass. If you are new to modules, they are essentially pieces of code that you can add to your code to give it extra functionality. The getpass module has only one function in it, called, oddly enough, getpass. To import this function add from getpass import getpass on a new line to the top of your program to add the getpass function to your program.
getpass is almost exactly like input, except for one key difference. Instead of just putting your prompt right between the parenthesis, append prompt= before the string. If you're interested, Google "python keyword arguments".
So, with our new knowledge, here is our new program:

from getpass import getpass

password = getpass(prompt="Please enter your password > ")
if password == "super_great_password":
    print("Tons of secrets over here!")

"But wait!", you say, realizing the fatal flaw in the plain "Brian is intelligent, and knows Python! He can read the right password within my code." Fortunately, there is also a fix to this. But first, we have to talk about hashes.


Hashes are way of turning a piece of text into a long, random-looking string. Every piece of text has its own unique hash, but you can't get find a string from a hash. All you can do is check if a hash is made with a specific piece of text.

So here is what we have to do - store a hashed password instead of a plaintext password. Then, when we get the password, hash that as well, and compare the two. If that sounds complicated, it turns out to be pretty simple. I won't go into great detail on initially generating hashes from passwords, but I wrote a tool that you can find at the end of the article to generate password hashes, and if you're curious, it's pretty easy to dissect. So let's start out our sample program with our hash (it's a string, so in quotes):

correct_password = # your hash goes here in quotes

Python comes to the rescue once again with its module, hashlib, which allows for the creation of hashes. For the purposes of this tutorial, we will be using the SHA256 hashing algorithm, as it is pretty difficult to crack and is fast for a hashing algorithm. If you need something completely cryptographically sound, check out Python's hashlib documentation for more hashing algorithms.
hashlib comes with the aptly-named function called sha256. Let's import that now with from hashlib import sha256 at the top of our file. sha256 takes only one argument, in binary text form (you can turn any string into binary text form by appending .encode() outside of the quote marks), which it then hashes. This function returns a hash object, but to make much use of it, we need to turn it back into text by appending .hexdigest().

from getpass import getpass
from hashlib import sha256

correct_password = # lengthy hash
password = sha256(getpass(prompt="Enter password: ").encode()).hexdigest()

Okay! With me so far? Now we just need to compare the hashed password we've got with our stored hash from earlier. Thus, here is the final program, with all my recommended adjustments.

from getpass import getpass
from hashlib import sha256

correct_password = # hash goes here in quotes
password = sha256(getpass(prompt="Enter password: ").encode()).hexdigest()

if password == correct_password:
    print("Great secrets lie here!")

Looks pretty good. Now Brian can neither look over your shoulder or at your code. Given that he's been thwarted, he's decided to turn away from a life of hacking to start his lifelong dream: his own cooking show.

I really hope you learned something today, and my greatest apologies for the inordinate length of the post!
Happy coding!

Small update: Thank you all for the feedback and support for this article! This is the first learn post I've ever made. Brian got picked up by Netflix, and his cooking show is really taking off! Another update: Unfortunately, Joe Exotic overtook him

You are viewing a single comment. View All
MatthewDoan1 (295)

Maybe Brian could simply use the SHA256 hash and just decode the password. (I'm not sure if that's possible, but I think it is.) What solutions would there be to that?

NotTani (46)

@MatthewDoan1 That is a good point! However, cryptographic hashes (such as SHA256) are specifically designed to be irreversible: that's what makes them secure.

MatthewDoan1 (295)

@drwhonerd99 Oh, thanks. I've used other things (I don't know if they're cryptographic hashes or not) like MD5, and those can be reversed, so I thought the same applied to SHA-256.

NotTani (46)

@MatthewDoan1 Well, theoretically, any hashing algorithm can be brute forced by guessing until you get it right, but decoding an SHA256 hash is infeasible as long as you have a pretty good password.

MatthewDoan1 (295)

@drwhonerd99 That is true. I'm thinking about this method of cracking a password where the hacker keeps sending in passwords and measures the response time from the server. Do you know what that's called? I'm completely blanking.

NotTani (46)

@MatthewDoan1 It's called a timing attack. It can be dangerous, but in this specific case, the correct password hash is not calculated during the program, so there isn't a danger of a timing attack here.

MatthewDoan1 (295)

@NotTani Yes, thanks for the answer. And I know that the correct password hash is not calculated during the program, but in a different application, it could be. So I just wanted to know the name and research it.