Georg Brandl | 116aa62 | 2007-08-15 14:28:22 +0000 | [diff] [blame] | 1 | :mod:`crypt` --- Function to check Unix passwords |
| 2 | ================================================= |
| 3 | |
| 4 | .. module:: crypt |
| 5 | :platform: Unix |
| 6 | :synopsis: The crypt() function used to check Unix passwords. |
| 7 | .. moduleauthor:: Steven D. Majewski <sdm7g@virginia.edu> |
| 8 | .. sectionauthor:: Steven D. Majewski <sdm7g@virginia.edu> |
| 9 | .. sectionauthor:: Peter Funk <pf@artcom-gmbh.de> |
| 10 | |
| 11 | |
| 12 | .. index:: |
| 13 | single: crypt(3) |
| 14 | pair: cipher; DES |
| 15 | |
| 16 | This module implements an interface to the :manpage:`crypt(3)` routine, which is |
| 17 | a one-way hash function based upon a modified DES algorithm; see the Unix man |
Sean Reifscheider | e2dfefb | 2011-02-22 10:55:44 +0000 | [diff] [blame] | 18 | page for further details. Possible uses include storing hashed passwords |
| 19 | so you can check passwords without storing the actual password, or attempting |
| 20 | to crack Unix passwords with a dictionary. |
Georg Brandl | 116aa62 | 2007-08-15 14:28:22 +0000 | [diff] [blame] | 21 | |
| 22 | .. index:: single: crypt(3) |
| 23 | |
| 24 | Notice that the behavior of this module depends on the actual implementation of |
| 25 | the :manpage:`crypt(3)` routine in the running system. Therefore, any |
| 26 | extensions available on the current implementation will also be available on |
| 27 | this module. |
| 28 | |
Sean Reifscheider | e2dfefb | 2011-02-22 10:55:44 +0000 | [diff] [blame] | 29 | Hashing Methods |
| 30 | --------------- |
Georg Brandl | 116aa62 | 2007-08-15 14:28:22 +0000 | [diff] [blame] | 31 | |
Éric Araujo | f215631 | 2011-05-29 03:27:48 +0200 | [diff] [blame] | 32 | .. versionadded:: 3.3 |
| 33 | |
Sean Reifscheider | e2dfefb | 2011-02-22 10:55:44 +0000 | [diff] [blame] | 34 | The :mod:`crypt` module defines the list of hashing methods (not all methods |
| 35 | are available on all platforms): |
| 36 | |
| 37 | .. data:: METHOD_SHA512 |
| 38 | |
| 39 | A Modular Crypt Format method with 16 character salt and 86 character |
| 40 | hash. This is the strongest method. |
| 41 | |
Sean Reifscheider | e2dfefb | 2011-02-22 10:55:44 +0000 | [diff] [blame] | 42 | .. data:: METHOD_SHA256 |
| 43 | |
| 44 | Another Modular Crypt Format method with 16 character salt and 43 |
| 45 | character hash. |
| 46 | |
Sean Reifscheider | e2dfefb | 2011-02-22 10:55:44 +0000 | [diff] [blame] | 47 | .. data:: METHOD_MD5 |
| 48 | |
| 49 | Another Modular Crypt Format method with 8 character salt and 22 |
| 50 | character hash. |
| 51 | |
Sean Reifscheider | e2dfefb | 2011-02-22 10:55:44 +0000 | [diff] [blame] | 52 | .. data:: METHOD_CRYPT |
| 53 | |
| 54 | The traditional method with a 2 character salt and 13 characters of |
| 55 | hash. This is the weakest method. |
| 56 | |
Brett Cannon | daa5799 | 2011-02-22 21:48:06 +0000 | [diff] [blame] | 57 | |
| 58 | Module Attributes |
| 59 | ----------------- |
| 60 | |
Éric Araujo | f215631 | 2011-05-29 03:27:48 +0200 | [diff] [blame] | 61 | .. versionadded:: 3.3 |
Brett Cannon | daa5799 | 2011-02-22 21:48:06 +0000 | [diff] [blame] | 62 | |
| 63 | .. attribute:: methods |
| 64 | |
| 65 | A list of available password hashing algorithms, as |
| 66 | ``crypt.METHOD_*`` objects. This list is sorted from strongest to |
Victor Stinner | 6661d88 | 2015-10-02 23:00:39 +0200 | [diff] [blame] | 67 | weakest. |
Brett Cannon | daa5799 | 2011-02-22 21:48:06 +0000 | [diff] [blame] | 68 | |
Brett Cannon | daa5799 | 2011-02-22 21:48:06 +0000 | [diff] [blame] | 69 | |
Sean Reifscheider | e2dfefb | 2011-02-22 10:55:44 +0000 | [diff] [blame] | 70 | Module Functions |
| 71 | ---------------- |
| 72 | |
| 73 | The :mod:`crypt` module defines the following functions: |
| 74 | |
| 75 | .. function:: crypt(word, salt=None) |
Georg Brandl | 116aa62 | 2007-08-15 14:28:22 +0000 | [diff] [blame] | 76 | |
| 77 | *word* will usually be a user's password as typed at a prompt or in a graphical |
Sean Reifscheider | e2dfefb | 2011-02-22 10:55:44 +0000 | [diff] [blame] | 78 | interface. The optional *salt* is either a string as returned from |
| 79 | :func:`mksalt`, one of the ``crypt.METHOD_*`` values (though not all |
| 80 | may be available on all platforms), or a full encrypted password |
| 81 | including salt, as returned by this function. If *salt* is not |
| 82 | provided, the strongest method will be used (as returned by |
| 83 | :func:`methods`. |
| 84 | |
| 85 | Checking a password is usually done by passing the plain-text password |
| 86 | as *word* and the full results of a previous :func:`crypt` call, |
| 87 | which should be the same as the results of this call. |
| 88 | |
| 89 | *salt* (either a random 2 or 16 character string, possibly prefixed with |
| 90 | ``$digit$`` to indicate the method) which will be used to perturb the |
| 91 | encryption algorithm. The characters in *salt* must be in the set |
| 92 | ``[./a-zA-Z0-9]``, with the exception of Modular Crypt Format which |
| 93 | prefixes a ``$digit$``. |
| 94 | |
| 95 | Returns the hashed password as a string, which will be composed of |
| 96 | characters from the same alphabet as the salt. |
Georg Brandl | 116aa62 | 2007-08-15 14:28:22 +0000 | [diff] [blame] | 97 | |
| 98 | .. index:: single: crypt(3) |
| 99 | |
| 100 | Since a few :manpage:`crypt(3)` extensions allow different values, with |
| 101 | different sizes in the *salt*, it is recommended to use the full crypted |
| 102 | password as salt when checking for a password. |
| 103 | |
Éric Araujo | f215631 | 2011-05-29 03:27:48 +0200 | [diff] [blame] | 104 | .. versionchanged:: 3.3 |
| 105 | Accept ``crypt.METHOD_*`` values in addition to strings for *salt*. |
Sean Reifscheider | e2dfefb | 2011-02-22 10:55:44 +0000 | [diff] [blame] | 106 | |
Sean Reifscheider | e2dfefb | 2011-02-22 10:55:44 +0000 | [diff] [blame] | 107 | |
| 108 | .. function:: mksalt(method=None) |
| 109 | |
| 110 | Return a randomly generated salt of the specified method. If no |
| 111 | *method* is given, the strongest method available as returned by |
| 112 | :func:`methods` is used. |
| 113 | |
| 114 | The return value is a string either of 2 characters in length for |
| 115 | ``crypt.METHOD_CRYPT``, or 19 characters starting with ``$digit$`` and |
| 116 | 16 random characters from the set ``[./a-zA-Z0-9]``, suitable for |
| 117 | passing as the *salt* argument to :func:`crypt`. |
| 118 | |
Éric Araujo | f215631 | 2011-05-29 03:27:48 +0200 | [diff] [blame] | 119 | .. versionadded:: 3.3 |
Sean Reifscheider | e2dfefb | 2011-02-22 10:55:44 +0000 | [diff] [blame] | 120 | |
| 121 | Examples |
| 122 | -------- |
| 123 | |
Nick Coghlan | 74cca70 | 2012-09-28 18:50:38 +0530 | [diff] [blame] | 124 | A simple example illustrating typical use (a constant-time comparison |
| 125 | operation is needed to limit exposure to timing attacks. |
| 126 | :func:`hmac.compare_digest` is suitable for this purpose):: |
Georg Brandl | 116aa62 | 2007-08-15 14:28:22 +0000 | [diff] [blame] | 127 | |
Éric Araujo | bc57789 | 2011-05-29 03:24:45 +0200 | [diff] [blame] | 128 | import pwd |
| 129 | import crypt |
| 130 | import getpass |
Nick Coghlan | 74cca70 | 2012-09-28 18:50:38 +0530 | [diff] [blame] | 131 | from hmac import compare_digest as compare_hash |
Georg Brandl | 116aa62 | 2007-08-15 14:28:22 +0000 | [diff] [blame] | 132 | |
Georg Brandl | 116aa62 | 2007-08-15 14:28:22 +0000 | [diff] [blame] | 133 | def login(): |
Éric Araujo | bc57789 | 2011-05-29 03:24:45 +0200 | [diff] [blame] | 134 | username = input('Python login: ') |
Georg Brandl | 116aa62 | 2007-08-15 14:28:22 +0000 | [diff] [blame] | 135 | cryptedpasswd = pwd.getpwnam(username)[1] |
| 136 | if cryptedpasswd: |
Georg Brandl | 48310cd | 2009-01-03 21:18:54 +0000 | [diff] [blame] | 137 | if cryptedpasswd == 'x' or cryptedpasswd == '*': |
Éric Araujo | bc57789 | 2011-05-29 03:24:45 +0200 | [diff] [blame] | 138 | raise ValueError('no support for shadow passwords') |
Georg Brandl | 116aa62 | 2007-08-15 14:28:22 +0000 | [diff] [blame] | 139 | cleartext = getpass.getpass() |
Nick Coghlan | 74cca70 | 2012-09-28 18:50:38 +0530 | [diff] [blame] | 140 | return compare_hash(crypt.crypt(cleartext, cryptedpasswd), cryptedpasswd) |
Georg Brandl | 116aa62 | 2007-08-15 14:28:22 +0000 | [diff] [blame] | 141 | else: |
Éric Araujo | bc57789 | 2011-05-29 03:24:45 +0200 | [diff] [blame] | 142 | return True |
Georg Brandl | 116aa62 | 2007-08-15 14:28:22 +0000 | [diff] [blame] | 143 | |
Sean Reifscheider | e2dfefb | 2011-02-22 10:55:44 +0000 | [diff] [blame] | 144 | To generate a hash of a password using the strongest available method and |
| 145 | check it against the original:: |
| 146 | |
| 147 | import crypt |
Nick Coghlan | 74cca70 | 2012-09-28 18:50:38 +0530 | [diff] [blame] | 148 | from hmac import compare_digest as compare_hash |
Sean Reifscheider | e2dfefb | 2011-02-22 10:55:44 +0000 | [diff] [blame] | 149 | |
| 150 | hashed = crypt.crypt(plaintext) |
Nick Coghlan | 74cca70 | 2012-09-28 18:50:38 +0530 | [diff] [blame] | 151 | if not compare_hash(hashed, crypt.crypt(plaintext, hashed)): |
Éric Araujo | bc57789 | 2011-05-29 03:24:45 +0200 | [diff] [blame] | 152 | raise ValueError("hashed version doesn't validate against original") |