Add OpenSSL.rand.bytes() function to wrap RAND_bytes(). Test cases and documentation included.
diff --git a/doc/README b/doc/README
new file mode 100644
index 0000000..63af700
--- /dev/null
+++ b/doc/README
@@ -0,0 +1,17 @@
+
+Only the .tex format documentation is original,
+because the others are derived from it, so don't
+edit them directly. To build the other formats
+use a command of ...
+
+ make all
+
+
+To build the documentation you will need to have
+latex2html and lynx installed. On fedora both can
+be obtained with...
+
+ sudo yum install latex2html lynx
+
+
+
diff --git a/doc/pyOpenSSL.tex b/doc/pyOpenSSL.tex
index cf69e0f..9f472b9 100644
--- a/doc/pyOpenSSL.tex
+++ b/doc/pyOpenSSL.tex
@@ -593,6 +593,10 @@
\var{string}, measured in bytes. For more information, see e.g. \rfc{1750}.
\end{funcdesc}
+\begin{funcdesc}{cleanup}{}
+Erase the memory used by the PRNG. It's a wrapper of the C function \function{RAND_cleanup}.
+\end{funcdesc}
+
\begin{funcdesc}{egd}{path\optional{, bytes}}
Query the Entropy Gathering Daemon\footnote{See
\url{http://www.lothar.com/tech/crypto/}} on socket \var{path} for \var{bytes}
@@ -605,6 +609,10 @@
the file \var{path} to seed the PRNG. The default value of \var{bytes} is -1.
\end{funcdesc}
+\begin{funcdesc}{bytes}{num_bytes}
+Get some random bytes as a string. It's a wrapper of the C function \function{RAND_bytes}.
+\end{funcdesc}
+
\begin{funcdesc}{screen}{}
Add the current contents of the screen to the PRNG state.
Availability: Windows.
diff --git a/setup.py b/setup.py
index 645e459..06d477b 100755
--- a/setup.py
+++ b/setup.py
@@ -88,6 +88,7 @@
'OpenSSL.version', 'OpenSSL.test.__init__',
'OpenSSL.test.util',
'OpenSSL.test.test_crypto',
+ 'OpenSSL.test.test_rand',
'OpenSSL.test.test_ssl'],
data_files = data_files,
description = 'Python wrapper module around the OpenSSL library',
diff --git a/src/rand/rand.c b/src/rand/rand.c
index f1c8440..cdb83bb 100644
--- a/src/rand/rand.c
+++ b/src/rand/rand.c
@@ -188,6 +188,36 @@
return PyInt_FromLong((long)RAND_write_file(filename));
}
+static char rand_bytes_doc[] = "\n\
+Get some randomm bytes as a string.\n\
+\n\
+@param num_bytes: The number of bytes to fetch\n\
+@return: A string of random bytes\n\
+";
+
+static PyObject *
+rand_bytes(PyObject *spam, PyObject *args, PyObject *keywds)
+{
+ int num_bytes;
+ static char *kwlist[] = {"num_bytes", NULL};
+ char *buf;
+ PyObject *obj;
+
+ if (!PyArg_ParseTupleAndKeywords(args, keywds, "i:bytes", kwlist, &num_bytes))
+ return NULL;
+ if(num_bytes < 0) {
+ PyErr_SetString(PyExc_ValueError, "num_bytes must not be negative");
+ return NULL;
+ }
+ buf = malloc(num_bytes);
+ if (buf == NULL) /* out of memory */
+ return NULL;
+ RAND_bytes(buf, num_bytes);
+ obj = PyString_FromStringAndSize(buf, num_bytes);
+ free(buf);
+ return obj;
+}
+
/* Methods in the OpenSSL.rand module */
static PyMethodDef rand_methods[] = {
@@ -201,6 +231,7 @@
{ "cleanup", (PyCFunction)rand_cleanup, METH_VARARGS, rand_cleanup_doc },
{ "load_file", (PyCFunction)rand_load_file, METH_VARARGS, rand_load_file_doc },
{ "write_file",(PyCFunction)rand_write_file, METH_VARARGS, rand_write_file_doc },
+ { "bytes", (PyCFunction)rand_bytes, METH_VARARGS|METH_KEYWORDS, rand_bytes_doc },
{ NULL, NULL }
};
diff --git a/test/test_rand.py b/test/test_rand.py
new file mode 100644
index 0000000..fe10ab9
--- /dev/null
+++ b/test/test_rand.py
@@ -0,0 +1,63 @@
+# Copyright (C) Frederick Dean 2009, All rights reserved
+
+"""
+Unit tests for L{OpenSSL.rand}.
+"""
+
+from unittest import main
+import os
+import stat
+
+from OpenSSL.test.util import TestCase
+from OpenSSL import rand
+
+class RandTests(TestCase):
+ def test_bytes(self):
+ """
+ Verify that we can obtain bytes from rand_bytes() and
+ that they are different each time. Test the parameter
+ of rand_bytes() for bad values.
+ """
+ b1 = rand.bytes(50)
+ self.assertEqual(len(b1), 50)
+ b2 = rand.bytes(num_bytes=50) # parameter by name
+ self.assertNotEqual(b1, b2) # Hip, Hip, Horay! FIPS complaince
+ b3 = rand.bytes(num_bytes=0)
+ self.assertEqual(len(b3), 0)
+ try:
+ b4 = rand.bytes(-1)
+ self.assertTrue(False) # We shouldn't get here
+ except ValueError, v:
+ self.assertTrue(v.message == "num_bytes must not be negative")
+
+
+ def test_add(self):
+ """
+ Test adding of entropy to the PRNG.
+ """
+ rand.add('hamburger', 3)
+ rand.seed('milk shake')
+ self.assertTrue(rand.status())
+
+
+ def test_files(self):
+ """
+ Test reading and writing of files via rand functions.
+ """
+ # Write random bytes to a file
+ tmpfile = self.mktemp()
+ rand.write_file(tmpfile)
+ # Verify length of written file
+ size = os.stat(tmpfile)[stat.ST_SIZE]
+ self.assertEquals(size, 1024)
+ # Read random bytes from file
+ rand.load_file(tmpfile)
+ rand.load_file(tmpfile, 4) # specify a length
+ # Cleanup
+ os.unlink(tmpfile)
+
+
+if __name__ == '__main__':
+ main()
+
+