Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add hashed passphrase generation and verification.

  • Loading branch information...
commit 551f71ec6c94325619225b6a08753f9ad120e913 1 parent 69a09eb
Stefan van der Walt authored
2  IPython/lib/__init__.py
View
@@ -25,6 +25,8 @@
current_gui
)
+from IPython.lib.security import passwd
+
#-----------------------------------------------------------------------------
# Code
#-----------------------------------------------------------------------------
79 IPython/lib/security.py
View
@@ -0,0 +1,79 @@
+"""
+Password generation for the IPython notebook.
+"""
+
+import hashlib
+import random
+
+def passwd(passphrase):
+ """Generate hashed password and salt for use in notebook configuration.
+
+ Parameters
+ ----------
+ passphrase : str
+ Password to hash.
+
+ Returns
+ -------
+ hashed_passphrase : str
+ Hashed password, in the format 'hash_algorithm:salt:passphrase_hash'.
+
+ Examples
+ --------
+ In [1]: passwd('mypassword')
+ Out[1]: 'sha1:7cf3:b7d6da294ea9592a9480c8f52e63cd42cfb9dd12'
+
+ """
+ algorithm = 'sha1'
+
+ h = hashlib.new(algorithm)
+ salt = hex(int(random.getrandbits(16)))[2:]
+ h.update(passphrase + salt)
+
+ return ':'.join((algorithm, salt, h.hexdigest()))
+
+def passwd_check(hashed_passphrase, passphrase):
+ """Verify that a given passphrase matches its hashed version.
+
+ Parameters
+ ----------
+ hashed_passphrase : str
+ Hashed password, in the format returned by `passwd`.
+ passphrase : str
+ Passphrase to validate.
+
+ Returns
+ -------
+ valid : bool
+ True if the passphrase matches the hash.
+
+ Examples
+ --------
+ In [1]: from IPython.lib.security import passwd_check
+
+ In [2]: passwd_check('sha1:7cf3:b7d6da294ea9592a9480c8f52e63cd42cfb9dd12',
+ ...: 'mypassword')
+ Out[2]: True
+
+ In [3]: passwd_check('sha1:7cf3:b7d6da294ea9592a9480c8f52e63cd42cfb9dd12',
+ ...: 'anotherpassword')
+ Out[3]: False
+
+ """
+ # Algorithm and hash length
+ supported_algorithms = {'sha1': 40}
+
+ try:
+ algorithm, salt, pw_digest = hashed_passphrase.split(':', 2)
+ except (ValueError, TypeError):
+ return False
+
+ if not (algorithm in supported_algorithms and \
+ len(pw_digest) == supported_algorithms[algorithm] and \
+ len(salt) == 4):
+ return False
+
+ h = hashlib.new(algorithm)
+ h.update(passphrase + salt)
+
+ return h.hexdigest() == pw_digest
21 IPython/lib/tests/test_security.py
View
@@ -0,0 +1,21 @@
+from IPython.lib import passwd
+from IPython.lib.security import passwd_check
+import nose.tools as nt
+
+def test_passwd_structure():
+ p = passwd('passphrase')
+ algorithm, salt, hashed = p.split(':')
+ nt.assert_equals(algorithm, 'sha1')
+ nt.assert_equals(len(salt), 4)
+ nt.assert_equals(len(hashed), 40)
+
+def test_roundtrip():
+ p = passwd('passphrase')
+ nt.assert_equals(passwd_check(p, 'passphrase'), True)
+
+def test_bad():
+ p = passwd('passphrase')
+ nt.assert_equals(passwd_check(p, p), False)
+ nt.assert_equals(passwd_check(p, 'a:b:c:d'), False)
+ nt.assert_equals(passwd_check(p, 'a:b'), False)
+
Please sign in to comment.
Something went wrong with that request. Please try again.