From b006607b33e3d925293fd094b0ccebb8ede49625 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 18 Dec 2016 18:36:05 -0600 Subject: [PATCH] add memory limit check for scrypt fixes #3323 Gbp-Pq: Name 0001-add-memory-limit-check-for-scrypt.patch --- .../hazmat/backends/openssl/backend.py | 8 +++++--- tests/hazmat/primitives/test_scrypt.py | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 71063c1..9e101a3 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -143,6 +143,7 @@ class Backend(object): self._cipher_registry = {} self._register_default_ciphers() self.activate_osrandom_engine() + self._scrypt_mem_limit = sys.maxsize // 2 def openssl_assert(self, ok): return binding._openssl_assert(self._lib, ok) @@ -1894,9 +1895,10 @@ class Backend(object): def derive_scrypt(self, key_material, salt, length, n, r, p): buf = self._ffi.new("unsigned char[]", length) - res = self._lib.EVP_PBE_scrypt(key_material, len(key_material), salt, - len(salt), n, r, p, sys.maxsize // 2, - buf, length) + res = self._lib.EVP_PBE_scrypt( + key_material, len(key_material), salt, len(salt), n, r, p, + self._scrypt_mem_limit, buf, length + ) self.openssl_assert(res == 1) return self._ffi.buffer(buf)[:] diff --git a/tests/hazmat/primitives/test_scrypt.py b/tests/hazmat/primitives/test_scrypt.py index 49b304e..450eb82 100644 --- a/tests/hazmat/primitives/test_scrypt.py +++ b/tests/hazmat/primitives/test_scrypt.py @@ -22,10 +22,28 @@ vectors = load_vectors_from_file( os.path.join("KDF", "scrypt.txt"), load_nist_vectors) +def _skip_if_memory_limited(memory_limit, params): + # Memory calc adapted from OpenSSL (URL split over 2 lines, thanks PEP8) + # https://github.com/openssl/openssl/blob/6286757141a8c6e14d647ec733634a + # e0c83d9887/crypto/evp/scrypt.c#L189-L221 + blen = int(params["p"]) * 128 * int(params["r"]) + vlen = 32 * int(params["r"]) * (int(params["n"]) + 2) * 4 + memory_required = blen + vlen + if memory_limit < memory_required: + pytest.skip("Test exceeds Scrypt memory limit. " + "This is likely a 32-bit platform.") + + +def test_memory_limit_skip(): + with pytest.raises(pytest.skip.Exception): + _skip_if_memory_limited(1000, {"p": 16, "r": 64, "n": 1024}) + + @pytest.mark.requires_backend_interface(interface=ScryptBackend) class TestScrypt(object): @pytest.mark.parametrize("params", vectors) def test_derive(self, backend, params): + _skip_if_memory_limited(backend._scrypt_mem_limit, params) password = params["password"] work_factor = int(params["n"]) block_size = int(params["r"]) @@ -77,6 +95,7 @@ class TestScrypt(object): @pytest.mark.parametrize("params", vectors) def test_verify(self, backend, params): + _skip_if_memory_limited(backend._scrypt_mem_limit, params) password = params["password"] work_factor = int(params["n"]) block_size = int(params["r"])