Reencryptor Gem 0.0.0 Released

01 March 2016 on . 6 minutes to read

Jefferson's Wheel Cipher aka M-94

Make Your Legacy App More Secure With Reencryptor

For those who have been charged with maintaining an old Ruby on Rails app, there’s an excellent chance that if you’re storing sensititive information in your database, you’re using the attr_encrypted gem. Old versions of this gem have a security flaw which new versions of the gem address. This flaw is that all rows in the database use the same salt and initialization vector. The new version of attr_encrypted will use mode: :per_attribute_iv by default. One of the applications in my case uses the legacy encryption scheme which makes it much quicker for a compromised app to yield up all its valuable information. Making the internet and internet connected applications more secure makes life better for everyone but thieves. Save yourself future trouble, and read on about the new gem I’ve created called Reencryptor which makes upgrading your legacy attr_encrypted fields to the new, more secure version a breeze.

How It Works: Put Reencryptor on Your App Right Now

I extracted the basic lib code I made for my previously unsecure app into a gem last night. This is actually my inaugural gem, so I’m sure I’ll run across some best practice gem release behaviour in the future. As of this posting, the gem is version 0.0.0. In it’s current state, it doesn’t take predefined pre/postfix words for encrypted fields into account, but works excellently on a vanilla attr_encrypted install. The subheadings below denote the steps to take to migrate your app using this gem. The following transitions the weakest encryption scheme to the strongest.

Install Reencryptor

Add the following to your Gemfile

gem 'reencryptor'

Run this:

bundle install

Generate the migrations

You’ll prep this command by doing the following:

  • Find all classes and associated legacy encryptions you’ll migrate to per attribute encryption.
  • Create a hash (I use the variable h in the example)
    • Each key is the name of a class
    • The value for each key is an array of fields you’re migrating

Boot up a rails console for your app, and enter:

Reencryptor::GlobalToPerAttributeIVSalt::Migrator.new(classes_hash: h).generate

Given I have the class Person with encrypted fields :social_security, :personal_secret and class Bank with encrypted field :vault_combination I’d enter the following string of commands to generate my migrations:

h = {
    "Person": ["social_security", "personal_secret"],
    "Bank":   ["vault_combination"]
  }
Reencryptor::GlobalToPerAttributeIVSalt::Migrator.new(classes_hash: h).generate

This would then output the following into your console. Copy and paste it into a new migration.

rename_column :people, :encrypted_social_security, :encrypted_social_security_old
add_column :people, :encrypted_social_security, :string
add_column :people, :encrypted_social_security_iv, :string
add_column :people, :encrypted_social_security_salt, :string
rename_column :people, :encrypted_personal_secret, :encrypted_personal_secret_old
add_column :people, :encrypted_personal_secret, :string
add_column :people, :encrypted_personal_secret_iv, :string
add_column :people, :encrypted_personal_secret_salt, :string
rename_column :banks, :encrypted_vault_combination, :encrypted_vault_combination_old
add_column :banks, :encrypted_vault_combination, :string
add_column :banks, :encrypted_vault_combination_iv, :string
add_column :banks, :encrypted_vault_combination_salt, :string

This just renames your original encrypted column with “_old” appended to it, and generates the new columns you’ll need for per attribute encryption.

Update Your Models

After you migrate, you’ll change your models to use the correct encryption schemes.

Given an original setup of:

class Person
  attr_encrypted :social_security, key: "your_encryption_key"
  attr_encrypted :personal_secret, key: "your_encryption_key"
end

class Bank
  attr_encrypted :vault_combination, key: "your_encryption_key"
end

Change it to the following:

class Person
  attr_encrypted :social_security_old, key: "your_encryption_key"
  attr_encrypted :social_security, key: "your_encryption_key", mode: :per_attribute_iv_and_salt
  attr_encrypted :personal_secret_old, key: "your_encryption_key"
  attr_encrypted :personal_secret, key: "your_encryption_key", mode: :per_attribute_iv_and_salt
end

class Bank
  attr_encrypted :vault_combination_old, key: "your_encryption_key"
  attr_encrypted :vault_combination, key: "your_encryption_key", mode: :per_attribute_iv_and_salt
end

Run Reencryptor

Then, run the following code. I recommend testing it with a copy of your production data first in your console, and then to run it in production via a rails migration. This way you can test to make sure everything gets reencrypted correctly, and ensure that it runs ONLY once on production. Don’t run it more than once.

Reencryptor::GlobalToPerAttributeIVSalt::GlobalToPerAttributeEncryption.new(classes_hash: h).perform

That will actually migrate the old data to the new encryption scheme. After that, ensure the old columns are dropped in a third migration and you remove the encrypted_field_old attributes from your model. Your final migration involving the Person and Bank classes would look like this:

remove_column :people, :encrypted_social_security_old
remove_column :people, :encrypted_personal_secret_old
remove_column :banks, :encrypted_vault_combination_old

And your model classes will look like this:

class Person
  attr_encrypted :social_security, key: "your_encryption_key", mode: :per_attribute_iv_and_salt
  attr_encrypted :personal_secret, key: "your_encryption_key", mode: :per_attribute_iv_and_salt
end

class Bank
  attr_encrypted :vault_combination, key: "your_encryption_key", mode: :per_attribute_iv_and_salt
end

That’s it; your class is now migrated.

Notes:

This version of the gem only includes migration from classic mode: :single_iv_and_salt to mode: :per_attribute_iv_and_salt. :per_attribute_iv_and_salt is deprecated in attr_encrypted v2.0.0. From the gem’s github page:

Lastly, while the :per_attribute_iv_and_salt mode is more secure than :per_attribute_iv mode because it uses a unique key per record, it uses a PBKDF function which introduces a huge performance hit (175x slower by my benchmarks). There are other ways of deriving a unique key per record that would be much faster.

There will be more gem versions in the future to handle migrations to the new standard as well as other improvements to take into account your app’s attr_encrypted config.


If you enjoy having free time and the peace of mind that a professional is on your side, then you’d love to have me work on your project.

Contact or view a list of available services to see how I’ll make your life better, easier and bring satisfaction back into you running your business.