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

[minion-cvs] Committing first version of mixminion code to CVS repos...



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

Added Files:
	_minionlib.h aes_ctr.c crypt.c main.c 
Log Message:
Committing first version of mixminion code to CVS repository.  Right
now, the code to generate and handle messages is in place, but we're
still missing all the networking logic... along with everything else
mentioned in TODO.

See HACKING if you want to make it go.

See TODO it you want to make it better.

Please don't circulate this beyond the list until we have more of it
working.

I'm going to have to work on my day job for a while, so I may be slow
writing more of this.  Nevertheless, I hope to get the
buildMessage/serverProcess logic well tested and debugged by this
weekend.


--- NEW FILE: _minionlib.h ---
/* Copyright (c) 2002 Nick Mathewson.  See LICENSE for licensing information */
/* $Id: _minionlib.h,v 1.1 2002/05/29 03:52:13 nickm Exp $ */
#ifndef _MINIONLIB_H
#define _MINIONLIB_H

#include <Python.h>
#include <openssl/aes.h>

#define AESCRYPT mix_AES_ctr128_encrypt
void mix_AES_ctr128_encrypt(const unsigned char *in, unsigned char *out,
			    const unsigned long length, const AES_KEY *key,
			    unsigned char *counter, unsigned int *num);

#define FUNC(fn) PyObject* fn(PyObject *self, PyObject *args, PyObject *kwdict)
#define DOC(fn) extern const char fn##__doc__[]
#define FUNC_DOC(fn) FUNC(fn); DOC(fn)

/* Functions from crypt.c */
FUNC_DOC(mm_sha1);
FUNC_DOC(mm_sha1);
FUNC_DOC(mm_aes_ctr128_crypt);
FUNC_DOC(mm_strxor);
FUNC_DOC(mm_openssl_seed);
FUNC_DOC(mm_add_oaep_padding);
FUNC_DOC(mm_check_oaep_padding);
FUNC_DOC(mm_rsa_generate);
FUNC_DOC(mm_rsa_crypt);
FUNC_DOC(mm_rsa_encode_key);
FUNC_DOC(mm_rsa_decode_key);
FUNC_DOC(mm_rsa_get_modulus_bytes);
FUNC_DOC(mm_rsa_get_public_key);
FUNC_DOC(mm_rsa_make_public_key);
extern PyObject *mm_SSLError;

#endif

--- NEW FILE: aes_ctr.c ---
/* crypto/aes/aes_ctr.c -*- mode:C; c-file-style: "eay" -*- */
/* ====================================================================
 * Copyright (c) 1998-2002 The OpenSSL Project.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer. 
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. All advertising materials mentioning features or use of this
 *    software must display the following acknowledgment:
 *    "This product includes software developed by the OpenSSL Project
 *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
 *
 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
 *    endorse or promote products derived from this software without
 *    prior written permission. For written permission, please contact
 *    openssl-core@openssl.org.
 *
 * 5. Products derived from this software may not be called "OpenSSL"
 *    nor may "OpenSSL" appear in their names without prior written
 *    permission of the OpenSSL Project.
 *
 * 6. Redistributions of any form whatsoever must retain the following
 *    acknowledgment:
 *    "This product includes software developed by the OpenSSL Project
 *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
 *
 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 * ====================================================================
 *
 */

#include <_minionlib.h>

/* Modified code for aes_ctr.c from openssl.  The difference is: this
 * code actually works.
 * 
 * I've submitted a bug report to the openssl people. -- NM 
 */
/* For some weird reason, openssl wants to count by 2**64, and wants
 * to increment funny.  I've given up an rewritten the incr function too.
 * I'm leaving the above copyright notice to be safe. -- NM
 */

#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] <<  8) ^ ((u32)(pt)[3]))
#define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >>  8); (ct)[3] = (u8)(st); }

typedef unsigned long u32;
typedef unsigned char u8;

/* increment counter (128-bit big-endian int) by 1 */
static void 
incr(unsigned char *counter) {
        unsigned long c;

	c = GETU32(counter+12);
	c++;
	PUTU32(counter+12,c);
	if (c) return;

	c = GETU32(counter+8);
	c++;
	PUTU32(counter+8,c);
	if (c) return;
		

	c = GETU32(counter+4);
	c++;
	PUTU32(counter+8,c);
	if (c) return;

	c = GETU32(counter+0);
	c++;
	PUTU32(counter+8,c);
	if (c) return;
}

/* The input encrypted as though 128bit counter mode is being
 * used.  The extra state information to record how much of the
 * 128bit block we have used is contained in *num;
 */
