[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[minion-cvs] Improved comments on performance.



Update of /home/minion/cvsroot/src/minion/src
In directory moria.seul.org:/tmp/cvs-serv8424/src

Modified Files:
	_minionlib.h crypt.c main.c 
Log Message:
Improved comments on performance.

Remove a (futile) optimization from _minionlib.sha1.

Add a (measurably productive) optimization: remember expanded AES keys.

New LIONESS key schedule.

Implement replay prevention.

Fix use of interfaces in ServerProcess.

New tests and benchmarks for the above.


Index: _minionlib.h
===================================================================
RCS file: /home/minion/cvsroot/src/minion/src/_minionlib.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- _minionlib.h	29 May 2002 03:52:13 -0000	1.1
+++ _minionlib.h	29 May 2002 17:46:24 -0000	1.2
@@ -18,6 +18,7 @@
 /* Functions from crypt.c */
 FUNC_DOC(mm_sha1);
 FUNC_DOC(mm_sha1);
+FUNC_DOC(mm_aes_key);
 FUNC_DOC(mm_aes_ctr128_crypt);
 FUNC_DOC(mm_strxor);
 FUNC_DOC(mm_openssl_seed);

Index: crypt.c
===================================================================
RCS file: /home/minion/cvsroot/src/minion/src/crypt.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- crypt.c	29 May 2002 03:52:13 -0000	1.1
+++ crypt.c	29 May 2002 17:46:24 -0000	1.2
@@ -28,27 +28,22 @@
 
 const char mm_sha1__doc__[] = 
   "sha1(s) -> str\n\n"
-  "Computes the SHA-1 hash of a string\n";
+  "Computes the SHA-1 hash of a string.\n";
 
 PyObject*
 mm_sha1(PyObject *self, PyObject *args, PyObject *kwdict) 
 {
-	static char *kwlist[] = { "string", "key", NULL};
-	unsigned char *cp = NULL, *keyp = NULL;
-	int len, keylen;
+	static char *kwlist[] = { "string", NULL};
+	unsigned char *cp = NULL;
+	int len;
 	SHA_CTX ctx;
 	PyObject *output;
 
-	if (!PyArg_ParseTupleAndKeywords(args, kwdict, "s#|s#:sha1", kwlist,
-					 &cp, &len, &keyp, &keylen))
+	if (!PyArg_ParseTupleAndKeywords(args, kwdict, "s#:sha1", kwlist,
+					 &cp, &len))
 		return NULL;
 	SHA1_Init(&ctx);
-	if (keyp)
-		SHA1_Update(&ctx,keyp,keylen); 
 	SHA1_Update(&ctx,cp,len); 
-	if (keyp)
-		SHA1_Update(&ctx,keyp,keylen); 
-	
 	output = PyString_FromStringAndSize(NULL, SHA_DIGEST_LENGTH);
 	if (!output) {
 		PyErr_NoMemory();
@@ -60,36 +55,103 @@
 	return output;
 }
 
+/* Destructor of PyCObject
+ */
+static void
+aes_destruct(void *obj, void *desc)
+{
+	assert(desc==aes_descriptor);
+	memset(obj, 0, sizeof(AES_KEY));
+	free(obj);
+}
+
+static char aes_descriptor[] = "AES key objects descriptor";
+
+static int
+aes_arg_convert(PyObject *obj, void *adr)
+{
+	if (PyCObject_Check(obj) && PyCObject_GetDesc(obj) == aes_descriptor) {
+		*((AES_KEY**) adr) = (AES_KEY*) PyCObject_AsVoidPtr(obj);
+		return 1;
+	} else {
+		TYPE_ERR("Expected an AES key as an argument.");
+		return 0;
+	}
+}
+
+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"
+    "\n(The performance advantage to doing so is only significant for small\n"
+    "(<1K) blocks.)\n";  
+
+PyObject*
+mm_aes_key(PyObject *self, PyObject *args, PyObject *kwdict)
+{
+	static char *kwlist[] = { "key", NULL }; 
+	char *key;
+	int keylen;
+	AES_KEY *aes_key = NULL;
+	PyObject *result;
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwdict, "s#:aes_key", kwlist,
+					 &key, &keylen))
+		return NULL;
+	if (keylen != 16) {
+		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_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; }
+	return result;
+
+ err:
+	if (aes_key) {
+		memset(aes_key, 0, sizeof(AES_KEY));
+		free(aes_key);
+	}
+	return NULL;
+}
+
+
 const char mm_aes_ctr128_crypt__doc__[] = 
   "aes_ctr128_crypt(key, string, idx=0, prng=0) -> str\n\n"
   "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.";
