/* * strxor.c: string XOR functions * * Written in 2008 by Dwayne C. Litzenberger * * =================================================================== * 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 #include #include 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: */