Created
November 15, 2012 07:28
-
-
Save Habbie/4077200 to your computer and use it in GitHub Desktop.
standalone Django hasher, adapted from http://www.bloggerpolis.com/2011/09/how-to-generate-a-django-password/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def get_random_string(length=12, allowed_chars='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'): | |
""" | |
Returns a random string of length characters from the set of a-z, A-Z, 0-9 | |
for use as a salt. | |
The default length of 12 with the a-z, A-Z, 0-9 character set returns | |
a 71-bit salt. log_2((26+26+10)^12) =~ 71 bits | |
""" | |
import random | |
try: | |
random = random.SystemRandom() | |
except NotImplementedError: | |
pass | |
return ''.join([random.choice(allowed_chars) for i in range(length)]) | |
class Promise(object): | |
""" | |
This is just a base class for the proxy class created in | |
the closure of the lazy function. It can be used to recognize | |
promises in code. | |
""" | |
pass | |
def smart_str(s, encoding='utf-8', strings_only=False, errors='strict'): | |
""" | |
Returns a bytestring version of 's', encoded as specified in 'encoding'. | |
If strings_only is True, don't convert (some) non-string-like objects. | |
""" | |
if strings_only and isinstance(s, (types.NoneType, int)): | |
return s | |
if isinstance(s, Promise): | |
return unicode(s).encode(encoding, errors) | |
elif not isinstance(s, basestring): | |
try: | |
return str(s) | |
except UnicodeEncodeError: | |
if isinstance(s, Exception): | |
# An Exception subclass containing non-ASCII data that doesn't | |
# know how to print itself properly. We shouldn't raise a | |
# further exception. | |
return ' '.join([smart_str(arg, encoding, strings_only, | |
errors) for arg in s]) | |
return unicode(s).encode(encoding, errors) | |
elif isinstance(s, unicode): | |
return s.encode(encoding, errors) | |
elif s and encoding != 'utf-8': | |
return s.decode('utf-8', errors).encode(encoding, errors) | |
else: | |
return s | |
def get_hexdigest(algorithm, salt, raw_password): | |
""" | |
Returns a string of the hexdigest of the given plaintext password and salt | |
using the given algorithm ('md5', 'sha1' or 'crypt'). | |
""" | |
raw_password, salt = smart_str(raw_password), smart_str(salt) | |
if algorithm == 'crypt': | |
try: | |
import crypt | |
except ImportError: | |
raise ValueError('"crypt" password algorithm not supported in this environment') | |
return crypt.crypt(raw_password, salt) | |
if algorithm == 'md5': | |
return hashlib.md5(salt + raw_password).hexdigest() | |
elif algorithm == 'sha1': | |
return hashlib.sha1(salt + raw_password).hexdigest() | |
raise ValueError("Got unknown password algorithm type in password.") | |
import hashlib, sys | |
algorithm='sha1' | |
salt=get_random_string() | |
raw_password=sys.stdin.readline().strip() | |
raw_password, salt = smart_str(raw_password), smart_str(salt) | |
hsh = get_hexdigest(algorithm, salt, raw_password) | |
print '%s$%s$%s' % (algorithm, salt, hsh) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment