Encrypt, decrypt using Rails

Ruby on-RailsEncryption

Ruby on-Rails Problem Overview


I saw a while ago the possibility to decrypt and encrypt strings in rails without including any library, but I can't find the blog post.

I want to be able to encrypt and decrypt strings without including anything. Using the same key has for the everything else in rails, signed cookies for example.

Any ideas?

Ruby on-Rails Solutions


Solution 1 - Ruby on-Rails

You mean this one?: ActiveSupport::MessageEncryptor. Here is the way to reuse Rails 5+ on Ruby 2.4+ application's secret:

crypt = ActiveSupport::MessageEncryptor.new(Rails.application.secrets.secret_key_base[0..31])
encrypted_data = crypt.encrypt_and_sign('my confidental data')

And encrypted data can be decrypted with:

decrypted_back = crypt.decrypt_and_verify(encrypted_data)

The above example uses first 32 characters of Rails app secret as an encryption and signing key, because the default MessageEncryptor cipher aes-256-gcm requires exactly 256 bit key. By convention, during the app creation, Rails generates a secret as a string of 128 hex digits.

Important! Ruby 2.4 upgrade note

Before Ruby 2.4 and Rails 5 there was no key size restriction and it was popular to just past full secret into the encryptor initializer:

# pre-2.4
crypt = ActiveSupport::MessageEncryptor.new(Rails.application.secrets.secret_key_base)

Internally the encryption algorithm (AES256GCM provided by OpenSSL) was using only 32 characters from the key, however the signing algorithm (SHA1) was consuming all 128 characters.

Therefore, while upgrading an app from pre-2.4 Ruby, and where the app previously encrypted the data with an unrestricted key size, the MessageEncryptor must get a full secret in the second parameter to avoid ActiveSupport::MessageVerifier::InvalidSignature on the legacy data decryption:

# post-2.4 upgrade
crypt = ActiveSupport::MessageEncryptor.new(Rails.application.secrets.secret_key_base[0..31], Rails.application.secrets.secret_key_base)

Solution 2 - Ruby on-Rails

Rails 5 requires that the key be 32 bytes.

Edit to Rails 4 answer that works for Rails 5:

 key = SecureRandom.random_bytes(32)
 crypt = ActiveSupport::MessageEncryptor.new(key) 
 encrypted_data = crypt.encrypt_and_sign('my confidental data')

Decrypt:

 decrypted_back = crypt.decrypt_and_verify(encrypted_data)

Solution 3 - Ruby on-Rails

Rails 5 update:

crypt = ActiveSupport::MessageEncryptor.new(Rails.application.secrets.secret_key_base[0..31])
encrypted_data = crypt.encrypt_and_sign('my confidental data')

Rails 5.x Needs a key of exactly 32 bytes.

To verify a previously signed message with a longer key:

crypt = ActiveSupport::MessageEncryptor.new(Rails.application.secrets.secret_key_base[0..31], Rails.application.secrets.secret_key_base)
encrypted_data = crypt.encrypt_and_sign('my confidental data')

as described in the docu

and the discussion on this change

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLinus OleanderView Question on Stackoverflow
Solution 1 - Ruby on-RailsgertasView Answer on Stackoverflow
Solution 2 - Ruby on-Railsguero64View Answer on Stackoverflow
Solution 3 - Ruby on-RailsestaniView Answer on Stackoverflow