Build Status Coverity Scan Build Status

Transcryptor provides utility functions to help migrate records encrypted with attr_encrypted from one encryption configuration to another.

Installation

Add this line to your application’s Gemfile:

gem 'transcryptor', github: 'riboseinc/transcryptor'

And then execute:

bundle

Or install it yourself as:

gem install transcryptor

Usage

Given:

  1. you have already set up tables to be encrypted with attr_encrypted,

  2. you’d like to migrate your columns from:

    (algorithm1, iv1, salt1, key1)

    to

    (algorithm2, iv2, salt2, key2)

    where:

    1. algorithm can be aes-256-cbc, aes-256-gcm or any others that attr_encrypted supports,

    2. salt can be optional,

    3. iv can be optional (!!).

Then:

  1. Create a migration like so:

    class ReencryptUsersAndDocumentsWithNewKeys < ActiveRecord::Migration
    
      def transcryptor
        Transcryptor.init(self)
      end
    
      # +keyifier+ mirrors the functionality provided by the :key Proc in
      # attr_encrypted.
      # NOTE: Has to return the entire Hash.
      #
      def old_keyifier
        -> opts {
          opts[:key] = ENV['old_master_encryption_key'] + opts[:key]
          opts
        }
      end
    
      def new_keyifier
        -> opts {
          opts[:key] = ENV['new_master_encryption_key'] + opts[:key]
          opts
        }
      end
    
      # Define the current DB schema for Transcryptor.
      # Format:
      # {
      #   <table_i>: {
      #     id_column: <the column name for record id>,
      #     columns: {
      #       <column_i>: {
      #         prefix: <attr_encrypted prefix string (optional)>,
      #         suffix: <attr_encrypted suffix string (optional)>,
      #         key: <the column storing the key to encrypt column_i>,
      #       },
      #     }
      #   },
      # }
      #
      def table_column_spec
        {
          users:  {
            id_column: :id,
            columns: {
              email: {
                prefix: 'encrypted_',
                key: :ekey,
              },
              birthday: {
                prefix: 'encrypted_',
                key: :ekey,
              },
            }
          },
          documents:  {
            id_column: :id,
            columns: {
              passphrase: {
                prefix: 'secret_',
                key: :enc_key,
              },
            }
          },
        }
      end
    
      #
      # Run transcryptor.updown_migrate() for both #up and #down.
      # Give it:
      # - the table-column specification,
      # - the old encryption configuration (at least any one of: algorithm, iv,
      # salt, key)
      # - the new encryption configuration (at least any one of: algorithm, iv,
      # salt, key)
      # - optional params-modifying Proc before passing to Encryptor.decrypt (used
      # by attr_encrypted)
      # - optional params-modifying Proc before passing to Encryptor.encrypt (used
      # by attr_encrypted)
      #
      def up
        transcryptor.updown_migrate(
          table_column_spec,
          {
            algorithm:      'aes-256-cbc',
            decode64_value: true,
          }, {
            algorithm:      'aes-256-gcm',
            encode64_iv:    true,
            encode64_value: true,
            iv: true,
          },
          old_keyifier,
          new_keyifier,
        )
      end
    
      def down
        transcryptor.updown_migrate(
          table_column_spec,
          {
            algorithm:      'aes-256-gcm',
            decode64_iv:    true,
            decode64_value: true,
          }, {
            algorithm:      'aes-256-cbc',
            iv:             false,
            salt:           false,
            encode64_value: true,
            insecure_mode:  true,
          },
          new_keyifier,
          old_keyifier,
        )
      end
  2. Run bundle exec db:migrate

  3. Done!

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/riboseinc/transcryptor. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

License

The gem is available as open source under the terms of the MIT License.