gh-104773: PEP 594: Remove the crypt module (#104908)

Remove the crypt module and its private _crypt extension, deprecated
in Python 3.11.
This commit is contained in:
Victor Stinner 2023-05-25 15:45:46 +02:00 committed by GitHub
parent 38539ef126
commit e4127eaa1e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 35 additions and 991 deletions

View File

@ -1,182 +0,0 @@
:mod:`crypt` --- Function to check Unix passwords
=================================================
.. module:: crypt
:platform: Unix
:synopsis: The crypt() function used to check Unix passwords.
:deprecated:
.. moduleauthor:: Steven D. Majewski <sdm7g@virginia.edu>
.. sectionauthor:: Steven D. Majewski <sdm7g@virginia.edu>
.. sectionauthor:: Peter Funk <pf@artcom-gmbh.de>
**Source code:** :source:`Lib/crypt.py`
.. index::
single: crypt(3)
pair: cipher; DES
.. deprecated-removed:: 3.11 3.13
The :mod:`crypt` module is deprecated
(see :pep:`PEP 594 <594#crypt>` for details and alternatives).
The :mod:`hashlib` module is a potential replacement for certain use cases.
--------------
This module implements an interface to the :manpage:`crypt(3)` routine, which is
a one-way hash function based upon a modified DES algorithm; see the Unix man
page for further details. Possible uses include storing hashed passwords
so you can check passwords without storing the actual password, or attempting
to crack Unix passwords with a dictionary.
.. index:: single: crypt(3)
Notice that the behavior of this module depends on the actual implementation of
the :manpage:`crypt(3)` routine in the running system. Therefore, any
extensions available on the current implementation will also be available on
this module.
.. availability:: Unix, not VxWorks.
.. include:: ../includes/wasm-notavail.rst
Hashing Methods
---------------
.. versionadded:: 3.3
The :mod:`crypt` module defines the list of hashing methods (not all methods
are available on all platforms):
.. data:: METHOD_SHA512
A Modular Crypt Format method with 16 character salt and 86 character
hash based on the SHA-512 hash function. This is the strongest method.
.. data:: METHOD_SHA256
Another Modular Crypt Format method with 16 character salt and 43
character hash based on the SHA-256 hash function.
.. data:: METHOD_BLOWFISH
Another Modular Crypt Format method with 22 character salt and 31
character hash based on the Blowfish cipher.
.. versionadded:: 3.7
.. data:: METHOD_MD5
Another Modular Crypt Format method with 8 character salt and 22
character hash based on the MD5 hash function.
.. data:: METHOD_CRYPT
The traditional method with a 2 character salt and 13 characters of
hash. This is the weakest method.
Module Attributes
-----------------
.. versionadded:: 3.3
.. attribute:: methods
A list of available password hashing algorithms, as
``crypt.METHOD_*`` objects. This list is sorted from strongest to
weakest.
Module Functions
----------------
The :mod:`crypt` module defines the following functions:
.. function:: crypt(word, salt=None)
*word* will usually be a user's password as typed at a prompt or in a graphical
interface. The optional *salt* is either a string as returned from
:func:`mksalt`, one of the ``crypt.METHOD_*`` values (though not all
may be available on all platforms), or a full encrypted password
including salt, as returned by this function. If *salt* is not
provided, the strongest method available in :attr:`methods` will be used.
Checking a password is usually done by passing the plain-text password
as *word* and the full results of a previous :func:`crypt` call,
which should be the same as the results of this call.
*salt* (either a random 2 or 16 character string, possibly prefixed with
``$digit$`` to indicate the method) which will be used to perturb the
encryption algorithm. The characters in *salt* must be in the set
``[./a-zA-Z0-9]``, with the exception of Modular Crypt Format which
prefixes a ``$digit$``.
Returns the hashed password as a string, which will be composed of
characters from the same alphabet as the salt.
.. index:: single: crypt(3)
Since a few :manpage:`crypt(3)` extensions allow different values, with
different sizes in the *salt*, it is recommended to use the full crypted
password as salt when checking for a password.
.. versionchanged:: 3.3
Accept ``crypt.METHOD_*`` values in addition to strings for *salt*.
.. function:: mksalt(method=None, *, rounds=None)
Return a randomly generated salt of the specified method. If no
*method* is given, the strongest method available in :attr:`methods` is
used.
The return value is a string suitable for passing as the *salt* argument
to :func:`crypt`.
*rounds* specifies the number of rounds for ``METHOD_SHA256``,
``METHOD_SHA512`` and ``METHOD_BLOWFISH``.
For ``METHOD_SHA256`` and ``METHOD_SHA512`` it must be an integer between
``1000`` and ``999_999_999``, the default is ``5000``. For
``METHOD_BLOWFISH`` it must be a power of two between ``16`` (2\ :sup:`4`)
and ``2_147_483_648`` (2\ :sup:`31`), the default is ``4096``
(2\ :sup:`12`).
.. versionadded:: 3.3
.. versionchanged:: 3.7
Added the *rounds* parameter.
Examples
--------
A simple example illustrating typical use (a constant-time comparison
operation is needed to limit exposure to timing attacks.
:func:`hmac.compare_digest` is suitable for this purpose)::
import pwd
import crypt
import getpass
from hmac import compare_digest as compare_hash
def login():
username = input('Python login: ')
cryptedpasswd = pwd.getpwnam(username)[1]
if cryptedpasswd:
if cryptedpasswd == 'x' or cryptedpasswd == '*':
raise ValueError('no support for shadow passwords')
cleartext = getpass.getpass()
return compare_hash(crypt.crypt(cleartext, cryptedpasswd), cryptedpasswd)
else:
return True
To generate a hash of a password using the strongest available method and
check it against the original::
import crypt
from hmac import compare_digest as compare_hash
hashed = crypt.crypt(plaintext)
if not compare_hash(hashed, crypt.crypt(plaintext, hashed)):
raise ValueError("hashed version doesn't validate against original")

View File

@ -8,7 +8,6 @@ Cryptographic Services
The modules described in this chapter implement various algorithms of a
cryptographic nature. They are available at the discretion of the installation.
On Unix systems, the :mod:`crypt` module may also be available.
Here's an overview:

View File

@ -39,10 +39,8 @@ raised if the entry asked for cannot be found.
.. note::
.. index:: pair: module; crypt
In traditional Unix the field ``pw_passwd`` usually contains a password
encrypted with a DES derived algorithm (see module :mod:`crypt`). However most
encrypted with a DES derived algorithm. However most
modern unices use a so-called *shadow password* system. On those unices the
*pw_passwd* field only contains an asterisk (``'*'``) or the letter ``'x'``
where the encrypted password is stored in a file :file:`/etc/shadow` which is

View File

@ -13,7 +13,6 @@ backwards compatibility. They have been superseded by other modules.
aifc.rst
audioop.rst
chunk.rst
crypt.rst
imghdr.rst
optparse.rst
uu.rst

View File

@ -655,7 +655,7 @@ copyright and licensing notice::
OpenSSL
-------
The modules :mod:`hashlib`, :mod:`posix`, :mod:`ssl`, :mod:`crypt` use
The modules :mod:`hashlib`, :mod:`posix` and :mod:`ssl` use
the OpenSSL library for added performance if made available by the
operating system. Additionally, the Windows and macOS installers for
Python may include a copy of the OpenSSL libraries, so we include a copy

View File

@ -1733,7 +1733,7 @@ Modules
+---------------------+---------------------+---------------------+---------------------+---------------------+
| :mod:`aifc` | :mod:`chunk` | :mod:`!msilib` | :mod:`!pipes` | :mod:`!telnetlib` |
+---------------------+---------------------+---------------------+---------------------+---------------------+
| :mod:`audioop` | :mod:`crypt` | :mod:`!nis` | :mod:`!sndhdr` | :mod:`uu` |
| :mod:`audioop` | :mod:`!crypt` | :mod:`!nis` | :mod:`!sndhdr` | :mod:`uu` |
+---------------------+---------------------+---------------------+---------------------+---------------------+
| :mod:`!cgi` | :mod:`imghdr` | :mod:`!nntplib` | :mod:`!spwd` | :mod:`!xdrlib` |
+---------------------+---------------------+---------------------+---------------------+---------------------+

View File

@ -923,7 +923,7 @@ Modules (see :pep:`594`):
* :mod:`!cgi`
* :mod:`!cgitb`
* :mod:`chunk`
* :mod:`crypt`
* :mod:`!crypt`
* :mod:`imghdr`
* :mod:`!mailcap`
* :mod:`!msilib`

View File

@ -201,6 +201,22 @@ Removed
* :pep:`594`: Remove the :mod:`!msilib` module, deprecated in Python 3.11.
(Contributed by Zachary Ware in :gh:`104773`.)
* :pep:`594`: Remove the :mod:`!crypt` module and its private :mod:`!_crypt`
extension, deprecated in Python 3.11.
The :mod:`hashlib` module is a potential replacement for certain use cases.
Otherwise, the following PyPI projects can be used:
* `bcrypt <https://pypi.org/project/bcrypt/>`_:
Modern password hashing for your software and your servers.
* `passlib <https://pypi.org/project/passlib/>`_:
Comprehensive password hashing framework supporting over 30 schemes.
* `argon2-cffi <https://pypi.org/project/argon2-cffi/>`_:
The secure Argon2 password hashing algorithm.
* `legacycrypt <https://pypi.org/project/legacycrypt/>`_:
Wrapper to the POSIX crypt library call and associated functionality.
(Contributed by Victor Stinner in :gh:`104773`.)
Porting to Python 3.13
======================

View File

@ -1052,8 +1052,8 @@ their ``__init__`` method (for example, file objects) or in their
crypt
-----
Addition of salt and modular crypt format (hashing method) and the :func:`~crypt.mksalt`
function to the :mod:`crypt` module.
Addition of salt and modular crypt format (hashing method) and the :func:`~!crypt.mksalt`
function to the :mod:`!crypt` module.
(:issue:`10924`)

View File

@ -2274,7 +2274,7 @@ Changes in the Python API
:class:`~collections.OrderedDict`.
(Contributed by Steve Holden in :issue:`27842`.)
* The :const:`crypt.METHOD_CRYPT` will no longer be added to ``crypt.methods``
* The :const:`!crypt.METHOD_CRYPT` will no longer be added to ``crypt.methods``
if unsupported by the platform.
(Contributed by Victor Stinner in :issue:`25287`.)

View File

@ -848,10 +848,10 @@ alternative to script path. (Contributed by Sanyam Khurana in :issue:`21862`.)
crypt
-----
The :mod:`crypt` module now supports the Blowfish hashing method.
The :mod:`!crypt` module now supports the Blowfish hashing method.
(Contributed by Serhiy Storchaka in :issue:`31664`.)
The :func:`~crypt.mksalt` function now allows specifying the number of rounds
The :func:`~!crypt.mksalt` function now allows specifying the number of rounds
for hashing. (Contributed by Serhiy Storchaka in :issue:`31702`.)

View File

@ -83,7 +83,7 @@ Interpreter improvements:
now sped up using :pep:`590` vectorcall;
* garbage collection does not block on resurrected objects;
* a number of Python modules (:mod:`_abc`, :mod:`audioop`, :mod:`_bz2`,
:mod:`_codecs`, :mod:`_contextvars`, :mod:`_crypt`, :mod:`_functools`,
:mod:`_codecs`, :mod:`_contextvars`, :mod:`!_crypt`, :mod:`_functools`,
:mod:`_json`, :mod:`_locale`, :mod:`math`, :mod:`operator`, :mod:`resource`,
:mod:`time`, :mod:`_weakref`) now use multiphase initialization as defined
by PEP 489;

View File

@ -1,124 +0,0 @@
"""Wrapper to the POSIX crypt library call and associated functionality."""
import sys as _sys
try:
import _crypt
except ModuleNotFoundError:
if _sys.platform == 'win32':
raise ImportError("The crypt module is not supported on Windows")
else:
raise ImportError("The required _crypt module was not built as part of CPython")
import errno
import string as _string
import warnings
from random import SystemRandom as _SystemRandom
from collections import namedtuple as _namedtuple
warnings._deprecated(__name__, remove=(3, 13))
_saltchars = _string.ascii_letters + _string.digits + './'
_sr = _SystemRandom()
class _Method(_namedtuple('_Method', 'name ident salt_chars total_size')):
"""Class representing a salt method per the Modular Crypt Format or the
legacy 2-character crypt method."""
def __repr__(self):
return '<crypt.METHOD_{}>'.format(self.name)
def mksalt(method=None, *, rounds=None):
"""Generate a salt for the specified method.
If not specified, the strongest available method will be used.
"""
if method is None:
method = methods[0]
if rounds is not None and not isinstance(rounds, int):
raise TypeError(f'{rounds.__class__.__name__} object cannot be '
f'interpreted as an integer')
if not method.ident: # traditional
s = ''
else: # modular
s = f'${method.ident}$'
if method.ident and method.ident[0] == '2': # Blowfish variants
if rounds is None:
log_rounds = 12
else:
log_rounds = int.bit_length(rounds-1)
if rounds != 1 << log_rounds:
raise ValueError('rounds must be a power of 2')
if not 4 <= log_rounds <= 31:
raise ValueError('rounds out of the range 2**4 to 2**31')
s += f'{log_rounds:02d}$'
elif method.ident in ('5', '6'): # SHA-2
if rounds is not None:
if not 1000 <= rounds <= 999_999_999:
raise ValueError('rounds out of the range 1000 to 999_999_999')
s += f'rounds={rounds}$'
elif rounds is not None:
raise ValueError(f"{method} doesn't support the rounds argument")
s += ''.join(_sr.choice(_saltchars) for char in range(method.salt_chars))
return s
def crypt(word, salt=None):
"""Return a string representing the one-way hash of a password, with a salt
prepended.
If ``salt`` is not specified or is ``None``, the strongest
available method will be selected and a salt generated. Otherwise,
``salt`` may be one of the ``crypt.METHOD_*`` values, or a string as
returned by ``crypt.mksalt()``.
"""
if salt is None or isinstance(salt, _Method):
salt = mksalt(salt)
return _crypt.crypt(word, salt)
# available salting/crypto methods
methods = []
def _add_method(name, *args, rounds=None):
method = _Method(name, *args)
globals()['METHOD_' + name] = method
salt = mksalt(method, rounds=rounds)
result = None
try:
result = crypt('', salt)
except OSError as e:
# Not all libc libraries support all encryption methods.
if e.errno in {errno.EINVAL, errno.EPERM, errno.ENOSYS}:
return False
raise
if result and len(result) == method.total_size:
methods.append(method)
return True
return False
_add_method('SHA512', '6', 16, 106)
_add_method('SHA256', '5', 16, 63)
# Choose the strongest supported version of Blowfish hashing.
# Early versions have flaws. Version 'a' fixes flaws of
# the initial implementation, 'b' fixes flaws of 'a'.
# 'y' is the same as 'b', for compatibility
# with openwall crypt_blowfish.
for _v in 'b', 'y', 'a', '':
if _add_method('BLOWFISH', '2' + _v, 22, 59 + len(_v), rounds=1<<4):
break
_add_method('MD5', '1', 8, 34)
_add_method('CRYPT', None, 2, 13)
del _v, _add_method

View File

@ -13,9 +13,9 @@ except ModuleNotFoundError:
if support.check_sanitizer(address=True, memory=True):
# bpo-46633: test___all__ is skipped because importing some modules
# directly can trigger known problems with ASAN (like tk or crypt).
# directly can trigger known problems with ASAN (like tk).
raise unittest.SkipTest("workaround ASAN build issues on loading tests "
"like tk or crypt")
"like tk")
class NoAll(RuntimeError):

