summaryrefslogtreecommitdiff
path: root/src/strxor.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/strxor.c')
-rw-r--r--src/strxor.c271
1 files changed, 271 insertions, 0 deletions
diff --git a/src/strxor.c b/src/strxor.c
new file mode 100644
index 0000000..55d8067
--- /dev/null
+++ b/src/strxor.c
@@ -0,0 +1,271 @@
+/*
+ * strxor.c: string XOR functions
+ *
+ * Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
+ *
+ * ===================================================================
+ * The contents of this file are dedicated to the public domain. To
+ * the extent that dedication to the public domain is not available,
+ * everyone is granted a worldwide, perpetual, royalty-free,
+ * non-exclusive license to exercise all rights associated with the
+ * contents of this file for any purpose whatsoever.
+ * No rights are reserved.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * ===================================================================
+ */
+
+#include "pycrypto_common.h"
+#include <stddef.h>
+#include <assert.h>
+#include <string.h>
+
+static const char rcsid[] = "$Id$";
+
+/*
+ * xor_strings - XOR two strings together to produce a third string
+ *
+ * dest[0..n-1] := src_a[0..n-1] ^ src_b[0..n-1]
+ *
+ */
+static void
+xor_strings(char *dest, const char *src_a, const char *src_b, size_t n)
+{
+ size_t i;
+
+ /* assert no pointer overflow */
+ assert(src_a + n > src_a);
+ assert(src_b + n > src_b);
+ assert(dest + n > dest);
+
+ for (i = 0; i < n; i++) {
+ dest[i] = src_a[i] ^ src_b[i];
+ }
+}
+
+/*
+ * xor_string_with_char - XOR a string with a char to produce another string
+ *
+ * dest[0..n-1] := src[0..n-1] ^ c
+ *
+ */
+static void
+xor_string_with_char(char *dest, const char *src, char c, size_t n)
+{
+ size_t i;
+
+ /* assert no pointer overflow */
+ assert(src + n > src);
+ assert(dest + n > dest);
+
+ for (i = 0; i < n; i++) {
+ dest[i] = src[i] ^ c;
+ }
+}
+
+/*
+ * "Import assertions"
+ *
+ * These runtime checks are performed when this module is first initialized
+ *
+ */
+
+#define IMP_ASSERT(exp) do {\
+ if (!(exp)) {\
+ PyErr_Format(PyExc_AssertionError, "%s:%d: assertion failure: '%s'", __FILE__, __LINE__, #exp);\
+ return;\
+ }\
+} while(0)
+
+static void
+runtime_test(void)
+{
+ /* size_t should be able to represent the length of any size buffer */
+ IMP_ASSERT(sizeof(size_t) == sizeof(void *));
+
+ /* we must be able to perform the assignment (Py_ssize_t) -> (size_t)
+ * as long as the value is non-negative. */
+ IMP_ASSERT(sizeof(size_t) >= sizeof(Py_ssize_t));
+
+ /* char must be one octet */
+ IMP_ASSERT(sizeof(char) == 1);
+
+ /* Perform a basic test of the xor_strings function, including a test for
+ * an off-by-one bug. */
+ {
+ char x[7] = "\x00hello"; /* NUL + "hello" + NUL */
+ char y[7] = "\xffworld"; /* 0xff + "world" + NUL */
+ char z[9] = "[ABCDEFG]"; /* "[ABCDEFG]" + NUL */
+
+ xor_strings(z+1, x, y, 7);
+ IMP_ASSERT(!memcmp(z, "[\xff\x1f\x0a\x1e\x00\x0b\x00]", 9));
+ }
+
+ /* Perform a basic test of the xor_string_with_char function, including a test for
+ * an off-by-one bug. */
+ {
+ char x[7] = "\x00hello"; /* NUL + "hello" + NUL */
+ char y = 170; /* 0xaa */
+ char z[9] = "[ABCDEFG]"; /* "[ABCDEFG]" + NUL */
+
+ xor_string_with_char(z+1, x, y, 7);
+ IMP_ASSERT(!memcmp(z, "[\xaa\xc2\xcf\xc6\xc6\xc5\xaa]", 9));
+ }
+}
+
+/*
+ * The strxor Python function
+ */
+
+static char strxor__doc__[] =
+"strxor(a:str, b:str) -> str\n"
+"\n"
+"Return a XOR b. Both a and b must have the same length.\n";
+
+static PyObject *
+strxor_function(PyObject *self, PyObject *args)
+{
+ PyObject *a, *b, *retval;
+ Py_ssize_t len_a, len_b;
+
+ if (!PyArg_ParseTuple(args, "SS", &a, &b))
+ return NULL;
+
+ len_a = PyBytes_GET_SIZE(a);
+ len_b = PyBytes_GET_SIZE(b);
+
+ assert(len_a >= 0);
+ assert(len_b >= 0);
+
+ if (len_a != len_b) {
+ PyErr_SetString(PyExc_ValueError, "length of both strings must be equal");
+ return NULL;
+ }
+
+ /* Create return string */
+ retval = PyBytes_FromStringAndSize(NULL, len_a);
+ if (!retval) {
+ return NULL;
+ }
+
+ /* retval := a ^ b */
+ xor_strings(PyBytes_AS_STRING(retval), PyBytes_AS_STRING(a), PyBytes_AS_STRING(b), len_a);
+
+ return retval;
+}
+
+/*
+ * The strxor_c Python function
+ */
+
+static char strxor_c__doc__[] =
+"strxor_c(s:str, c:int) -> str\n"
+"\n"
+"Return s XOR chr(c). c must be in range(256).\n";
+
+static PyObject *
+strxor_c_function(PyObject *self, PyObject *args)
+{
+ PyObject *s, *retval;
+ int c;
+ Py_ssize_t length;
+
+ if (!PyArg_ParseTuple(args, "Si", &s, &c))
+ return NULL;
+
+ if ((c < 0) || (c > 255)) {
+ PyErr_SetString(PyExc_ValueError, "c must be in range(256)");
+ return NULL;
+ }
+
+ length = PyBytes_GET_SIZE(s);
+ assert(length >= 0);
+
+ /* Create return string */
+ retval = PyBytes_FromStringAndSize(NULL, length);
+ if (!retval) {
+ return NULL;
+ }
+
+ /* retval := a ^ chr(c)*length */
+ xor_string_with_char(PyBytes_AS_STRING(retval), PyBytes_AS_STRING(s), (char) c, length);
+
+ return retval;
+}
+
+/*
+ * Module-level method table and module initialization function
+ */
+
+static PyMethodDef strxor_methods[] = {
+ {"strxor", strxor_function, METH_VARARGS, strxor__doc__},
+ {"strxor_c", strxor_c_function, METH_VARARGS, strxor_c__doc__},
+
+ {NULL, NULL, 0, NULL} /* end-of-list sentinel value */
+};
+
+#ifdef IS_PY3K
+static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ "strxor",
+ NULL,
+ -1,
+ strxor_methods,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+#endif
+
+PyMODINIT_FUNC
+#ifdef IS_PY3K
+PyInit_strxor(void)
+#else
+initstrxor(void)
+#endif
+{
+ PyObject *m = NULL;
+
+ /* Initialize the module */
+#ifdef IS_PY3K
+ m = PyModule_Create(&moduledef);
+#else
+ m = Py_InitModule("strxor", strxor_methods);
+#endif
+ if (m == NULL)
+ goto errout;
+
+ /* Perform runtime tests */
+ runtime_test();
+
+out:
+ /* Final error check */
+ if (m == NULL && !PyErr_Occurred()) {
+ PyErr_SetString(PyExc_ImportError, "can't initialize module");
+ goto errout;
+ }
+
+ /* Free local objects here */
+
+ /* Return */
+#ifdef IS_PY3K
+ return m;
+#else
+ return;
+#endif
+
+errout:
+ /* Free the module and other global objects here */
+ Py_CLEAR(m);
+ goto out;
+}
+
+/* vim:set ts=4 sw=4 sts=4 expandtab: */