Last updated: April 22, 2025

<span aria-hidden="true" id="secure-file-verification-with-ruby-and-sha384"></span>

# Secure file verification with Ruby and SHA384

![Tim Koschützki](/assets/images/teammates/avatar-tim-kos-1.jpg?dpl=dpl_BY7TrZQKuzkQ5PseorQMAAVfrV9b)

#### Tim Koschützki

Co-founder · Berlin, Germany · Show bio

[](https://x.com/tim%5Fkos)[](https://github.com/tim-kos)

Ensuring file integrity is crucial for developers, especially when handling sensitive data or distributing software. SHA384 hashing provides a robust method to verify that files haven't been altered or corrupted. Let's explore how you can implement SHA384 hashing in Ruby using the OpenSSL library.

<span aria-hidden="true" id="why-sha384"></span>

## Why SHA384?

SHA384 is part of the SHA-2 family, offering a secure hashing algorithm that generates a unique 384-bit (48-byte) hash. It's widely used for verifying file integrity, ensuring data hasn't been tampered with during transfers or storage.

SHA384 hashing enhances file security by:

* Detecting file corruption or unauthorized modifications.
* Providing a unique fingerprint for each file.
* Ensuring data integrity during transfers.
* Offering stronger security than SHA256 with minimal performance impact.

<span aria-hidden="true" id="setting-up-your-ruby-environment"></span>

## Setting up your Ruby environment

Ruby's OpenSSL integration comes built-in, but you'll need a proper Ruby installation. Here's how to set it up using rbenv:

<span aria-hidden="true" id="on-macos-or-linux-with-homebrew"></span>

### On macOS or Linux with homebrew

```bash
brew install rbenv
rbenv init
# Follow the printed Instructions to update your shell configuration

```

<span aria-hidden="true" id="on-linux-without-homebrew"></span>

### On Linux without homebrew

```bash
git clone https://github.com/rbenv/rbenv.git ~/.rbenv
cd ~/.rbenv && src/configure && make -C src
echo 'export PATH=\"$HOME/.rbenv/bin:$PATH\"' >> ~/.bashrc
~/.rbenv/bin/rbenv init
# Follow the printed Instructions to update your shell configuration

```

After installation, install Ruby:

```bash
rbenv install 3.2.2  # or latest stable version
rbenv global 3.2.2
ruby -v  # Verify installation

```

<span aria-hidden="true" id="hashing-files-with-ruby-and-openssl"></span>

## Hashing files with Ruby and openssl

Here's a robust implementation for hashing files using Ruby's built-in OpenSSL library:

```ruby
require 'openssl'

def sha384_hash(file_path)
  digest = OpenSSL::Digest.new('SHA384')
  File.open(file_path, 'rb') do |file|
    buffer = ""
    # Read file in chunks to handle large files efficiently
    digest.update(buffer) while file.read(8192, buffer)
  end
  digest.hexdigest
end

# Usage example with error handling
begin
  hash = sha384_hash('example.txt')
  puts \"SHA384 hash: #{hash}\"
rescue Errno::ENOENT
  puts \"Error: File not found\"
rescue => e
  puts \"Error: #{e.message}\"
end

```

This implementation:

* Reads the file in chunks (8KB at a time), efficiently handling large files without loading them entirely into memory.
* Uses binary mode (`'rb'`) for file reading to ensure consistent results across platforms.
* Includes proper error handling for common issues like missing files.

<span aria-hidden="true" id="verifying-file-integrity"></span>

## Verifying file integrity

To verify file integrity, compare the generated hash against a known good hash. It's crucial to use a constant-time comparison function to prevent timing attacks, where an attacker could deduce information about the hash by measuring the time it takes for the comparison to complete.

```ruby
require 'openssl'

# Constant-time comparison function
def secure_compare(a, b)
  # Ensure strings are of the same type and encoding for accurate byte comparison
  a = a.b unless a.encoding == Encoding::BINARY
  b = b.b unless b.encoding == Encoding::BINARY

  return false unless a.bytesize == b.bytesize

  l = a.unpack \"C*\"

  res = 0
  b.each_byte { |byte| res |= byte ^ l.shift }
  res == 0
end

# Assume sha384_hash function from previous example is defined
expected_hash = \"your_known_good_hash_here\" # Replace with the actual expected hash

begin
  file_hash = sha384_hash('example.txt')

  if secure_compare(file_hash, expected_hash)
    puts \"File integrity verified.\"
  else
    puts \"File integrity compromised!\"
  end
rescue Errno::ENOENT
  puts \"Error: File not found\"
rescue => e
  puts \"Error verifying file: #{e.message}\"
end

```

<span aria-hidden="true" id="cross-platform-considerations"></span>

## Cross-platform considerations

When verifying files across different operating systems, be aware of potential line-ending differences (CRLF on Windows vs. LF on macOS/Linux) that can affect hash values if files are read in text mode. Always use binary mode when reading files for hashing to ensure consistent results:

```ruby
# Always use binary mode ('rb') for consistent cross-platform results
File.open(file_path, 'rb') do |file|
  # Hashing logic here...
end

```

If you absolutely must compare hashes of text files generated on different platforms and cannot guarantee binary mode was used initially, you might consider normalizing line endings \_before\_hashing. However, the best practice is to always hash the file byte-for-byte using binary mode.

```ruby
# Example of normalizing line endings (use with caution)
def normalize_and_hash(file_path)
  content = File.read(file_path, mode: 'rb')
  # Normalize to LF line endings
  normalized = content.gsub(/\r\n?/, \"\n\")

  digest = OpenSSL::Digest.new('SHA384')
  digest.update(normalized)
  digest.hexdigest
end

```

<span aria-hidden="true" id="automating-file-verification"></span>

## Automating file verification

Automating file verification can streamline your workflow, especially when dealing with multiple files, such as during software distribution or data validation pipelines. Here's a script to automate verification for multiple files against a list of known hashes:

```ruby
require 'openssl'

# Assume sha384_hash and secure_compare functions are defined as above

files_to_verify = {
  'example.txt' => 'known_good_hash_for_example_txt',
  'another_file.dat' => 'known_good_hash_for_another_file'
  # Add more files and their expected hashes here
}

files_to_verify.each do |file, expected_hash|
  begin
    actual_hash = sha384_hash(file)
    if secure_compare(actual_hash, expected_hash)
      puts \"#{file}: Verified ✅\"
    else
      puts \"#{file}: Verification failed ❌ (Hash mismatch)\"
    end
  rescue Errno::ENOENT
    puts \"#{file}: Verification failed ❌ (File not found)\"
  rescue => e
    puts \"#{file}: Error - #{e.message} ❌\"
  end
end

```

<span aria-hidden="true" id="troubleshooting-common-issues"></span>

## Troubleshooting common issues

When working with SHA384 hashing in Ruby, you might encounter these common issues:

1. **Inconsistent hashes across platforms**: Ensure you're using binary mode (`'rb'`) when opening files for hashing. Line ending differences in text mode will alter the hash.
2. **Memory issues with large files**: Verify you're using the chunked reading approach (reading the file piece by piece) as shown in the `sha384_hash` example, rather than loading the entire file into memory.
3. **Incorrect hash comparisons**: Use a constant-time comparison function (`secure_compare`) to prevent timing side-channel attacks. Simple string comparison (`==`) can be vulnerable.
4. **Encoding issues**: While binary mode mitigates most encoding problems for hashing, be mindful if you manipulate file content as strings before hashing. Ensure consistent encoding.
5. **Performance concerns**: For extremely large files or high-throughput scenarios, native extensions or external tools might offer better performance, though Ruby's OpenSSL binding is generally efficient.

<span aria-hidden="true" id="best-practices-for-secure-file-handling-and-verification"></span>

## Best practices for secure file handling and verification

1. **Always use binary mode**: Read files in binary mode (`File.open(file_path, 'rb')`) for hashing to ensure consistency across platforms and prevent issues with line endings or character encodings.
2. **Process large files in chunks**: Avoid reading entire large files into memory. Use buffered reading (e.g., `file.read(chunk_size, buffer)`) to manage memory efficiently.
3. **Implement proper error handling**: Anticipate issues like file not found (`Errno::ENOENT`), permissions errors, or I/O errors, and handle them gracefully.
4. **Store hashes securely**: Keep the known good hashes separate from the files they verify. Store them in a secure database, configuration file, or signed manifest.
5. **Use constant-time comparison**: When verifying hashes, always use a constant-time string comparison function to prevent timing attacks.
6. **Keep libraries updated**: Ensure your Ruby installation and its OpenSSL library are up-to-date to benefit from the latest security patches.
7. **Consider the source of truth**: Establish a secure process for generating and distributing the initial "known good" hashes.

<span aria-hidden="true" id="using-sha384-with-transloadit"></span>

## Using SHA384 with Transloadit

Transloadit's Robot ecosystem includes the [🤖 /file/hash Robot](/docs/robots/file-hash.md)as part of our [Media Cataloging service](/services/media-cataloging.md). This Robotsupports various hashing algorithms including SHA384, allowing you to generate hashes as part of your file processing workflows. Here's an example Assembly Instruction:

```json
{
  "steps": {
    "hash": {
      "robot": "/file/hash",
      "use": ":original",
      "algorithm": "sha384"
    }
  }
}

```

By integrating SHA384 hashing into your Ruby applications, you add a strong layer of security, ensuring your files remain integral and tamper-proof throughout their lifecycle.

\#ruby#openssl#file-integrity#secure-hashing#file-verification#media-cataloging-service

### 👩‍💻 Join 20k+ developers

Sign up for our [monthly newsletter](/newsletters.md) to receive direct links to 3 exclusive tech — and 2 product updates. No less, no more.

Your email:

Get access

## File uploading and encoding. Made simple.

Transloadit streamlines file handling for developers, trusted by brands like Coursera and The New York Times. We’re known for a reliable API, top-notch support, and a strong commitment to open source, with projects like [Uppy⁠](https://uppy.io) and [Tus⁠](https://tus.io) setting standards in file processing.

[Sign up](/c/)[Book a Demo](https://survey.typeform.com/to/kRg47Xi5)

No credit card needed · 5 GB included in the free plan

Cancel anytime