View File

@ -1,112 +0,0 @@
import sys
import unittest
from test.support import check_sanitizer, warnings_helper
try:
if check_sanitizer(address=True, memory=True):
raise unittest.SkipTest("The crypt module SEGFAULTs on ASAN/MSAN builds")
crypt = warnings_helper.import_deprecated("crypt")
IMPORT_ERROR = None
except ImportError as ex:
if sys.platform != 'win32':
raise unittest.SkipTest(str(ex))
crypt = None
IMPORT_ERROR = str(ex)
@unittest.skipUnless(sys.platform == 'win32', 'This should only run on windows')
@unittest.skipIf(crypt, 'import succeeded')
class TestWhyCryptDidNotImport(unittest.TestCase):
def test_import_failure_message(self):
self.assertIn('not supported', IMPORT_ERROR)
@unittest.skipUnless(crypt, 'crypt module is required')
class CryptTestCase(unittest.TestCase):
def test_crypt(self):
cr = crypt.crypt('mypassword')
cr2 = crypt.crypt('mypassword', cr)
self.assertEqual(cr2, cr)
cr = crypt.crypt('mypassword', 'ab')
if cr is not None:
cr2 = crypt.crypt('mypassword', cr)
self.assertEqual(cr2, cr)
def test_salt(self):
self.assertEqual(len(crypt._saltchars), 64)
for method in crypt.methods:
salt = crypt.mksalt(method)
self.assertIn(len(salt) - method.salt_chars, {0, 1, 3, 4, 6, 7})
if method.ident:
self.assertIn(method.ident, salt[:len(salt)-method.salt_chars])
def test_saltedcrypt(self):
for method in crypt.methods:
cr = crypt.crypt('assword', method)
self.assertEqual(len(cr), method.total_size)
cr2 = crypt.crypt('assword', cr)
self.assertEqual(cr2, cr)
cr = crypt.crypt('assword', crypt.mksalt(method))
self.assertEqual(len(cr), method.total_size)
def test_methods(self):
self.assertTrue(len(crypt.methods) >= 1)
if sys.platform.startswith('openbsd'):
self.assertEqual(crypt.methods, [crypt.METHOD_BLOWFISH])
else:
self.assertEqual(crypt.methods[-1], crypt.METHOD_CRYPT)
@unittest.skipUnless(
crypt
and (
crypt.METHOD_SHA256 in crypt.methods or crypt.METHOD_SHA512 in crypt.methods
),
'requires support of SHA-2',
)
def test_sha2_rounds(self):
for method in (crypt.METHOD_SHA256, crypt.METHOD_SHA512):
for rounds in 1000, 10_000, 100_000:
salt = crypt.mksalt(method, rounds=rounds)
self.assertIn('$rounds=%d$' % rounds, salt)
self.assertEqual(len(salt) - method.salt_chars,
11 + len(str(rounds)))
cr = crypt.crypt('mypassword', salt)
self.assertTrue(cr)
cr2 = crypt.crypt('mypassword', cr)
self.assertEqual(cr2, cr)
@unittest.skipUnless(
crypt and crypt.METHOD_BLOWFISH in crypt.methods, 'requires support of Blowfish'
)
def test_blowfish_rounds(self):
for log_rounds in range(4, 11):
salt = crypt.mksalt(crypt.METHOD_BLOWFISH, rounds=1 << log_rounds)
self.assertIn('$%02d$' % log_rounds, salt)
self.assertIn(len(salt) - crypt.METHOD_BLOWFISH.salt_chars, {6, 7})
cr = crypt.crypt('mypassword', salt)
self.assertTrue(cr)
cr2 = crypt.crypt('mypassword', cr)
self.assertEqual(cr2, cr)
def test_invalid_rounds(self):
for method in (crypt.METHOD_SHA256, crypt.METHOD_SHA512,
crypt.METHOD_BLOWFISH):
with self.assertRaises(TypeError):
crypt.mksalt(method, rounds='4096')
with self.assertRaises(TypeError):
crypt.mksalt(method, rounds=4096.0)
for rounds in (0, 1, -1, 1<<999):
with self.assertRaises(ValueError):
crypt.mksalt(method, rounds=rounds)
with self.assertRaises(ValueError):
crypt.mksalt(crypt.METHOD_BLOWFISH, rounds=1000)
for method in (crypt.METHOD_CRYPT, crypt.METHOD_MD5):
with self.assertRaisesRegex(ValueError, 'support'):
crypt.mksalt(method, rounds=4096)
if __name__ == "__main__":
unittest.main()

