Search code examples
powershellcurlhashmd5content-length

How to match MD5 Hash of a File on web URL vs when its downloaded


Using Powershell script we always match the HASH value of a file on the WEB URI and the hash after it's downloaded and report failure if the hash does not match.

I'm now dealing with the below URL where Im unable to match the HASH MD5 on URI totmYatp14JwNhBLZwYpog== to MD5 on local B68B6661AB69D7827036104B670629A2?.

https://cdn.windwardstudios.com/Archive/23.X/23.3.5/JavaRESTfulEngine-23.3.5.1.zip

There is Content-MD5 mentioned totmYatp14JwNhBLZwYpog== on the below URL for the file:

https://cdn.windwardstudios.com/?prefix=Archive/23.X/23.3.5/

enter image description here

Is it possible to match Hash or any other solution to make sure that the file on the webpage and the one after the download match?

Below is what I tried but the MD5 does not match:

MD5 and content-length for the concerned file from headers are below:

PS C:\Users\HOME> $response = Invoke-WebRequest -Uri "https://cdn.windwardstudios.com/Archive/23.X/23.3.5/JavaRESTfulEngine-23.3.5.1.zip" -Method Head
PS C:\Users\HOME> $response.Headers['Content-MD5']
totmYatp14JwNhBLZwYpog==
PS C:\Users\HOME> $response.Headers['Content-Length']
189583636

However, when the same file is downloaded locally its content-length MATCHES but the content-md5 DOES NOT MATCH when it should:

$filePath = 'C:\Users\HOME\Downloads\JavaRESTfulEngine-23.3.5.1.zip'

# Calculate the MD5 hash of the file
$md5 = Get-FileHash -Path $filePath -Algorithm MD5

Write-Host ("MD5 hash (Content-MD5) of " + $filePath + ": " + $md5.Hash)

$fileInfo = Get-Item $filePath
$fileInfo.Length

As you can see from the output the content-length matches but the content-MD5 does not.

PS C:\Users\HOME> C:\Logs\getkey.ps1
MD5 hash (Content-MD5) of C:\Users\HOME\Downloads\JavaRESTfulEngine-23.3.5.1.zip: B68B6661AB69D7827036104B670629A2
189583636

How can I get the MD5 on URI totmYatp14JwNhBLZwYpog== to match MD5 on local B68B6661AB69D7827036104B670629A2?

**** Trying solution by @vonPryz ****

# Convert MD5 hash to Base64
$md5Base64 = [Convert]::ToBase64String($md5.Hash)
Write-Host "MD5 in Base64: $md5Base64"

# Convert Base64 MD5 hash to Hex
$md5Bytes = [Convert]::FromBase64String($md5Base64)
$md5Hex = [System.BitConverter]::ToString($md5Bytes) -replace '[-\s]', ''
Write-Host "MD5 in Hex: $md5Hex"

Output:

Cannot convert argument "inArray", with value: "B68B6661AB69D7827036104B670629A2", for "ToBase64String" to type "System.Byte[]": "Cannot convert value 
"B68B6661AB69D7827036104B670629A2" to type "System.Byte[]". Error: "Cannot convert value "B68B6661AB69D7827036104B670629A2" to type "System.Byte". Error: "Input string 
was not in a correct format."""
At C:\Logs\getkey.ps1:31 char:1
+ $md5Base64 = [Convert]::ToBase64String($md5.Hash)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodException
    + FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument

Solution

  • The reason is the hash is represented in Base64 encoded format, whilst hashes are usually represented in hex strings.

    Convert the format from Base64 and then to hex format. Like so,

    ([System.Convert]::FromBase64String($base64data) | Format-Hex).HexBytes -replace ' ',''
    

    The .HexBytes property contains bytes separated by spaces, so -replace ' ', '' will trim the withespaces and you'll get an uppercase string containing the hash.