void 
mix_AES_ctr128_encrypt(const unsigned char *in, unsigned char *out,
		       const unsigned long length, const AES_KEY *key,
		       unsigned char *counter, unsigned int *num) {
        unsigned int n;
        unsigned long l=length;
        unsigned char tmp[AES_BLOCK_SIZE];

        assert(in && out && key && counter && num);
        n = *num;

	AES_encrypt(counter,tmp,key);

        while (l--) {
                *(out++) = *(in++) ^ tmp[n];
                n = (n+1) % AES_BLOCK_SIZE;
		if (n == 0 && l) {
                        incr(counter);
                        AES_encrypt(counter, tmp, key);
                }			
        }

        *num=n;
}

/*
  Local Variables:
  mode:c
  c-basic-offset:8
  End:
*/

--- NEW FILE: crypt.c ---
/* Copyright (c) 2002 Nick Mathewson.  See LICENSE for licensing information */
/* $Id: crypt.c,v 1.1 2002/05/29 03:52:13 nickm Exp $ */
#include <Python.h>

#include <openssl/bn.h>
#include <openssl/rsa.h>
#include <openssl/aes.h>
#include <openssl/sha.h>
#include <openssl/rand.h>
#include <openssl/err.h>
#include <_minionlib.h>

#define TYPE_ERR(s) PyErr_SetString(PyExc_TypeError, s)
#define KEY_IS_PRIVATE(rsa) ((rsa)->p)

PyObject *mm_SSLError = NULL;

static void 
SSL_ERR() 
{
	int err = ERR_get_error();
	const char *str = ERR_reason_error_string(err);
	if (str)
		PyErr_SetString(mm_SSLError, str);
	else
		PyErr_SetString(mm_SSLError, "SSL error");
}

