blob: c0aa42c343a7f00bdab690061078b8f7970d2856 [file] [log] [blame] [edit]
/* -*- C -*- */
/*
* stream_template.c : Generic framework for stream ciphers
*
* Written by Andrew Kuchling and others
*
* ===================================================================
* The contents of this file are dedicated to the public domain. To
* the extent that dedication to the public domain is not available,
* everyone is granted a worldwide, perpetual, royalty-free,
* non-exclusive license to exercise all rights associated with the
* contents of this file for any purpose whatsoever.
* No rights are reserved.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
* ===================================================================
*/
#include "pycrypto_common.h"
#include "modsupport.h"
#define _STR(x) #x
#define _XSTR(x) _STR(x)
#define _PASTE(x,y) x##y
#define _PASTE2(x,y) _PASTE(x,y)
#ifdef IS_PY3K
#define _MODULE_NAME _PASTE2(PyInit_,MODULE_NAME)
#else
#define _MODULE_NAME _PASTE2(init,MODULE_NAME)
#endif
#define _MODULE_STRING _XSTR(MODULE_NAME)
/*
*
* Python interface
*
*/
typedef struct
{
PyObject_HEAD
stream_state st;
} ALGobject;
/* Please see PEP3123 for a discussion of PyObject_HEAD and changes made in 3.x to make it conform to Standard C.
* These changes also dictate using Py_TYPE to check type, and PyVarObject_HEAD_INIT(NULL, 0) to initialize
*/
staticforward PyTypeObject ALGtype;
static ALGobject *
newALGobject(void)
{
ALGobject * new;
new = PyObject_New(ALGobject, &ALGtype);
return new;
}
static void
ALGdealloc(PyObject *ptr)
{
ALGobject *self = (ALGobject *)ptr;
/* Overwrite the contents of the object */
memset((char*)&(self->st), 0, sizeof(stream_state));
PyObject_Del(ptr);
}
static char ALGnew__doc__[] =
"Return a new " _MODULE_STRING " encryption object.";
static char *kwlist[] = {"key", NULL};
static ALGobject *
ALGnew(PyObject *self, PyObject *args, PyObject *kwdict)
{
unsigned char *key;
ALGobject * new;
int keylen;
new = newALGobject();
if (!PyArg_ParseTupleAndKeywords(args, kwdict, "s#", kwlist,
&key, &keylen))
{
Py_DECREF(new);
return NULL;
}
if (KEY_SIZE!=0 && keylen != KEY_SIZE)
{
PyErr_SetString(PyExc_ValueError,
_MODULE_STRING " key must be "
"KEY_SIZE bytes long");
return NULL;
}
if (KEY_SIZE== 0 && keylen == 0)
{
PyErr_SetString(PyExc_ValueError,
_MODULE_STRING " key cannot be "
"the null string (0 bytes long)");
return NULL;
}
stream_init(&(new->st), key, keylen);
if (PyErr_Occurred())
{
Py_DECREF(new);
return NULL;
}
return new;
}
static char ALG_Encrypt__doc__[] =
"Decrypt the provided string of binary data.";
static PyObject *
ALG_Encrypt(ALGobject *self, PyObject *args)
{
unsigned char *buffer, *str;
int len;
PyObject *result;
if (!PyArg_Parse(args, "s#", &str, &len))
return NULL;
if (len == 0) /* Handle empty string */
{
return PyBytes_FromStringAndSize(NULL, 0);
}
buffer = malloc(len);
if (buffer == NULL)
{
PyErr_SetString(PyExc_MemoryError, "No memory available in "
_MODULE_STRING " encrypt");
return NULL;
}
Py_BEGIN_ALLOW_THREADS;
memcpy(buffer, str, len);
stream_encrypt(&(self->st), buffer, len);
Py_END_ALLOW_THREADS;
result = PyBytes_FromStringAndSize((char *)buffer, len);
free(buffer);
return (result);
}
static char ALG_Decrypt__doc__[] =
"decrypt(string): Decrypt the provided string of binary data.";
static PyObject *
ALG_Decrypt(ALGobject *self, PyObject *args)
{
unsigned char *buffer, *str;
int len;
PyObject *result;
if (!PyArg_Parse(args, "s#", &str, &len))
return NULL;
if (len == 0) /* Handle empty string */
{
return PyBytes_FromStringAndSize(NULL, 0);
}
buffer = malloc(len);
if (buffer == NULL)
{
PyErr_SetString(PyExc_MemoryError, "No memory available in "
_MODULE_STRING " decrypt");
return NULL;
}
Py_BEGIN_ALLOW_THREADS;
memcpy(buffer, str, len);
stream_decrypt(&(self->st), buffer, len);
Py_END_ALLOW_THREADS;
result = PyBytes_FromStringAndSize((char *)buffer, len);
free(buffer);
return (result);
}
/* ALGobject methods */
static PyMethodDef ALGmethods[] =
{
{"encrypt", (PyCFunction) ALG_Encrypt, METH_O, ALG_Encrypt__doc__},
{"decrypt", (PyCFunction) ALG_Decrypt, METH_O, ALG_Decrypt__doc__},
{NULL, NULL} /* sentinel */
};
static PyObject *
ALGgetattro(PyObject *self, PyObject *attr)
{
if (!PyString_Check(attr))
goto generic;
if (PyString_CompareWithASCIIString(attr, "block_size") == 0)
{
return PyInt_FromLong(BLOCK_SIZE);
}
if (PyString_CompareWithASCIIString(attr, "key_size") == 0)
{
return PyInt_FromLong(KEY_SIZE);
}
generic:
#if PYTHON_API_VERSION >= 1011 /* Python 2.2 and later */
return PyObject_GenericGetAttr(self, attr);
#else
if (PyString_Check(attr) < 0) {
PyErr_SetObject(PyExc_AttributeError, attr);
return NULL;
}
return Py_FindMethod(ALGmethods, (PyObject *)self, PyString_AsString(attr));
#endif
}
/* List of functions defined in the module */
static struct PyMethodDef modulemethods[] =
{
{"new", (PyCFunction) ALGnew,
METH_VARARGS|METH_KEYWORDS, ALGnew__doc__},
{NULL, NULL} /* sentinel */
};
static PyTypeObject ALGtype =
{
PyVarObject_HEAD_INIT(NULL, 0) /* deferred type init for compilation on Windows, type will be filled in at runtime */
_MODULE_STRING, /*tp_name*/
sizeof(ALGobject), /*tp_size*/
0, /*tp_itemsize*/
/* methods */
(destructor) ALGdealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash*/
0, /*tp_call*/
0, /*tp_str*/
ALGgetattro, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT, /*tp_flags*/
0, /*tp_doc*/
0, /*tp_traverse*/
0, /*tp_clear*/
0, /*tp_richcompare*/
0, /*tp_weaklistoffset*/
#if PYTHON_API_VERSION >= 1011 /* Python 2.2 and later */
0, /*tp_iter*/
0, /*tp_iternext*/
ALGmethods, /*tp_methods*/
#endif
};
#ifdef IS_PY3K
static struct PyModuleDef moduledef = {
PyModuleDef_HEAD_INIT,
"Crypto.Cipher." _MODULE_STRING,
NULL,
-1,
modulemethods,
NULL,
NULL,
NULL,
NULL
};
#endif
/* Initialization function for the module */
PyMODINIT_FUNC
_MODULE_NAME (void)
{
PyObject *m = NULL;
PyObject *__all__ = NULL;
if (PyType_Ready(&ALGtype) < 0)
goto errout;
#ifdef IS_PY3K
/* Create the module and add the functions */
m = PyModule_Create(&moduledef);
#else
/* Create the module and add the functions */
m = Py_InitModule("Crypto.Cipher." _MODULE_STRING, modulemethods);
#endif
if (m == NULL)
goto errout;
/* Add the type object to the module (using the name of the module itself),
* so that its methods docstrings are discoverable by introspection tools. */
PyObject_SetAttrString(m, _MODULE_STRING, (PyObject *)&ALGtype);
/* Add some symbolic constants to the module */
PyModule_AddIntConstant(m, "block_size", BLOCK_SIZE);
PyModule_AddIntConstant(m, "key_size", KEY_SIZE);
/* Create __all__ (to help generate documentation) */
__all__ = PyList_New(4);
if (__all__ == NULL)
goto errout;
PyList_SetItem(__all__, 0, PyString_FromString(_MODULE_STRING)); /* This is the ALGType object */
PyList_SetItem(__all__, 1, PyString_FromString("new"));
PyList_SetItem(__all__, 2, PyString_FromString("block_size"));
PyList_SetItem(__all__, 3, PyString_FromString("key_size"));
PyObject_SetAttrString(m, "__all__", __all__);
out:
/* Final error check */
if (m == NULL && !PyErr_Occurred()) {
PyErr_SetString(PyExc_ImportError, "can't initialize module");
goto errout;
}
/* Free local objects here */
Py_CLEAR(__all__);
/* Return */
#ifdef IS_PY3K
return m;
#else
return;
#endif
errout:
/* Free the module and other global objects here */
Py_CLEAR(m);
goto out;
}
/* vim:set ts=4 sw=4 sts=0 noexpandtab: */