View File

@ -2650,7 +2650,7 @@ calling any callbacks. Patch by Kumar Aditya.
.. section: Library
Fail gracefully if :data:`~errno.EPERM` or :data:`~errno.ENOSYS` is raised
when loading :mod:`crypt` methods. This may happen when trying to load
when loading :mod:`!crypt` methods. This may happen when trying to load
``MD5`` on a Linux kernel with :abbr:`FIPS (Federal Information Processing
Standard)` enabled.

View File

@ -4856,7 +4856,7 @@ Patch by Srinivas Nyayapati.
.. nonce: Akreij
.. section: Windows
Trying to import the :mod:`crypt` module on Windows will result in an
Trying to import the :mod:`!crypt` module on Windows will result in an
:exc:`ImportError` with a message explaining that the module isn't supported
on Windows. On other platforms, if the underlying ``_crypt`` module is not
available, the ImportError will include a message explaining the problem.

View File

@ -0,0 +1,2 @@
:pep:`594`: Remove the :mod:`!crypt` module and its private :mod:`!_crypt`
extension, deprecated in Python 3.11. Patch by Victor Stinner.

View File

@ -188,10 +188,6 @@ PYTHONPATH=$(COREPYTHONPATH)
#syslog syslogmodule.c
#termios termios.c
# Modules with UNIX dependencies that require external libraries
#_crypt _cryptmodule.c -lcrypt
# Modules that require external libraries.
#_bz2 _bz2module.c -lbz2

