Blame SOURCES/00165-crypt-module-salt-backport.patch

6e8c2f
diff -up Python-2.7.3/Doc/library/crypt.rst.crypt-module-salt-backport Python-2.7.3/Doc/library/crypt.rst
6e8c2f
--- Python-2.7.3/Doc/library/crypt.rst.crypt-module-salt-backport	2012-04-09 19:07:28.000000000 -0400
6e8c2f
+++ Python-2.7.3/Doc/library/crypt.rst	2013-02-19 16:44:20.465334062 -0500
6e8c2f
@@ -16,9 +16,9 @@
6e8c2f
 
6e8c2f
 This module implements an interface to the :manpage:`crypt(3)` routine, which is
6e8c2f
 a one-way hash function based upon a modified DES algorithm; see the Unix man
6e8c2f
-page for further details.  Possible uses include allowing Python scripts to
6e8c2f
-accept typed passwords from the user, or attempting to crack Unix passwords with
6e8c2f
-a dictionary.
6e8c2f
+page for further details.  Possible uses include storing hashed passwords
6e8c2f
+so you can check passwords without storing the actual password, or attempting
6e8c2f
+to crack Unix passwords with a dictionary.
6e8c2f
 
6e8c2f
 .. index:: single: crypt(3)
6e8c2f
 
6e8c2f
@@ -27,15 +27,81 @@ the :manpage:`crypt(3)` routine in the r
6e8c2f
 extensions available on the current implementation will also  be available on
6e8c2f
 this module.
6e8c2f
 
6e8c2f
+Hashing Methods
6e8c2f
+---------------
6e8c2f
 
6e8c2f
-.. function:: crypt(word, salt)
6e8c2f
+The :mod:`crypt` module defines the list of hashing methods (not all methods
6e8c2f
+are available on all platforms):
6e8c2f
+
6e8c2f
+.. data:: METHOD_SHA512
6e8c2f
+
6e8c2f
+   A Modular Crypt Format method with 16 character salt and 86 character
6e8c2f
+   hash.  This is the strongest method.
6e8c2f
+
6e8c2f
+.. versionadded:: 3.3
6e8c2f
+
6e8c2f
+.. data:: METHOD_SHA256
6e8c2f
+
6e8c2f
+   Another Modular Crypt Format method with 16 character salt and 43
6e8c2f
+   character hash.
6e8c2f
+
6e8c2f
+.. versionadded:: 3.3
6e8c2f
+
6e8c2f
+.. data:: METHOD_MD5
6e8c2f
+
6e8c2f
+   Another Modular Crypt Format method with 8 character salt and 22
6e8c2f
+   character hash.
6e8c2f
+
6e8c2f
+.. versionadded:: 3.3
6e8c2f
+
6e8c2f
+.. data:: METHOD_CRYPT
6e8c2f
+
6e8c2f
+   The traditional method with a 2 character salt and 13 characters of
6e8c2f
+   hash.  This is the weakest method.
6e8c2f
+
6e8c2f
+.. versionadded:: 3.3
6e8c2f
+
6e8c2f
+
6e8c2f
+Module Attributes
6e8c2f
+-----------------
6e8c2f
+
6e8c2f
+
6e8c2f
+.. attribute:: methods
6e8c2f
+
6e8c2f
+   A list of available password hashing algorithms, as
6e8c2f
+   ``crypt.METHOD_*`` objects.  This list is sorted from strongest to
6e8c2f
+   weakest, and is guaranteed to have at least ``crypt.METHOD_CRYPT``.
6e8c2f
+
6e8c2f
+.. versionadded:: 3.3
6e8c2f
+
6e8c2f
+
6e8c2f
+Module Functions
6e8c2f
+----------------
6e8c2f
+
6e8c2f
+The :mod:`crypt` module defines the following functions:
6e8c2f
+
6e8c2f
+.. function:: crypt(word, salt=None)
6e8c2f
 
6e8c2f
    *word* will usually be a user's password as typed at a prompt or  in a graphical
