/* timing safe bytes / ASCII unicode equal function * * The function leaks when both objects aren't of the same length or when an * error has occured. * * Return: * 1: if both objects are equal * 0: if unequal * -1: if an error has occured (not bytes or compact ASCII unicode) */ int timingsafe_eq(PyObject *a, PyObject *b) { const unsigned char *va=NULL; const unsigned char *vb=NULL; Py_ssize_t length=-1; Py_ssize_t i; Py_ssize_t result; if (PyBytes_CheckExact(a) && PyBytes_CheckExact(b)) { length = PyBytes_GET_SIZE(a); if (length != PyBytes_GET_SIZE(b)) { return 0; } va = (const unsigned char *)PyBytes_AS_STRING(a); vb = (const unsigned char *)PyBytes_AS_STRING(b); } else if(PyUnicode_CheckExact(a) && PyUnicode_CheckExact(b)) { if (PyUnicode_READY(a) == -1 || PyUnicode_READY(b) == -1) { assert(0 && "unicode_eq ready fail"); return -1; } if (!PyUnicode_IS_COMPACT_ASCII(a) || !PyUnicode_IS_COMPACT_ASCII(b)) { return -1; } length = PyUnicode_GET_LENGTH(a); if (length != PyUnicode_GET_LENGTH(b)) { return 0; } va = (const unsigned char *)_PyUnicode_COMPACT_DATA(a); vb = (const unsigned char *)_PyUnicode_COMPACT_DATA(b); } else { // not exact bytes or unicode return -1; } assert(length != -1 && "length not set"); assert(va && "va not set"); assert(vb && "vb not set"); /* don't optimize for length == 0 */ result = 0; for (i=0; i < length; i++) { result |= *va++ ^ *vb++; } return (result == 0); }