Issue #12049: Add RAND_bytes() and RAND_pseudo_bytes() functions to the ssl

module.
This commit is contained in:
Victor Stinner 2011-05-24 12:05:19 +02:00
parent b7b1930fe3
commit 99c8b16143
6 changed files with 106 additions and 4 deletions

View File

@ -162,6 +162,20 @@ instead.
Random generation
^^^^^^^^^^^^^^^^^
.. function:: RAND_bytes(num)
Returns *num* cryptographically strong pseudo-random bytes.
.. versionadded:: 3.3
.. function:: RAND_pseudo_bytes(num)
Returns (bytes, is_cryptographic): bytes are *num* pseudo-random bytes,
is_cryptographic is True if the bytes generated are cryptographically
strong.
.. versionadded:: 3.3
.. function:: RAND_status()
Returns True if the SSL pseudo-random number generator has been seeded with
@ -171,7 +185,7 @@ Random generation
.. function:: RAND_egd(path)
If you are running an entropy-gathering daemon (EGD) somewhere, and ``path``
If you are running an entropy-gathering daemon (EGD) somewhere, and *path*
is the pathname of a socket connection open to it, this will read 256 bytes
of randomness from the socket, and add it to the SSL pseudo-random number
generator to increase the security of generated secret keys. This is
@ -182,8 +196,8 @@ Random generation
.. function:: RAND_add(bytes, entropy)
Mixes the given ``bytes`` into the SSL pseudo-random number generator. The
parameter ``entropy`` (a float) is a lower bound on the entropy contained in
Mixes the given *bytes* into the SSL pseudo-random number generator. The
parameter *entropy* (a float) is a lower bound on the entropy contained in
string (so you can always use :const:`0.0`). See :rfc:`1750` for more
information on sources of entropy.

View File

@ -152,6 +152,16 @@ signal
instead of a RuntimeError: OSError has an errno attribute.
ssl
---
The :mod:`ssl` module has new functions:
* :func:`~ssl.RAND_bytes`: generate cryptographically strong
pseudo-random bytes.
* :func:`~ssl.RAND_pseudo_bytes`: generate pseudo-random bytes.
Optimizations
=============

View File

@ -63,7 +63,7 @@ from _ssl import OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_INFO, OPENSSL_VERSION
from _ssl import _SSLContext, SSLError
from _ssl import CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED
from _ssl import OP_ALL, OP_NO_SSLv2, OP_NO_SSLv3, OP_NO_TLSv1
from _ssl import RAND_status, RAND_egd, RAND_add
from _ssl import RAND_status, RAND_egd, RAND_add, RAND_bytes, RAND_pseudo_bytes
from _ssl import (
SSL_ERROR_ZERO_RETURN,
SSL_ERROR_WANT_READ,

View File

@ -102,6 +102,14 @@ class BasicSocketTests(unittest.TestCase):
sys.stdout.write("\n RAND_status is %d (%s)\n"
% (v, (v and "sufficient randomness") or
"insufficient randomness"))
data, is_cryptographic = ssl.RAND_pseudo_bytes(16)
self.assertEqual(len(data), 16)
self.assertEqual(is_cryptographic, v == 1)
if v:
data = ssl.RAND_bytes(16)
self.assertEqual(len(data), 16)
try:
ssl.RAND_egd(1)
except TypeError:

View File

@ -156,6 +156,9 @@ Core and Builtins
Library
-------
- Issue #12049: Add RAND_bytes() and RAND_pseudo_bytes() functions to the ssl
module.
- Issue #12125: fixed the failures under Solaris due to improper test cleanup.
- Issue #6501: os.device_encoding() returns None on Windows if the application

View File

@ -1886,6 +1886,69 @@ PyDoc_STRVAR(PySSL_RAND_add_doc,
Mix string into the OpenSSL PRNG state. entropy (a float) is a lower\n\
bound on the entropy contained in string. See RFC 1750.");
static PyObject *
PySSL_RAND(int len, int pseudo)
{
int ok;
PyObject *bytes;
unsigned long err;
const char *errstr;
PyObject *v;
bytes = PyBytes_FromStringAndSize(NULL, len);
if (bytes == NULL)
return NULL;
if (pseudo) {
ok = RAND_pseudo_bytes((unsigned char*)PyBytes_AS_STRING(bytes), len);
if (ok == 0 || ok == 1)
return Py_BuildValue("NO", bytes, ok == 1 ? Py_True : Py_False);
}
else {
ok = RAND_bytes((unsigned char*)PyBytes_AS_STRING(bytes), len);
if (ok == 1)
return bytes;
}
Py_DECREF(bytes);
err = ERR_get_error();
errstr = ERR_reason_error_string(err);
v = Py_BuildValue("(ks)", err, errstr);
if (v != NULL) {
PyErr_SetObject(PySSLErrorObject, v);
Py_DECREF(v);
}
return NULL;
}
static PyObject *
PySSL_RAND_bytes(PyObject *self, PyObject *args)
{
int len;
if (!PyArg_ParseTuple(args, "i:RAND_bytes", &len))
return NULL;
return PySSL_RAND(len, 0);
}
PyDoc_STRVAR(PySSL_RAND_bytes_doc,
"RAND_bytes(n) -> bytes\n\
\n\
Generate n cryptographically strong pseudo-random bytes.");
static PyObject *
PySSL_RAND_pseudo_bytes(PyObject *self, PyObject *args)
{
int len;
if (!PyArg_ParseTuple(args, "i:RAND_pseudo_bytes", &len))
return NULL;
return PySSL_RAND(len, 1);
}
PyDoc_STRVAR(PySSL_RAND_pseudo_bytes_doc,
"RAND_pseudo_bytes(n) -> (bytes, is_cryptographic)\n\
\n\
Generate n pseudo-random bytes. is_cryptographic is True if the bytes\
generated are cryptographically strong.");
static PyObject *
PySSL_RAND_status(PyObject *self)
{
@ -1939,6 +2002,10 @@ static PyMethodDef PySSL_methods[] = {
#ifdef HAVE_OPENSSL_RAND
{"RAND_add", PySSL_RAND_add, METH_VARARGS,
PySSL_RAND_add_doc},
{"RAND_bytes", PySSL_RAND_bytes, METH_VARARGS,
PySSL_RAND_bytes_doc},
{"RAND_pseudo_bytes", PySSL_RAND_pseudo_bytes, METH_VARARGS,
PySSL_RAND_pseudo_bytes_doc},
{"RAND_egd", PySSL_RAND_egd, METH_VARARGS,
PySSL_RAND_egd_doc},
{"RAND_status", (PyCFunction)PySSL_RAND_status, METH_NOARGS,