diff options
author | Micah Anderson <micah@riseup.net> | 2013-08-22 16:39:52 -0400 |
---|---|---|
committer | Micah Anderson <micah@riseup.net> | 2013-08-22 16:57:38 -0400 |
commit | 6d35b188b668c5007409e63a15e8340ed34dcfb8 (patch) | |
tree | c9dd25f3675b3b6f9b29b0786057f8a4d377bc2b /src/pycryptopp/hash | |
parent | 86a1089dc6694f58d0f3356bdf9c8fe4061421f5 (diff) | |
parent | 5e60e0e3af85f22aa0afe8bf0ecf85619afacfeb (diff) |
Merge tag 'upstream/0.6.0.12'
Upstream version 0.6.0.12
Diffstat (limited to 'src/pycryptopp/hash')
-rw-r--r-- | src/pycryptopp/hash/__init__.py | 3 | ||||
-rw-r--r-- | src/pycryptopp/hash/sha256.py | 43 | ||||
-rw-r--r-- | src/pycryptopp/hash/sha256module.cpp | 189 | ||||
-rw-r--r-- | src/pycryptopp/hash/sha256module.hpp | 7 |
4 files changed, 242 insertions, 0 deletions
diff --git a/src/pycryptopp/hash/__init__.py b/src/pycryptopp/hash/__init__.py new file mode 100644 index 0000000..5399f81 --- /dev/null +++ b/src/pycryptopp/hash/__init__.py @@ -0,0 +1,3 @@ +import sha256 + +quiet_pyflakes=[sha256] diff --git a/src/pycryptopp/hash/sha256.py b/src/pycryptopp/hash/sha256.py new file mode 100644 index 0000000..cf52a31 --- /dev/null +++ b/src/pycryptopp/hash/sha256.py @@ -0,0 +1,43 @@ +from pycryptopp import _import_my_names + +# These initializations to None are just to pacify pyflakes, which +# doesn't understand that we have to do some funky import trickery +# below in _import_my_names() in order to get sensible namespaces. +SHA256=None +Error=None + +_import_my_names(globals(), "sha256_") + +del _import_my_names + +def start_up_self_test(): + """ + This is a quick test intended to detect major errors such as the library being + miscompiled and segfaulting or returning incorrect answers. We've had problems + of that kind many times, thus justifying running this self-test on import. + This idea was suggested to me by the second edition of "Practical + Cryptography" by Ferguson, Schneier, and Kohno. + This test was copied from pycryptopp/test/test_sha256.py on 2010-09-04. + + This test takes up to 1.5 milliseconds on a VirtualBox instance on + my Macbook Pro (fast 64-bit Intel dual-core). + + Test that updating a hasher with various sized inputs yields + the expected answer. This is somewhat redundant with + test_chunksize(), but that's okay. This one exercises some + slightly different situations (such as finalizing a hash after + different length inputs.) This one is recursive so that there + is a single fixed result that we expect. + """ + hx = SHA256() + s = ''.join([ chr(c) for c in range(65) ]) + for i in range(0, 65): + hy = SHA256(s[:i]).digest() + hx.update(hy) + for i in range(0, 65): + hx.update(chr(0xFE)) + hx.update(s[:64]) + if hx.hexdigest().lower() != '5191c7841dd4e16aa454d40af924585dffc67157ffdbfd0236acddd07901629d': + raise Error("pycryptopp failed startup self-test. Please run pycryptopp unit tests.") + +start_up_self_test() diff --git a/src/pycryptopp/hash/sha256module.cpp b/src/pycryptopp/hash/sha256module.cpp new file mode 100644 index 0000000..bf9d8e3 --- /dev/null +++ b/src/pycryptopp/hash/sha256module.cpp @@ -0,0 +1,189 @@ +/** + * sha256module.cpp -- Python wrappers around Crypto++'s SHA-256 + */ + +#define PY_SSIZE_T_CLEAN +#include <Python.h> +#if (PY_VERSION_HEX < 0x02050000) +typedef int Py_ssize_t; +#endif + +#include <assert.h> + +/* from Crypto++ */ +#ifdef DISABLE_EMBEDDED_CRYPTOPP +#include <cryptopp/sha.h> +#include <cryptopp/hex.h> +#include <cryptopp/filters.h> +#else +#include <src-cryptopp/sha.h> +#include <src-cryptopp/hex.h> +#include <src-cryptopp/filters.h> +#endif + +static const char*const sha256___doc__ = "_sha256 hash function"; + +static PyObject *sha256_error; + +typedef struct { + PyObject_HEAD + + /* internal */ + CryptoPP::SHA256* h; + PyStringObject* digest; +} SHA256; + +PyDoc_STRVAR(SHA256__doc__, +"a SHA256 hash object\n\ +Its constructor takes an optional string, which has the same effect as\n\ +calling .update() with that string."); + +static PyObject * +SHA256_update(SHA256* self, PyObject* msgobj) { + if (self->digest) + return PyErr_Format(sha256_error, "Precondition violation: once .digest() has been called you are required to never call .update() again."); + + const char *msg; + Py_ssize_t msgsize; + if (PyString_AsStringAndSize(msgobj, const_cast<char**>(&msg), &msgsize)) + return NULL; + self->h->Update(reinterpret_cast<const byte*>(msg), msgsize); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(SHA256_update__doc__, +"Update the hash object with the string msg. Repeated calls are equivalent to\n\ +a single call with the concatenation of all the messages."); + +static PyObject * +SHA256_digest(SHA256* self, PyObject* dummy) { + if (!self->digest) { + assert (self->h); + self->digest = reinterpret_cast<PyStringObject*>(PyString_FromStringAndSize(NULL, self->h->DigestSize())); + if (!self->digest) + return NULL; + self->h->Final(reinterpret_cast<byte*>(PyString_AS_STRING(self->digest))); + } + + Py_INCREF(self->digest); + return reinterpret_cast<PyObject*>(self->digest); +} + +PyDoc_STRVAR(SHA256_digest__doc__, +"Return the binary digest of the messages that were passed to the update()\n\ +method (including the initial message if any)."); + +static PyObject * +SHA256_hexdigest(SHA256* self, PyObject* dummy) { + PyObject* digest = SHA256_digest(self, NULL); + if (!digest) + return NULL; + Py_ssize_t dsize = PyString_GET_SIZE(digest); + PyStringObject* hexdigest = reinterpret_cast<PyStringObject*>(PyString_FromStringAndSize(NULL, dsize*2)); + CryptoPP::ArraySink* as = new CryptoPP::ArraySink(reinterpret_cast<byte*>(PyString_AS_STRING(hexdigest)), dsize*2); + CryptoPP::HexEncoder enc; + enc.Attach(as); + enc.Put(reinterpret_cast<const byte*>(PyString_AS_STRING(digest)), static_cast<size_t>(dsize)); + Py_DECREF(digest); digest = NULL; + + return reinterpret_cast<PyObject*>(hexdigest); +} + +PyDoc_STRVAR(SHA256_hexdigest__doc__, +"Return the hex-encoded digest of the messages that were passed to the update()\n\ +method (including the initial message if any)."); + +static PyMethodDef SHA256_methods[] = { + {"update", reinterpret_cast<PyCFunction>(SHA256_update), METH_O, SHA256_update__doc__}, + {"digest", reinterpret_cast<PyCFunction>(SHA256_digest), METH_NOARGS, SHA256_digest__doc__}, + {"hexdigest", reinterpret_cast<PyCFunction>(SHA256_hexdigest), METH_NOARGS, SHA256_hexdigest__doc__}, + {NULL}, +}; + +static PyObject * +SHA256_new(PyTypeObject* type, PyObject *args, PyObject *kwdict) { + SHA256* self = reinterpret_cast<SHA256*>(type->tp_alloc(type, 0)); + if (!self) + return NULL; + self->h = new CryptoPP::SHA256(); + if (!self->h) + return PyErr_NoMemory(); + self->digest = NULL; + return reinterpret_cast<PyObject*>(self); +} + +static void +SHA256_dealloc(SHA256* self) { + Py_XDECREF(self->digest); + delete self->h; + self->ob_type->tp_free((PyObject*)self); +} + +static int +SHA256_init(PyObject* self, PyObject *args, PyObject *kwdict) { + static const char *kwlist[] = { "msg", NULL }; + const char *msg = NULL; + Py_ssize_t msgsize = 0; + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|t#", const_cast<char**>(kwlist), &msg, &msgsize)) + return -1; + + if (msg) + reinterpret_cast<SHA256*>(self)->h->Update(reinterpret_cast<const byte*>(msg), msgsize); + return 0; +} + +static PyTypeObject SHA256_type = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "_sha256.SHA256", /*tp_name*/ + sizeof(SHA256), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + reinterpret_cast<destructor>(SHA256_dealloc), /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + SHA256__doc__, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + SHA256_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + //reinterpret_cast<initproc>(SHA256_init), /* tp_init */ + SHA256_init, /* tp_init */ + 0, /* tp_alloc */ + SHA256_new, /* tp_new */ +}; + +void +init_sha256(PyObject* module) { + if (PyType_Ready(&SHA256_type) < 0) + return; + Py_INCREF(&SHA256_type); + PyModule_AddObject(module, "sha256_SHA256", (PyObject *)&SHA256_type); + + sha256_error = PyErr_NewException(const_cast<char*>("_sha256.Error"), NULL, NULL); + PyModule_AddObject(module, "sha256_Error", sha256_error); + + PyModule_AddStringConstant(module, "sha256___doc__", const_cast<char*>(sha256___doc__)); +} diff --git a/src/pycryptopp/hash/sha256module.hpp b/src/pycryptopp/hash/sha256module.hpp new file mode 100644 index 0000000..2dac9b5 --- /dev/null +++ b/src/pycryptopp/hash/sha256module.hpp @@ -0,0 +1,7 @@ +#ifndef __INCL_SHA256MODULE_HPP +#define __INCL_SHA256MODULE_HPP + +extern void +init_sha256(PyObject* module); + +#endif /* #ifndef __INCL_SHA256MODULE_HPP */ |