View File

@ -106,8 +106,6 @@
# Modules with some UNIX dependencies
#
# needs -lcrypt on some systems
@MODULE__CRYPT_TRUE@_crypt _cryptmodule.c
@MODULE_FCNTL_TRUE@fcntl fcntlmodule.c
@MODULE_GRP_TRUE@grp grpmodule.c
@MODULE_MMAP_TRUE@mmap mmapmodule.c

View File

@ -1,81 +0,0 @@
/* cryptmodule.c - by Steve Majewski
*/
#include "Python.h"
#include <sys/types.h>
#ifdef HAVE_CRYPT_H
#include <crypt.h>
#endif
/* Module crypt */
/*[clinic input]
module crypt
[clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c6252cf4f2f2ae81]*/
#include "clinic/_cryptmodule.c.h"
/*[clinic input]
crypt.crypt
word: str
salt: str
/
Hash a *word* with the given *salt* and return the hashed password.
*word* will usually be a user's password. *salt* (either a random 2 or 16
character string, possibly prefixed with $digit$ to indicate the method)
will be used to perturb the encryption algorithm and produce distinct
results for a given *word*.
[clinic start generated code]*/
static PyObject *
crypt_crypt_impl(PyObject *module, const char *word, const char *salt)
/*[clinic end generated code: output=0512284a03d2803c input=0e8edec9c364352b]*/
{
char *crypt_result;
#ifdef HAVE_CRYPT_R
struct crypt_data data;
memset(&data, 0, sizeof(data));
crypt_result = crypt_r(word, salt, &data);
#else
crypt_result = crypt(word, salt);
#endif
if (crypt_result == NULL) {
return PyErr_SetFromErrno(PyExc_OSError);
}
return Py_BuildValue("s", crypt_result);
}
static PyMethodDef crypt_methods[] = {
CRYPT_CRYPT_METHODDEF
{NULL, NULL} /* sentinel */
};
static PyModuleDef_Slot _crypt_slots[] = {
{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
{0, NULL}
};
static struct PyModuleDef cryptmodule = {
PyModuleDef_HEAD_INIT,
"_crypt",
NULL,
0,
crypt_methods,
_crypt_slots,
NULL,
NULL,
NULL
};
PyMODINIT_FUNC
PyInit__crypt(void)
{
return PyModuleDef_Init(&cryptmodule);
}

View File

@ -1,69 +0,0 @@
/*[clinic input]
preserve
[clinic start generated code]*/
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
# include "pycore_gc.h" // PyGC_Head
# include "pycore_runtime.h" // _Py_ID()
#endif
PyDoc_STRVAR(crypt_crypt__doc__,
"crypt($module, word, salt, /)\n"
"--\n"
"\n"
"Hash a *word* with the given *salt* and return the hashed password.\n"
"\n"
"*word* will usually be a user\'s password. *salt* (either a random 2 or 16\n"
"character string, possibly prefixed with $digit$ to indicate the method)\n"
"will be used to perturb the encryption algorithm and produce distinct\n"
"results for a given *word*.");
#define CRYPT_CRYPT_METHODDEF \
{"crypt", _PyCFunction_CAST(crypt_crypt), METH_FASTCALL, crypt_crypt__doc__},
static PyObject *
crypt_crypt_impl(PyObject *module, const char *word, const char *salt);
static PyObject *
crypt_crypt(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *return_value = NULL;
const char *word;
const char *salt;
if (!_PyArg_CheckPositional("crypt", nargs, 2, 2)) {
goto exit;
}
if (!PyUnicode_Check(args[0])) {
_PyArg_BadArgument("crypt", "argument 1", "str", args[0]);
goto exit;
}
Py_ssize_t word_length;
word = PyUnicode_AsUTF8AndSize(args[0], &word_length);
if (word == NULL) {
goto exit;
}
if (strlen(word) != (size_t)word_length) {
PyErr_SetString(PyExc_ValueError, "embedded null character");
goto exit;
}
if (!PyUnicode_Check(args[1])) {
_PyArg_BadArgument("crypt", "argument 2", "str", args[1]);
goto exit;
}
Py_ssize_t salt_length;
salt = PyUnicode_AsUTF8AndSize(args[1], &salt_length);
if (salt == NULL) {
goto exit;
}
if (strlen(salt) != (size_t)salt_length) {
PyErr_SetString(PyExc_ValueError, "embedded null character");
goto exit;
}
return_value = crypt_crypt_impl(module, word, salt);
exit:
return return_value;
}
/*[clinic end generated code: output=235ccef9211184f4 input=a9049054013a1b77]*/

View File

@ -22,7 +22,6 @@ static const char* _Py_stdlib_module_names[] = {
"_compat_pickle",
"_compression",
"_contextvars",
"_crypt",
"_csv",
"_ctypes",
"_curses",
@ -121,7 +120,6 @@ static const char* _Py_stdlib_module_names[] = {
"contextvars",
"copy",
"copyreg",
"crypt",
"csv",
"ctypes",
"curses",

View File

@ -3,7 +3,6 @@
_asyncio
audioop
_bz2
_crypt
_decimal
_pickle
pyexpat _elementtree

View File

@ -81,7 +81,6 @@ OMIT_NETWORKING_FILES = (
OMIT_MODULE_FILES = {
"_asyncio": ["asyncio/"],
"audioop": ["aifc.py", "wave.py"],
"_crypt": ["crypt.py"],
"_curses": ["curses/"],
"_ctypes": ["ctypes/"],
"_decimal": ["decimal.py"],

342
configure generated vendored
View File

@ -678,8 +678,6 @@ MODULE__CURSES_FALSE
MODULE__CURSES_TRUE
MODULE__CTYPES_FALSE
MODULE__CTYPES_TRUE
MODULE__CRYPT_FALSE
MODULE__CRYPT_TRUE
MODULE__BLAKE2_FALSE
MODULE__BLAKE2_TRUE
MODULE__SHA3_FALSE
@ -818,8 +816,6 @@ HAVE_GETHOSTBYNAME_R
HAVE_GETHOSTBYNAME_R_3_ARG
HAVE_GETHOSTBYNAME_R_5_ARG
HAVE_GETHOSTBYNAME_R_6_ARG
LIBCRYPT_LIBS
LIBCRYPT_CFLAGS
LIBOBJS
LIBLZMA_LIBS
LIBLZMA_CFLAGS
@ -1118,8 +1114,6 @@ BZIP2_CFLAGS
BZIP2_LIBS
LIBLZMA_CFLAGS
LIBLZMA_LIBS
LIBCRYPT_CFLAGS
LIBCRYPT_LIBS
LIBREADLINE_CFLAGS
LIBREADLINE_LIBS
LIBEDIT_CFLAGS
@ -1940,10 +1934,6 @@ Some influential environment variables:
C compiler flags for LIBLZMA, overriding pkg-config
LIBLZMA_LIBS
linker flags for LIBLZMA, overriding pkg-config
LIBCRYPT_CFLAGS
C compiler flags for LIBCRYPT, overriding pkg-config
LIBCRYPT_LIBS
linker flags for LIBCRYPT, overriding pkg-config
LIBREADLINE_CFLAGS
C compiler flags for LIBREADLINE, overriding pkg-config
LIBREADLINE_LIBS
@ -9618,7 +9608,7 @@ $as_echo "#define STDC_HEADERS 1" >>confdefs.h
# checks for header files
for ac_header in \
alloca.h asm/types.h bluetooth.h conio.h crypt.h direct.h dlfcn.h endian.h errno.h fcntl.h grp.h \
alloca.h asm/types.h bluetooth.h conio.h direct.h dlfcn.h endian.h errno.h fcntl.h grp.h \
ieeefp.h io.h langinfo.h libintl.h libutil.h linux/auxvec.h sys/auxv.h linux/fs.h linux/memfd.h \
linux/random.h linux/soundcard.h \
linux/tipc.h linux/wait.h netdb.h net/ethernet.h netinet/in.h netpacket/packet.h poll.h process.h pthread.h pty.h \
@ -18767,297 +18757,6 @@ fi
done
pkg_failed=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBCRYPT" >&5
$as_echo_n "checking for LIBCRYPT... " >&6; }
if test -n "$LIBCRYPT_CFLAGS"; then
pkg_cv_LIBCRYPT_CFLAGS="$LIBCRYPT_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libxcrypt >= 3.1.1\""; } >&5
($PKG_CONFIG --exists --print-errors "libxcrypt >= 3.1.1") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LIBCRYPT_CFLAGS=`$PKG_CONFIG --cflags "libxcrypt >= 3.1.1" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
fi
else
pkg_failed=untried
fi
if test -n "$LIBCRYPT_LIBS"; then
pkg_cv_LIBCRYPT_LIBS="$LIBCRYPT_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libxcrypt >= 3.1.1\""; } >&5
($PKG_CONFIG --exists --print-errors "libxcrypt >= 3.1.1") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LIBCRYPT_LIBS=`$PKG_CONFIG --libs "libxcrypt >= 3.1.1" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
fi
else
pkg_failed=untried
fi
if test $pkg_failed = yes; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
LIBCRYPT_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libxcrypt >= 3.1.1" 2>&1`
else
LIBCRYPT_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libxcrypt >= 3.1.1" 2>&1`
fi
# Put the nasty error message in config.log where it belongs
echo "$LIBCRYPT_PKG_ERRORS" >&5
save_CFLAGS=$CFLAGS
save_CPPFLAGS=$CPPFLAGS
save_LDFLAGS=$LDFLAGS
save_LIBS=$LIBS
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing crypt_r" >&5
$as_echo_n "checking for library containing crypt_r... " >&6; }
if ${ac_cv_search_crypt_r+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char crypt_r ();
int
main ()
{
return crypt_r ();
;
return 0;
}
_ACEOF
for ac_lib in '' crypt; do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
if ac_fn_c_try_link "$LINENO"; then :
ac_cv_search_crypt_r=$ac_res
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext
if ${ac_cv_search_crypt_r+:} false; then :
break
fi
done
if ${ac_cv_search_crypt_r+:} false; then :
else
ac_cv_search_crypt_r=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_crypt_r" >&5
$as_echo "$ac_cv_search_crypt_r" >&6; }
ac_res=$ac_cv_search_crypt_r
if test "$ac_res" != no; then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
$as_echo "#define HAVE_CRYPT_R 1" >>confdefs.h
if test "$ac_cv_search_crypt_r" = "none required"; then
libcrypt=
else
libcrypt="$ac_cv_search_crypt_r"
fi
LIBCRYPT_LIBS=${LIBCRYPT_LIBS-$libcrypt}
fi
CFLAGS=$save_CFLAGS
CPPFLAGS=$save_CPPFLAGS
LDFLAGS=$save_LDFLAGS
LIBS=$save_LIBS
elif test $pkg_failed = untried; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
save_CFLAGS=$CFLAGS
save_CPPFLAGS=$CPPFLAGS
save_LDFLAGS=$LDFLAGS
save_LIBS=$LIBS
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing crypt_r" >&5
$as_echo_n "checking for library containing crypt_r... " >&6; }
if ${ac_cv_search_crypt_r+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char crypt_r ();
int
main ()
{
return crypt_r ();
;
return 0;
}
_ACEOF
for ac_lib in '' crypt; do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
if ac_fn_c_try_link "$LINENO"; then :
ac_cv_search_crypt_r=$ac_res
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext
if ${ac_cv_search_crypt_r+:} false; then :
break
fi
done
if ${ac_cv_search_crypt_r+:} false; then :
else
ac_cv_search_crypt_r=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_crypt_r" >&5
$as_echo "$ac_cv_search_crypt_r" >&6; }
ac_res=$ac_cv_search_crypt_r
if test "$ac_res" != no; then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
$as_echo "#define HAVE_CRYPT_R 1" >>confdefs.h
if test "$ac_cv_search_crypt_r" = "none required"; then
libcrypt=
else
libcrypt="$ac_cv_search_crypt_r"
fi
LIBCRYPT_LIBS=${LIBCRYPT_LIBS-$libcrypt}
fi
CFLAGS=$save_CFLAGS
CPPFLAGS=$save_CPPFLAGS
LDFLAGS=$save_LDFLAGS
LIBS=$save_LIBS
else
LIBCRYPT_CFLAGS=$pkg_cv_LIBCRYPT_CFLAGS
LIBCRYPT_LIBS=$pkg_cv_LIBCRYPT_LIBS
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
$as_echo "#define HAVE_CRYPT_R 1" >>confdefs.h
fi
save_CFLAGS=$CFLAGS
save_CPPFLAGS=$CPPFLAGS
save_LDFLAGS=$LDFLAGS
save_LIBS=$LIBS
CPPFLAGS="$CPPFLAGS $LIBCRYPT_CFLAGS"
LIBS="$LIBCRYPT_LIBS $LIBS"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for crypt or crypt_r" >&5
$as_echo_n "checking for crypt or crypt_r... " >&6; }
if ${ac_cv_crypt_crypt+:} false; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#ifdef HAVE_CRYPT_H
#include <crypt.h>
#endif
#include <unistd.h>
int
main ()
{
#ifdef HAVE_CRYPT_R
void *x = crypt_r;
#else
void *x = crypt;
#endif
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
ac_cv_crypt_crypt=yes
else
ac_cv_crypt_crypt=no
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_crypt_crypt" >&5
$as_echo "$ac_cv_crypt_crypt" >&6; }
CFLAGS=$save_CFLAGS
CPPFLAGS=$save_CPPFLAGS
LDFLAGS=$save_LDFLAGS
LIBS=$save_LIBS
for ac_func in clock_gettime
do :
ac_fn_c_check_func "$LINENO" "clock_gettime" "ac_cv_func_clock_gettime"
@ -25376,7 +25075,6 @@ case $ac_sys_system in #(
py_cv_module__scproxy=n/a
py_cv_module__crypt=n/a
py_cv_module_termios=n/a
py_cv_module_grp=n/a
;; #(
@ -26774,40 +26472,6 @@ $as_echo "$py_cv_module__blake2" >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _crypt" >&5
$as_echo_n "checking for stdlib extension module _crypt... " >&6; }
if test "$py_cv_module__crypt" != "n/a"; then :
if true; then :
if test "$ac_cv_crypt_crypt" = yes; then :
py_cv_module__crypt=yes
else
py_cv_module__crypt=missing
fi
else
py_cv_module__crypt=disabled
fi
fi
as_fn_append MODULE_BLOCK "MODULE__CRYPT_STATE=$py_cv_module__crypt$as_nl"
if test "x$py_cv_module__crypt" = xyes; then :
as_fn_append MODULE_BLOCK "MODULE__CRYPT_CFLAGS=$LIBCRYPT_CFLAGS$as_nl"
as_fn_append MODULE_BLOCK "MODULE__CRYPT_LDFLAGS=$LIBCRYPT_LIBS$as_nl"
fi
if test "$py_cv_module__crypt" = yes; then
MODULE__CRYPT_TRUE=
MODULE__CRYPT_FALSE='#'
else
MODULE__CRYPT_TRUE='#'
MODULE__CRYPT_FALSE=
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__crypt" >&5
$as_echo "$py_cv_module__crypt" >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _ctypes" >&5
$as_echo_n "checking for stdlib extension module _ctypes... " >&6; }
if test "$py_cv_module__ctypes" != "n/a"; then :
@ -28046,10 +27710,6 @@ if test -z "${MODULE__BLAKE2_TRUE}" && test -z "${MODULE__BLAKE2_FALSE}"; then
as_fn_error $? "conditional \"MODULE__BLAKE2\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${MODULE__CRYPT_TRUE}" && test -z "${MODULE__CRYPT_FALSE}"; then
as_fn_error $? "conditional \"MODULE__CRYPT\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${MODULE__CTYPES_TRUE}" && test -z "${MODULE__CTYPES_FALSE}"; then
as_fn_error $? "conditional \"MODULE__CTYPES\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5

