Skip to content

Instantly share code, notes, and snippets.

@warmwaffles
Created July 2, 2013 05:29
Show Gist options
  • Save warmwaffles/5906963 to your computer and use it in GitHub Desktop.
Save warmwaffles/5906963 to your computer and use it in GitHub Desktop.
# A wrapper library for the `OpenSSL::Cipher::Aes` library. It's fairly simple
# and allows for an easier way to call.
#
# @see http://www.ruby-doc.org/stdlib-1.9.3/libdoc/openssl/rdoc/OpenSSL/Cipher.html OpenSSL::Cipher::AES
#
# @author Matthew A. Johnston
class Aes
# The only valid key sizes
KEY_SIZES = %w{128 192 256}
# The only valid modes
MODES = %w{CBC CFB CFB1 CFB8 ECB OFB}
# Constructs a new Aes object
#
# @param [String] key_size the only valid sizes are: 128, 192, and 256
# @param [String] mode the only valid modes are: CBC, CFB, CFB1, CFB8, ECB,
# and OFB
def initialize(key_size, mode)
raise ArgumentError.new("Invalid key size") unless KEY_SIZES.include?(key_size)
raise ArgumentError.new("Invalid mode") unless MODES.include?(mode.upcase)
@cipher = ::OpenSSL::Cipher::AES.new(key_size, mode.upcase)
end
# Encrypts the data provided
#
# @param [String] data the secret you wish to encrypt
# @param [String] key the key that is used in the encryption
# @param [String] iv the initialization vector
def encrypt(data, key, iv)
@cipher.encrypt
@cipher.key = key
@cipher.iv = iv
@cipher.update(data) + @cipher.final
end
# Decrypts the data provided
#
# @param [String] data the message you are trying to decrypt
# @param [String] key the key that is used in the encryption
# @param [String] iv the initialization vector
def decrypt(data, key, iv)
@cipher.decrypt
@cipher.key = key
@cipher.iv = iv
@cipher.update(data) + @cipher.final
end
end
# Allows you to append encryptable fields to the model.
#
# == Examples
#
# class SomeModel < ActiveRecord::Base
# include Encryptable
# encryptable :some_field, :some_field_encrypted
# end
#
# s = SomeModel.new
# s.some_field = 'sooper sekret'
# s.some_field #=> 'sooper sekret'
# s.some_field_encrypted #=> base64 encoded AES value
#
# @author Matthew A. Johnston (warmwaffles)
module Encryptable
extend ActiveSupport::Concern
# Encrypts the secret that you provide
#
# @param [String] secret the message you want to encrypt
# @return [String] Base64 encoded
def encrypt(secret)
return nil if secret.blank?
aes = Aes.new('256', 'cbc')
encrypted = aes.encrypt(secret, ENV['AES_KEY'], ENV['AES_IV'])
Base64.encode64(encrypted)
end
# Decrypts the data provided
#
# @param [String] data the data you want to decrypt. The data must be Base64
# encoded
# @return [String]
def decrypt(data)
return nil if data.blank?
aes = Aes.new('256','cbc')
decoded = Base64.decode64(data)
aes.decrypt(decoded, ENV['AES_KEY'], ENV['AES_IV'])
end
module ClassMethods
# Defines methods on the model that allow you to get and set encrypted
# values.
#
# @param [String] field the name of the method you want to access the secret
# @param [String] name the name of the method that will store the encrypted
# secret
# @return [void]
def encryptable(field, name)
field = field.to_s
name = name.to_s
class_eval %Q{
def #{field}
decrypt(self.#{name})
end
def #{field}= val
self.#{name} = encrypt(val)
end
}
end
end
end
class Another < ActiveRecord::Base
include Encryptable
encryptable :some_field, :some_field_encrypted
end
s = Another.new
s.some_field = 'sooper sekret'
s.some_field #=> 'sooper sekret'
s.some_field_encrypted #=> base64 encoded AES value
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment