Never wanting to get stale professionally, I regularly experiment with different libraries, frameworks programming languages, and tools. It helps me stay on top of what’s going on in the industry. The Rust programming language seems to be getting used and talked about much more these days. I even saw it referenced in a TV/stream commercial for a staffing company recently; although, I can’t remember that company’s name.

But “acquiring” new programming languages requires more justification for me to want to my precious personal time. It’s not something you can usually experiment with for just a few hours and walk away from having a sound opinion. You must spend significant amount time using a language to really understand it.

Now, going through tutorials isn’t a very good way to learn a language. Sure, it makes getting tooling setup and a simple working program running easy. But the moment you step off the narrative trail of the tutorial, you find yourself unsupported, having to put in signficant energy to self-learn what went wrong and get back on track. If the tutorial is typical, it doesn’t seem all that interesting. You face the question, “how much work do I want to put in to make a dumb tutorial app that I don’t care about work better?”

So, I tend to reframe the learning experience as one where I build something I want to build with the new technology. This gives me a goal to shoot for and helps me stay motivated. The trick is to not be overly ambitious.

I opted, this time, to make a little tool I could use to simplfy verification of digests on files I’ve downloaded. You know, hashes, checksums, fingerprints…those strings filled with random-looking alpha-numeric values that most people have seen on download sites, but which few people know how to use, and fewer acutally use. You’ll typically only see them for:

  • executables that aren’t signed by a publisher
  • archives used to prepare executables that don’t include signatures that operating systems automatically verify
  • for files you download from vendors who are particularly security-minded

For example:

Digests on Arch Linux download page
Digests on Arch Linux download page

Digest on IntelliJ IDEA download page
Digest on IntelliJ IDEA download page

Digest on Visual Studio Code  download page
Digest on Visual Studio Code download page

The Problem

Most operating systems have some sort of tool available to check the digests (certutil, md5sum, shasum, sha256sum, openssl But they:

  • are usually command line tools
  • require you enter the algorithm name
  • require you visually/manually compare your computed digest against the public one

I don’t mind using command-line tools, but I though it’d be nice to use the same tool in each environment I’m in.

The other two issue make the tedious task of performing the verification all on the user’s shoulders. It should be lower effort to performt he vericication.

Inferring Algorithm from Digest Length

The computer can guess the possible algorithm from the length of the digest. Most digests are published in hex-encoded form. If you look at the most commonly used algoritms, they all have use distinct bit-lengths. You have to get into pretty weird territory before you start to see algorithms with digest sizes equal in length to more popular algorithms.

AlgorithmBit Size
CRC3232
MD5128
SHA-1160
SHA256256
SHA384384
SHA512512
RIPEMD160160

Compaing Noise to Noise

Why should I waste effort visually comparing two digests? I can hope to take advantage of the characteric of cryptographic hashes that makes small changes in input result in obvious changes in output. Or I can just let my computer do that comparison

Digestify

So I created digestify to take the little bit of extra effort out of digest verification.

You give it a file and a digest. It guesses the candidate digest algorithms from the provided digest length. For each candidate, it computes the digest and compares it, telling you when they do or don’t match.

It currently supports SHA-512, SHA-256, SHA-1, MD5, and CRC-32.

At the moment, I haven’t set up packaging of distributable binaries. So it’s not the easied to install. If you’ve installed the rust toolchain with rustup, you can run:

cargo install digestify

Sources are available on github.

Examples in us:

$ digestify Cargo.lock ac4a0ad1af6773ce6980cc9958cfd18820275f28b8055b93e4d69688e2fd72c8

Verifying 'Cargo.lock' against provided digest of size 64 hex chars / 256 bits.  Candidate digest(s): SHA-256.

 SHA-256: MATCHES
    Expected=ac4a0ad1af6773ce6980cc9958cfd18820275f28b8055b93e4d69688e2fd72c8
      Actual=ac4a0ad1af6773ce6980cc9958cfd18820275f28b8055b93e4d69688e2fd72c8

$ echo $?
0
$ digestify Cargo.toml f26c2e4e001349b737a3a5cc5fc4afc87b423773
Verifying 'Cargo.toml' against provided digest of size 40 hex chars / 160 bits.  Candidate digest(s): SHA-1.

 SHA-1: FAIL
        Expected=f26c2e4e001349b737a3a5cc5fc4afc87b423773
          Actual=a30d387b67f1e4d26fd59b3ddb94cfde58d23287

$ echo $?
254

Maybe someday I’ll:

  • set up CI to build signed prebuilt binaries for common platforms
  • add colored terminal output to highlight differences
  • learn how to write docs for rust code
  • perhaps even experiment with some UI libraries to build a simple front end to help those that despise command line tools

About the Author

Evan is always learning new things, often drawing blood in the process.

And no, I'm not a pirate. But I say, "Arrrgh!" a lot as it's my first name.