diff options
author | Paul Kehrer <paul.l.kehrer@gmail.com> | 2017-01-05 14:11:17 -0500 |
---|---|---|
committer | Alex Gaynor <alex.gaynor@gmail.com> | 2017-01-05 14:11:17 -0500 |
commit | d74ba3298ddd4d3558224af85768e28f4c7f8d0d (patch) | |
tree | 82dcb0f34338310fa70163b5290f2ca1c775c5c2 | |
parent | 1c2458e0ceb1685b80dfe115a796926d3f1f4d86 (diff) | |
download | cryptography-d74ba3298ddd4d3558224af85768e28f4c7f8d0d.tar.gz cryptography-d74ba3298ddd4d3558224af85768e28f4c7f8d0d.tar.bz2 cryptography-d74ba3298ddd4d3558224af85768e28f4c7f8d0d.zip |
add memory limit check for scrypt (#3328)
* add memory limit check for scrypt
fixes #3323
* test a pass
* move _MEM_LIMIT to the scrypt module
-rw-r--r-- | src/cryptography/hazmat/backends/openssl/backend.py | 9 | ||||
-rw-r--r-- | src/cryptography/hazmat/primitives/kdf/scrypt.py | 7 | ||||
-rw-r--r-- | tests/hazmat/primitives/test_scrypt.py | 23 |
3 files changed, 34 insertions, 5 deletions
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 76ecc08c..397a0210 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -9,7 +9,6 @@ import calendar import collections import contextlib import itertools -import sys from contextlib import contextmanager import six @@ -59,6 +58,7 @@ from cryptography.hazmat.primitives.ciphers.algorithms import ( from cryptography.hazmat.primitives.ciphers.modes import ( CBC, CFB, CFB8, CTR, ECB, GCM, OFB ) +from cryptography.hazmat.primitives.kdf import scrypt _MemoryBIO = collections.namedtuple("_MemoryBIO", ["bio", "char_ptr"]) @@ -1833,9 +1833,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, + scrypt._MEM_LIMIT, buf, length + ) self.openssl_assert(res == 1) return self._ffi.buffer(buf)[:] diff --git a/src/cryptography/hazmat/primitives/kdf/scrypt.py b/src/cryptography/hazmat/primitives/kdf/scrypt.py index 20935409..77dcf9ab 100644 --- a/src/cryptography/hazmat/primitives/kdf/scrypt.py +++ b/src/cryptography/hazmat/primitives/kdf/scrypt.py @@ -4,6 +4,8 @@ from __future__ import absolute_import, division, print_function +import sys + from cryptography import utils from cryptography.exceptions import ( AlreadyFinalized, InvalidKey, UnsupportedAlgorithm, _Reasons @@ -13,6 +15,11 @@ from cryptography.hazmat.primitives import constant_time from cryptography.hazmat.primitives.kdf import KeyDerivationFunction +# This is used by the scrypt tests to skip tests that require more memory +# than the MEM_LIMIT +_MEM_LIMIT = sys.maxsize // 2 + + @utils.register_interface(KeyDerivationFunction) class Scrypt(object): def __init__(self, salt, length, n, r, p, backend): diff --git a/tests/hazmat/primitives/test_scrypt.py b/tests/hazmat/primitives/test_scrypt.py index 49b304e0..87aee1f1 100644 --- a/tests/hazmat/primitives/test_scrypt.py +++ b/tests/hazmat/primitives/test_scrypt.py @@ -14,7 +14,7 @@ from cryptography.exceptions import ( AlreadyFinalized, InvalidKey, UnsupportedAlgorithm ) from cryptography.hazmat.backends.interfaces import ScryptBackend -from cryptography.hazmat.primitives.kdf.scrypt import Scrypt +from cryptography.hazmat.primitives.kdf.scrypt import Scrypt, _MEM_LIMIT from tests.utils import load_nist_vectors, load_vectors_from_file @@ -22,10 +22,30 @@ 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}) + + _skip_if_memory_limited(2 ** 31, {"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(_MEM_LIMIT, params) password = params["password"] work_factor = int(params["n"]) block_size = int(params["r"]) @@ -77,6 +97,7 @@ class TestScrypt(object): @pytest.mark.parametrize("params", vectors) def test_verify(self, backend, params): + _skip_if_memory_limited(_MEM_LIMIT, params) password = params["password"] work_factor = int(params["n"]) block_size = int(params["r"]) |