Ticket #46: ciphercomb.cpp

File ciphercomb.cpp, 8.1 KB (added by xueyu, at 2010-08-11T14:25:04Z)

cipher combiner c++ cpp file

Line 
1/**
2* ciphercomb.cpp -- Python wrappers around Crypto++'s AES-CTR and XSalsa20
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 "ciphercomb.hpp"
12#include <iostream>
13/* from Crypto++ */
14#ifdef USE_NAME_CRYPTO_PLUS_PLUS
15#include <crypto++/modes.h>
16#include <crypto++/aes.h>
17#include <crypto++/salsa.h>
18#include <crypto++/sha.h>
19#include <crypto++/hmac.h>
20#else
21#include <cryptopp/modes.h>
22#include <cryptopp/aes.h>
23#include <cryptopp/salsa.h>
24#include <cryptopp/sha.h>
25#include <cryptopp/hmac.h>
26#endif
27using namespace std;
28
29static const char*const ciphercomb___doc__ = "_ciphercomb mode\n\
30You are advised to run aes.start_up_self_test() after importing this module.";
31
32static PyObject *ciphercomb_error;
33
34typedef struct {
35    PyObject_HEAD
36
37    /* internal */
38    CryptoPP::CTR_Mode<CryptoPP::AES>::Encryption * e1;
39    CryptoPP::XSalsa20::Encryption *e2;
40} CipherComb;
41
42PyDoc_STRVAR(CipherComb__doc__,
43"A CipherComb cipher object.\n\
44\n\
45This object encrypts/decrypts in Combiner mode.\n\
46\n\
47");
48
49static PyObject *
50CipherComb_process(CipherComb* self, PyObject* msgobj) {
51    if (!PyString_CheckExact(msgobj)) {
52        PyStringObject* typerepr = reinterpret_cast<PyStringObject*>(PyObject_Repr(reinterpret_cast<PyObject*>(msgobj->ob_type)));
53        if (typerepr) {
54            PyErr_Format(ciphercomb_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)));
55            Py_DECREF(typerepr);
56        } else
57            PyErr_Format(ciphercomb_error, "Precondition violation: you are required to pass a Python string object (not a unicode, a subclass of string, or anything else).");
58        return NULL;
59    }
60
61    const char *msg;
62    Py_ssize_t msgsize;
63    if (PyString_AsStringAndSize(msgobj, const_cast<char**>(&msg), &msgsize))
64        return NULL;
65    assert (msgsize >= 0);
66
67    PyStringObject* result1 = reinterpret_cast<PyStringObject*>(PyString_FromStringAndSize(NULL, msgsize));
68    if (!result1)
69        return NULL;
70
71    self->e1->ProcessData(reinterpret_cast<byte*>(PyString_AS_STRING(result1)), reinterpret_cast<const byte*>(msg), msgsize);
72
73    PyStringObject* result2 = reinterpret_cast<PyStringObject*>(PyString_FromStringAndSize(NULL, msgsize));
74    if (!result2)
75        return NULL;
76    self->e2->ProcessString(reinterpret_cast<byte*>(PyString_AS_STRING(result2)), reinterpret_cast<const byte*>(PyString_AS_STRING(result1)), msgsize);
77   
78    return reinterpret_cast<PyObject*>(result2);
79}
80
81PyDoc_STRVAR(CipherComb_process__doc__,
82        "Encrypt or decrypt the next bytes, returning the result.");
83
84static PyMethodDef CipherComb_methods[] = {
85    {"process", reinterpret_cast<PyCFunction>(CipherComb_process), METH_O, CipherComb_process__doc__},
86    {NULL},
87};
88
89static PyObject *
90CipherComb_new(PyTypeObject* type, PyObject *args, PyObject *kwdict) {
91    CipherComb* self = reinterpret_cast<CipherComb*>(type->tp_alloc(type, 0));
92    if (!self)
93        return NULL;
94    self->e1 = NULL;
95    self->e2 = NULL;
96    return reinterpret_cast<PyObject*>(self);
97}
98
99static void
100CipherComb_dealloc(PyObject* self) {
101    if (reinterpret_cast<CipherComb*>(self)->e1)
102        delete reinterpret_cast<CipherComb*>(self)->e1;
103    if (reinterpret_cast<CipherComb*>(self)->e2)
104        delete reinterpret_cast<CipherComb*>(self)->e2;
105    self->ob_type->tp_free(self);
106}
107
108static int
109CipherComb_init(PyObject* self, PyObject *args, PyObject *kwdict) {
110    static const char *kwlist[] = { "key", "iv", NULL };
111    const char *key = NULL;
112    Py_ssize_t keysize = 0;
113    const char *iv = NULL;
114    const char defaultiv[40] = {0};
115    Py_ssize_t ivsize = 0;
116    if (!PyArg_ParseTupleAndKeywords(args, kwdict, "t#|t#:CipherComb.__init__", const_cast<char**>(kwlist), &key, &keysize, &iv, &ivsize))
117        return -1;
118    assert (keysize >= 0);
119    assert (ivsize >= 0);
120
121    char prk[32];
122    char* salt="";
123    CryptoPP::HMAC<CryptoPP::SHA256>(reinterpret_cast<byte*>(salt), 0).CalculateDigest(reinterpret_cast<byte*>(prk), reinterpret_cast<const byte*>(key), keysize);
124
125    char t1[32];
126    char t2[32];
127    char ext1[1] = {0x01};
128    CryptoPP::HMAC<CryptoPP::SHA256>(reinterpret_cast<byte*>(prk), 32).CalculateDigest(reinterpret_cast<byte*>(t1), reinterpret_cast<const byte*>(ext1), 1);
129    char ext2[33];
130    memcpy(ext2, t1, 32);
131    ext2[32] = 0x02;
132    CryptoPP::HMAC<CryptoPP::SHA256>(reinterpret_cast<byte*>(prk), 32).CalculateDigest(reinterpret_cast<byte*>(t2), reinterpret_cast<const byte*>(ext2), 33);
133
134    char aeskey[16];
135    int aeskeysize = 16;
136    char xsalsakey[32];
137    int xskeysize = 32;
138    memcpy(aeskey, t1, 16);
139    memcpy(xsalsakey, t1+16, 16);
140    memcpy(xsalsakey+16, t2, 16);
141   
142    char aesiv[16];
143    char xsalsaiv[24];
144    if (!iv)
145        iv = defaultiv;
146    memcpy(aesiv, iv, 16);
147    memcpy(xsalsaiv, iv+16, 24);
148    try {
149        reinterpret_cast<CipherComb*>(self)->e1 = new CryptoPP::CTR_Mode<CryptoPP::AES>::Encryption(reinterpret_cast<const byte*>(aeskey), aeskeysize, reinterpret_cast<const byte*>(aesiv));
150        reinterpret_cast<CipherComb*>(self)->e2 = new CryptoPP::XSalsa20::Encryption(reinterpret_cast<const byte*>(xsalsakey), xskeysize, reinterpret_cast<const byte*>(xsalsaiv));
151       
152    } catch (CryptoPP::InvalidKeyLength le) {
153        PyErr_Format(ciphercomb_error, "Precondition violation: you are required to pass a valid key size.  Crypto++ gave this exception: %s", le.what());
154        return -1;
155    }
156    if (!reinterpret_cast<CipherComb*>(self)->e1 || !reinterpret_cast<CipherComb*>(self)->e2 ) {
157        PyErr_NoMemory();
158        return -1;
159    }
160    return 0;
161}
162
163static PyTypeObject CipherComb_type = {
164    PyObject_HEAD_INIT(NULL)
165    0,                         /*ob_size*/
166    "_ciphercomb.CipherComb", /*tp_name*/
167    sizeof(CipherComb),             /*tp_basicsize*/
168    0,                         /*tp_itemsize*/
169    CipherComb_dealloc, /*tp_dealloc*/
170    0,                         /*tp_print*/
171    0,                         /*tp_getattr*/
172    0,                         /*tp_setattr*/
173    0,                         /*tp_compare*/
174    0,                         /*tp_repr*/
175    0,                         /*tp_as_number*/
176    0,                         /*tp_as_sequence*/
177    0,                         /*tp_as_mapping*/
178    0,                         /*tp_hash */
179    0,                         /*tp_call*/
180    0,                         /*tp_str*/
181    0,                         /*tp_getattro*/
182    0,                         /*tp_setattro*/
183    0,                         /*tp_as_buffer*/
184    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
185    CipherComb__doc__,           /* tp_doc */
186    0,                     /* tp_traverse */
187    0,                     /* tp_clear */
188    0,                     /* tp_richcompare */
189    0,                     /* tp_weaklistoffset */
190    0,                     /* tp_iter */
191    0,                     /* tp_iternext */
192    CipherComb_methods,      /* tp_methods */
193    0,                         /* tp_members */
194    0,                         /* tp_getset */
195    0,                         /* tp_base */
196    0,                         /* tp_dict */
197    0,                         /* tp_descr_get */
198    0,                         /* tp_descr_set */
199    0,                         /* tp_dictoffset */
200    CipherComb_init,               /* tp_init */
201    0,                         /* tp_alloc */
202    CipherComb_new,                /* tp_new */
203};
204
205void init_ciphercomb(PyObject*const module) {
206    if (PyType_Ready(&CipherComb_type) < 0)
207        return;
208    Py_INCREF(&CipherComb_type);
209    PyModule_AddObject(module, "ciphercomb_CipherComb", (PyObject *)&CipherComb_type);
210
211    ciphercomb_error = PyErr_NewException(const_cast<char*>("_ciphercomb.Error"), NULL, NULL);
212    PyModule_AddObject(module, "ciphercomb_Error", ciphercomb_error);
213
214    PyModule_AddStringConstant(module, "ciphercomb___doc__", const_cast<char*>(ciphercomb___doc__));
215}
216
217