const char mm_sha1__doc__[] = 
  "sha1(s) -> str\n\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;
	SHA_CTX ctx;
	PyObject *output;

	if (!PyArg_ParseTupleAndKeywords(args, kwdict, "s#|s#:sha1", kwlist,
					 &cp, &len, &keyp, &keylen))
		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();
		return NULL;
	}
	SHA1_Final(PyString_AS_STRING(output),&ctx);
	memset(&ctx,0,sizeof(ctx));

	return output;
}

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.";

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;
	long idx=0;
	int shortidx;
	AES_KEY aes_key;

	unsigned char *counter;
	PyObject *output;

	if (!PyArg_ParseTupleAndKeywords(args, kwdict, 
					 "s#s#|li:aes_ctr128_crypt", kwlist,
					 &key, &keylen, &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;

	shortidx = idx & 0x0f;
	idx >>= 4;
	counter = malloc(AES_BLOCK_SIZE);
	if (!counter) { PyErr_NoMemory(); return NULL; }
		
	memset(counter, 0, AES_BLOCK_SIZE);
	if (idx != 0) {
		counter[15] =  idx        & 0xff;
		counter[14] = (idx >> 8)  & 0xff;
		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);
	if (!output) {
		PyErr_NoMemory(); 
		free(counter); 
		if (prng) free(input);
		return NULL;
	}

	AESCRYPT(input, PyString_AS_STRING(output),
		 inputlen, &aes_key,
		 counter, &shortidx);

	memset(&aes_key, 0, sizeof(AES_KEY));
	free(counter);
	if (prng) free(input);

	return output;
}

const char mm_strxor__doc__[]=
  "strxor(str1, str2) -> str\n\n"
  "Computes the bitwise xor of two equally-long strings.  Throws TypeError\n"
  "if the strings\' lengths are not the same.";

PyObject*
mm_strxor(PyObject *self, PyObject *args, PyObject *kwdict)
{
	static char *kwlist[] = { "str1", "str2", NULL };
	unsigned char *s1, *s2;
	unsigned char *outp;
	int s1len, s2len;
	PyObject *output;

	if (!PyArg_ParseTupleAndKeywords(args, kwdict,
					 "s#s#:strxor", kwlist,
					 &s1, &s1len, &s2, &s2len))
		return NULL;
	if (s1len != s2len) {
		TYPE_ERR("Mismatch between argument lengths");
		return NULL;
	}

	output = PyString_FromStringAndSize(s1,s1len);
	if (! output) { PyErr_NoMemory(); return NULL; }

	outp = PyString_AS_STRING(output);
	while (s1len--) {
		*(outp++) ^= *(s2++);
	}

	return output;
}

const char mm_openssl_seed__doc__[]=
  "openssl_seed(str)\n\n"
  "Seeds OpenSSL\'s internal random number generator with a provided source\n"
  "of entropy.  This method must be called before generating RSA keys or\n"
  "OAEP padding.\n";

PyObject *
mm_openssl_seed(PyObject *self, PyObject *args, PyObject *kwdict) 
{
	static char *kwlist[] = { "seed", NULL };
	unsigned char *seed;
	int seedlen;

	if (!PyArg_ParseTupleAndKeywords(args, kwdict, "s#:openssl_seed", 
					 kwlist,
					 &seed, &seedlen))
		return NULL;

	
	RAND_seed(seed, seedlen);
	Py_INCREF(Py_None);
	return Py_None;
}

/* Destructor for PyCObject
 */
static void
rsa_destruct(void *obj, void *desc) 
{
	assert(desc==rsa_descriptor);
	RSA_free( (RSA*) obj);
}

static char rsa_descriptor[] = "RSA objects descriptor";

static int
rsa_arg_convert(PyObject *obj, void *adr) {
	if (PyCObject_Check(obj) && PyCObject_GetDesc(obj) == rsa_descriptor) {
		*((RSA**) adr) = (RSA*) PyCObject_AsVoidPtr(obj);
		return 1;
	} else {
		TYPE_ERR("Expected an RSA key as an argument.");
		return 0;
	}
}


#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"
  "encrypts; else, decrypts.  If public is true, performs a public-key\n"
  "operation; else, performs a private-key operation.";

PyObject *
mm_rsa_crypt(PyObject *self, PyObject *args, PyObject *kwdict) 
{
	static char *kwlist[] = { "key", "string", "public", "encrypt", NULL };

	RSA *rsa;
	unsigned char *string;
	int stringlen, pub, encrypt;

	int keylen, i;
	char *out;
	PyObject *output;
	
	if (!PyArg_ParseTupleAndKeywords(args, kwdict, 
					 "O&s#ii:rsa_crypt", kwlist,
					 rsa_arg_convert, &rsa, 
					 &string, &stringlen, &pub, &encrypt))
		return NULL;
	if (!pub && !KEY_IS_PRIVATE(rsa)) {
		TYPE_ERR("Can\'t use public key for private-key operation");
		return NULL;
	}

	keylen = BN_num_bytes(rsa->n);

	output = PyString_FromStringAndSize(NULL, keylen);
	out = PyString_AS_STRING(output);
	if (encrypt) {
		if (pub)
			i = RSA_public_encrypt(stringlen, string, out, rsa, 
					       RSA_NO_PADDING);
		else 
			i = RSA_private_encrypt(stringlen, string, out, rsa, 
						RSA_NO_PADDING);
	} else {
		if (pub)
			i = RSA_public_decrypt(stringlen, string, out, rsa,
					       RSA_NO_PADDING);
		else
			i = RSA_private_decrypt(stringlen, string, out, rsa,
						RSA_NO_PADDING);
	}

	if (i <= 0) {
		Py_DECREF(output);
		SSL_ERR();
		return NULL;
	}
	if(_PyString_Resize(&output, i)) return NULL; 

	return output;
}

const char mm_rsa_generate__doc__[]=
  "rsa_generate(bits,e) -> rsa\n\n"
  "Generates a new RSA key with a requested number of bits and e parameter.\n"
  "Remember to seed the OpenSSL rng before calling this method.\n";

PyObject *
mm_rsa_generate(PyObject *self, PyObject *args, PyObject *kwdict) 
{
	static char *kwlist[] = {"bits", "e", NULL};
	int bits, e;
	RSA *rsa;

	if (!PyArg_ParseTupleAndKeywords(args, kwdict, "ii:rsa_generate", 
					 kwlist,
					 &bits, &e))
		return NULL;
	
	rsa = RSA_generate_key(bits, e, NULL, NULL);
	if (rsa == NULL) {
		SSL_ERR();
		return NULL;
	}
	
	return WRAP_RSA(rsa);
}

const char mm_rsa_encode_key__doc__[]=
  "rsa_encode_key(rsa,public) -> str\n\n"
  "Computes the DER encoding of a given key.  If 'public' is true, encodes\n"
  "only the public-key portions of rsa.\n";
 
PyObject *
mm_rsa_encode_key(PyObject *self, PyObject *args, PyObject *kwdict) 
{
	static char *kwlist[] = { "key", "public", NULL };
	
	RSA *rsa;
	int public;

	int len;
	PyObject *output;
	unsigned char *out, *outp;

	if (!PyArg_ParseTupleAndKeywords(args, kwdict, 
					 "O&i:rsa_encode_key", kwlist,
					 rsa_arg_convert, &rsa, &public))
		return NULL;

	if (!public && !KEY_IS_PRIVATE(rsa)) {
		TYPE_ERR("Can\'t use public key for private-key operation");
		return NULL;
	}

	len = public ? i2d_RSAPublicKey(rsa,NULL) : 
		i2d_RSAPrivateKey(rsa,NULL);
	if (len < 0) {
		SSL_ERR();
		return NULL;
	}
	out = outp = malloc(len+1);
	if (public) 
		len = i2d_RSAPublicKey(rsa, &outp);
	else 
		len = i2d_RSAPrivateKey(rsa, &outp);
	if (len < 0) {
		free(out);
		SSL_ERR();
		return NULL;
	}

	output = PyString_FromStringAndSize(out, len);
	free(out);
	if (!output) {
		PyErr_NoMemory();
		return NULL;
	}
	return output;
}

const char mm_rsa_decode_key__doc__[]=
  "rsa_decode_key(key, public) -> rsa\n\n"
  "Extracts an RSA key from its DER encoding.  If public is true, expects a\n"
  "public key only.  Otherwise, expects a private key.\n";

PyObject *
mm_rsa_decode_key(PyObject *self, PyObject *args, PyObject *kwdict) 
{
	static char *kwlist[] = { "key", "public", NULL };
	
	const unsigned char *string;
	int stringlen, public;

	RSA *rsa;

	if (!PyArg_ParseTupleAndKeywords(args, kwdict, 
					 "s#i:rsa_decode_key", kwlist,
					 &string, &stringlen, &public))
		return NULL;

	rsa = public ? d2i_RSAPublicKey(NULL, &string, stringlen) : 
		d2i_RSAPrivateKey(NULL, &string, stringlen);
	if (!rsa) {
		SSL_ERR();
		return NULL;
	}
	return WRAP_RSA(rsa);
}

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;
}