+  "BUG: only the 32 least significant bits of idx are used.\n\n"
+  "Performance notes:  PRNG mode is much faster (33% @ 32K) than generating\n"
+  "a string of NULs in Python and encrypting it.  Encryption, on the other\n"
+  "hand, is only slightly faster (11% @ 32K) than XORing the prng output\n"
+  "with the plaintext.\n";
 
 PyObject*
 mm_aes_ctr128_crypt(PyObject *self, PyObject *args, PyObject *kwdict) 
 {
 	static char *kwlist[] = { "key", "string", "idx", "prng", NULL };
-	unsigned char *key, *input;
-        int keylen, inputlen, prng=0;
+	unsigned char *input;
+        int inputlen, prng=0;
 	long idx=0;
 	int shortidx;
-	AES_KEY aes_key;
+	AES_KEY *aes_key =NULL;
 
 	unsigned char *counter;
 	PyObject *output;
 
 	if (!PyArg_ParseTupleAndKeywords(args, kwdict, 
-					 "s#s#|li:aes_ctr128_crypt", kwlist,
-					 &key, &keylen, &input, &inputlen,
+					 "O&s#|li:aes_ctr128_crypt", kwlist,
+					 aes_arg_convert, &aes_key, 
+					 &input, &inputlen,
 					 &idx, &prng))
 		return NULL;
 	
-	if (keylen != 16) {
-		TYPE_ERR("AES key wasn\'t 128 bits long");
-		return NULL;
-	}
 	if (idx < 0) idx = 0;
 	if (prng < 0) prng = 0;
 
@@ -105,20 +167,13 @@
 		counter[13] = (idx >> 16) & 0xff;
 		counter[12] = (idx >> 24) & 0xff;
 	}
-	if (AES_set_encrypt_key(key, keylen*8, &aes_key)) {
-		SSL_ERR();
-		free(counter);
-		return NULL;
-	}
-
 	if (prng) { 
 		inputlen = prng;
 		input = malloc(prng);
 		if (!input) { PyErr_NoMemory(); return NULL; }
-		memset(input, 0, prng);
-	        output = PyString_FromStringAndSize(NULL, prng);
-	} else
-		output = PyString_FromStringAndSize(input, inputlen);
+		memset(input, 0, inputlen);
+	} 
+	output = PyString_FromStringAndSize(NULL, inputlen);
 	if (!output) {
 		PyErr_NoMemory(); 
 		free(counter); 
@@ -126,14 +181,13 @@
 		return NULL;
 	}
 
-	AESCRYPT(input, PyString_AS_STRING(output),
-		 inputlen, &aes_key,
+	AESCRYPT((const char*)input, PyString_AS_STRING(output),
+		 inputlen, aes_key,
 		 counter, &shortidx);
 
-	memset(&aes_key, 0, sizeof(AES_KEY));
 	free(counter);
-	if (prng) free(input);
 
+	if (prng) free(input);
 	return output;
 }
 
@@ -160,12 +214,12 @@
 		return NULL;
 	}
 
-	output = PyString_FromStringAndSize(s1,s1len);
+	output = PyString_FromStringAndSize(NULL,s1len);
 	if (! output) { PyErr_NoMemory(); return NULL; }
 
 	outp = PyString_AS_STRING(output);
 	while (s1len--) {
-		*(outp++) ^= *(s2++);
+		*(outp++) = *(s1++) ^ *(s2++);
 	}
 
 	return output;
@@ -207,7 +261,8 @@
 static char rsa_descriptor[] = "RSA objects descriptor";
 
 static int
-rsa_arg_convert(PyObject *obj, void *adr) {
+rsa_arg_convert(PyObject *obj, void *adr) 
+{
 	if (PyCObject_Check(obj) && PyCObject_GetDesc(obj) == rsa_descriptor) {
 		*((RSA**) adr) = (RSA*) PyCObject_AsVoidPtr(obj);
 		return 1;
@@ -221,8 +276,6 @@
 #define WRAP_RSA(rsa) (PyCObject_FromVoidPtrAndDesc( (void*) (rsa),\
 		       (void*) rsa_descriptor, rsa_destruct))
 					     
-
-
 const char mm_rsa_crypt__doc__[]=
   "rsa_crypt(key, string, public, encrypt) -> str\n\n"
   "Uses RSA to encrypt or decrypt a provided string.  If encrypt is true,\n"

Index: main.c
===================================================================
RCS file: /home/minion/cvsroot/src/minion/src/main.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- main.c	29 May 2002 03:52:13 -0000	1.1
+++ main.c	29 May 2002 17:46:24 -0000	1.2
@@ -12,6 +12,7 @@
 
 static struct PyMethodDef _mixcryptlib_functions[] = {
 	ENTRY(sha1),
+	ENTRY(aes_key),
 	ENTRY(aes_ctr128_crypt),
 	ENTRY(strxor),
 	ENTRY(openssl_seed),