source: trunk/src-ed25519/glue/ed25519module.c

Last change on this file was 1ae745a, checked in by Brian Warner <warner@…>, at 2012-02-15T22:22:14Z

ed25519: fix last Py_ssize_t, avoiding a segfault on Fedora/gcc-4.7/64bit

This comes from python-ed25519 1.1 . Many thanks to Samuel "Dcoder" Neves for
the analysis and fix.

  • Property mode set to 100644
File size: 7.0 KB
Line 
1
2/* Use this file as a template to start implementing a module that
3   also declares object types. All occurrences of 'FOOOBJ' should be changed
4   to something reasonable for your objects. After that, all other
5   occurrences of 'ed25519' should be changed to something reasonable for your
6   module. If your module is named foo your sourcefile should be named
7   foomodule.c.
8
9   You will probably want to delete all references to 'x_attr' and add
10   your own types of attributes instead.  Maybe you want to name your
11   local variables other than 'self'.  If your object type is needed in
12   other files, you'll have to create a file "foobarobject.h"; see
13   intobject.h for an example. */
14
15// this makes "s#" use Py_ssize_t instead of int
16#define PY_SSIZE_T_CLEAN 1
17#include "Python.h"
18#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
19typedef int Py_ssize_t;
20#define PY_SSIZE_T_MAX INT_MAX
21#define PY_SSIZE_T_MIN INT_MIN
22#endif
23
24static PyObject *BadSignatureError,
25    *SECRETKEYBYTESObject, *PUBLICKEYBYTESObject, *SIGNATUREBYTESObject;
26/* --------------------------------------------------------------------- */
27
28#include "crypto_sign.h"
29
30PyDoc_STRVAR(ed25519_publickey_doc,
31"publickey(signkey_seed)\n\
32\n\
33Accepts a 32-byte seed. Return a tuple of (verfkey, signkey), with the\n\
3464-byte private signing key and the corresponding 32-byte public\n\
35verfiying key.");
36
37#include <stdio.h>
38
39static PyObject *
40ed25519_publickey(PyObject *self, PyObject *args)
41{
42    unsigned char verfkey[PUBLICKEYBYTES];
43    unsigned char signkey[SECRETKEYBYTES];
44    unsigned char *seed;
45    Py_ssize_t seed_len;
46    if (!PyArg_ParseTuple(args, "s#", &seed, &seed_len))
47        return NULL;
48    crypto_sign_publickey(verfkey, signkey, seed);
49    return Py_BuildValue("(s#s#)",
50                         verfkey, PUBLICKEYBYTES,
51                         signkey, SECRETKEYBYTES);
52}
53
54PyDoc_STRVAR(ed25519_sign_doc,
55"sign(message, signing_key)\n\
56\n\
57Return the concatenation of three parts: the 32-byte R signature value,\n\
58the original message, and the 32-byte S signature value.");
59
60static PyObject *
61ed25519_sign(PyObject *self, PyObject *args)
62{
63    const unsigned char *msg; Py_ssize_t msg_len;
64    const unsigned char *signkey; Py_ssize_t signkey_len;
65    unsigned char *sig_and_msg; unsigned long long sig_and_msg_len1;
66    Py_ssize_t sig_and_msg_len2;
67    PyObject *ret;
68
69    // NOTE: using s# copies the message. It'd be nicer to use it in-place.
70    // Consider s* and using a Py_buffer. Don't forget PyBuffer_Release.
71    // Py_buffer is available in py2.6 and later.
72    //// on the other hand, the funky NaCl API means we're already doing 3
73    //// copies anyway, so a 4th isn't a big deal.
74    if (!PyArg_ParseTuple(args, "s#s#:signature",
75                          &msg, &msg_len,
76                          &signkey, &signkey_len))
77        return NULL;
78    if (signkey_len != SECRETKEYBYTES) { // 64
79        PyErr_SetString(PyExc_TypeError,
80                        "Private signing keys are 64 byte strings");
81        return NULL;
82    }
83    sig_and_msg = PyMem_Malloc(msg_len + SIGNATUREBYTES);
84    if (!sig_and_msg)
85        return PyErr_NoMemory();
86    crypto_sign(sig_and_msg, &sig_and_msg_len1, msg, msg_len, signkey);
87    sig_and_msg_len2 = sig_and_msg_len1;
88    ret = Py_BuildValue("s#", sig_and_msg, sig_and_msg_len2);
89    PyMem_Free(sig_and_msg);
90    return ret;
91}
92
93PyDoc_STRVAR(ed25519_open_doc,
94"open(message+signature, verifying_key)\n\
95\n\
96Check the signature for validity. Returns the message if valid, raises\n\
97ed25519.error if not.");
98
99static PyObject *
100ed25519_open(PyObject *self, PyObject *args)
101{
102    const unsigned char *sig_and_msg; Py_ssize_t sig_and_msg_len;
103    const unsigned char *verfkey; Py_ssize_t verfkey_len;
104    unsigned char *msg; unsigned long long msg_len1;
105    Py_ssize_t msg_len2;
106    PyObject *ret;
107    int result;
108    if (!PyArg_ParseTuple(args, "s#s#:checkvalid",
109                          &sig_and_msg, &sig_and_msg_len,
110                          &verfkey, &verfkey_len ))
111        return NULL;
112    if (sig_and_msg_len < SIGNATUREBYTES) { // 64
113        PyErr_SetString(PyExc_TypeError,
114                        "signature-and-message must be at least 64 bytes long");
115        return NULL;
116    }
117    if (verfkey_len != PUBLICKEYBYTES) { // 32
118        PyErr_SetString(PyExc_TypeError,
119                        "Public verifying keys are 32 byte strings");
120        return NULL;
121    }
122
123    // crypto_sign_open() uses the output buffer as a scratchpad, and thus
124    // requires an extra 64 bytes beyond the expected message. So allocate
125    // sig_and_msg_len, not sig_and_msg_len-SIGNATUREBYTES
126    msg = PyMem_Malloc(sig_and_msg_len);
127    if (!msg)
128        return PyErr_NoMemory();
129    result = crypto_sign_open(msg, &msg_len1, sig_and_msg, sig_and_msg_len,
130                              verfkey);
131    // be faithful to the NaCl interface and return the message, even though
132    // it's a waste.
133    if (result == 0) {
134        // good signature
135        msg_len2 = msg_len1;
136        ret = Py_BuildValue("s#", msg, msg_len2);
137        PyMem_Free(msg);
138        return ret;
139    }
140    // bad signature. We do throw an exception when the signature is bad, so
141    // it can't be silently ignored
142    PyMem_Free(msg);
143    PyErr_SetString(BadSignatureError, "Bad Signature");
144    return NULL;
145}
146
147
148/* List of functions defined in the module */
149
150static PyMethodDef ed25519_methods[] = {
151    {"publickey",  ed25519_publickey,  METH_VARARGS, ed25519_publickey_doc},
152    {"sign",  ed25519_sign,  METH_VARARGS, ed25519_sign_doc},
153    {"open", ed25519_open, METH_VARARGS, ed25519_open_doc},
154    {NULL, NULL} /* sentinel */
155};
156
157PyDoc_STRVAR(module_doc,
158"Low-level Ed25519 signature/verification functions.");
159
160/* Initialization function for the module (*must* be called init_ed25519) */
161
162PyMODINIT_FUNC
163init_ed25519(void)
164{
165    PyObject *m;
166
167    /* Create the module and add the functions */
168    m = Py_InitModule3("_ed25519", ed25519_methods, module_doc);
169    if (m == NULL)
170        return;
171
172    /* Add some symbolic constants to the module */
173    if (BadSignatureError == NULL) {
174        BadSignatureError = PyErr_NewException("ed25519.BadSignatureError",
175                                               NULL, NULL);
176        if (BadSignatureError == NULL)
177            return;
178    }
179    if (SECRETKEYBYTESObject == NULL) {
180        SECRETKEYBYTESObject = PyInt_FromLong(SECRETKEYBYTES);
181        if (SECRETKEYBYTESObject == NULL)
182            return;
183    }
184    if (PUBLICKEYBYTESObject == NULL) {
185        PUBLICKEYBYTESObject = PyInt_FromLong(PUBLICKEYBYTES);
186        if (PUBLICKEYBYTESObject == NULL)
187            return;
188    }
189    if (SIGNATUREBYTESObject == NULL) {
190        SIGNATUREBYTESObject = PyInt_FromLong(SIGNATUREBYTES);
191        if (SIGNATUREBYTESObject == NULL)
192            return;
193    }
194    Py_INCREF(BadSignatureError);
195    PyModule_AddObject(m, "BadSignatureError", BadSignatureError);
196    PyModule_AddObject(m, "SECRETKEYBYTES", SECRETKEYBYTESObject);
197    PyModule_AddObject(m, "PUBLICKEYBYTES", PUBLICKEYBYTESObject);
198    PyModule_AddObject(m, "SIGNATUREKEYBYTES", SIGNATUREBYTESObject);
199}
Note: See TracBrowser for help on using the repository browser.