diff --git a/yt/data_objects/data_containers.py b/yt/data_objects/data_containers.py index ebf1f1d9e27..09944f36663 100644 --- a/yt/data_objects/data_containers.py +++ b/yt/data_objects/data_containers.py @@ -1365,7 +1365,7 @@ def _hash(self): try: import hashlib - return hashlib.md5(s.encode("utf-8")).hexdigest() + return hashlib.md5(s.encode("utf-8"), usedforsecurity=False).hexdigest() except ImportError: return s diff --git a/yt/data_objects/static_output.py b/yt/data_objects/static_output.py index b21c0011a9d..c00c928fd40 100644 --- a/yt/data_objects/static_output.py +++ b/yt/data_objects/static_output.py @@ -441,7 +441,7 @@ def __str__(self): def _hash(self): s = f"{self.basename};{self.current_time};{self.unique_identifier}" - return hashlib.md5(s.encode("utf-8")).hexdigest() + return hashlib.md5(s.encode("utf-8"), usedforsecurity=False).hexdigest() @cached_property def checksum(self): @@ -463,7 +463,7 @@ def generate_file_md5(m, filename, blocksize=2**20): break m.update(buf) - m = hashlib.md5() + m = hashlib.md5(usedforsecurity=False) if os.path.isdir(self.parameter_filename): for root, _, files in os.walk(self.parameter_filename): for fname in files: diff --git a/yt/testing.py b/yt/testing.py index 9d92faf62df..33c9452ed08 100644 --- a/yt/testing.py +++ b/yt/testing.py @@ -1476,7 +1476,7 @@ def _func(*args, **kwargs): st = _rv.std(dtype="float64") su = _rv.sum(dtype="float64") si = _rv.size - ha = hashlib.md5(_rv.tobytes()).hexdigest() + ha = hashlib.md5(_rv.tobytes(), usedforsecurity=False).hexdigest() fn = f"func_results_ref_{name}.cpkl" with open(fn, "wb") as f: pickle.dump((mi, ma, st, su, si, ha), f) @@ -1509,7 +1509,7 @@ def _func(*args, **kwargs): _rv.std(dtype="float64"), _rv.sum(dtype="float64"), _rv.size, - hashlib.md5(_rv.tobytes()).hexdigest(), + hashlib.md5(_rv.tobytes(), usedforsecurity=False).hexdigest(), ) fn = f"func_results_ref_{name}.cpkl" if not os.path.exists(fn): diff --git a/yt/utilities/answer_testing/answer_tests.py b/yt/utilities/answer_testing/answer_tests.py index 31a6fbb8a7e..30f3dd29e8f 100644 --- a/yt/utilities/answer_testing/answer_tests.py +++ b/yt/utilities/answer_testing/answer_tests.py @@ -52,7 +52,9 @@ def grid_values(ds, field): result = None for g in ds.index.grids: if result is None: - result = hashlib.md5(bytes(g.id) + g[field].tobytes()) + result = hashlib.md5( + bytes(g.id) + g[field].tobytes(), usedforsecurity=False + ) else: result.update(bytes(g.id) + g[field].tobytes()) g.clear_data() @@ -78,7 +80,7 @@ def projection_values(ds, axis, field, weight_field, dobj_type): for k, v in proj.field_data.items(): k = k.__repr__().encode("utf8") if result is None: - result = hashlib.md5(k + v.tobytes()) + result = hashlib.md5(k + v.tobytes(), usedforsecurity=False) else: result.update(k + v.tobytes()) return result.hexdigest() @@ -128,7 +130,7 @@ def pixelized_projection_values(ds, axis, field, weight_field=None, dobj_type=No for k, v in d.items(): k = k.__repr__().encode("utf8") if result is None: - result = hashlib.md5(k + v.tobytes()) + result = hashlib.md5(k + v.tobytes(), usedforsecurity=False) else: result.update(k + v.tobytes()) return result.hexdigest() diff --git a/yt/utilities/answer_testing/framework.py b/yt/utilities/answer_testing/framework.py index 6abd1dc366d..a3d2d7a2053 100644 --- a/yt/utilities/answer_testing/framework.py +++ b/yt/utilities/answer_testing/framework.py @@ -683,7 +683,9 @@ def __init__(self, ds_fn, field): def run(self): hashes = {} for g in self.ds.index.grids: - hashes[g.id] = hashlib.md5(g[self.field].tobytes()).hexdigest() + hashes[g.id] = hashlib.md5( + g[self.field].tobytes(), usedforsecurity=False + ).hexdigest() g.clear_data() return hashes diff --git a/yt/utilities/answer_testing/testing_utilities.py b/yt/utilities/answer_testing/testing_utilities.py index 6f7729b85b1..dbf9f4292f9 100644 --- a/yt/utilities/answer_testing/testing_utilities.py +++ b/yt/utilities/answer_testing/testing_utilities.py @@ -152,7 +152,7 @@ def _hash_dict(data): if isinstance(hashed_data, str): hashed_data = hashed_data.encode("utf8") if hd is None: - hd = hashlib.md5(hashed_data) + hd = hashlib.md5(hashed_data, usedforsecurity=False) else: hd.update(hashed_data) return hd.hexdigest() @@ -181,7 +181,7 @@ def generate_hash(data): # Try to hash. Some tests return hashable types (like ndarrays) and # others don't (such as dictionaries) try: - hd = hashlib.md5(data).hexdigest() + hd = hashlib.md5(data, usedforsecurity=False).hexdigest() # Handle those tests that return non-hashable types. This is done # here instead of in the tests themselves to try and reduce boilerplate # and provide a central location where all of this is done in case it needs @@ -190,7 +190,9 @@ def generate_hash(data): if isinstance(data, dict): hd = _hash_dict(data) elif data is None: - hd = hashlib.md5(bytes(str(-1).encode("utf-8"))).hexdigest() + hd = hashlib.md5( + bytes(str(-1).encode("utf-8")), usedforsecurity=False + ).hexdigest() else: raise return hd diff --git a/yt/utilities/tests/test_answer_testing.py b/yt/utilities/tests/test_answer_testing.py new file mode 100644 index 00000000000..ed595dacad8 --- /dev/null +++ b/yt/utilities/tests/test_answer_testing.py @@ -0,0 +1,23 @@ +import hashlib + +import pytest + +from yt.utilities.answer_testing.testing_utilities import generate_hash + + +@pytest.mark.parametrize( + ("data", "payload"), + [(b"yt", b"yt"), (None, b"-1"), ({"a": b"b"}, b"ab")], +) +def test_generate_hash_in_fips_mode(monkeypatch, data, payload): + expected = hashlib.md5(payload, usedforsecurity=False).hexdigest() + original_md5 = hashlib.md5 + + def fips_md5(data=b"", *, usedforsecurity=True): + if usedforsecurity: + raise ValueError("MD5 is disabled for FIPS") + return original_md5(data) + + monkeypatch.setattr(hashlib, "md5", fips_md5) + + assert generate_hash(data) == expected