View File

@ -2810,7 +2810,7 @@ AC_DEFINE(STDC_HEADERS, 1, [Define to 1 if you have the ANSI C header files.])
# checks for header files
AC_CHECK_HEADERS([ \
alloca.h asm/types.h bluetooth.h conio.h crypt.h direct.h dlfcn.h endian.h errno.h fcntl.h grp.h \
alloca.h asm/types.h bluetooth.h conio.h direct.h dlfcn.h endian.h errno.h fcntl.h grp.h \
ieeefp.h io.h langinfo.h libintl.h libutil.h linux/auxvec.h sys/auxv.h linux/fs.h linux/memfd.h \
linux/random.h linux/soundcard.h \
linux/tipc.h linux/wait.h netdb.h net/ethernet.h netinet/in.h netpacket/packet.h poll.h process.h pthread.h pty.h \
@ -5049,48 +5049,6 @@ AC_CHECK_FUNCS(setpgrp,
# check for namespace functions
AC_CHECK_FUNCS([setns unshare])
dnl We search for both crypt and crypt_r as one or the other may be defined
dnl libxcrypt provides <crypt.h> and libcrypt with crypt_r() since
dnl at least 3.1.1 from 2015.
dnl FreeBSD defines crypt_r() in <unistd.h>
AH_TEMPLATE([HAVE_CRYPT_R], [Define if you have the crypt_r() function.])
PKG_CHECK_MODULES([LIBCRYPT], [libxcrypt >= 3.1.1], [
AC_DEFINE([HAVE_CRYPT_R], [1])
], [
WITH_SAVE_ENV([
AC_SEARCH_LIBS([crypt_r], [crypt], [
AC_DEFINE([HAVE_CRYPT_R], [1])
if test "$ac_cv_search_crypt_r" = "none required"; then
libcrypt=
else
libcrypt="$ac_cv_search_crypt_r"
fi
LIBCRYPT_LIBS=${LIBCRYPT_LIBS-$libcrypt}
])
])
])
WITH_SAVE_ENV([
CPPFLAGS="$CPPFLAGS $LIBCRYPT_CFLAGS"
LIBS="$LIBCRYPT_LIBS $LIBS"
AC_CACHE_CHECK([for crypt or crypt_r], [ac_cv_crypt_crypt], [
AC_LINK_IFELSE([AC_LANG_PROGRAM([
#ifdef HAVE_CRYPT_H
#include <crypt.h>
#endif
#include <unistd.h>
], [
#ifdef HAVE_CRYPT_R
void *x = crypt_r;
#else
void *x = crypt;
#endif
])
], [ac_cv_crypt_crypt=yes], [ac_cv_crypt_crypt=no])
])
])
AC_CHECK_FUNCS(clock_gettime, [], [
AC_CHECK_LIB(rt, clock_gettime, [
LIBS="$LIBS -lrt"
@ -7060,10 +7018,9 @@ AC_DEFUN([PY_STDLIB_MOD_SET_NA], [
# stdlib not available
dnl Modules that are not available on some platforms
dnl VxWorks does not provide crypt() function
AS_CASE([$ac_sys_system],
[AIX], [PY_STDLIB_MOD_SET_NA([_scproxy])],
[VxWorks*], [PY_STDLIB_MOD_SET_NA([_scproxy], [_crypt], [termios], [grp])],
[VxWorks*], [PY_STDLIB_MOD_SET_NA([_scproxy], [termios], [grp])],
dnl The _scproxy module is available on macOS
[Darwin], [],
[CYGWIN*], [PY_STDLIB_MOD_SET_NA([_scproxy])],
@ -7271,9 +7228,6 @@ PY_STDLIB_MOD([_blake2],
[test "$with_builtin_blake2" = yes], [],
[$LIBB2_CFLAGS], [$LIBB2_LIBS])
PY_STDLIB_MOD([_crypt],
[], [test "$ac_cv_crypt_crypt" = yes],
[$LIBCRYPT_CFLAGS], [$LIBCRYPT_LIBS])
PY_STDLIB_MOD([_ctypes],
[], [test "$have_libffi" = yes],
[$NO_STRICT_OVERFLOW_CFLAGS $LIBFFI_CFLAGS], [$LIBFFI_LIBS])

View File

@ -175,12 +175,6 @@
/* Define to 1 if you have the `copy_file_range' function. */
#undef HAVE_COPY_FILE_RANGE
/* Define to 1 if you have the <crypt.h> header file. */
#undef HAVE_CRYPT_H
/* Define if you have the crypt_r() function. */
#undef HAVE_CRYPT_R
/* Define to 1 if you have the `ctermid' function. */
#undef HAVE_CTERMID