Digest — Hashing with MD5, SHA256 and More

· 3 min read · Updated April 6, 2026 · intermediate
digest hashing md5 sha256 cryptography security

Hashing turns any chunk of data — a password, a file, a JSON payload — into a fixed-length fingerprint. The same input always produces the same output, but there’s no way to reverse it. Ruby’s standard library ships with this capability through the Digest module, which wraps a range of hash functions from OpenSSL underneath.

You don’t need any gems for this. require 'digest' is all it takes.

One-Shot Hashing

The quickest way to hash something is with the class method:

require 'digest'

Digest::SHA256.hexdigest("hello")
# => "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"

hexdigest returns a human-readable hex string. If you’d rather work with the raw binary bytes, use digest:

Digest::SHA256.digest("hello")
# => "\xaci\r\xba_\xb0\xa3\x0e&S\xb2\xac[~\x92\xe1\xb1a..."

For base64 encoding (useful in HTTP headers or JSON payloads):

Digest::SHA256.base64digest("hello")
# => "rMhdrF+woD4m46K8W56S4xsYXsH6dCXF6zBDYimL6Jg="

Available Algorithms

The module provides one class per algorithm:

Digest::MD5.hexdigest("hello")      # "5d41402abc4b2a76b9719d911017c592" (insecure, do not use)
Digest::SHA1.hexdigest("hello")      # "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d" (insecure, do not use)
Digest::SHA256.hexdigest("hello")   # the SHA256 example above
Digest::SHA384.hexdigest("hello")
Digest::SHA512.hexdigest("hello")
Digest::RMD160.hexdigest("hello")   # RIPEMD-160

MD5 and SHA1 are cryptographically broken and should never be used for security-sensitive work. SHA256 is the minimum recommended for new code. SHA512 is fine if you prefer a longer hash.

Incremental Hashing with update

When your data arrives in chunks — a streaming file read, a large payload — build the hash incrementally:

sha = Digest::SHA256.new
sha.update("hello")
sha.update(" ")
sha.update("world")
sha.hexdigest
# => "b3d9e23f4c7e2f1a8c6b5d4e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a"

The << operator is an alias for update, so you can chain more elegantly:

sha = Digest::SHA256.new
sha << "hello" << " " << "world"
sha.hexdigest

Once you’re done, call reset to clear the state for a fresh round:

sha.reset
sha << "new data"
sha.hexdigest

Hashing Files

Hashing a file without loading it entirely into memory uses file:

sha = Digest::SHA256.file("/path/to/large.zip")
sha.hexdigest

Or more concisely as a one-liner:

Digest::SHA256.file("/path/to/large.zip").hexdigest

file reads in chunks, so it works on arbitrarily large files without blowing up your memory.

Checking Equality with ==

Compare a digest object directly against a string:

sha = Digest::SHA256.file("/etc/hosts")
sha == "a7b3c2d1e9f0..."  # false if mismatched

This is handy for password verification in a login flow:

def verify_password(input, stored_hash)
  Digest::SHA256.hexdigest(input) == stored_hash
end

Though for actual passwords, you should use a dedicated key derivation function like bcrypt or Argon2 instead of a plain hash — those are designed to be slow to resist brute-force attacks.

Choosing an Algorithm

SHA256 is the default recommendation for most uses. It strikes a balance between speed and security for non-cryptographic applications like checksums and content-addressable storage.

SHA512 is preferred when you want a longer hash or are working in an environment where SHA256’s 32-byte output feels tight. SHA384 is essentially SHA512 truncated, if you want a shorter output without switching algorithms.

MD5 and SHA1 remain useful only for legacy compatibility — for example, validating the checksum of an old download that was published with an MD5 hash. Never use them for new security work.

Common Pitfalls

Reusing a digest object without resetting. After calling hexdigest, the digest state still holds the accumulated data. Call reset before starting a new hash:

# Wrong — second call hashes nothing
sha = Digest::SHA256.new
sha << "hello"
sha.hexdigest     # correct
sha.hexdigest     # wrong — same result

# Right
sha.reset
sha << "world"
sha.hexdigest     # correct

Storing passwords as plain hashes. A SHA256 hash of a password can be cracked with a dictionary attack in minutes. Use bcrypt or Argon2 with built-in salting instead.

See Also