6e8c2f
-   interface.  *salt* is usually a random two-character string which will be used
6e8c2f
-   to perturb the DES algorithm in one of 4096 ways.  The characters in *salt* must
6e8c2f
-   be in the set ``[./a-zA-Z0-9]``.  Returns the hashed password as a string, which
6e8c2f
-   will be composed of characters from the same alphabet as the salt (the first two
6e8c2f
-   characters represent the salt itself).
6e8c2f
+   interface.  The optional *salt* is either a string as returned from
6e8c2f
+   :func:`mksalt`, one of the ``crypt.METHOD_*`` values (though not all
6e8c2f
+   may be available on all platforms), or a full encrypted password
6e8c2f
+   including salt, as returned by this function.  If *salt* is not
6e8c2f
+   provided, the strongest method will be used (as returned by
6e8c2f
+   :func:`methods`.
6e8c2f
+
6e8c2f
+   Checking a password is usually done by passing the plain-text password
6e8c2f
+   as *word* and the full results of a previous :func:`crypt` call,
6e8c2f
+   which should be the same as the results of this call.
6e8c2f
+
6e8c2f
+   *salt* (either a random 2 or 16 character string, possibly prefixed with
6e8c2f
+   ``$digit$`` to indicate the method) which will be used to perturb the
6e8c2f
+   encryption algorithm.  The characters in *salt* must be in the set
6e8c2f
+   ``[./a-zA-Z0-9]``, with the exception of Modular Crypt Format which
6e8c2f
+   prefixes a ``$digit$``.
6e8c2f
+
6e8c2f
+   Returns the hashed password as a string, which will be composed of
6e8c2f
+   characters from the same alphabet as the salt.
6e8c2f
 
6e8c2f
    .. index:: single: crypt(3)
6e8c2f
 
6e8c2f
@@ -43,6 +109,27 @@ this module.
6e8c2f
    different sizes in the *salt*, it is recommended to use  the full crypted
6e8c2f
    password as salt when checking for a password.
6e8c2f
 
6e8c2f
+.. versionchanged:: 3.3
6e8c2f
+   Before version 3.3, *salt*  must be specified as a string and cannot
6e8c2f
+   accept ``crypt.METHOD_*`` values (which don't exist anyway).
6e8c2f
+
6e8c2f
+
6e8c2f
+.. function:: mksalt(method=None)
6e8c2f
+
6e8c2f
+   Return a randomly generated salt of the specified method.  If no
6e8c2f
+   *method* is given, the strongest method available as returned by
6e8c2f
+   :func:`methods` is used.
6e8c2f
+
6e8c2f
+   The return value is a string either of 2 characters in length for
6e8c2f
+   ``crypt.METHOD_CRYPT``, or 19 characters starting with ``$digit$`` and
6e8c2f
+   16 random characters from the set ``[./a-zA-Z0-9]``, suitable for
6e8c2f
+   passing as the *salt* argument to :func:`crypt`.
6e8c2f
+
6e8c2f
+.. versionadded:: 3.3
6e8c2f
+
6e8c2f
+Examples
6e8c2f
+--------
6e8c2f
+
6e8c2f
 A simple example illustrating typical use::
6e8c2f
 
6e8c2f
    import crypt, getpass, pwd
6e8c2f
@@ -59,3 +146,11 @@ A simple example illustrating typical us
6e8c2f
        else:
6e8c2f
            return 1
6e8c2f
 
6e8c2f
+To generate a hash of a password using the strongest available method and
6e8c2f
+check it against the original::
6e8c2f
+
6e8c2f
+   import crypt
6e8c2f
+
6e8c2f
+   hashed = crypt.crypt(plaintext)
6e8c2f
+   if hashed != crypt.crypt(plaintext, hashed):
6e8c2f
+      raise "Hashed version doesn't validate against original"
6e8c2f
diff -up Python-2.7.3/Lib/crypt.py.crypt-module-salt-backport Python-2.7.3/Lib/crypt.py
6e8c2f
--- Python-2.7.3/Lib/crypt.py.crypt-module-salt-backport	2013-02-19 16:44:20.465334062 -0500
6e8c2f
+++ Python-2.7.3/Lib/crypt.py	2013-02-19 16:49:56.425311089 -0500
6e8c2f
@@ -0,0 +1,71 @@
6e8c2f
+"""Wrapper to the POSIX crypt library call and associated functionality.
6e8c2f
+
6e8c2f
+Note that the ``methods`` and ``METHOD_*`` attributes are non-standard
6e8c2f
+extensions to Python 2.7, backported from 3.3"""
6e8c2f
+
6e8c2f
+import _crypt
6e8c2f
+import string as _string
6e8c2f
+from random import SystemRandom as _SystemRandom
6e8c2f
+from collections import namedtuple as _namedtuple
6e8c2f
+
6e8c2f
+
6e8c2f
+_saltchars = _string.ascii_letters + _string.digits + './'
6e8c2f
+_sr = _SystemRandom()
6e8c2f
+
6e8c2f
+
6e8c2f
+class _Method(_namedtuple('_Method', 'name ident salt_chars total_size')):
6e8c2f
+
6e8c2f
+    """Class representing a salt method per the Modular Crypt Format or the
6e8c2f
+    legacy 2-character crypt method."""
6e8c2f
+
6e8c2f
+    def __repr__(self):
6e8c2f
+        return '<crypt.METHOD_%s>' % self.name
6e8c2f
+
6e8c2f
+
6e8c2f
+def mksalt(method=None):
6e8c2f
+    """Generate a salt for the specified method.
6e8c2f
+
6e8c2f
+    If not specified, the strongest available method will be used.
6e8c2f
+
6e8c2f
+    This is a non-standard extension to Python 2.7, backported from 3.3
6e8c2f
+    """
6e8c2f
+    if method is None:
6e8c2f
+        method = methods[0]
6e8c2f
+    s = '$%s$' % method.ident if method.ident else ''
6e8c2f
+    s += ''.join(_sr.sample(_saltchars, method.salt_chars))
6e8c2f
+    return s
6e8c2f
+
6e8c2f
+
6e8c2f
+def crypt(word, salt=None):
6e8c2f
+    """Return a string representing the one-way hash of a password, with a salt
6e8c2f
+    prepended.
6e8c2f
+
6e8c2f
+    If ``salt`` is not specified or is ``None``, the strongest
6e8c2f
+    available method will be selected and a salt generated.  Otherwise,
6e8c2f
+    ``salt`` may be one of the ``crypt.METHOD_*`` values, or a string as
6e8c2f
+    returned by ``crypt.mksalt()``.
6e8c2f
+
6e8c2f
+    Note that these are non-standard extensions to Python 2.7's crypt.crypt()
6e8c2f
+    entrypoint, backported from 3.3: the standard Python 2.7 crypt.crypt()
6e8c2f
+    entrypoint requires two strings as the parameters, and does not support
6e8c2f
+    keyword arguments.
6e8c2f
+    """
6e8c2f
+    if salt is None or isinstance(salt, _Method):
6e8c2f
+        salt = mksalt(salt)
6e8c2f
+    return _crypt.crypt(word, salt)
6e8c2f
+
6e8c2f
+
6e8c2f
+#  available salting/crypto methods
6e8c2f
+METHOD_CRYPT = _Method('CRYPT', None, 2, 13)
6e8c2f
+METHOD_MD5 = _Method('MD5', '1', 8, 34)
6e8c2f
+METHOD_SHA256 = _Method('SHA256', '5', 16, 63)
6e8c2f
+METHOD_SHA512 = _Method('SHA512', '6', 16, 106)
6e8c2f
+
6e8c2f
+methods = []
6e8c2f
+for _method in (METHOD_SHA512, METHOD_SHA256, METHOD_MD5):
6e8c2f
+    _result = crypt('', _method)
6e8c2f
+    if _result and len(_result) == _method.total_size:
6e8c2f
+        methods.append(_method)
6e8c2f
+methods.append(METHOD_CRYPT)
6e8c2f
+del _result, _method
6e8c2f
+
6e8c2f
diff -up Python-2.7.3/Lib/test/test_crypt.py.crypt-module-salt-backport Python-2.7.3/Lib/test/test_crypt.py
6e8c2f
--- Python-2.7.3/Lib/test/test_crypt.py.crypt-module-salt-backport	2012-04-09 19:07:31.000000000 -0400
6e8c2f
+++ Python-2.7.3/Lib/test/test_crypt.py	2013-02-19 16:44:20.465334062 -0500
6e8c2f
@@ -10,6 +10,25 @@ class CryptTestCase(unittest.TestCase):
6e8c2f
         if test_support.verbose:
6e8c2f
             print 'Test encryption: ', c
6e8c2f
 
6e8c2f
+    def test_salt(self):
6e8c2f
+        self.assertEqual(len(crypt._saltchars), 64)
6e8c2f
+        for method in crypt.methods:
6e8c2f
+            salt = crypt.mksalt(method)
6e8c2f
+            self.assertEqual(len(salt),
6e8c2f
+                    method.salt_chars + (3 if method.ident else 0))
6e8c2f
+
6e8c2f
+    def test_saltedcrypt(self):
6e8c2f
+        for method in crypt.methods:
6e8c2f
+            pw = crypt.crypt('assword', method)
6e8c2f
+            self.assertEqual(len(pw), method.total_size)
6e8c2f
+            pw = crypt.crypt('assword', crypt.mksalt(method))
6e8c2f
+            self.assertEqual(len(pw), method.total_size)
6e8c2f
+
6e8c2f
+    def test_methods(self):
6e8c2f
+        # Gurantee that METHOD_CRYPT is the last method in crypt.methods.
6e8c2f
+        self.assertTrue(len(crypt.methods) >= 1)
6e8c2f
+        self.assertEqual(crypt.METHOD_CRYPT, crypt.methods[-1])
6e8c2f
+
6e8c2f
 def test_main():
6e8c2f
     test_support.run_unittest(CryptTestCase)
6e8c2f
 
6e8c2f
diff -up Python-2.7.3/Modules/cryptmodule.c.crypt-module-salt-backport Python-2.7.3/Modules/cryptmodule.c
6e8c2f
--- Python-2.7.3/Modules/cryptmodule.c.crypt-module-salt-backport	2012-04-09 19:07:34.000000000 -0400
6e8c2f
+++ Python-2.7.3/Modules/cryptmodule.c	2013-02-19 16:44:20.466334063 -0500
6e8c2f
@@ -43,7 +43,7 @@ static PyMethodDef crypt_methods[] = {
6e8c2f
 };
6e8c2f
 
6e8c2f
 PyMODINIT_FUNC
6e8c2f
-initcrypt(void)
6e8c2f
+init_crypt(void)
6e8c2f
 {
6e8c2f
-    Py_InitModule("crypt", crypt_methods);
6e8c2f
+    Py_InitModule("_crypt", crypt_methods);
6e8c2f
 }
6e8c2f
diff -up Python-2.7.3/Modules/Setup.dist.crypt-module-salt-backport Python-2.7.3/Modules/Setup.dist
6e8c2f
--- Python-2.7.3/Modules/Setup.dist.crypt-module-salt-backport	2013-02-19 16:44:20.463334063 -0500
6e8c2f
+++ Python-2.7.3/Modules/Setup.dist	2013-02-19 16:44:20.466334063 -0500
6e8c2f
@@ -221,7 +221,7 @@ _ssl _ssl.c \
6e8c2f
 #
6e8c2f
 # First, look at Setup.config; configure may have set this for you.
6e8c2f
 
6e8c2f
-crypt cryptmodule.c # -lcrypt	# crypt(3); needs -lcrypt on some systems
6e8c2f
+_crypt _cryptmodule.c -lcrypt	# crypt(3); needs -lcrypt on some systems
6e8c2f
 
6e8c2f
 
6e8c2f
 # Some more UNIX dependent modules -- off by default, since these
6e8c2f
diff -up Python-2.7.3/setup.py.crypt-module-salt-backport Python-2.7.3/setup.py
6e8c2f
--- Python-2.7.3/setup.py.crypt-module-salt-backport	2013-02-19 16:44:20.425334067 -0500
6e8c2f
+++ Python-2.7.3/setup.py	2013-02-19 16:44:20.466334063 -0500
6e8c2f
@@ -693,7 +693,7 @@ class PyBuildExt(build_ext):
6e8c2f
             libs = ['crypt']
6e8c2f
         else:
6e8c2f
             libs = []
6e8c2f
-        exts.append( Extension('crypt', ['cryptmodule.c'], libraries=libs) )
6e8c2f
+        exts.append( Extension('_crypt', ['_cryptmodule.c'], libraries=libs) )
6e8c2f
 
6e8c2f
         # CSV files
6e8c2f
         exts.append( Extension('_csv', ['_csv.c']) )