/*
 * 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

static BIGNUM*
pylong2bn(PyObject *pylong)
{
	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);
		return NULL;
	}
	result = BN_bin2bn(buf,MAX_LONG_BYTES,NULL);
	if (result == NULL) { free(buf); PyErr_NoMemory(); return NULL; }
	
	free(buf);
	return result;
}

const char mm_rsa_get_public_key__doc__[]=
   "rsa_get_public_key(rsa) -> (n,e)\n";

PyObject *
mm_rsa_get_public_key(PyObject *self, PyObject *args, PyObject *kwdict) 
{
	static char *kwlist[] = { "key", NULL };
	
	RSA *rsa;
	PyObject *n, *e;
	PyObject *output;

	if (!PyArg_ParseTupleAndKeywords(args, kwdict, 
					 "O&:rsa_get_public_key", kwlist,
					 rsa_arg_convert, &rsa))
		return NULL;
	
	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; }

	output = Py_BuildValue("OO", n, e);
	Py_DECREF(n);
	Py_DECREF(e);
	return output;
}

const char mm_rsa_make_public_key__doc__[]=
   "rsa_make_public_key(n,e) -> rsa\n\n"
   "n and e must both be long integers.  Ints won't work.\n";

PyObject *
mm_rsa_make_public_key(PyObject *self, PyObject *args, PyObject *kwdict) 
{
	static char *kwlist[] = { "n","e", NULL };
	
	RSA *rsa;
	PyObject *n, *e;
	PyObject *output;

	if (!PyArg_ParseTupleAndKeywords(args, kwdict, 
					 "O!O!:rsa_make_public_key", kwlist,
					 &PyLong_Type, &n, &PyLong_Type, &e))
		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; }

	output = WRAP_RSA(rsa);
	
	return output;
}

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";

PyObject *
mm_rsa_get_modulus_bytes(PyObject *self, PyObject *args, PyObject *kwdict) 
{
	static char *kwlist[] = { "key", NULL };
	
	RSA *rsa;

	if (!PyArg_ParseTupleAndKeywords(args, kwdict, 
					 "O&:rsa_get_modulus_bytes", kwlist,
					 rsa_arg_convert, &rsa))
		return NULL;
	
	return PyInt_FromLong(BN_num_bytes(rsa->n));
}

const char mm_add_oaep_padding__doc__[]=
   "add_oaep_padding(s, param, keylen) -> str\n\n"
   "Adds OAEP padding to a string.  Keylen is the length of the RSA key to\n"
   "be used, in bytes;  Param is the security parameter string.\n";

PyObject *
mm_add_oaep_padding(PyObject *self, PyObject *args, PyObject *kwdict) 
{
	static char *kwlist[] = { "s", "param", "keylen", NULL };

	const unsigned char *param, *input;
	int paramlen, inputlen;
	int keylen, r;

	PyObject *output;
	
	if (!PyArg_ParseTupleAndKeywords(args, kwdict, 
					 "s#s#i:add_oaep_padding", kwlist,
			      &input,&inputlen,&param,&paramlen,&keylen))
		return NULL;
	
	if (inputlen >= keylen) {
		TYPE_ERR("String too long to pad.");
		return NULL;
	}
	output = PyString_FromStringAndSize(NULL,keylen);
	if (!output) { PyErr_NoMemory(); return NULL; }
	
	r = RSA_padding_add_PKCS1_OAEP(PyString_AS_STRING(output), keylen,
				       input, inputlen,
				       param, paramlen);
	if (r <= 0) {
		SSL_ERR(); 
		Py_DECREF(output);
		return NULL;
	}
	
	return output;
}

const char mm_check_oaep_padding__doc__[]=
   "check_oaep_padding(s, param, keylen) -> str\n\n"
   "Checks OAEP padding on a string.  Keylen is the length of the RSA key to\n"
   "be used, in bytes;  Param is the security parameter string.\n"
   "If the padding is in tact, the original string is returned.\n";

PyObject *
mm_check_oaep_padding(PyObject *self, PyObject *args, PyObject *kwdict) 
{
	static char *kwlist[] = { "s", "param", "keylen", NULL };

	const unsigned char *param, *input;
	int paramlen, inputlen;
	int keylen, r;

	PyObject *output;
	
	if (!PyArg_ParseTupleAndKeywords(args, kwdict, 
					 "s#s#i:check_oaep_padding", kwlist,
				  &input,&inputlen,&param,&paramlen,&keylen))
		return NULL;

	if (inputlen == 0 || *input != '\000') {
		PyErr_SetString(mm_SSLError,
				"Bad padding, or our assumptions about "
				"OAEP padding are gravely mistaken");
		return NULL;
	}
	
	output = PyString_FromStringAndSize(NULL,keylen);
	if (!output) { PyErr_NoMemory(); return NULL; }
	
	r = RSA_padding_check_PKCS1_OAEP(PyString_AS_STRING(output), keylen,
					 input+1, inputlen-1, keylen,
					 param, paramlen);
	if (r <= 0) {
		SSL_ERR();
		Py_DECREF(output);
		return NULL;
	}
	if(_PyString_Resize(&output, r)) return NULL;

	return output;
}

/*
  Local Variables:
  mode:c
  c-basic-offset:8
  End:
*/

