gh-132987: Support __index__() in hashlib.scrypt() (GH-133100)

Even if such signature is not supported by PyArg_ParseTupleAndKeywords(),
Argument Clinic supports it with inlined converters.
This commit is contained in:
Serhiy Storchaka 2025-04-29 16:16:05 +03:00 committed by GitHub
parent 07edc0d2b2
commit d6da6803a1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 28 additions and 84 deletions

View File

@ -1388,19 +1388,15 @@ end:
#ifdef PY_OPENSSL_HAS_SCRYPT
/* XXX: Parameters salt, n, r and p should be required keyword-only parameters.
They are optional in the Argument Clinic declaration only due to a
limitation of PyArg_ParseTupleAndKeywords. */
/*[clinic input]
_hashlib.scrypt
password: Py_buffer
*
salt: Py_buffer = None
n as n_obj: object(subclass_of='&PyLong_Type') = None
r as r_obj: object(subclass_of='&PyLong_Type') = None
p as p_obj: object(subclass_of='&PyLong_Type') = None
salt: Py_buffer
n: unsigned_long
r: unsigned_long
p: unsigned_long
maxmem: long = 0
dklen: long = 64
@ -1410,14 +1406,13 @@ scrypt password-based key derivation function.
static PyObject *
_hashlib_scrypt_impl(PyObject *module, Py_buffer *password, Py_buffer *salt,
PyObject *n_obj, PyObject *r_obj, PyObject *p_obj,
unsigned long n, unsigned long r, unsigned long p,
long maxmem, long dklen)
/*[clinic end generated code: output=14849e2aa2b7b46c input=48a7d63bf3f75c42]*/
/*[clinic end generated code: output=d424bc3e8c6b9654 input=0c9a84230238fd79]*/
{
PyObject *key_obj = NULL;
char *key;
int retval;
unsigned long n, r, p;
if (password->len > INT_MAX) {
PyErr_SetString(PyExc_OverflowError,
@ -1425,43 +1420,18 @@ _hashlib_scrypt_impl(PyObject *module, Py_buffer *password, Py_buffer *salt,
return NULL;
}
if (salt->buf == NULL) {
PyErr_SetString(PyExc_TypeError,
"salt is required");
return NULL;
}
if (salt->len > INT_MAX) {
PyErr_SetString(PyExc_OverflowError,
"salt is too long.");
return NULL;
}
n = PyLong_AsUnsignedLong(n_obj);
if (n == (unsigned long) -1 && PyErr_Occurred()) {
PyErr_SetString(PyExc_TypeError,
"n is required and must be an unsigned int");
return NULL;
}
if (n < 2 || n & (n - 1)) {
PyErr_SetString(PyExc_ValueError,
"n must be a power of 2.");
return NULL;
}
r = PyLong_AsUnsignedLong(r_obj);
if (r == (unsigned long) -1 && PyErr_Occurred()) {
PyErr_SetString(PyExc_TypeError,
"r is required and must be an unsigned int");
return NULL;
}
p = PyLong_AsUnsignedLong(p_obj);
if (p == (unsigned long) -1 && PyErr_Occurred()) {
PyErr_SetString(PyExc_TypeError,
"p is required and must be an unsigned int");
return NULL;
}
if (maxmem < 0 || maxmem > INT_MAX) {
/* OpenSSL 1.1.0 restricts maxmem to 32 MiB. It may change in the
future. The maxmem constant is private to OpenSSL. */

View File

@ -7,6 +7,7 @@ preserve
# include "pycore_runtime.h" // _Py_ID()
#endif
#include "pycore_abstract.h" // _PyNumber_Index()
#include "pycore_long.h" // _PyLong_UnsignedLong_Converter()
#include "pycore_modsupport.h" // _PyArg_UnpackKeywords()
PyDoc_STRVAR(EVP_copy__doc__,
@ -1381,8 +1382,7 @@ exit:
#if defined(PY_OPENSSL_HAS_SCRYPT)
PyDoc_STRVAR(_hashlib_scrypt__doc__,
"scrypt($module, /, password, *, salt=None, n=None, r=None, p=None,\n"
" maxmem=0, dklen=64)\n"
"scrypt($module, /, password, *, salt, n, r, p, maxmem=0, dklen=64)\n"
"--\n"
"\n"
"scrypt password-based key derivation function.");
@ -1392,7 +1392,7 @@ PyDoc_STRVAR(_hashlib_scrypt__doc__,
static PyObject *
_hashlib_scrypt_impl(PyObject *module, Py_buffer *password, Py_buffer *salt,
PyObject *n_obj, PyObject *r_obj, PyObject *p_obj,
unsigned long n, unsigned long r, unsigned long p,
long maxmem, long dklen);
static PyObject *
@ -1427,64 +1427,38 @@ _hashlib_scrypt(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObj
};
#undef KWTUPLE
PyObject *argsbuf[7];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 5;
Py_buffer password = {NULL, NULL};
Py_buffer salt = {NULL, NULL};
PyObject *n_obj = Py_None;
PyObject *r_obj = Py_None;
PyObject *p_obj = Py_None;
unsigned long n;
unsigned long r;
unsigned long p;
long maxmem = 0;
long dklen = 64;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
/*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
/*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 4, /*varpos*/ 0, argsbuf);
if (!args) {
goto exit;
}
if (PyObject_GetBuffer(args[0], &password, PyBUF_SIMPLE) != 0) {
goto exit;
}
if (PyObject_GetBuffer(args[1], &salt, PyBUF_SIMPLE) != 0) {
goto exit;
}
if (!_PyLong_UnsignedLong_Converter(args[2], &n)) {
goto exit;
}
if (!_PyLong_UnsignedLong_Converter(args[3], &r)) {
goto exit;
}
if (!_PyLong_UnsignedLong_Converter(args[4], &p)) {
goto exit;
}
if (!noptargs) {
goto skip_optional_kwonly;
}
if (args[1]) {
if (PyObject_GetBuffer(args[1], &salt, PyBUF_SIMPLE) != 0) {
goto exit;
}
if (!--noptargs) {
goto skip_optional_kwonly;
}
}
if (args[2]) {
if (!PyLong_Check(args[2])) {
_PyArg_BadArgument("scrypt", "argument 'n'", "int", args[2]);
goto exit;
}
n_obj = args[2];
if (!--noptargs) {
goto skip_optional_kwonly;
}
}
if (args[3]) {
if (!PyLong_Check(args[3])) {
_PyArg_BadArgument("scrypt", "argument 'r'", "int", args[3]);
goto exit;
}
r_obj = args[3];
if (!--noptargs) {
goto skip_optional_kwonly;
}
}
if (args[4]) {
if (!PyLong_Check(args[4])) {
_PyArg_BadArgument("scrypt", "argument 'p'", "int", args[4]);
goto exit;
}
p_obj = args[4];
if (!--noptargs) {
goto skip_optional_kwonly;
}
}
if (args[5]) {
maxmem = PyLong_AsLong(args[5]);
if (maxmem == -1 && PyErr_Occurred()) {
@ -1499,7 +1473,7 @@ _hashlib_scrypt(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObj
goto exit;
}
skip_optional_kwonly:
return_value = _hashlib_scrypt_impl(module, &password, &salt, n_obj, r_obj, p_obj, maxmem, dklen);
return_value = _hashlib_scrypt_impl(module, &password, &salt, n, r, p, maxmem, dklen);
exit:
/* Cleanup for password */
@ -1897,4 +1871,4 @@ exit:
#ifndef _HASHLIB_SCRYPT_METHODDEF
#define _HASHLIB_SCRYPT_METHODDEF
#endif /* !defined(_HASHLIB_SCRYPT_METHODDEF) */
/*[clinic end generated code: output=d908fa85e0251426 input=a9049054013a1b77]*/
/*[clinic end generated code: output=2c78822e38be64a8 input=a9049054013a1b77]*/