storage: download integrity check

- [x] integrity tests
- [x] merge #299

Picking up from #299, where we're implementing integrity checks for uploads.
The way I understand it is the API can respond without an MD5 hash if the file format is of a certain type -- not sure which, how, or under what exact circumstance this happens -- but it will always reply with a crc32c. In order to handle that case without matching the API's logic, we run both validation types, then use MD5 if available, falling back to crc32c if it wasn't.

Should I update the docs to say a more readable version of the above?