Ticket #40: xsalsamodule.cpp

File xsalsamodule.cpp, 5.3 KB (added by dragonxue, at 2010-07-03T01:31:38Z)
Line 
1/**
2 * xsalsamodule.cpp -- Python wrappers around Crypto++'s salsa
3 */
4
5#define PY_SSIZE_T_CLEAN
6#include <Python.h>
7#if (PY_VERSION_HEX < 0x02050000)
8typedef int Py_ssize_t;
9#endif
10
11#include "xsalsamodule.hpp"
12
13#ifdef USE_NAME_CRYPTO_PLUS_PLUS
14//#include <crypto++/modes.h>
15#include <crypto++/salsa.h>
16#else
17//#include <cryptopp/modes.h>
18#include <cryptopp/salsa.h>
19#endif
20
21static const char* const xsalsa__doc__ = "_xsalsa cipher";
22
23static PyObject *xsalsa_error;
24
25typedef struct {
26        PyObject_HEAD
27
28        /* internal */
29//      CryptoPP::CTR_Mode<CryptoPP::XSalsa20>::Encryption *e;
30        CryptoPP::XSalsa20::Encryption *e;
31} XSalsa;
32
33PyDoc_STRVAR(XSalsa__doc__,
34"An XSalsa20 cipher object.\n\
35\n\
36This object encrypts/decrypts in CTR mode, using a counter that is initialized\n\
37to zero when you instantiate the object. Successive calls to .process() will \n\
38use the current counter and increment it.\n\
39\n\
40");
41
42static PyObject *XSalsa_process(XSalsa* self, PyObject* msgobj) {
43        if(!PyString_CheckExact(msgobj)) {
44                PyStringObject* typerepr = reinterpret_cast<PyStringObject*>(PyObject_Repr(reinterpret_cast<PyObject*>(msgobj->ob_type)));
45                if (typerepr) {
46                        PyErr_Format(xsalsa_error, "Precondition violation: you are required to pass a Python string object (not a unicode, a subclass of string, or anything else), but you passed %s.", PyString_AS_STRING(reinterpret_cast<PyObject*>(typerepr)));
47                        Py_DECREF(typerepr);
48                } else
49                        PyErr_Format(xsalsa_error, "Precondition violation: you are required to pass a Python string object (not a unicode, a subclass of string, or anything else).");
50                return NULL;
51        }
52
53        const char* msg;
54        Py_ssize_t msgsize;
55        if (PyString_AsStringAndSize(msgobj, const_cast<char**>(&msg), &msgsize))
56                return NULL;
57        assert (msgsize >= 0);
58
59        PyStringObject* result = reinterpret_cast<PyStringObject*>(PyString_FromStringAndSize(NULL, msgsize));
60        if (!result)
61                return NULL;
62
63        self->e->ProcessString(reinterpret_cast<byte*>(PyString_AS_STRING(result)), reinterpret_cast<const byte*>(msg), msgsize);
64        return reinterpret_cast<PyObject*>(result);
65}
66
67PyDoc_STRVAR(XSalsa_process__doc__,
68"Encrypt or decrypt the next bytes, returning the result.");
69
70static PyMethodDef XSalsa_methods[] = {
71        {"process", reinterpret_cast<PyCFunction>(XSalsa_process), METH_O, XSalsa_process__doc__},
72        {NULL},
73};
74
75static PyObject* XSalsa_new(PyTypeObject* type, PyObject *args, PyObject *kwdict) {
76        XSalsa* self = reinterpret_cast<XSalsa*>(type->tp_alloc(type, 0));
77        if (!self)
78                return NULL;
79        self->e = NULL;
80        return reinterpret_cast<PyObject*>(self);
81}
82
83static void XSalsa_dealloc(PyObject* self) {
84        if (reinterpret_cast<XSalsa*>(self)->e)
85                delete reinterpret_cast<XSalsa*>(self)->e;
86        self->ob_type->tp_free(self);
87}
88
89static int XSalsa_init(PyObject* self, PyObject *args, PyObject *kwdict) {
90        static const char *kwlist[] = { "key", "iv", NULL};
91        const char *key = NULL;
92        Py_ssize_t keysize = 0;
93        const char *iv = NULL;
94        const char defaultiv[24] = {0};
95        Py_ssize_t ivsize = 0;
96        if (!PyArg_ParseTupleAndKeywords(args, kwdict, "t#|t#:XSalsa.__init__", const_cast<char**>(kwlist), &key, &keysize, &iv, &ivsize))
97                return -1;
98        assert (keysize >= 0);
99        assert (ivsize >= 0);
100
101        if(!iv)
102                iv = defaultiv;
103        try {
104                reinterpret_cast<XSalsa*>(self)->e = new CryptoPP::XSalsa20::Encryption(reinterpret_cast<const byte*>(key), keysize, reinterpret_cast<const byte*>(iv));
105        } 
106        catch (CryptoPP::InvalidKeyLength le)
107        {
108                PyErr_Format(xsalsa_error, "Precondition violation: you are required to pass a valid key size.  Crypto++ gave this exception: %s", le.what());
109                return -1;     
110        }
111        if (!reinterpret_cast<XSalsa*>(self)->e)
112        {
113                PyErr_NoMemory();
114                return -1;
115        }
116        return 0;
117}
118       
119       
120static PyTypeObject XSalsa_type = {
121        PyObject_HEAD_INIT(NULL)
122        0,                       /*ob_size*/
123        "_xsalsa.XSalsa",        /*tp_name*/
124        sizeof(XSalsa),  /*tp_basicsize*/
125        0,                       /*tp_itemsize*/
126        XSalsa_dealloc,          /*tp_dealloc*/
127        0,                       /*tp_print*/
128        0,                       /*tp_getattr*/
129        0,                       /*tp_setattr*/
130        0,                       /*tp_compare*/
131        0,                       /*tp_repr*/
132        0,                       /*tp_as_number*/
133        0,                       /*tp_as_sequence*/
134        0,                       /*tp_as_mapping*/
135        0,                       /*tp_hash*/
136        0,                       /*tp_call*/
137        0,                       /*tp_str*/
138        0,                       /*tp_getattro*/
139        0,                       /*tp_setattro*/
140        0,                       /*tp_as_buffer*/
141        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
142        XSalsa__doc__,           /*tp_doc*/
143        0,                       /*tp_traverse*/
144        0,                       /*tp_clear*/
145        0,                       /*tp_richcompare*/
146        0,                       /*tp_weaklistoffset*/
147        0,                       /*tp_iter*/
148        0,                       /*tp_iternext*/
149        XSalsa_methods,          /*tp_methods*/
150        0,                       /*tp_members*/
151        0,                       /*tp_getset*/
152        0,                       /*tp_base*/
153        0,                       /*tp_dict*/
154        0,                       /*tp_descr_get*/
155        0,                       /*tp_descr_set*/
156        0,                       /*tp_dictoffset*/
157        XSalsa_init,             /*tp_init*/
158        0,                       /*tp_alloc*/
159        XSalsa_new,              /*tp_new*/
160};
161
162void init_xsalsa(PyObject*const module) 
163{
164        if (PyType_Ready(&XSalsa_type) < 0)
165                return;
166        Py_INCREF(&XSalsa_type);
167        PyModule_AddObject(module, "xsalsa_XSalsa", (PyObject *)&XSalsa_type);
168
169        xsalsa_error = PyErr_NewException(const_cast<char*>("_xsalsa.Error"), NULL, NULL);
170        PyModule_AddObject(module, "xsalsa_Error", xsalsa_error);
171
172        PyModule_AddStringConstant(module, "xsalsa__doc__", const_cast<char*>(xsalsa__doc__));
173}