Jeremy
Jeremy

Reputation: 1002

Why is `Rails.application.key_generator.generate_key` generating different output?

Lately a piece of code broke and I realised that my calls to OpenSSL::HMAC.hexdigest('SHA1', Rails.application.key_generator.generate_key('abcdef123456'), 'something') generated different output on different machine running the function.

I originally though this was due to a change in OpenSSL, but running OpenSSL::HMAC.hexdigest('SHA1', 'abcdef123', 'something') lead to the same result on all machines.

Turns out that Rails.application.key_generator.generate_key('abcdef123456') returns different values on different machines.

Running locally, I obtain a different results that on the server.

Same Ruby version, same Rails version, the only difference is the platform (x86_64-darwin21 vs x86_64-linux).

Shouldn't Rails.application.key_generator.generate_key always return the same results?

Otherwise the code will break if it migrates to another machine.

Upvotes: 1

Views: 407

Answers (1)

anothermh
anothermh

Reputation: 10536

I have tested this in three different Linux distributions, each using a different version of OpenSSL. I am unable to reproduce the issue that you have described.

You said that there were two commands that you ran:

  • OpenSSL::HMAC.hexdigest('SHA1', 'abcdef123', 'something') which you said returned the same value on every machine
  • OpenSSL::HMAC.hexdigest('SHA1', Rails.application.key_generator.generate_key('abcdef123456'), 'something') which you said returned different values on each machine

I believe that the cause of the latter returning different values is that each machine is using a different secret_key_base value. The only unique element of generate_key is @secret which is the value of Rails.application.secret_key_base.

I recommend that you double-check:

  1. That every machine is running in the same environment (RAILS_ENV)
  2. That every machine is using the same secret_key_base value for that environment

The only way that I've been able to get different values for each is to change the secret_key_env value. This value is set automatically in test and development environments and can be set in a variety of ways for other environments. You can check the value in the Rails console with Rails.application.secret_key_base.

Below you can find the steps to validate that different versions of OpenSSL have no impact on the value generated.

Alpine 3.17.0 and OpenSSL 3.0.7

docker run -it alpine:3.17.0 sh
apk add build-base libc6-compat openssl openssl-dev readline readline-dev tzdata zlib zlib-dev
wget https://cache.ruby-lang.org/pub/ruby/3.1/ruby-3.1.3.tar.gz && tar xvf ruby-3.1.3.tar.gz && cd ruby-3.1.3 && ./configure --with-openssl-dir=/usr && make && make install

openssl version
# OpenSSL 3.0.7 1 Nov 2022 (Library: OpenSSL 3.0.7 1 Nov 2022)

ruby -ropenssl -e 'puts OpenSSL::OPENSSL_VERSION; puts OpenSSL::OPENSSL_VERSION_NUMBER'
# OpenSSL 3.0.7 1 Nov 2022
# 805306480

cd /
gem install rails
rails new foo --skip-git --skip-keeps --skip-mailer --skip-mailbox --skip-text --skip-active-record --skip-active-job --skip-active-storage --skip-action-cable --skip-asset-pipeline --skip-javascript --skip-hotwire --skip-jbuilder --skip-test --skip-system-test --api --minimal
cd foo
export RAILS_ENV=production
export SECRET_KEY_BASE="eedfd5f234fbca535134ae551981d319df449c096c9bcd041b01ef77b7810eb4e480a7671c2b8788adb8782f950e9684ff582c5135d76ff088795d284f5917ff"
rails console
OpenSSL::HMAC.hexdigest('SHA1', Rails.application.key_generator.generate_key('abcdef123456'), 'something')
=> "f1ba53b65a27d443ae8bc60fcc248230c651032f"

Alpine 3.16.3 and OpenSSL 1.1.1s

docker run -it alpine:3.16.3 sh
apk add build-base libc6-compat openssl openssl-dev readline readline-dev tzdata zlib zlib-dev
wget https://cache.ruby-lang.org/pub/ruby/3.1/ruby-3.1.3.tar.gz && tar xvf ruby-3.1.3.tar.gz && cd ruby-3.1.3 && ./configure --with-openssl-dir=/usr && make && make install

openssl version
# OpenSSL 1.1.1s  1 Nov 2022

ruby -ropenssl -e 'puts OpenSSL::OPENSSL_VERSION; puts OpenSSL::OPENSSL_VERSION_NUMBER'
# OpenSSL 1.1.1s  1 Nov 2022
# 269488447

cd /
gem install rails
rails new foo --skip-git --skip-keeps --skip-mailer --skip-mailbox --skip-text --skip-active-record --skip-active-job --skip-active-storage --skip-action-cable --skip-asset-pipeline --skip-javascript --skip-hotwire --skip-jbuilder --skip-test --skip-system-test --api --minimal
cd foo
export RAILS_ENV=production
export SECRET_KEY_BASE="eedfd5f234fbca535134ae551981d319df449c096c9bcd041b01ef77b7810eb4e480a7671c2b8788adb8782f950e9684ff582c5135d76ff088795d284f5917ff"
rails console
OpenSSL::HMAC.hexdigest('SHA1', Rails.application.key_generator.generate_key('abcdef123456'), 'something')
=> "f1ba53b65a27d443ae8bc60fcc248230c651032f"

Debian 11.5 and OpenSSL 1.1.1n

docker run -it debian:11.5 sh
apt update && apt install -y build-essential libreadline-dev libreadline8 openssl libssl-dev tzdata wget zlib1g zlib1g-dev
wget https://cache.ruby-lang.org/pub/ruby/3.1/ruby-3.1.3.tar.gz && tar xvf ruby-3.1.3.tar.gz && cd ruby-3.1.3 && ./configure --with-openssl-dir=/usr && make && make install

openssl version
# OpenSSL 1.1.1n  15 Mar 2022

ruby -ropenssl -e 'puts OpenSSL::OPENSSL_VERSION; puts OpenSSL::OPENSSL_VERSION_NUMBER'
# OpenSSL 1.1.1n  15 Mar 2022
# 269488367

cd /
gem install rails
rails new foo --skip-git --skip-keeps --skip-mailer --skip-mailbox --skip-text --skip-active-record --skip-active-job --skip-active-storage --skip-action-cable --skip-asset-pipeline --skip-javascript --skip-hotwire --skip-jbuilder --skip-test --skip-system-test --api --minimal
cd foo
export RAILS_ENV=production
export SECRET_KEY_BASE="eedfd5f234fbca535134ae551981d319df449c096c9bcd041b01ef77b7810eb4e480a7671c2b8788adb8782f950e9684ff582c5135d76ff088795d284f5917ff"
rails console
OpenSSL::HMAC.hexdigest('SHA1', Rails.application.key_generator.generate_key('abcdef123456'), 'something')
=> "f1ba53b65a27d443ae8bc60fcc248230c651032f"

Upvotes: 2

Related Questions