security.py 3.3 KB

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