Rails中的加密和解密算法

时间:2011-12-13 12:46:15

标签: ruby-on-rails ruby-on-rails-3 ruby-on-rails-3.1

我希望使用AES算法加密解密 模型的一个属性字符串值。

我想知道 Rails ,最简单的方法是什么?是否有可以直接使用的 AES gem库?以及如何使用它?

基本上我需要一些关于如何在Rails应用中应用 AES 加密/解密的指南。

-------更新-------

我注意到AES gem。如果我将这个gem添加到我的GemFile中,我如何在我的加密应用程序中使用它?解密?

5 个答案:

答案 0 :(得分:7)

AFAIK,aes gem包装了openssl Ruby标准库,以提供更加简化的界面。它仅支持aes-256-cbc,这是具有密码块链接的256位AES。您可能会在Rails中为模型添加加密/解密方法。

加密的基本操作顺序是:

  1. 计算AES对称加密密钥,256位
  2. 可选地计算用于aes-256-cbc的初始化向量(aes gem实际上可以为您执行此操作,因此您可以跳过此步骤)
  3. 加密你的消息,可选地指示输出:format(默认为Base64,否则为纯Ruby字节串)和/或初始化向量:iv
  4. 那将是:

    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 $
    

    然后,您可以通过传入整个enc64 + :iv +加密的消息字符串以及AES 256位$来解密key

    AES.decrypt(enc64, key)
    => "hello, secret world"
    

    在Ruby中使用openssl标准库有一些经验,我可以告诉你,英文文档很少,而日文文档非常好。无论如何,使用openssl API最多会让人感到困惑,所以如果你不介意将自己限制在aes-256-cbc,那么这个aes gem看起来非常有用。

    请注意,作者确实对速度有一个警告。如果您发现需要更快的解决方案,则应该查看FastAES。但是,FastAES是一个C扩展,并且需要为您的目标平台编译。

答案 1 :(得分:5)

我建议在您的应用中制作一个模块,并将其包含在您想要使用的位置,并使用模块方法:

模块

require 'openssl'
require 'base64'

module Preventurl
  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

在应用程序控制器include MyModule

现在来自任何控制器:

encrypt("This is a text")
==> "h0RGuW5m3Wk9AAspik9ZXVysOcy2IeQrhQDn85mdo5I=%0A"

decrypt("h0RGuW5m3Wk9AAspik9ZXVysOcy2IeQrhQDn85mdo5I=%0A")

==> "This is a text"

答案 2 :(得分:2)

您可以使用OpenSSL库。创建以下功能,然后您可以使用加密和解密方法。

def aes(m,k,t)
  (aes = OpenSSL::Cipher::Cipher.new('aes-256-cbc').send(m)).key = Digest::SHA256.digest(k)
  aes.update(t) << aes.final
end

def encrypt(key, text)
  aes(:encrypt, key, text)
end

def decrypt(key, text)
  aes(:decrypt, key, text)
end

答案 3 :(得分:2)

https://github.com/shuber/attr_encrypted

http://ezcrypto.rubyforge.org/

attr_encrypted对我很有用 - 虽然我也使用过Ezcrypto。它充当OpenSSL库的包装器。

答案 4 :(得分:2)

我偶然发现了同样的问题并为此创建了一个简单的模型问题(rails 5):

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

将其包含在您希望拥有加密属性的模型中

class Post < ApplicationRecord
  include EncryptableModelConcern
  encryptable_attributes :title, :content
end

现在,您的模型属性将在before_save上加密,并将在after_saveafter_find挂钩上解密。