--- NEW FILE: main.c ---
/* Copyright 2002 Nick Mathewson.  See LICENSE for licensing information */
/* $Id: main.c,v 1.1 2002/05/29 03:52:13 nickm Exp $ */
#include <_minionlib.h>

#include <openssl/err.h>
#include <openssl/rsa.h>

#define ENTRY_ND(fn) { #fn, (PyCFunction)mm_##fn, METH_VARARGS|METH_KEYWORDS,\
                       0}
#define ENTRY(fn) { #fn, (PyCFunction)mm_##fn, METH_VARARGS|METH_KEYWORDS, \
             (char*)mm_##fn##__doc__}

static struct PyMethodDef _mixcryptlib_functions[] = {
	ENTRY(sha1),
	ENTRY(aes_ctr128_crypt),
	ENTRY(strxor),
	ENTRY(openssl_seed),
	ENTRY(add_oaep_padding),
	ENTRY(check_oaep_padding),
	ENTRY(rsa_generate),
	ENTRY(rsa_crypt),
	ENTRY(rsa_encode_key),
	ENTRY(rsa_decode_key),
	ENTRY(rsa_get_modulus_bytes),
	ENTRY(rsa_get_public_key),
	ENTRY(rsa_make_public_key),
	
	{ NULL, NULL }
};

DL_EXPORT(void)
init_minionlib(void)
{
	PyObject *m, *d;
	m = Py_InitModule("_minionlib", _mixcryptlib_functions);
	d = PyModule_GetDict(m);

	/* crypt */
	ERR_load_ERR_strings();
 	ERR_load_RSA_strings();
	mm_SSLError = PyErr_NewException("mixminion.SSLError", PyExc_Exception, NULL);

	if (PyDict_SetItemString(d, "SSLError", mm_SSLError) < 0)
		return;
}

/*
  Local Variables:
  mode:c
  c-basic-offset:8
  End:
*/