diff --git a/CHANGELOG.md b/CHANGELOG.md index 591eb1d8..119b4e99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Added +- Support for generating md5 file upload checksums, even if Python's `hashlib` + was configured for FIPS mode. The fallback uses the `usedforsecurity` option which is + available in Python 3.9 and later. + + ## [1.5.2] - 2021-04-02 ### Added diff --git a/rsconnect/bundle.py b/rsconnect/bundle.py index 51a394c0..1b7316d0 100644 --- a/rsconnect/bundle.py +++ b/rsconnect/bundle.py @@ -75,10 +75,20 @@ def manifest_add_buffer(manifest, filename, buf): manifest["files"][filename] = {"checksum": buffer_checksum(buf)} +def make_hasher(): + try: + return hashlib.md5() + except Exception: + # md5 is not available in FIPS mode, see if the usedforsecurity option is available + # (it was added in python 3.9). We set usedforsecurity=False since we are only + # using this for a file upload integrity check. + return hashlib.md5(usedforsecurity=False) + + def file_checksum(path): """Calculate the md5 hex digest of the specified file""" with open(path, "rb") as f: - m = hashlib.md5() + m = make_hasher() chunk_size = 64 * 1024 chunk = f.read(chunk_size) @@ -90,7 +100,7 @@ def file_checksum(path): def buffer_checksum(buf): """Calculate the md5 hex digest of a buffer (str or bytes)""" - m = hashlib.md5() + m = make_hasher() m.update(to_bytes(buf)) return m.hexdigest()