Index: docs/topics/auth.txt
===================================================================
--- docs/topics/auth.txt	(revision 15346)
+++ docs/topics/auth.txt	(working copy)
@@ -386,11 +386,12 @@
 
 That's hashtype, salt and hash, separated by the dollar-sign character.
 
-Hashtype is either ``sha1`` (default), ``md5`` or ``crypt`` -- the algorithm
-used to perform a one-way hash of the password. Salt is a random string used
-to salt the raw password to create the hash. Note that the ``crypt`` method is
-only supported on platforms that have the standard Python ``crypt`` module
-available.
+Hashtype is either ``sha1`` (default), ``sha256``, ``sha512``, ``md5`` or 
+``crypt`` -- the algorithm used to perform a one-way hash of the password. 
+Salt is a random string used to salt the raw password to create the hash. 
+Note that the ``crypt`` method is only supported on platforms that have the 
+standard Python ``crypt`` module available. Also note that the ``sha256`` and
+``sha512`` methods are only available under Python 2.5 or newer.
 
 For example::
 
Index: docs/ref/settings.txt
===================================================================
--- docs/ref/settings.txt	(revision 15346)
+++ docs/ref/settings.txt	(working copy)
@@ -117,6 +117,19 @@
 authenticate a user. See the :doc:`authentication backends documentation
 </ref/authbackends>` for details.
 
+.. setting:: AUTH_HASH_ALGORITHM
+
+AUTH_HASH_ALGORITHM
+-------------------
+
+Default: ``'sha1'``
+
+The hash algorithm that should be used by the authentication backend.
+Available options are ``sha1``, ``sha256``, ``sha512``, ``md5`` and ``crypt``.
+Please note that the two strongest ones, ``sha512`` and ``sha256``, are only 
+available when running Python >= 2.5, since it uses the then-introduced 
+``hashlib``.
+
 .. setting:: AUTH_PROFILE_MODULE
 
 AUTH_PROFILE_MODULE
Index: django/conf/global_settings.py
===================================================================
--- django/conf/global_settings.py	(revision 15346)
+++ django/conf/global_settings.py	(working copy)
@@ -477,6 +477,8 @@
 
 AUTHENTICATION_BACKENDS = ('django.contrib.auth.backends.ModelBackend',)
 
+AUTH_HASH_ALGORITHM = 'sha1'
+
 LOGIN_URL = '/accounts/login/'
 
 LOGOUT_URL = '/accounts/logout/'
Index: django/contrib/auth/models.py
===================================================================
--- django/contrib/auth/models.py	(revision 15346)
+++ django/contrib/auth/models.py	(working copy)
@@ -1,6 +1,7 @@
 import datetime
 import urllib
 
+from django.conf import settings
 from django.contrib import auth
 from django.contrib.auth.signals import user_logged_in
 from django.core.exceptions import ImproperlyConfigured
@@ -14,6 +15,12 @@
 
 UNUSABLE_PASSWORD = '!' # This will never be a valid hash
 
+# we're using 160 bits for the salt length, and then 'only' use a 128 bit
+# chunk of that as the actual salt
+SALT_LENGTH = 28 # ceil(160/7) + 5 as safety margin
+SALT_HEX_LENGTH = 128 // 4
+
+
 def get_hexdigest(algorithm, salt, raw_password):
     """
     Returns a string of the hexdigest of the given plaintext password and salt
@@ -31,6 +38,18 @@
         return md5_constructor(salt + raw_password).hexdigest()
     elif algorithm == 'sha1':
         return sha_constructor(salt + raw_password).hexdigest()
+    elif algorithm in ('sha256', 'sha512'):
+        try:
+            import hashlib
+        except ImportError:
+            raise ValueError('"%s" password algorithm not supported in this environment' % algorithm)
+        thehash = None
+        if algorithm == 'sha256':
+            thehash = hashlib.sha256
+        else:
+            thehash = hashlib.sha512
+        return thehash(salt + raw_password).hexdigest()
+
     raise ValueError("Got unknown password algorithm type in password.")
 
 def check_password(raw_password, enc_password):
@@ -147,8 +166,8 @@
         "Generates a random password with the given length and given allowed_chars"
         # Note that default value of allowed_chars does not have "I" or letters
         # that look like it -- just to avoid confusion.
-        from random import choice
-        return ''.join([choice(allowed_chars) for i in range(length)])
+        from random import sample
+        return ''.join(sample(allowed_chars, length))
 
 
 # A few helper functions for common logic between User and AnonymousUser.
@@ -251,9 +270,24 @@
         if raw_password is None:
             self.set_unusable_password()
         else:
-            import random
-            algo = 'sha1'
-            salt = get_hexdigest(algo, str(random.random()), str(random.random()))[:5]
+            import os
+            algo = settings.AUTH_HASH_ALGORITHM
+            salt = None
+            try:
+                # try to get some really strong salt first
+                salt = sha1_constructor(
+                    os.urandom(SALT_LENGTH))[:SALT_HEX_LENGTH]
+            except NotImplementedError:
+                # if that fails, use some weaker stuff
+                import random
+                salt = ''
+                salt_salt = ''
+                for i in xrange(SALT_LENGTH):
+                    salt += chr(random.randint(0, 255))
+                    salt_salt += chr(random.randint(0, 255))
+                # but let it work the extra mile
+                salt = get_hexdigest(algo, salt_salt,
+                    salt)[:SALT_HEX_LENGTH]
             hsh = get_hexdigest(algo, salt, raw_password)
             self.password = '%s$%s$%s' % (algo, salt, hsh)
 
