From 8dda3371a7b378b896086f460f49078ea34e82ca Mon Sep 17 00:00:00 2001 From: jenswehner Date: Fri, 24 Jul 2026 13:23:08 +0000 Subject: [PATCH 1/4] Fix Content-MD5 in FIPS environments --- .../azure/storage/blob/_shared/validation.py | 2 +- .../tests/test_content_validation.py | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/validation.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/validation.py index 7161a31bb15e..5d31476fc478 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/validation.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/validation.py @@ -77,7 +77,7 @@ def is_crc64_validation( def calculate_content_md5(data: Union[bytes, IO[bytes]]) -> bytes: - md5 = hashlib.md5() # nosec + md5 = hashlib.md5(usedforsecurity=False) # nosec if isinstance(data, bytes): md5.update(data) elif hasattr(data, "read"): diff --git a/sdk/storage/azure-storage-blob/tests/test_content_validation.py b/sdk/storage/azure-storage-blob/tests/test_content_validation.py index bc7633b087d3..802272a6ac68 100644 --- a/sdk/storage/azure-storage-blob/tests/test_content_validation.py +++ b/sdk/storage/azure-storage-blob/tests/test_content_validation.py @@ -18,6 +18,20 @@ from azure.core.exceptions import ResourceExistsError from azure.storage.blob import BlobBlock, BlobClient, BlobServiceClient, BlobType, ContainerClient +from azure.storage.blob._shared import validation + + +def test_content_md5_is_not_used_for_security(monkeypatch): + original_md5 = validation.hashlib.md5 + + def fips_md5(*args, **kwargs): + if kwargs.get("usedforsecurity") is not False: + raise ValueError("MD5 is unavailable for security use") + return original_md5(*args, **kwargs) + + monkeypatch.setattr(validation.hashlib, "md5", fips_md5) + + assert validation.calculate_content_md5(b"test") == bytes.fromhex("098f6bcd4621d373cade4e832627b4f6") def assert_content_md5(request): From 189b2543e82727d98ced49cd2aa1680a65fb7dd6 Mon Sep 17 00:00:00 2001 From: Jens Wehner Date: Sun, 26 Jul 2026 22:33:18 +0200 Subject: [PATCH 2/4] fix all hashlib.md5 calls --- .../_vendor/storage/blob/_shared/policies.py | 2 +- .../azure/storage/filedatalake/_shared/validation.py | 2 +- .../azure/storage/fileshare/_shared/validation.py | 2 +- .../azure/storage/queue/_shared/validation.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sdk/eventhub/azure-eventhub-checkpointstoreblob/azure/eventhub/extensions/checkpointstoreblob/_vendor/storage/blob/_shared/policies.py b/sdk/eventhub/azure-eventhub-checkpointstoreblob/azure/eventhub/extensions/checkpointstoreblob/_vendor/storage/blob/_shared/policies.py index ee75cd5a466c..f52b65e1ec0a 100644 --- a/sdk/eventhub/azure-eventhub-checkpointstoreblob/azure/eventhub/extensions/checkpointstoreblob/_vendor/storage/blob/_shared/policies.py +++ b/sdk/eventhub/azure-eventhub-checkpointstoreblob/azure/eventhub/extensions/checkpointstoreblob/_vendor/storage/blob/_shared/policies.py @@ -342,7 +342,7 @@ def get_content_md5(data): # Since HTTP does not differentiate between no content and empty content, # we have to perform a None check. data = data or b"" - md5 = hashlib.md5() # nosec + md5 = hashlib.md5(usedforsecurity=False) # nosec if isinstance(data, bytes): md5.update(data) elif hasattr(data, 'read'): diff --git a/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/validation.py b/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/validation.py index 7161a31bb15e..5d31476fc478 100644 --- a/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/validation.py +++ b/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/validation.py @@ -77,7 +77,7 @@ def is_crc64_validation( def calculate_content_md5(data: Union[bytes, IO[bytes]]) -> bytes: - md5 = hashlib.md5() # nosec + md5 = hashlib.md5(usedforsecurity=False) # nosec if isinstance(data, bytes): md5.update(data) elif hasattr(data, "read"): diff --git a/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/validation.py b/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/validation.py index 7161a31bb15e..5d31476fc478 100644 --- a/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/validation.py +++ b/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/validation.py @@ -77,7 +77,7 @@ def is_crc64_validation( def calculate_content_md5(data: Union[bytes, IO[bytes]]) -> bytes: - md5 = hashlib.md5() # nosec + md5 = hashlib.md5(usedforsecurity=False) # nosec if isinstance(data, bytes): md5.update(data) elif hasattr(data, "read"): diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/validation.py b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/validation.py index 7161a31bb15e..5d31476fc478 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/validation.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/validation.py @@ -77,7 +77,7 @@ def is_crc64_validation( def calculate_content_md5(data: Union[bytes, IO[bytes]]) -> bytes: - md5 = hashlib.md5() # nosec + md5 = hashlib.md5(usedforsecurity=False) # nosec if isinstance(data, bytes): md5.update(data) elif hasattr(data, "read"): From 5a9d82788a9dba2e22bf16f96224dc0d6ce2303d Mon Sep 17 00:00:00 2001 From: Jens Wehner Date: Sun, 26 Jul 2026 22:35:08 +0200 Subject: [PATCH 3/4] missed one --- .../_vendor/storage/blob/_shared/policies.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/eventhub/azure-eventhub-checkpointstoreblob-aio/azure/eventhub/extensions/checkpointstoreblobaio/_vendor/storage/blob/_shared/policies.py b/sdk/eventhub/azure-eventhub-checkpointstoreblob-aio/azure/eventhub/extensions/checkpointstoreblobaio/_vendor/storage/blob/_shared/policies.py index ee75cd5a466c..f52b65e1ec0a 100644 --- a/sdk/eventhub/azure-eventhub-checkpointstoreblob-aio/azure/eventhub/extensions/checkpointstoreblobaio/_vendor/storage/blob/_shared/policies.py +++ b/sdk/eventhub/azure-eventhub-checkpointstoreblob-aio/azure/eventhub/extensions/checkpointstoreblobaio/_vendor/storage/blob/_shared/policies.py @@ -342,7 +342,7 @@ def get_content_md5(data): # Since HTTP does not differentiate between no content and empty content, # we have to perform a None check. data = data or b"" - md5 = hashlib.md5() # nosec + md5 = hashlib.md5(usedforsecurity=False) # nosec if isinstance(data, bytes): md5.update(data) elif hasattr(data, 'read'): From 1429caee22c5f013551c4db98ca36e1f71270998 Mon Sep 17 00:00:00 2001 From: Jens Wehner Date: Mon, 27 Jul 2026 23:20:12 +0200 Subject: [PATCH 4/4] revert eventhub --- .../_vendor/storage/blob/_shared/policies.py | 2 +- .../_vendor/storage/blob/_shared/policies.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/eventhub/azure-eventhub-checkpointstoreblob-aio/azure/eventhub/extensions/checkpointstoreblobaio/_vendor/storage/blob/_shared/policies.py b/sdk/eventhub/azure-eventhub-checkpointstoreblob-aio/azure/eventhub/extensions/checkpointstoreblobaio/_vendor/storage/blob/_shared/policies.py index f52b65e1ec0a..ee75cd5a466c 100644 --- a/sdk/eventhub/azure-eventhub-checkpointstoreblob-aio/azure/eventhub/extensions/checkpointstoreblobaio/_vendor/storage/blob/_shared/policies.py +++ b/sdk/eventhub/azure-eventhub-checkpointstoreblob-aio/azure/eventhub/extensions/checkpointstoreblobaio/_vendor/storage/blob/_shared/policies.py @@ -342,7 +342,7 @@ def get_content_md5(data): # Since HTTP does not differentiate between no content and empty content, # we have to perform a None check. data = data or b"" - md5 = hashlib.md5(usedforsecurity=False) # nosec + md5 = hashlib.md5() # nosec if isinstance(data, bytes): md5.update(data) elif hasattr(data, 'read'): diff --git a/sdk/eventhub/azure-eventhub-checkpointstoreblob/azure/eventhub/extensions/checkpointstoreblob/_vendor/storage/blob/_shared/policies.py b/sdk/eventhub/azure-eventhub-checkpointstoreblob/azure/eventhub/extensions/checkpointstoreblob/_vendor/storage/blob/_shared/policies.py index f52b65e1ec0a..ee75cd5a466c 100644 --- a/sdk/eventhub/azure-eventhub-checkpointstoreblob/azure/eventhub/extensions/checkpointstoreblob/_vendor/storage/blob/_shared/policies.py +++ b/sdk/eventhub/azure-eventhub-checkpointstoreblob/azure/eventhub/extensions/checkpointstoreblob/_vendor/storage/blob/_shared/policies.py @@ -342,7 +342,7 @@ def get_content_md5(data): # Since HTTP does not differentiate between no content and empty content, # we have to perform a None check. data = data or b"" - md5 = hashlib.md5(usedforsecurity=False) # nosec + md5 = hashlib.md5() # nosec if isinstance(data, bytes): md5.update(data) elif hasattr(data, 'read'):