PageRenderTime 43ms CodeModel.GetById 3ms app.highlight 33ms RepoModel.GetById 1ms app.codeStats 1ms

/Modules/_hashopenssl.c

http://unladen-swallow.googlecode.com/
C | 519 lines | 394 code | 85 blank | 40 comment | 40 complexity | ae31f55ddb31c0cb80d2bd3267ba4825 MD5 | raw file
  1/* Module that wraps all OpenSSL hash algorithms */
  2
  3/*
  4 * Copyright (C) 2005   Gregory P. Smith (greg@krypto.org)
  5 * Licensed to PSF under a Contributor Agreement.
  6 *
  7 * Derived from a skeleton of shamodule.c containing work performed by:
  8 *
  9 * Andrew Kuchling (amk@amk.ca)
 10 * Greg Stein (gstein@lyra.org)
 11 *
 12 */
 13
 14#define PY_SSIZE_T_CLEAN
 15
 16#include "Python.h"
 17#include "structmember.h"
 18
 19/* EVP is the preferred interface to hashing in OpenSSL */
 20#include <openssl/evp.h>
 21
 22#define MUNCH_SIZE INT_MAX
 23
 24
 25#ifndef HASH_OBJ_CONSTRUCTOR
 26#define HASH_OBJ_CONSTRUCTOR 0
 27#endif
 28
 29typedef struct {
 30    PyObject_HEAD
 31    PyObject            *name;  /* name of this hash algorithm */
 32    EVP_MD_CTX          ctx;    /* OpenSSL message digest context */
 33} EVPobject;
 34
 35
 36static PyTypeObject EVPtype;
 37
 38
 39#define DEFINE_CONSTS_FOR_NEW(Name)  \
 40    static PyObject *CONST_ ## Name ## _name_obj; \
 41    static EVP_MD_CTX CONST_new_ ## Name ## _ctx; \
 42    static EVP_MD_CTX *CONST_new_ ## Name ## _ctx_p = NULL;
 43
 44DEFINE_CONSTS_FOR_NEW(md5)
 45DEFINE_CONSTS_FOR_NEW(sha1)
 46DEFINE_CONSTS_FOR_NEW(sha224)
 47DEFINE_CONSTS_FOR_NEW(sha256)
 48DEFINE_CONSTS_FOR_NEW(sha384)
 49DEFINE_CONSTS_FOR_NEW(sha512)
 50
 51
 52static EVPobject *
 53newEVPobject(PyObject *name)
 54{
 55    EVPobject *retval = (EVPobject *)PyObject_New(EVPobject, &EVPtype);
 56
 57    /* save the name for .name to return */
 58    if (retval != NULL) {
 59        Py_INCREF(name);
 60        retval->name = name;
 61    }
 62
 63    return retval;
 64}
 65
 66/* Internal methods for a hash object */
 67
 68static void
 69EVP_dealloc(PyObject *ptr)
 70{
 71    EVP_MD_CTX_cleanup(&((EVPobject *)ptr)->ctx);
 72    Py_XDECREF(((EVPobject *)ptr)->name);
 73    PyObject_Del(ptr);
 74}
 75
 76
 77/* External methods for a hash object */
 78
 79PyDoc_STRVAR(EVP_copy__doc__, "Return a copy of the hash object.");
 80
 81static PyObject *
 82EVP_copy(EVPobject *self, PyObject *unused)
 83{
 84    EVPobject *newobj;
 85
 86    if ( (newobj = newEVPobject(self->name))==NULL)
 87        return NULL;
 88
 89    EVP_MD_CTX_copy(&newobj->ctx, &self->ctx);
 90    return (PyObject *)newobj;
 91}
 92
 93PyDoc_STRVAR(EVP_digest__doc__,
 94"Return the digest value as a string of binary data.");
 95
 96static PyObject *
 97EVP_digest(EVPobject *self, PyObject *unused)
 98{
 99    unsigned char digest[EVP_MAX_MD_SIZE];
100    EVP_MD_CTX temp_ctx;
101    PyObject *retval;
102    unsigned int digest_size;
103
104    EVP_MD_CTX_copy(&temp_ctx, &self->ctx);
105    digest_size = EVP_MD_CTX_size(&temp_ctx);
106    EVP_DigestFinal(&temp_ctx, digest, NULL);
107
108    retval = PyString_FromStringAndSize((const char *)digest, digest_size);
109    EVP_MD_CTX_cleanup(&temp_ctx);
110    return retval;
111}
112
113PyDoc_STRVAR(EVP_hexdigest__doc__,
114"Return the digest value as a string of hexadecimal digits.");
115
116static PyObject *
117EVP_hexdigest(EVPobject *self, PyObject *unused)
118{
119    unsigned char digest[EVP_MAX_MD_SIZE];
120    EVP_MD_CTX temp_ctx;
121    PyObject *retval;
122    char *hex_digest;
123    unsigned int i, j, digest_size;
124
125    /* Get the raw (binary) digest value */
126    EVP_MD_CTX_copy(&temp_ctx, &self->ctx);
127    digest_size = EVP_MD_CTX_size(&temp_ctx);
128    EVP_DigestFinal(&temp_ctx, digest, NULL);
129
130    EVP_MD_CTX_cleanup(&temp_ctx);
131
132    /* Create a new string */
133    /* NOTE: not thread safe! modifying an already created string object */
134    /* (not a problem because we hold the GIL by default) */
135    retval = PyString_FromStringAndSize(NULL, digest_size * 2);
136    if (!retval)
137	    return NULL;
138    hex_digest = PyString_AsString(retval);
139    if (!hex_digest) {
140	    Py_DECREF(retval);
141	    return NULL;
142    }
143
144    /* Make hex version of the digest */
145    for(i=j=0; i<digest_size; i++) {
146        char c;
147        c = (digest[i] >> 4) & 0xf;
148	c = (c>9) ? c+'a'-10 : c + '0';
149        hex_digest[j++] = c;
150        c = (digest[i] & 0xf);
151	c = (c>9) ? c+'a'-10 : c + '0';
152        hex_digest[j++] = c;
153    }
154    return retval;
155}
156
157PyDoc_STRVAR(EVP_update__doc__,
158"Update this hash object's state with the provided string.");
159
160static PyObject *
161EVP_update(EVPobject *self, PyObject *args)
162{
163    unsigned char *cp;
164    Py_ssize_t len;
165
166    if (!PyArg_ParseTuple(args, "s#:update", &cp, &len))
167        return NULL;
168
169    if (len > 0 && len <= MUNCH_SIZE) {
170    EVP_DigestUpdate(&self->ctx, cp, Py_SAFE_DOWNCAST(len, Py_ssize_t,
171                                                      unsigned int));
172    } else {
173        Py_ssize_t offset = 0;
174        while (len) {
175            unsigned int process = len > MUNCH_SIZE ? MUNCH_SIZE : len;
176            EVP_DigestUpdate(&self->ctx, cp + offset, process);
177            len -= process;
178            offset += process;
179        }
180    }
181    Py_INCREF(Py_None);
182    return Py_None;
183}
184
185static PyMethodDef EVP_methods[] = {
186    {"update",	  (PyCFunction)EVP_update,    METH_VARARGS, EVP_update__doc__},
187    {"digest",	  (PyCFunction)EVP_digest,    METH_NOARGS,  EVP_digest__doc__},
188    {"hexdigest", (PyCFunction)EVP_hexdigest, METH_NOARGS,  EVP_hexdigest__doc__},
189    {"copy",	  (PyCFunction)EVP_copy,      METH_NOARGS,  EVP_copy__doc__},
190    {NULL,	  NULL}		/* sentinel */
191};
192
193static PyObject *
194EVP_get_block_size(EVPobject *self, void *closure)
195{
196    return PyInt_FromLong(EVP_MD_CTX_block_size(&((EVPobject *)self)->ctx));
197}
198
199static PyObject *
200EVP_get_digest_size(EVPobject *self, void *closure)
201{
202    return PyInt_FromLong(EVP_MD_CTX_size(&((EVPobject *)self)->ctx));
203}
204
205static PyMemberDef EVP_members[] = {
206    {"name", T_OBJECT, offsetof(EVPobject, name), READONLY, PyDoc_STR("algorithm name.")},
207    {NULL}  /* Sentinel */
208};
209
210static PyGetSetDef EVP_getseters[] = {
211    {"digest_size",
212     (getter)EVP_get_digest_size, NULL,
213     NULL,
214     NULL},
215    {"block_size",
216     (getter)EVP_get_block_size, NULL,
217     NULL,
218     NULL},
219    /* the old md5 and sha modules support 'digest_size' as in PEP 247.
220     * the old sha module also supported 'digestsize'.  ugh. */
221    {"digestsize",
222     (getter)EVP_get_digest_size, NULL,
223     NULL,
224     NULL},
225    {NULL}  /* Sentinel */
226};
227
228
229static PyObject *
230EVP_repr(PyObject *self)
231{
232    char buf[100];
233    PyOS_snprintf(buf, sizeof(buf), "<%s HASH object @ %p>",
234            PyString_AsString(((EVPobject *)self)->name), self);
235    return PyString_FromString(buf);
236}
237
238#if HASH_OBJ_CONSTRUCTOR
239static int
240EVP_tp_init(EVPobject *self, PyObject *args, PyObject *kwds)
241{
242    static char *kwlist[] = {"name", "string", NULL};
243    PyObject *name_obj = NULL;
244    char *nameStr;
245    unsigned char *cp = NULL;
246    Py_ssize_t len = 0;
247    const EVP_MD *digest;
248
249    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|s#:HASH", kwlist,
250                                     &name_obj, &cp, &len)) {
251        return -1;
252    }
253
254    if (!PyArg_Parse(name_obj, "s", &nameStr)) {
255        PyErr_SetString(PyExc_TypeError, "name must be a string");
256        return -1;
257    }
258
259    digest = EVP_get_digestbyname(nameStr);
260    if (!digest) {
261        PyErr_SetString(PyExc_ValueError, "unknown hash function");
262        return -1;
263    }
264    EVP_DigestInit(&self->ctx, digest);
265
266    self->name = name_obj;
267    Py_INCREF(self->name);
268
269    if (cp && len) {
270        if (len > 0 && len <= MUNCH_SIZE) {
271        EVP_DigestUpdate(&self->ctx, cp, Py_SAFE_DOWNCAST(len, Py_ssize_t,
272                                                          unsigned int));
273        } else {
274            Py_ssize_t offset = 0;
275            while (len) {
276                unsigned int process = len > MUNCH_SIZE ? MUNCH_SIZE : len;
277                EVP_DigestUpdate(&self->ctx, cp + offset, process);
278                len -= process;
279                offset += process;
280            }
281        }
282    }
283    
284    return 0;
285}
286#endif
287
288
289PyDoc_STRVAR(hashtype_doc,
290"A hash represents the object used to calculate a checksum of a\n\
291string of information.\n\
292\n\
293Methods:\n\
294\n\
295update() -- updates the current digest with an additional string\n\
296digest() -- return the current digest value\n\
297hexdigest() -- return the current digest as a string of hexadecimal digits\n\
298copy() -- return a copy of the current hash object\n\
299\n\
300Attributes:\n\
301\n\
302name -- the hash algorithm being used by this object\n\
303digest_size -- number of bytes in this hashes output\n");
304
305static PyTypeObject EVPtype = {
306    PyVarObject_HEAD_INIT(NULL, 0)
307    "_hashlib.HASH",    /*tp_name*/
308    sizeof(EVPobject),	/*tp_basicsize*/
309    0,			/*tp_itemsize*/
310    /* methods */
311    EVP_dealloc,	/*tp_dealloc*/
312    0,			/*tp_print*/
313    0,                  /*tp_getattr*/
314    0,                  /*tp_setattr*/
315    0,                  /*tp_compare*/
316    EVP_repr,           /*tp_repr*/
317    0,                  /*tp_as_number*/
318    0,                  /*tp_as_sequence*/
319    0,                  /*tp_as_mapping*/
320    0,                  /*tp_hash*/
321    0,                  /*tp_call*/
322    0,                  /*tp_str*/
323    0,                  /*tp_getattro*/
324    0,                  /*tp_setattro*/
325    0,                  /*tp_as_buffer*/
326    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
327    hashtype_doc,       /*tp_doc*/
328    0,                  /*tp_traverse*/
329    0,			/*tp_clear*/
330    0,			/*tp_richcompare*/
331    0,			/*tp_weaklistoffset*/
332    0,			/*tp_iter*/
333    0,			/*tp_iternext*/
334    EVP_methods,	/* tp_methods */
335    EVP_members,	/* tp_members */
336    EVP_getseters,      /* tp_getset */
337#if 1
338    0,                  /* tp_base */
339    0,                  /* tp_dict */
340    0,                  /* tp_descr_get */
341    0,                  /* tp_descr_set */
342    0,                  /* tp_dictoffset */
343#endif
344#if HASH_OBJ_CONSTRUCTOR
345    (initproc)EVP_tp_init, /* tp_init */
346#endif
347};
348
349static PyObject *
350EVPnew(PyObject *name_obj,
351       const EVP_MD *digest, const EVP_MD_CTX *initial_ctx,
352       const unsigned char *cp, Py_ssize_t len)
353{
354    EVPobject *self;
355
356    if (!digest && !initial_ctx) {
357        PyErr_SetString(PyExc_ValueError, "unsupported hash type");
358        return NULL;
359    }
360
361    if ((self = newEVPobject(name_obj)) == NULL)
362        return NULL;
363
364    if (initial_ctx) {
365        EVP_MD_CTX_copy(&self->ctx, initial_ctx);
366    } else {
367        EVP_DigestInit(&self->ctx, digest);
368    }
369
370    if (cp && len) {
371        if (len > 0 && len <= MUNCH_SIZE) {
372            EVP_DigestUpdate(&self->ctx, cp, Py_SAFE_DOWNCAST(len, Py_ssize_t,
373                                                              unsigned int));
374        } else {
375            Py_ssize_t offset = 0;
376            while (len) {
377                unsigned int process = len > MUNCH_SIZE ? MUNCH_SIZE : len;
378                EVP_DigestUpdate(&self->ctx, cp + offset, process);
379                len -= process;
380                offset += process;
381            }
382        }
383    }
384
385    return (PyObject *)self;
386}
387
388
389/* The module-level function: new() */
390
391PyDoc_STRVAR(EVP_new__doc__,
392"Return a new hash object using the named algorithm.\n\
393An optional string argument may be provided and will be\n\
394automatically hashed.\n\
395\n\
396The MD5 and SHA1 algorithms are always supported.\n");
397
398static PyObject *
399EVP_new(PyObject *self, PyObject *args, PyObject *kwdict)
400{
401    static char *kwlist[] = {"name", "string", NULL};
402    PyObject *name_obj = NULL;
403    char *name;
404    const EVP_MD *digest;
405    unsigned char *cp = NULL;
406    Py_ssize_t len = 0;
407
408    if (!PyArg_ParseTupleAndKeywords(args, kwdict, "O|s#:new", kwlist,
409                                     &name_obj, &cp, &len)) {
410        return NULL;
411    }
412
413    if (!PyArg_Parse(name_obj, "s", &name)) {
414        PyErr_SetString(PyExc_TypeError, "name must be a string");
415        return NULL;
416    }
417
418    digest = EVP_get_digestbyname(name);
419
420    return EVPnew(name_obj, digest, NULL, cp, len);
421}
422
423/*
424 *  This macro generates constructor function definitions for specific
425 *  hash algorithms.  These constructors are much faster than calling
426 *  the generic one passing it a python string and are noticably
427 *  faster than calling a python new() wrapper.  Thats important for
428 *  code that wants to make hashes of a bunch of small strings.
429 */
430#define GEN_CONSTRUCTOR(NAME)  \
431    static PyObject * \
432    EVP_new_ ## NAME (PyObject *self, PyObject *args) \
433    { \
434        unsigned char *cp = NULL; \
435        Py_ssize_t len = 0; \
436     \
437        if (!PyArg_ParseTuple(args, "|s#:" #NAME , &cp, &len)) { \
438            return NULL; \
439        } \
440     \
441        return EVPnew( \
442                CONST_ ## NAME ## _name_obj, \
443                NULL, \
444                CONST_new_ ## NAME ## _ctx_p, \
445                cp, len); \
446    }
447
448/* a PyMethodDef structure for the constructor */
449#define CONSTRUCTOR_METH_DEF(NAME)  \
450    {"openssl_" #NAME, (PyCFunction)EVP_new_ ## NAME, METH_VARARGS, \
451        PyDoc_STR("Returns a " #NAME \
452                  " hash object; optionally initialized with a string") \
453    }
454
455/* used in the init function to setup a constructor */
456#define INIT_CONSTRUCTOR_CONSTANTS(NAME)  do { \
457    CONST_ ## NAME ## _name_obj = PyString_FromString(#NAME); \
458    if (EVP_get_digestbyname(#NAME)) { \
459        CONST_new_ ## NAME ## _ctx_p = &CONST_new_ ## NAME ## _ctx; \
460        EVP_DigestInit(CONST_new_ ## NAME ## _ctx_p, EVP_get_digestbyname(#NAME)); \
461    } \
462} while (0);
463
464GEN_CONSTRUCTOR(md5)
465GEN_CONSTRUCTOR(sha1)
466GEN_CONSTRUCTOR(sha224)
467GEN_CONSTRUCTOR(sha256)
468GEN_CONSTRUCTOR(sha384)
469GEN_CONSTRUCTOR(sha512)
470
471/* List of functions exported by this module */
472
473static struct PyMethodDef EVP_functions[] = {
474    {"new", (PyCFunction)EVP_new, METH_VARARGS|METH_KEYWORDS, EVP_new__doc__},
475    CONSTRUCTOR_METH_DEF(md5),
476    CONSTRUCTOR_METH_DEF(sha1),
477    CONSTRUCTOR_METH_DEF(sha224),
478    CONSTRUCTOR_METH_DEF(sha256),
479    CONSTRUCTOR_METH_DEF(sha384),
480    CONSTRUCTOR_METH_DEF(sha512),
481    {NULL,	NULL}		 /* Sentinel */
482};
483
484
485/* Initialize this module. */
486
487PyMODINIT_FUNC
488init_hashlib(void)
489{
490    PyObject *m;
491
492    OpenSSL_add_all_digests();
493
494    /* TODO build EVP_functions openssl_* entries dynamically based
495     * on what hashes are supported rather than listing many
496     * but having some be unsupported.  Only init appropriate
497     * constants. */
498
499    Py_TYPE(&EVPtype) = &PyType_Type;
500    if (PyType_Ready(&EVPtype) < 0)
501        return;
502
503    m = Py_InitModule("_hashlib", EVP_functions);
504    if (m == NULL)
505        return;
506
507#if HASH_OBJ_CONSTRUCTOR
508    Py_INCREF(&EVPtype);
509    PyModule_AddObject(m, "HASH", (PyObject *)&EVPtype);
510#endif
511
512    /* these constants are used by the convenience constructors */
513    INIT_CONSTRUCTOR_CONSTANTS(md5);
514    INIT_CONSTRUCTOR_CONSTANTS(sha1);
515    INIT_CONSTRUCTOR_CONSTANTS(sha224);
516    INIT_CONSTRUCTOR_CONSTANTS(sha256);
517    INIT_CONSTRUCTOR_CONSTANTS(sha384);
518    INIT_CONSTRUCTOR_CONSTANTS(sha512);
519}