views:

52

answers:

2

I am looking to generate passwords using strings typed by the user, the book I am reading recommends using sha over md5 because it is considered stronger.

sha however has been deprecated and I am now using the hashlib module to encrypt me strings in a similar way to that shown here: http://docs.python.org/py3k/library/hashlib.html#module-hashlib.

import os
import hashlib
from getpass import getpass

print('Username: ' + os.environ['USER'])
passwd = getpass('Password: ')
h = hashlib.md5()
h.update(passwd.encode())
passwd_encrypt = h.hexdigest()

I am then comparing passwd_encrypt with a plain ascii file containing a list of usernames and encrypted passwords like so:

THO     5f4dcc3b5aa765d61d8327deb882cf99

Is this a suitable technique for encryption of the password or is there a better way? I am also interested in whether storing the passwords in this way is suitable and what the alternatives may be.

Thank you

A: 

Comparing the hash of the password with a saved hash is a suitable method for authentication.

Ignacio Vazquez-Abrams
It's not suitable without salt.
bstpierre
+4  A: 

There is no "sha" algorithm. The sha1 algorithm is much stronger than md5, since md5 is completely broken. I believe there is an algorithm that takes microseconds to generate a collision.

Sha1 has been considerably weakened by cryptanalysts, and the search is on for the next big thing, but it is still currently suitable for all but the most paranoid.

With regard to their use in passwords, the purpose is to prevent discovery of the original password. So it doesn't really matter much that md5 collisions are trivial to generate, since a collision simply yields an alternate password that has the same md5 hash as the original password, it doesn't reveal the original password.

Important note:

Your version is missing an important component: the salt. This is a random string that is concatenated to the original password in order to generate the hash, and then concatenated to the hash itself for storage. The purpose is to ensure that users with the same password don't end up with the same stored hash.

import random

print('Username: ' + os.environ['USER'])
passwd = getpass('Password: ')
salt = ''.join(random.choice('BCDFGHJKLMNPQRSTVWXYZ') for range(4))
h = hashlib.md5()
h.update(salt)
h.update(passwd.encode())
passwd_encrypt = salt + h.hexdigest()

You then verify the password by reusing the stored salt:

passwd = getpass('Password: ')
salt = passwd_encrypt[:4]
h = hashlib.md5()
h.update(salt)
h.update(passwd.encode())
if passwd_encrypt != salt + h.hexdigest():
    raise LoginFailed()
Marcelo Cantos
I have just returned from the wikipedia salt entry, with a view to asking the question. You beat me to it :-) Thank you
Thorsley
+1 for mention of the salt. It's such a trivial piece to add, yet it adds a good layer of extra security - and if you're storing something like an MD5 hash it also has the added benefit of preventing a rainbow table lookup, if implemented correctly (i.e. your mechanism is not exposed)
Wayne Werner
@Marcelo, is there good reason to omit the vowels in the salt? could I use something similar to `salt = ''.join(chr(random.randint(0, 255)) for i in range(4))`?
Thorsley
@Thorsley: It avoids swear words. Is that a good reason? That's a very subjective question. ;-)
Marcelo Cantos