summaryrefslogtreecommitdiff
path: root/src/pycryptopp/hash
diff options
context:
space:
mode:
authorMicah Anderson <micah@riseup.net>2013-08-22 16:39:52 -0400
committerMicah Anderson <micah@riseup.net>2013-08-22 16:39:52 -0400
commit5e60e0e3af85f22aa0afe8bf0ecf85619afacfeb (patch)
tree6a91a3de86fa8de0b4167cc947ab72991bf8da31 /src/pycryptopp/hash
parent30e9097985656920f01a72efc1088caa2b8d41b3 (diff)
Imported Upstream version 0.6.0.12upstream/0.6.0.12
Diffstat (limited to 'src/pycryptopp/hash')
-rw-r--r--src/pycryptopp/hash/__init__.py3
-rw-r--r--src/pycryptopp/hash/sha256.py43
-rw-r--r--src/pycryptopp/hash/sha256module.cpp189
-rw-r--r--src/pycryptopp/hash/sha256module.hpp7
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 */