Skip to content

ActiveRecord Encryption initializes with SHA1 and then new Rails 7 default switches to SHA256 #42922

@boomer196

Description

@boomer196

ActiveRecord::Railtie initialization fires before ActiveSupport::Railtie

In Rails::Application::Configuration#load_defaults(7.0) it sets active_support.key_generator_hash_digest_class = OpenSSL::Digest::SHA256

Then in the ActiveSupport::Railtie it sets ActiveSupport::KeyGenerator.hash_digest_class = active_support.key_generator_hash_digest_class

However, the ActiveRecord::Railtie configures ActiveRecord::Encryption before this configuration change happens.

What this causes is the ActiveRecord::Encryption::Configurable.configure to set the context.key_provider = ActiveRecord::Encryption::DerivedSecretKeyProvider.new(primary_key), which uses the ActiveSupport::KeyGenerator from ActiveRecord::Encryption::KeyGenerator#derive_key_from method. At this point it uses the classes default hash_digest_class of OpenSSL::Digest::SHA1.

After ActiveSupport::Railtie runs the ActiveSupport::KeyGenerator.hash_digest_class changes to OpenSSL::Digest::SHA256

I am not sure what the best fix is and there may be others, but a couple I can think of are:

  • ActiveRecord::Encryption is "explicit" about how it configures/uses the ActiveSupport::KeyGenerator and possibly adds additional options for hash_digest_class and iterations. This removes the dependency. It also allows the database to live past future changes to ActiveSupport defaults.
  • ActiveSupport::KeyGenerator changes it's class default to be OpenSSL::Digest::SHA256 and the new_framework_defaults_7_0.rb file sets it back to OpenSSL::Digest::SHA1

Steps to reproduce

  1. Create a new rails 7 project using all rails 7 defaults (removed new_framework_defaults_7_0.rb file and application.rb changes to config.load_defaults 7.0)
  2. Configure Encryption by running bin/rails db:encryption:init and adding the generated credentials (bin/rails credentials:edit)
Add this entry to the credentials of the target environment:

active_record_encryption:
  primary_key: nYeEQD0EqOKXeRMFcUq7BX6goxGt0hPq
  deterministic_key: aduCGCnZWFtRIN3xc8CiM15kZKt2Az8T
  key_derivation_salt: fidtmePZxQNmR6Gc4Yv7j1lko06ISaBu
  1. Start a rails console (bin/rails console)
ActiveRecord::Encryption.key_provider.encryption_key.secret
primary_key = "nYeEQD0EqOKXeRMFcUq7BX6goxGt0hPq"
key_derivation_salt = "fidtmePZxQNmR6Gc4Yv7j1lko06ISaBu"
ActiveRecord::Encryption::DerivedSecretKeyProvider.new(primary_key).encryption_key.secret
OpenSSL::PKCS5.pbkdf2_hmac(primary_key, key_derivation_salt, 2**16, 32, OpenSSL::Digest::SHA1.new)
OpenSSL::PKCS5.pbkdf2_hmac(primary_key, key_derivation_salt, 2**16, 32, OpenSSL::Digest::SHA256.new)

Expected behavior

ActiveRecord::Encryption.key_provider.encryption_key.secret
\xE547G\xE7\x99?\x95\xAEX\xE1\xEFS\xE9p\x87}\x93\xF8\x8A\x9Ch\x80\x95#Bee\x95\nD\x7F

Actual behavior

ActiveRecord::Encryption.key_provider.encryption_key.secret
\x8B\x17k\xA1\xC9:a\x05>N\x10\xE4\eYD\xCFUh\x10\x9Ep\x89\x10\x15vt\xE0\x94\xAAN

ActiveRecord::Encryption::DerivedSecretKeyProvider.new(primary_key).encryption_key.secret
\xE547G\xE7\x99?\x95\xAEX\xE1\xEFS\xE9p\x87}\x93\xF8\x8A\x9Ch\x80\x95#Bee\x95\nD\x7F

OpenSSL::PKCS5.pbkdf2_hmac(primary_key, key_derivation_salt, 2**16, 32, OpenSSL::Digest::SHA1.new)
\x8B\x17k\xA1\xC9:a\x05>N\x10\xE4\eYD\xCFUh\x10\x9Ep\x89\x10\x15vt\xE0\x94\xAAN

OpenSSL::PKCS5.pbkdf2_hmac(primary_key, key_derivation_salt, 2**16, 32, OpenSSL::Digest::SHA256.new)
\xE547G\xE7\x99?\x95\xAEX\xE1\xEFS\xE9p\x87}\x93\xF8\x8A\x9Ch\x80\x95#Bee\x95\nD\x7F

System configuration

Rails version: 7.0 (gem 'rails', github: 'rails/rails', branch: 'main')

Ruby version: ruby 2.7.2p137

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions