diff --git a/src/nacl/bindings/crypto_generichash.py b/src/nacl/bindings/crypto_generichash.py index 521873cc..3499bf0f 100644 --- a/src/nacl/bindings/crypto_generichash.py +++ b/src/nacl/bindings/crypto_generichash.py @@ -271,6 +271,12 @@ def generichash_blake2b_final(state: Blake2State) -> bytes: raising=exc.TypeError, ) + ensure( + state.digest_size <= crypto_generichash_BYTES_MAX, + _TOOBIG.format("Digest_size", crypto_generichash_BYTES_MAX), + raising=exc.ValueError, + ) + _digest = ffi.new("unsigned char[]", crypto_generichash_BYTES_MAX) rc = lib.crypto_generichash_blake2b_final( state._statebuf, _digest, state.digest_size diff --git a/tests/test_generichash.py b/tests/test_generichash.py index 7aee1e4e..7d1d8ad5 100644 --- a/tests/test_generichash.py +++ b/tests/test_generichash.py @@ -155,6 +155,23 @@ def test_expected_bindings_level_pickle_and_copy_failures(): copy.copy(st) +def test_generichash_blake2b_final_rejects_oversized_directly_constructed_state(): + # Regression test for https://github.com/pyca/pynacl/issues/964 + # A Blake2State constructed directly (bypassing + # generichash_blake2b_init()'s parameter validation) with an + # out-of-range digest_size used to crash the process with SIGABRT + # inside libsodium instead of raising a Python exception. + from nacl.bindings.crypto_generichash import ( + Blake2State, + crypto_generichash_BYTES_MAX, + generichash_blake2b_final, + ) + + state = Blake2State(crypto_generichash_BYTES_MAX + 1) + with pytest.raises(exc.ValueError): + generichash_blake2b_final(state) + + @pytest.mark.parametrize( ["message", "key", "outlen", "output"], blake2_reference_vectors() )