Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

encryption and decryption algorithm in Rails

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?

like image 919
Mellon Avatar asked Dec 13 '11 12:12

Mellon


3 Answers

Make a module in your app and include this where you want to call the module method:

  1. You can create a file encrytion_algo.rb under lib folder of rails project
  2. Inside config/application.rb add 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
  1. Inside ApplicationController include above file include MyModule

  2. 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"

like image 199
Jai Kumar Rajput Avatar answered Sep 27 '22 20:09

Jai Kumar Rajput


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.

like image 25
Adones Pitogo Avatar answered Sep 27 '22 20:09

Adones Pitogo


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:

  1. compute an AES symmetric encryption key, 256 bits
  2. optionally compute an initialization vector for use with aes-256-cbc (the aes gem can actually do this for you, so you could skip this step)
  3. encrypt your message, optionally indicating output :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.

like image 42
buruzaemon Avatar answered Sep 27 '22 20:09

buruzaemon