##// END OF EJS Templates
Fix password hashing for Python 3...
Thomas Kluyver -
Show More
@@ -1,117 +1,118 b''
1 1 """
2 2 Password generation for the IPython notebook.
3 3 """
4 4 #-----------------------------------------------------------------------------
5 5 # Imports
6 6 #-----------------------------------------------------------------------------
7 7 # Stdlib
8 8 import getpass
9 9 import hashlib
10 10 import random
11 11
12 12 # Our own
13 13 from IPython.core.error import UsageError
14 14 from IPython.testing.skipdoctest import skip_doctest
15 from IPython.utils.py3compat import cast_bytes, str_to_bytes
15 16
16 17 #-----------------------------------------------------------------------------
17 18 # Globals
18 19 #-----------------------------------------------------------------------------
19 20
20 21 # Length of the salt in nr of hex chars, which implies salt_len * 4
21 22 # bits of randomness.
22 23 salt_len = 12
23 24
24 25 #-----------------------------------------------------------------------------
25 26 # Functions
26 27 #-----------------------------------------------------------------------------
27 28
28 29 @skip_doctest
29 30 def passwd(passphrase=None, algorithm='sha1'):
30 31 """Generate hashed password and salt for use in notebook configuration.
31 32
32 33 In the notebook configuration, set `c.NotebookApp.password` to
33 34 the generated string.
34 35
35 36 Parameters
36 37 ----------
37 38 passphrase : str
38 39 Password to hash. If unspecified, the user is asked to input
39 40 and verify a password.
40 41 algorithm : str
41 42 Hashing algorithm to use (e.g, 'sha1' or any argument supported
42 43 by :func:`hashlib.new`).
43 44
44 45 Returns
45 46 -------
46 47 hashed_passphrase : str
47 48 Hashed password, in the format 'hash_algorithm:salt:passphrase_hash'.
48 49
49 50 Examples
50 51 --------
51 52 In [1]: passwd('mypassword')
52 53 Out[1]: 'sha1:7cf3:b7d6da294ea9592a9480c8f52e63cd42cfb9dd12'
53 54
54 55 """
55 56 if passphrase is None:
56 57 for i in range(3):
57 58 p0 = getpass.getpass('Enter password: ')
58 59 p1 = getpass.getpass('Verify password: ')
59 60 if p0 == p1:
60 61 passphrase = p0
61 62 break
62 63 else:
63 64 print('Passwords do not match.')
64 65 else:
65 66 raise UsageError('No matching passwords found. Giving up.')
66 67
67 68 h = hashlib.new(algorithm)
68 69 salt = ('%0' + str(salt_len) + 'x') % random.getrandbits(4 * salt_len)
69 h.update(passphrase + salt)
70 h.update(cast_bytes(passphrase, 'utf-8') + str_to_bytes(salt, 'ascii'))
70 71
71 72 return ':'.join((algorithm, salt, h.hexdigest()))
72 73
73 74
74 75 def passwd_check(hashed_passphrase, passphrase):
75 76 """Verify that a given passphrase matches its hashed version.
76 77
77 78 Parameters
78 79 ----------
79 80 hashed_passphrase : str
80 81 Hashed password, in the format returned by `passwd`.
81 82 passphrase : str
82 83 Passphrase to validate.
83 84
84 85 Returns
85 86 -------
86 87 valid : bool
87 88 True if the passphrase matches the hash.
88 89
89 90 Examples
90 91 --------
91 92 In [1]: from IPython.lib.security import passwd_check
92 93
93 94 In [2]: passwd_check('sha1:0e112c3ddfce:a68df677475c2b47b6e86d0467eec97ac5f4b85a',
94 95 ...: 'mypassword')
95 96 Out[2]: True
96 97
97 98 In [3]: passwd_check('sha1:0e112c3ddfce:a68df677475c2b47b6e86d0467eec97ac5f4b85a',
98 99 ...: 'anotherpassword')
99 100 Out[3]: False
100 101
101 102 """
102 103 try:
103 104 algorithm, salt, pw_digest = hashed_passphrase.split(':', 2)
104 105 except (ValueError, TypeError):
105 106 return False
106 107
107 108 try:
108 109 h = hashlib.new(algorithm)
109 110 except ValueError:
110 111 return False
111 112
112 113 if len(pw_digest) == 0:
113 114 return False
114 115
115 h.update(passphrase + salt)
116 h.update(cast_bytes(passphrase, 'utf-8') + str_to_bytes(salt, 'ascii'))
116 117
117 118 return h.hexdigest() == pw_digest
General Comments 0
You need to be logged in to leave comments. Login now