aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Reifscheider <jafo@tummy.com>2011-02-22 10:55:44 +0000
committerSean Reifscheider <jafo@tummy.com>2011-02-22 10:55:44 +0000
commite2dfefbe85e0471c35062146a218aea2270ea600 (patch)
tree779b690c9e097108530f75b9bf443f8566bd93d7 /Lib/crypt.py
parentIssue #11074: Make 'tokenize' so it can be reloaded. (diff)
downloadcpython-e2dfefbe85e0471c35062146a218aea2270ea600.tar.gz
cpython-e2dfefbe85e0471c35062146a218aea2270ea600.tar.bz2
cpython-e2dfefbe85e0471c35062146a218aea2270ea600.zip
Issue #10924: Adding salt and Modular Crypt Format to crypt library.
Diffstat (limited to 'Lib/crypt.py')
-rw-r--r--Lib/crypt.py61
1 files changed, 61 insertions, 0 deletions
diff --git a/Lib/crypt.py b/Lib/crypt.py
new file mode 100644
index 00000000000..dc62dba8a32
--- /dev/null
+++ b/Lib/crypt.py
@@ -0,0 +1,61 @@
+'''Wrapper to the POSIX crypt library call and associated functionality.
+'''
+
+import _crypt
+
+saltchars = 'abcdefghijklmnopqrstuvwxyz'
+saltchars += saltchars.upper()
+saltchars += '0123456789./'
+
+
+class _MethodClass:
+ '''Class representing a salt method per the Modular Crypt Format or the
+ legacy 2-character crypt method.'''
+ def __init__(self, name, ident, salt_chars, total_size):
+ self.name = name
+ self.ident = ident
+ self.salt_chars = salt_chars
+ self.total_size = total_size
+
+ def __repr__(self):
+ return '<crypt.METHOD_%s>' % self.name
+
+
+# available salting/crypto methods
+METHOD_CRYPT = _MethodClass('CRYPT', None, 2, 13)
+METHOD_MD5 = _MethodClass('MD5', '1', 8, 34)
+METHOD_SHA256 = _MethodClass('SHA256', '5', 16, 63)
+METHOD_SHA512 = _MethodClass('SHA512', '6', 16, 106)
+
+
+def methods():
+ '''Return a list of methods that are available in the platform ``crypt()``
+ library, sorted from strongest to weakest. This is guaranteed to always
+ return at least ``[METHOD_CRYPT]``'''
+ method_list = [ METHOD_SHA512, METHOD_SHA256, METHOD_MD5 ]
+ ret = [ method for method in method_list
+ if len(crypt('', method)) == method.total_size ]
+ ret.append(METHOD_CRYPT)
+ return ret
+
+
+def mksalt(method = None):
+ '''Generate a salt for the specified method. If not specified, the
+ strongest available method will be used.'''
+ import random
+
+ if method == None: method = methods()[0]
+ s = '$%s$' % method.ident if method.ident else ''
+ s += ''.join([ random.choice(saltchars) for x in range(method.salt_chars) ])
+ return(s)
+
+
+def crypt(word, salt = None):
+ '''Return a string representing the one-way hash of a password, preturbed
+ by a salt. If ``salt`` is not specified or is ``None``, the strongest
+ available method will be selected and a salt generated. Otherwise,
+ ``salt`` may be one of the ``crypt.METHOD_*`` values, or a string as
+ returned by ``crypt.mksalt()``.'''
+ if salt == None: salt = mksalt()
+ elif isinstance(salt, _MethodClass): salt = mksalt(salt)
+ return(_crypt.crypt(word, salt))