Baike.dev
All toolsOnline toolsAI codingTrendingOpen sourceNewsSubmit
Log in
< Back to tools
A

attr_encrypted

> 编程语言
Open source

Generates attr_accessors that encrypt and decrypt attributes

2.0K stars0 likes0 views
WebsiteGitHub

About

Generates attr_accessors that encrypt and decrypt attributes

attr_encrypted

Generates attr_accessors that transparently encrypt and decrypt attributes.

It works with ANY class, however, you get a few extra features when you're using it with ActiveRecord or Sequel.

Installation

Add attr_encrypted to your gemfile:

ruby
  gem "attr_encrypted"

Then install the gem:

bash
  bundle install

Usage

If you're using an ORM like ActiveRecord or Sequel, using attr_encrypted is easy:

ruby
  class User
    attr_encrypted :ssn, key: 'This is a key that is 256 bits!!'
  end

If you're using a PORO, you have to do a little bit more work by extending the class:

ruby
  class User
    extend AttrEncrypted
    attr_accessor :name
    attr_encrypted :ssn, key: 'This is a key that is 256 bits!!'

    def load
      # loads the stored data
    end

    def save
      # saves the :name and :encrypted_ssn attributes somewhere (e.g. filesystem, database, etc)
    end
  end

  user = User.new
  user.ssn = '123-45-6789'
  user.ssn # returns the unencrypted object ie. '123-45-6789'
  user.encrypted_ssn # returns the encrypted version of :ssn
  user.save

  user = User.load
  user.ssn # decrypts :encrypted_ssn and returns '123-45-6789'

Encrypt/decrypt attribute class methods

Two class methods are available for each attribute: User.encrypt_email and User.decrypt_email. They accept as arguments the same options that the attr_encrypted class method accepts. For example:

ruby
  key = SecureRandom.random_bytes(32)
  iv = SecureRandom.random_bytes(12)
  encrypted_email = User.encrypt_email('[email protected]', iv: iv, key: key)
  email = User.decrypt_email(encrypted_email, iv: iv, key: key)

