summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorGeorg Brandl <georg@python.org>2012-02-20 18:54:16 (GMT)
committerGeorg Brandl <georg@python.org>2012-02-20 18:54:16 (GMT)
commit2daf6ae2495c862adf8bc717bfe9964081ea0b10 (patch)
treeebd7efe668e4f7842c6d51bdbde47b00f92a57db /Objects
parentec1712a1662282c909b4cd4cc0c7486646bc9246 (diff)
downloadcpython-2daf6ae2495c862adf8bc717bfe9964081ea0b10.zip
cpython-2daf6ae2495c862adf8bc717bfe9964081ea0b10.tar.gz
cpython-2daf6ae2495c862adf8bc717bfe9964081ea0b10.tar.bz2
Issue #13703: add a way to randomize the hash values of basic types (str, bytes, datetime)
in order to make algorithmic complexity attacks on (e.g.) web apps much more complicated. The environment variable PYTHONHASHSEED and the new command line flag -R control this behavior.
Diffstat (limited to 'Objects')
-rw-r--r--Objects/bytesobject.c12
-rw-r--r--Objects/object.c2
-rw-r--r--Objects/unicodeobject.c12
3 files changed, 24 insertions, 2 deletions
diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c
index f2ee131..e6ab440 100644
--- a/Objects/bytesobject.c
+++ b/Objects/bytesobject.c
@@ -899,11 +899,21 @@ bytes_hash(PyBytesObject *a)
if (a->ob_shash != -1)
return a->ob_shash;
len = Py_SIZE(a);
+ /*
+ We make the hash of the empty string be 0, rather than using
+ (prefix ^ suffix), since this slightly obfuscates the hash secret
+ */
+ if (len == 0) {
+ a->ob_shash = 0;
+ return 0;
+ }
p = (unsigned char *) a->ob_sval;
- x = *p << 7;
+ x = _Py_HashSecret.prefix;
+ x ^= *p << 7;
while (--len >= 0)
x = (1000003*x) ^ *p++;
x ^= Py_SIZE(a);
+ x ^= _Py_HashSecret.suffix;
if (x == -1)
x = -2;
a->ob_shash = x;
diff --git a/Objects/object.c b/Objects/object.c
index ac57cd7..0b1c656 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -712,6 +712,8 @@ PyObject_HashNotImplemented(PyObject *v)
return -1;
}
+_Py_HashSecret_t _Py_HashSecret;
+
long
PyObject_Hash(PyObject *v)
{
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
index 2cdbc0e..5986fb8 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -7344,11 +7344,21 @@ unicode_hash(PyUnicodeObject *self)
if (self->hash != -1)
return self->hash;
len = Py_SIZE(self);
+ /*
+ We make the hash of the empty string be 0, rather than using
+ (prefix ^ suffix), since this slightly obfuscates the hash secret
+ */
+ if (len == 0) {
+ self->hash = 0;
+ return 0;
+ }
p = self->str;
- x = *p << 7;
+ x = _Py_HashSecret.prefix;
+ x ^= *p << 7;
while (--len >= 0)
x = (1000003*x) ^ *p++;
x ^= Py_SIZE(self);
+ x ^= _Py_HashSecret.suffix;
if (x == -1)
x = -2;
self->hash = x;