I would like to encrypt and decrypt one attribute string value of a model by using AES algorithm.
I am wondering in Rails, what is the easiest way to have it? Is there any AES gem library which can be used directly? And how to use it?
Basically I need some guideline on how to apply AES encryption/decryption in Rails app.
------- update -------
I just notice that there is AES gem. If I add this gem into my GemFile, how can I use it in my application for encryption & decryption?
Make a module in your app and include this where you want to call the module method:
config.autoload_paths += %W(#{config.root}/lib)
encrytion_algo.rb
require 'openssl'
require 'base64'
module EncrytionAlgo
  def self.included(base)
    base.extend self
  end
  def cipher
    OpenSSL::Cipher::Cipher.new('aes-256-cbc')  # ('aes-256-cbc')
  end
  def cipher_key
    'jabcderfghfhfddd!'
  end
  def decrypt(value)
    c = cipher.decrypt
    c.key = Digest::SHA256.digest(cipher_key)
    c.update(Base64.decode64(value.to_s)) + c.final
  end
  def encrypt(value)
    c = cipher.encrypt
    c.key = Digest::SHA256.digest(cipher_key)
    Base64.encode64(c.update(value.to_s) + c.final)
  end
end
Inside ApplicationController include above file  include MyModule
Now you can use encrypt and decrypt method from any controller:
encrypt("This is a text")
==> "h0RGuW5m3Wk9AAspik9ZXVysOcy2IeQrhQDn85mdo5I=%0A"
decrypt("h0RGuW5m3Wk9AAspik9ZXVysOcy2IeQrhQDn85mdo5I=%0A")
==> "This is a text"
I stumbled the same problem and created a simple model concern (rails 5) for that:
require 'openssl'
require 'base64'
module EncryptableModelConcern
  extend ActiveSupport::Concern
  included do
    before_save :encrypt_encryptable_attributes
    after_save :decrypt_encryptable_attributes
    after_find :decrypt_encryptable_attributes
  end
  module ClassMethods
    # Sets the model `@encryptable_attributes` class instance variable.
    # Encryptable attributes are encrypted before saving using `before_save` hook and decrypted using `after_save` and `after_find` hooks.
    # Example:
    # ```
    #   class Board < BaseModel
    #     encryptable_attributes :name, :title, :content
    #   end
    # ```
    def encryptable_attributes(*attrs)
      @encryptable_attributes = attrs
    end
  end
  # Returns the model's `@encryptable_attributes` class instance variable.
  #
  def encryptable_attributes
    self.class.instance_variable_get(:@encryptable_attributes) || []
  end
  # Encryptes the model's encryptable attributes before saving using Rails' `before_save` hook.
  #
  # **Note: Be careful in calling this method manually as it can corrupt the data.**
  def encrypt_encryptable_attributes
    encryptable_attributes.each do |k|
      self[k] = encrypt(self[k])
    end
  end
  # Decrypts the model's encryptable attributes using Rails' `after_save` and `after_find` hooks.
  #
  # **Note: Be careful in calling this method manually as it can corrupt the data.**
  def decrypt_encryptable_attributes
    encryptable_attributes.each do |k|
      self[k] = decrypt(self[k])
    end
  end
  private
    def cipher
      OpenSSL::Cipher::Cipher.new('aes-256-cbc')
    end
    def cipher_key
      Rails.configuration.crypto['key'] # <-- your own key generator here
    end
    def encrypt(value)
      c = cipher.encrypt
      c.key = Digest::SHA256.digest(cipher_key)
      c.iv = iv = c.random_iv
      Base64.encode64(iv) + Base64.encode64(c.update(value.to_s) + c.final)
    end
    def decrypt(value)
      c = cipher.decrypt
      c.key = Digest::SHA256.digest(cipher_key)
      c.iv = Base64.decode64 value.slice!(0,25)
      c.update(Base64.decode64(value.to_s)) + c.final
    end
end
Include it in your model you wish to have encryptable attributes
class Post < ApplicationRecord
  include EncryptableModelConcern
  encryptable_attributes :title, :content
end
Now, your model attributes will be encrypted on before_save and will be decrypted on after_save and on after_find hooks.
AFAIK, the aes gem wraps the openssl Ruby standard library to provide a much more simplified interface. It supports only aes-256-cbc, which is 256-bit AES with cipher-block chaining. You would probably add encryption/decryption methods to your models in Rails.
The basic order of operation for encryption would be:
aes-256-cbc (the aes gem can actually do this for you, so you could skip this step):format (Base64 by default, otherwise plain Ruby byte-strings) and/or initialization vector :iv
That would be:
key = AES.key
=> "6476b3f5ec6dcaddb637e9c9654aa687"    # key ends up as a 32-char long hex string
iv = AES.iv(:base_64)
=> "PPDRCMsZhumCdEO1Zm05uw=="
enc64 = AES.encrypt("hello, secret world", key, {:iv => iv})
=> "PPDRCMsZhumCdEO1Zm05uw==$b3CCy/1dAMJ2JG5T50igEMGtvo9Ppkla1c9vrKbo+zQ="
# note that the encrypted result is the :iv 
# and Base64-transformed encrypted message
# concatenated with $
You would then decrypt enc64 by passing in the entire :iv + $ + encrypted message string, as well as the AES 256-bit key.
AES.decrypt(enc64, key)
=> "hello, secret world"
Having had some experience using the openssl standard library in Ruby, I can tell you that the documentation in English is sparse, while the Japanese documentation is very good. At any rate, using the openssl API is confusing at best, so if you do not mind limiting yourself to aes-256-cbc, then this aes gem looks to be very helpful. 
Mind you, the author does have a caveat with regards to speed. If you find that you require a faster solution, you should have a look at FastAES. FastAES is a C-extension, however, and will require a compiler for your target platform.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With