[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[minion-cvs] Backport; tests; hacking: Core code is clean, commented...
Update of /home/minion/cvsroot/src/minion/src
In directory moria.seul.org:/tmp/cvs-serv23515/src
Modified Files:
aes_ctr.c crypt.c
Log Message:
Backport; tests; hacking: Core code is clean, commented, documented, and tested
- Backported to older versions of Python. We now support 2.0 through
2.2 inclusive. This included:
- Removing uses of // operator.
- Checking version properly in setup.py
- Removing use of nested scopes.
- Replace type(foo) == str with type(foo) == type("")
- Bundling Python's unittest.py module so we can run tests on systems
(Python 2.0) that don't include it.
- In crypt.c, we can no longer go from openssl BIGNUMs to Python Longs
using _PyLong_(To|From)ByteArray -- the latter method didn't exist
until 2.2. We have to to/from a hex representation instead.
- Better message on insane-endianness case.
- Rename 'Formats' module to 'Packet'.
- Rename 'ServerProcess' module to 'PacketHandler'.
- Document and comment all remaining code.
- Changes to Packet: (Formerly Formats)
- Add ReplyBlock object
- Fix bugs in header slicing
- Freak out on overlong subheaders.
- Changes to BuildMessage:
- Make BuildStatelessReplyBlock a bit more paranoid about missing userKey.
- Rejoin _buildFoo and _buildFoo_impl
- Grouse early if header will be too long.
- Misc cleanups
- New tests: Long intermediate info, fail on overlong routing info
- Changes to Crypto:
- Use symbolic constants throughout
- Add cache for TRNG
- Changes to Hashlog:
- Make 'sync' method conditional on underlying sync: this allows us
to support dumbdbm.
- Changes to PacketHandler: (formerly ServerProcess)
- Remove processMessage intermediary; rename _processMessage.
- Add support for multiple keys
- Make setup more sane
- Add note on timing attacks
- New tests: Most failing cases
- Changes to benchMark:
- Restructure handling of primitives, loop overhead
- Make cleanup process handle dumbdbm.
- Add actual vs ideal comparisons for Lioness and PacketHandler
- Changes to crypt.c:
- Write more idiomatic and paranoid C.
- Make failing SHA cases fail faster
- Backport to py2.0->py2.2; see above
Index: aes_ctr.c
===================================================================
RCS file: /home/minion/cvsroot/src/minion/src/aes_ctr.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- aes_ctr.c 31 May 2002 12:39:18 -0000 1.2
+++ aes_ctr.c 2 Jun 2002 06:11:16 -0000 1.3
@@ -35,8 +35,8 @@
#if 0 /* On my Athlon, bswap_32 is actually slower. Surprisingly,
the code in glib/gtypes.h _is_ faster; but shaves only 1%
- off encryption. We seem to have reached the point of diminishing
- returns here.*/
+ off encryption. We seem to be near the point of diminishing
+ returns here. */
#ifdef MM_L_ENDIAN
#ifdef MM_HAVE_BYTESWAP_H
#include <byteswap.h>
@@ -60,7 +60,6 @@
#define SET_U32(ptr,i) SET_U32_cp(((u8*)(ptr)), i)
#endif
-
static inline void
mm_incr(u32 const* ctr32)
{
@@ -114,4 +113,3 @@
c-basic-offset:8
End:
*/
-
Index: crypt.c
===================================================================
RCS file: /home/minion/cvsroot/src/minion/src/crypt.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- crypt.c 31 May 2002 12:39:18 -0000 1.3
+++ crypt.c 2 Jun 2002 06:11:16 -0000 1.4
@@ -9,17 +9,25 @@
#include <openssl/rand.h>
#include <openssl/err.h>
#include <_minionlib.h>
+#include <assert.h>
#define TYPE_ERR(s) PyErr_SetString(PyExc_TypeError, s)
#define KEY_IS_PRIVATE(rsa) ((rsa)->p)
PyObject *mm_SSLError = NULL;
+/* Helper function: raise an SSLError with appropriate text from the
+ * underlying SSL exception.
+ *
+ * Requires that mm_SSLError is initialized and ERR_load_*_strings
+ * have been called.
+ */
static void
SSL_ERR()
{
int err = ERR_get_error();
const char *str = ERR_reason_error_string(err);
+ assert(mm_SSLError);
if (str)
PyErr_SetString(mm_SSLError, str);
else
@@ -41,20 +49,22 @@
if (!PyArg_ParseTupleAndKeywords(args, kwdict, "s#:sha1", kwlist,
&cp, &len))
- return NULL;
- SHA1_Init(&ctx);
- SHA1_Update(&ctx,cp,len);
- output = PyString_FromStringAndSize(NULL, SHA_DIGEST_LENGTH);
- if (!output) {
+ return NULL;
+ if (!(output = PyString_FromStringAndSize(NULL, SHA_DIGEST_LENGTH))) {
PyErr_NoMemory();
return NULL;
}
+
+ SHA1_Init(&ctx);
+ SHA1_Update(&ctx,cp,len);
SHA1_Final(PyString_AS_STRING(output),&ctx);
memset(&ctx,0,sizeof(ctx));
-
+
return output;
}
+static char aes_descriptor[] = "AES key objects descriptor";
+
/* Destructor of PyCObject
*/
static void
@@ -65,8 +75,7 @@
free(obj);
}
-static char aes_descriptor[] = "AES key objects descriptor";
-
+/* Converter fn for "O&" argument conversion with AES keys. */
static int
aes_arg_convert(PyObject *obj, void *adr)
{
@@ -79,6 +88,9 @@
}
}
+#define WRAP_AES(aes) (PyCObject_FromVoidPtrAndDesc( (void*) (aes),\
+ (void*) aes_descriptor, aes_destruct))
+
const char mm_aes_key__doc__[] =
"aes_key(str) -> key\n\n"
"Converts a 16-byte string to an AES key for use with aes_ctr128_crypt.\n"
@@ -101,15 +113,17 @@
TYPE_ERR("aes_key() requires a 128-bit (16 byte) string");
return NULL;
}
- aes_key = malloc(sizeof(AES_KEY));
- if (!aes_key) { PyErr_NoMemory(); goto err; }
+
+ if (!(aes_key = malloc(sizeof(AES_KEY)))) {
+ PyErr_NoMemory(); goto err;
+ }
if (AES_set_encrypt_key(key, keylen*8, aes_key)) {
SSL_ERR();
goto err;
}
- result = PyCObject_FromVoidPtrAndDesc( (void*) aes_key,
- (void*) aes_descriptor, aes_destruct );
- if (!result) { PyErr_NoMemory(); goto err; }
+ if (!(result = WRAP_AES(aes_key))) {
+ PyErr_NoMemory(); goto err;
+ }
return result;
err:
@@ -126,7 +140,7 @@
"Encrypts a string in counter mode. If idx is nonzero, the counter begins\n"
"at idx. If prng is nonzero, ignores string and just produces a stream of\n"
"length prng.\n\n"
- "BUG: only the 32 least significant bits of idx are used.\n\n"
+ "WART: only the 32 least significant bits of idx are used.\n\n"
"Performance notes: PRNG mode is much faster (36% @ 32K) than generating\n"
"a string of NULs in Python and encrypting it. Encryption, on the other\n"
"hand, is only slightly faster (15% @ 32K) than XORing the prng output\n"
@@ -155,12 +169,11 @@
if (prng) {
inputlen = prng;
- input = malloc(prng);
- if (!input) { PyErr_NoMemory(); return NULL; }
+ if (!(input = malloc(prng))) { PyErr_NoMemory(); return NULL; }
memset(input, 0, inputlen);
}
- output = PyString_FromStringAndSize(NULL, inputlen);
- if (!output) {
+
+ if (!(output = PyString_FromStringAndSize(NULL, inputlen))) {
PyErr_NoMemory();
if (prng) free(input);
return NULL;
@@ -196,8 +209,11 @@
return NULL;
}
- output = PyString_FromStringAndSize(NULL,s1len);
- if (! output) { PyErr_NoMemory(); return NULL; }
+
+ if (!(output = PyString_FromStringAndSize(NULL,s1len))) {
+ PyErr_NoMemory();
+ return NULL;
+ }
outp = PyString_AS_STRING(output);
while (s1len--) {
@@ -231,6 +247,8 @@
return Py_None;
}
+static char rsa_descriptor[] = "RSA objects descriptor";
+
/* Destructor for PyCObject
*/
static void
@@ -240,8 +258,7 @@
RSA_free( (RSA*) obj);
}
-static char rsa_descriptor[] = "RSA objects descriptor";
-
+/* Converter fn for "O&" argument conversion with RSA keys. */
static int
rsa_arg_convert(PyObject *obj, void *adr)
{
@@ -254,7 +271,6 @@
}
}
-
#define WRAP_RSA(rsa) (PyCObject_FromVoidPtrAndDesc( (void*) (rsa),\
(void*) rsa_descriptor, rsa_destruct))
@@ -333,7 +349,7 @@
kwlist,
&bits, &e))
return NULL;
-
+
rsa = RSA_generate_key(bits, e, NULL, NULL);
if (rsa == NULL) {
SSL_ERR();
@@ -425,52 +441,54 @@
return WRAP_RSA(rsa);
}
+/**
+ * Converts a BIGNUM into a newly allocated PyLongObject.
+ **/
static PyObject*
bn2pylong(const BIGNUM *bn)
{
- int len, len2;
- unsigned char *buf;
PyObject *output;
- len = BN_num_bytes(bn);
- buf = malloc(len);
- if (!buf) { PyErr_NoMemory(); return NULL; }
- len2 = BN_bn2bin(bn, buf);
- assert(len == len2);
-
- /* read big-endian. */
- output = _PyLong_FromByteArray(buf, len, 0, 0);
-
- free(buf);
- return output;
+ /**
+ * We could get better performance with _PyLong_FromByteArray,
+ * but that wasn't introduced until Python 2.2. We go with
+ * only a single implementation here, since this isn't in the
+ * critical path. See CVS version 1.3 of this file for such
+ * an implementation.
+ **/
+ char *hex = BN_bn2hex(bn);
+ output = PyLong_FromString(hex, NULL, 16);
+ OPENSSL_free(hex);
+ return output; /* pass along errors */
}
-/*
- * It's hard to actually get Python to tell you the order-of-magnitude
- * of a long. Instead, we give an overflow error if you're over 2**4096.
- */
-#define MAX_LONG_BYTES 4096/8
-
+/**
+ * Converts a PyLongObject into a freshly allocated BIGNUM.
+ **/
static BIGNUM*
pylong2bn(PyObject *pylong)
{
+ PyObject *str;
+ char *buf;
+ BIGNUM *result = NULL;
int r;
- unsigned char *buf;
- BIGNUM *result;
-
- buf = malloc(MAX_LONG_BYTES);
- if (!buf) { PyErr_NoMemory(); return NULL; }
-
- r = _PyLong_AsByteArray((PyLongObject*)pylong,
- buf, MAX_LONG_BYTES, 0, 0);
- if (r<0) {
- free(buf);
+ assert(PyLong_Check(pylong));
+ assert(pylong && pylong->ob_type
+ && pylong->ob_type->tp_as_number
+ && pylong->ob_type->tp_as_number->nb_hex);
+
+ if (!(str = pylong->ob_type->tp_as_number->nb_hex(pylong)))
return NULL;
- }
- result = BN_bin2bn(buf,MAX_LONG_BYTES,NULL);
- if (result == NULL) { free(buf); PyErr_NoMemory(); return NULL; }
- free(buf);
+ buf = PyString_AsString(str);
+ if (!buf || buf[0]!='0' || buf[1]!='x') {
+ Py_DECREF(str); return NULL;
+ }
+ r = BN_hex2bn(&result, &buf[2]);
+ if (r<0 || result == NULL) {
+ Py_DECREF(str); return NULL;
+ }
+ Py_DECREF(str);
return result;
}
@@ -493,11 +511,12 @@
if (!rsa->n) { TYPE_ERR("Key has no modulus"); return NULL;}
if (!rsa->e) { TYPE_ERR("Key has no e"); return NULL; }
- n = bn2pylong(rsa->n);
- if (n == NULL) { PyErr_NoMemory(); return NULL; }
- e = bn2pylong(rsa->e);
- if (e == NULL) { PyErr_NoMemory(); Py_DECREF(n); return NULL; }
-
+ if (!(n = bn2pylong(rsa->n))) {
+ PyErr_NoMemory(); return NULL;
+ }
+ if (!(e = bn2pylong(rsa->e))) {
+ PyErr_NoMemory(); Py_DECREF(n); return NULL;
+ }
output = Py_BuildValue("OO", n, e);
Py_DECREF(n);
Py_DECREF(e);
@@ -523,12 +542,11 @@
return NULL;
rsa = RSA_new();
- if (!rsa) { PyErr_NoMemory(); return NULL; }
-
- rsa->n = pylong2bn(n);
- if (!rsa->n) { RSA_free(rsa); return NULL; }
- rsa->e = pylong2bn(e);
- if (!rsa->e) { RSA_free(rsa); BN_free(rsa->n); return NULL; }
+ if (!(rsa = RSA_new())) { PyErr_NoMemory(); return NULL; }
+ if (!(rsa->n = pylong2bn(n))) { RSA_free(rsa); return NULL; }
+ if (!(rsa->e = pylong2bn(e))) {
+ RSA_free(rsa); BN_free(rsa->n); return NULL;
+ }
output = WRAP_RSA(rsa);
@@ -537,7 +555,7 @@
const char mm_rsa_get_modulus_bytes__doc__[]=
"rsa_get_modulus_bytes(rsa) -> int\n\n"
- "Returns the numbe of *bytes* (not bits) in an RSA modulus.\n";
+ "Returns the number of *bytes* (not bits) in an RSA modulus.\n";
PyObject *
mm_rsa_get_modulus_bytes(PyObject *self, PyObject *args, PyObject *kwdict)
@@ -579,8 +597,10 @@
TYPE_ERR("String too long to pad.");
return NULL;
}
- output = PyString_FromStringAndSize(NULL,keylen);
- if (!output) { PyErr_NoMemory(); return NULL; }
+
+ if (!(output = PyString_FromStringAndSize(NULL,keylen))) {
+ PyErr_NoMemory(); return NULL;
+ }
r = RSA_padding_add_PKCS1_OAEP(PyString_AS_STRING(output), keylen,
input, inputlen,
@@ -628,8 +648,10 @@
return NULL;
}
- output = PyString_FromStringAndSize(NULL,keylen);
- if (!output) { PyErr_NoMemory(); return NULL; }
+
+ if (!(output = PyString_FromStringAndSize(NULL,keylen))) {
+ PyErr_NoMemory(); return NULL;
+ }
r = RSA_padding_check_PKCS1_OAEP(PyString_AS_STRING(output), keylen,
input+1, inputlen-1, keylen,