115 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			115 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
|   | """
 | ||
|  | Password generation for the yap_ipython notebook. | ||
|  | """
 | ||
|  | #----------------------------------------------------------------------------- | ||
|  | # Imports | ||
|  | #----------------------------------------------------------------------------- | ||
|  | # Stdlib | ||
|  | import getpass | ||
|  | import hashlib | ||
|  | import random | ||
|  | 
 | ||
|  | # Our own | ||
|  | from yap_ipython.core.error import UsageError | ||
|  | from yap_ipython.utils.py3compat import encode | ||
|  | 
 | ||
|  | #----------------------------------------------------------------------------- | ||
|  | # Globals | ||
|  | #----------------------------------------------------------------------------- | ||
|  | 
 | ||
|  | # Length of the salt in nr of hex chars, which implies salt_len * 4 | ||
|  | # bits of randomness. | ||
|  | salt_len = 12 | ||
|  | 
 | ||
|  | #----------------------------------------------------------------------------- | ||
|  | # Functions | ||
|  | #----------------------------------------------------------------------------- | ||
|  | 
 | ||
|  | def passwd(passphrase=None, algorithm='sha1'): | ||
|  |     """Generate hashed password and salt for use in notebook configuration.
 | ||
|  | 
 | ||
|  |     In the notebook configuration, set `c.NotebookApp.password` to | ||
|  |     the generated string. | ||
|  | 
 | ||
|  |     Parameters | ||
|  |     ---------- | ||
|  |     passphrase : str | ||
|  |         Password to hash.  If unspecified, the user is asked to input | ||
|  |         and verify a password. | ||
|  |     algorithm : str | ||
|  |         Hashing algorithm to use (e.g, 'sha1' or any argument supported | ||
|  |         by :func:`hashlib.new`). | ||
|  | 
 | ||
|  |     Returns | ||
|  |     ------- | ||
|  |     hashed_passphrase : str | ||
|  |         Hashed password, in the format 'hash_algorithm:salt:passphrase_hash'. | ||
|  | 
 | ||
|  |     Examples | ||
|  |     -------- | ||
|  |     >>> passwd('mypassword') | ||
|  |     'sha1:7cf3:b7d6da294ea9592a9480c8f52e63cd42cfb9dd12' | ||
|  | 
 | ||
|  |     """
 | ||
|  |     if passphrase is None: | ||
|  |         for i in range(3): | ||
|  |             p0 = getpass.getpass('Enter password: ') | ||
|  |             p1 = getpass.getpass('Verify password: ') | ||
|  |             if p0 == p1: | ||
|  |                 passphrase = p0 | ||
|  |                 break | ||
|  |             else: | ||
|  |                 print('Passwords do not match.') | ||
|  |         else: | ||
|  |             raise UsageError('No matching passwords found. Giving up.') | ||
|  | 
 | ||
|  |     h = hashlib.new(algorithm) | ||
|  |     salt = ('%0' + str(salt_len) + 'x') % random.getrandbits(4 * salt_len) | ||
|  |     h.update(encode(passphrase, 'utf-8') + encode(salt, 'ascii')) | ||
|  | 
 | ||
|  |     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 | ||
|  |     -------- | ||
|  |     >>> from yap_ipython.lib.security import passwd_check | ||
|  |     >>> passwd_check('sha1:0e112c3ddfce:a68df677475c2b47b6e86d0467eec97ac5f4b85a', | ||
|  |     ...              'mypassword') | ||
|  |     True | ||
|  | 
 | ||
|  |     >>> passwd_check('sha1:0e112c3ddfce:a68df677475c2b47b6e86d0467eec97ac5f4b85a', | ||
|  |     ...              'anotherpassword') | ||
|  |     False | ||
|  |     """
 | ||
|  |     try: | ||
|  |         algorithm, salt, pw_digest = hashed_passphrase.split(':', 2) | ||
|  |     except (ValueError, TypeError): | ||
|  |         return False | ||
|  | 
 | ||
|  |     try: | ||
|  |         h = hashlib.new(algorithm) | ||
|  |     except ValueError: | ||
|  |         return False | ||
|  | 
 | ||
|  |     if len(pw_digest) == 0: | ||
|  |         return False | ||
|  | 
 | ||
|  |     h.update(encode(passphrase, 'utf-8') + encode(salt, 'ascii')) | ||
|  | 
 | ||
|  |     return h.hexdigest() == pw_digest |