Skip to content

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

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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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