The attr_encrypted class method is also aliased as attr_encryptor to conform to Ruby's attr_ naming conventions. I should have called this project attr_encryptor but it was too late when I realized it ='(.

attr_encrypted with database persistence

By default, attr_encrypted uses the :per_attribute_iv encryption mode. This mode requires a column to store your cipher text and a column to store your IV (initialization vector).

Create or modify the table that your model uses to add a column with the encrypted_ prefix (which can be modified, see below), e.g. encrypted_ssn via a migration like the following:

ruby
  create_table :users do |t|
    t.string :name
    t.string :encrypted_ssn
    t.string :encrypted_ssn_iv
    t.timestamps
  end

You can use a string or binary column type. (See the encode option section below for more info)

If you use the same key for each record, add a unique index on the IV. Repeated IVs with AES-GCM (the default algorithm) allow an attacker to recover the key.

ruby
  add_index :users, :encrypted_ssn_iv, unique: true

Specifying the encrypted attribute name

By default, the encrypted attribute name is encrypted_#{attribute} (e.g. attr_encrypted :email would create an attribute named encrypted_email). So, if you're storing the encrypted attribute in the database, you need to make sure the encrypted_#{attribute} field exists in your table. You have a couple of options if you want to name your attribute or db column something else, see below for more details.

attr_encrypted options

Options are evaluated

All options will be evaluated at the instance level. If you pass in a symbol it will be passed as a message to the instance of your class. If you pass a proc or any object that responds to :call it will be called. You can pass in the instance of your class as an argument to the proc. Anything else will be returned. For example:

Symbols representing instance methods

Here is an example class that uses an instance method to determines the encryption key to use.

ruby
  class User
    attr_encrypted :email, key: :encryption_key

    def encryption_key
      # does some fancy logic and returns an encryption key
    end
  end
Procs

Here is an example of passing a proc/lambda object as the :key option as well:

ruby
  class User
    attr_encrypted :email, key: proc { |user| user.key }
  end

Default options

The following are the default options used by attr_encrypted:

ruby
  prefix:            'encrypted_',
  suffix:            '',
  if:                true,
  unless:            false,
  encode:            false,
  encode_iv:         true,
  encode_salt:       true,
  default_encoding:  'm',
  marshal:           false,
  marshaler:         Marshal,
  dump_method:       'dump',
  load_method:       'load',
  encryptor:         Encryptor,
  encrypt_method:    'encrypt',
  decrypt_method:    'decrypt',
  mode:              :per_attribute_iv,
  algorithm:         'aes-256-gcm',
  allow_empty_value: false

All of the aforementioned options are explained in depth below.

Additionally, you can specify default options for all encrypted attributes in your class. Instead of having to define your class like this:

ruby
  class User
    attr_encrypted :email, key: 'This is a key that is 256 bits!!', prefix: '', suffix: '_crypted'
    attr_encrypted :ssn, key: 'a different secret key', prefix: '', suffix: '_crypted'
    attr_encrypted :credit_card, key: 'another secret key', prefix: '', suffix: '_crypted'
  end

You can simply define some default options like so:

ruby
  class User
    attr_encrypted_options.merge!(prefix: '', :suffix => '_crypted')
    attr_encrypted :email, key: 'This is a key that is 256 bits!!'
    attr_encrypted :ssn, key: 'a different secret key'
    attr_encrypted :credit_card, key: 'another secret key'
  end

This should help keep your classes clean and DRY.

The :attribute option

You can simply pass the name of the encrypted attribute as the :attribute option:

ruby
  class User
    attr_encrypted :email, key: 'This is a key that is 256 bits!!', attribute: 'email_encrypted'
  end

This would generate an attribute named email_encrypted

The :prefix and :suffix options

If you don't like the encrypted_#{attribute} naming convention then you can specify your own:

ruby
  class User
    attr_encrypted :email, key: 'This is a key that is 256 bits!!', prefix: 'secret_', suffix: '_crypted'
  end

This would generate the following attribute: secret_email_crypted.

The :key option

The :key option is used to pass in a data encryption key to be used with whatever encryption class you use. If you're using Encryptor, the key must meet minimum length requirements respective to the algorithm that you use; aes-256 requires a 256 bit key, etc. The :key option is not required (see custom encryptor below).

Unique keys for each attribute

You can specify unique keys for each attribute if you'd like:

ruby
  class User
    attr_encrypted :email, key: 'This is a key that is 256 bits!!'
    attr_encrypted :ssn, key: 'a different secret key'
  end

It is recommended to use a symbol or a proc for the key and to store information regarding what key was used to encrypt your data. (See below for more details.)

The :if and :unless options

There may be times that you want to only encrypt when certain conditions are met. For example maybe you're using rails and you don't want to encrypt attributes when you're in development mode. You can specify conditions like this:

ruby
  class User < ActiveRecord::Base
    attr_encrypted :email, key: 'This is a key that is 256 bits!!', unless: Rails.env.development?
    attr_encrypted :ssn, key: 'This is a key that is 256 bits!!', if: Rails.env.development?
  end

You can specify both :if and :unless options.

The :encryptor, :encrypt_method, and :decrypt_method options

The Encryptor class is used by default. You may use your own custom encryptor by specifying the :encryptor, :encrypt_method, and :decrypt_method options.

Lets suppose you'd like to use this custom encryptor class:

ruby
  class SillyEncryptor
    def self.silly_encrypt(options)
      (options[:value] + options[:secret_key]).reverse
    end

    def self.silly_decrypt(options)
      options[:value].reverse.gsub(/#{options[:secret_key]}$/, '')
    end
  end

Simply set up your class like so:

ruby
  class User
    attr_encrypted :email, secret_key: 'This is a key that is 256 bits!!', encryptor: SillyEncryptor, encrypt_method: :silly_encrypt, decrypt_method: :silly_decrypt
  end

Any options that you pass to attr_encrypted will be passed to the encryptor class along with the :value option which contains the string to encrypt/decrypt. Notice that the above example uses :secret_key instead of :key. See encryptor for more info regarding the default encryptor class.

The :mode option

The mode options allows you to specify in what mode your data will be encrypted. There are currently three modes: :per_attribute_iv, :per_attribute_iv_and_salt, and :single_iv_and_salt.

NOTE: :per_attribute_iv_and_salt and :single_iv_and_salt modes are deprecated and will be removed in the next major release.

The :algorithm option

The default Encryptor class uses the standard ruby OpenSSL library. Its default algorithm is aes-256-gcm. You can modify this by passing the :algorithm option to the attr_encrypted call like so:

ruby
  class User
    attr_encrypted :email, key: 'This is a key that is 256 bits!!', algorithm: 'aes-256-cbc'
  end

To view a list of all cipher algorithms that are supported on your platform, run the following code in your favorite Ruby REPL:

ruby
  require 'openssl'
  puts OpenSSL::Cipher.ciphers

See Encryptor for more information.

The :encode, :encode_iv, :encode_salt, and :default_encoding options

You're probably going to be storing your encrypted attributes somehow (e.g. filesystem, database, etc). You can simply pass the :encode option to automatically encode/decode when encrypting/decrypting. The default behavior assumes that you're using a string column type and will base64 encode your cipher text. If you choose to use the binary column type then encoding is not required, but be sure to pass in false with the :encode option.

ruby
  class User
    attr_encrypted :email, key: 'some secret key', encode: true, encode_iv: true, encode_salt: true
  end

The default encoding is m (base64). You can change this by setting encode: 'some encoding'. See Array#pack for more encoding options.

The :marshal, :dump_method, and :load_method options

You may want to encrypt objects other than strings (e.g. hashes, arrays, etc). If this is the case, simply pass the :marshal option to automatically marshal when encrypting/decrypting.

ruby
  class User
    attr_encrypted :credentials, key: 'some secret key', marshal: true
  end

You may also optionally specify :marshaler, :dump_method, and :load_method if you want to use something other than the default Marshal object.

The :allow_empty_value option

You may want to encrypt empty strings or nil so as to not reveal which records are populated and which records are not.

ruby
  class User
    attr_encrypted :credentials, key: 'some secret key', marshal: true, allow_empty_value: true
  end

ORMs

ActiveRecord

If you're using this gem with ActiveRecord, you get a few extra features:

Default options

The :encode option is set to true by default.

Dynamic find_by_ and scoped_by_ methods

Let's say you'd like to encrypt your user's email addresses, but you also need a way for them to login. Simply set up your class like so:

ruby
  class User < ActiveRecord::Base
    attr_encrypted :email, key: 'This is a key that is 256 bits!!'
    attr_encrypted :password, key: 'some other secret key'
  end

You can now lookup and log

Issues· 0 open

View all issuesOpen on GitHub

No open issues yet, or sync has not completed.

> Tags

Ruby

No comments yet. Be the first to share.

> Details

PublishedAug 1, 2026
UpdatedSep 17, 2026
Category编程语言
PricingOpen source

> Related tools

T
TypeScript
JavaScript 的超集,为前端与全栈提供静态类型
P
Python
通用编程语言,广泛用于 Web、数据与 AI
G
Go
Google 推出的简洁高效系统语言