Using OpenSSL to verify downloads

Hashes are commonly offered by download pages for you to verify the integrity of your downloaded files. I typically verify these hashes using OpenSSL which supports many types of hashing algorithms and is available on many unix-like systems (and can often be installed on them easily enough if it is not yet present).

The basic method for verification works as follows: after downloading a file enter the command openssl {hashalgorithm} {/path/to/downloaded.file} to calculate a hash based on the file’s contents. If the hash shown matches the hash on the download page the file is as intended.

To see the list of algorithms that are supported by the openssl command you can enter the command openssl help like shown below:

➜  openssl help                                       
Standard commands
asn1parse         ca                ciphers           cms               
crl               crl2pkcs7         dgst              dhparam           
dsa               dsaparam          ec                ecparam           
enc               engine            errstr            gendsa            
genpkey           genrsa            help              list              
nseq              ocsp              passwd            pkcs12            
pkcs7             pkcs8             pkey              pkeyparam         
pkeyutl           prime             rand              rehash            
req               rsa               rsautl            s_client          
s_server          s_time            sess_id           smime             
speed             spkac             srp               storeutl          
ts                verify            version           x509              

Message Digest commands (see the `dgst' command for more details)
blake2b512        blake2s256        gost              md4               
md5               rmd160            sha1              sha224            
sha256            sha3-224          sha3-256          sha3-384          
sha3-512          sha384            sha512            sha512-224        
sha512-256        shake128          shake256          sm3               

Cipher commands (see the `enc' command for more details)
aes-128-cbc       aes-128-ecb       aes-192-cbc       aes-192-ecb       
aes-256-cbc       aes-256-ecb       aria-128-cbc      aria-128-cfb      
aria-128-cfb1     aria-128-cfb8     aria-128-ctr      aria-128-ecb      
aria-128-ofb      aria-192-cbc      aria-192-cfb      aria-192-cfb1     
aria-192-cfb8     aria-192-ctr      aria-192-ecb      aria-192-ofb      
aria-256-cbc      aria-256-cfb      aria-256-cfb1     aria-256-cfb8     
aria-256-ctr      aria-256-ecb      aria-256-ofb      base64            
bf                bf-cbc            bf-cfb            bf-ecb            
bf-ofb            camellia-128-cbc  camellia-128-ecb  camellia-192-cbc  
camellia-192-ecb  camellia-256-cbc  camellia-256-ecb  cast              
cast-cbc          cast5-cbc         cast5-cfb         cast5-ecb         
cast5-ofb         des               des-cbc           des-cfb           
des-ecb           des-ede           des-ede-cbc       des-ede-cfb       
des-ede-ofb       des-ede3          des-ede3-cbc      des-ede3-cfb      
des-ede3-ofb      des-ofb           des3              desx              
rc2               rc2-40-cbc        rc2-64-cbc        rc2-cbc           
rc2-cfb           rc2-ecb           rc2-ofb           rc4               
rc4-40            seed              seed-cbc          seed-cfb          
seed-ecb          seed-ofb          sm4-cbc           sm4-cfb           
sm4-ctr           sm4-ecb           sm4-ofb           

When verifying a file with its hash you will have to look at the download page to see what hashing algorithm they used and compare it to the list under “Message Digest commands”. Note that the output on your system may differ depending on the OpenSSL version that is installed (so you may not have all of the above options).

An example

I’ll demonstrate this with SQLite. If you look at the SQLite downloads page you will see that they offer sha3 hashes for you to verify their downloads with. OpenSSL offers four type of sha3 hashing algorithms: sha3-224, sha3-256, sha3-384 and sha3-512. I downloaded the “Precompiled Binaries for Linux” and checked the download against all four of these:

➜  openssl sha3-224 sqlite-tools-linux-x86-3330000.zip
SHA3-224(sqlite-tools-linux-x86-3330000.zip)= 04ca86bb7906fbf8a17187310d65c692d5c4ce36eb2a7a1aeec86338
➜  openssl sha3-256 sqlite-tools-linux-x86-3330000.zip
SHA3-256(sqlite-tools-linux-x86-3330000.zip)= 2803a8edaa029d567cb01d472ddb86480ef4acc89ef6c6d4d85c6839dbb58cdb
➜  openssl sha3-384 sqlite-tools-linux-x86-3330000.zip
SHA3-384(sqlite-tools-linux-x86-3330000.zip)= 66a8bcdcb698e66a1ed278343d7db9c932b528705fe0264f6fc4c3d0c3015984c00f8a6ecbc9584f70e00d405be3a8d7
➜  openssl sha3-512 sqlite-tools-linux-x86-3330000.zip
SHA3-512(sqlite-tools-linux-x86-3330000.zip)= 3777e3d71b2b7917b861d192323fde24e84f440cf2a28853865d941f25e2237183db71057f2f485a9c9d2adf371e78575bad81d562f3e130b5ce38664dd22650

The long string next to the equals sign in each of the outputs is the hash, they are quite long and checking them by eye is kind of hard. One way to check if the hash from your file matches the webpage is to copy it to your clipboard, go to the browser page that shows the hash that you are verifying and paste it into the page search function and search for it. If the file matches the hash you will see it. I am using Firefox in the screenshot below with the result of sha3-256 (which is the hashing algorithm that was used on the SQLite website):

My preferred method however is to verify this directly in the shell, which you can do with something like the following:

➜  if [[ "$(openssl sha3-256 sqlite-tools-linux-x86-3330000.zip | awk '{print $NF}')" =~ "2803a8edaa029d567cb01d472ddb86480ef4acc89ef6c6d4d85c6839dbb58cdb" ]]; then; echo 'verified'; fi
verified

The above will work in bash and zsh but also requires you to have awk (which is also commonly available on unix-like systems) next to OpenSSL. The above shell script checks the output of the command against the hash and echoes “verified” if the file’s hash matches the hash of on the right hand side of the comparison.

As a shell function

While the earlier shown bit of shell script works its not very convenient to type that all in every time you want to verify a download. You can however convert it into a reusable shell function like so:

function checkhash() { 
  if [[ "$(openssl $1 $2 | awk '{print $NF}')" =~ "$3" ]]; then
    echo 'verified'
    return 0
  fi
  return 1
}

If you add the above function to your bash or zsh initialization file you can then verify your download like so:

➜  checkhash sha3-256 sqlite-tools-linux-x86-3330000.zip 2803a8edaa029d567cb01d472ddb86480ef4acc89ef6c6d4d85c6839dbb58cdb
verified

An addition in the function (compared to the earlier shown ad hoc version) is that it now also gives a return value of 0 when verified or 1 when it fails, this means that you can check if the command succeeded before executing other commands like so:

➜  checkhash sha3-256 sqlite-tools-linux-x86-3330000.zip 2803a8edaa029d567cb01d472ddb86480ef4acc89ef6c6d4d85c6839dbb58cdb && echo 'it works'
verified
it works

If you string commands together with && then each command after && will only get executed if the command before the && returned exit code 0 (which means it succeeded), this can be convenient if you want to script together a download with a verification and then an automated install or something of that sort.

In conclusion

And that’s all for this article. If you have feedback on this article or have questions based on its contents then feel free to reach out to me on Twitter or through e-mail.