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) |
---|
8 | typedef 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 | |
---|
21 | static const char* const xsalsa__doc__ = "_xsalsa cipher"; |
---|
22 | |
---|
23 | static PyObject *xsalsa_error; |
---|
24 | |
---|
25 | typedef struct { |
---|
26 | PyObject_HEAD |
---|
27 | |
---|
28 | /* internal */ |
---|
29 | // CryptoPP::CTR_Mode<CryptoPP::XSalsa20>::Encryption *e; |
---|
30 | CryptoPP::XSalsa20::Encryption *e; |
---|
31 | } XSalsa; |
---|
32 | |
---|
33 | PyDoc_STRVAR(XSalsa__doc__, |
---|
34 | "An XSalsa20 cipher object.\n\ |
---|
35 | \n\ |
---|
36 | This object encrypts/decrypts in CTR mode, using a counter that is initialized\n\ |
---|
37 | to zero when you instantiate the object. Successive calls to .process() will \n\ |
---|
38 | use the current counter and increment it.\n\ |
---|
39 | \n\ |
---|
40 | "); |
---|
41 | |
---|
42 | static 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 | |
---|
67 | PyDoc_STRVAR(XSalsa_process__doc__, |
---|
68 | "Encrypt or decrypt the next bytes, returning the result."); |
---|
69 | |
---|
70 | static PyMethodDef XSalsa_methods[] = { |
---|
71 | {"process", reinterpret_cast<PyCFunction>(XSalsa_process), METH_O, XSalsa_process__doc__}, |
---|
72 | {NULL}, |
---|
73 | }; |
---|
74 | |
---|
75 | static 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 | |
---|
83 | static 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 | |
---|
89 | static 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 | |
---|
120 | static 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 | |
---|
162 | void 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 | } |
---|