File: lib/redmine/ciphering.rb

Overview
Module Structure
Code

Overview

Module Structure

  module: <Toplevel Module>
  module: Redmine#18
  module: Ciphering#19
has properties
module method: included / 1 #20
module method: encrypt_text / 1 #25
module method: decrypt_text / 1 #40
module method: cipher_key #59
module method: logger #64
method: read_ciphered_attribute / 1 #94
method: write_ciphered_attribute / 2 #99
  module: ClassMethods#69
has properties
method: encrypt_all / 1 #70
method: decrypt_all / 1 #80

Code

   1  # Redmine - project management software
   2  # Copyright (C) 2006-2011  Jean-Philippe Lang
   3  #
   4  # This program is free software; you can redistribute it and/or
   5  # modify it under the terms of the GNU General Public License
   6  # as published by the Free Software Foundation; either version 2
   7  # of the License, or (at your option) any later version.
   8  #
   9  # This program is distributed in the hope that it will be useful,
  10  # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  # GNU General Public License for more details.
  13  #
  14  # You should have received a copy of the GNU General Public License
  15  # along with this program; if not, write to the Free Software
  16  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  17 
  18  module Redmine
  19    module Ciphering
  20      def self.included(base)
  21        base.extend ClassMethods
  22      end
  23 
  24      class << self
  25        def encrypt_text(text)
  26          if cipher_key.blank? || text.blank?
  27            text
  28          else
  29            c = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
  30            iv = c.random_iv
  31            c.encrypt
  32            c.key = cipher_key
  33            c.iv = iv
  34            e = c.update(text.to_s)
  35            e << c.final
  36            "aes-256-cbc:" + [e, iv].map {|v| Base64.encode64(v).strip}.join('--')
  37          end
  38        end
  39 
  40        def decrypt_text(text)
  41          if text && match = text.match(/\Aaes-256-cbc:(.+)\Z/)
  42            if cipher_key.blank?
  43              logger.error "Attempt to decrypt a ciphered text with no cipher key configured in config/configuration.yml" if logger
  44              return text
  45            end
  46            text = match[1]
  47            c = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
  48            e, iv = text.split("--").map {|s| Base64.decode64(s)}
  49            c.decrypt
  50            c.key = cipher_key
  51            c.iv = iv
  52            d = c.update(e)
  53            d << c.final
  54          else
  55            text
  56          end
  57        end
  58 
  59        def cipher_key
  60          key = Redmine::Configuration['database_cipher_key'].to_s
  61          key.blank? ? nil : Digest::SHA256.hexdigest(key)
  62        end
  63        
  64        def logger
  65          Rails.logger
  66        end
  67      end
  68 
  69      module ClassMethods
  70        def encrypt_all(attribute)
  71          transaction do
  72            all.each do |object|
  73              clear = object.send(attribute)
  74              object.send "#{attribute}=", clear
  75              raise(ActiveRecord::Rollback) unless object.save(false)
  76            end
  77          end ? true : false
  78        end
  79 
  80        def decrypt_all(attribute)
  81          transaction do
  82            all.each do |object|
  83              clear = object.send(attribute)
  84              object.write_attribute attribute, clear
  85              raise(ActiveRecord::Rollback) unless object.save(false)
  86            end
  87          end
  88        end ? true : false
  89      end
  90 
  91      private
  92 
  93      # Returns the value of the given ciphered attribute
  94      def read_ciphered_attribute(attribute)
  95        Redmine::Ciphering.decrypt_text(read_attribute(attribute))
  96      end
  97 
  98      # Sets the value of the given ciphered attribute
  99      def write_ciphered_attribute(attribute, value)
 100        write_attribute(attribute, Redmine::Ciphering.encrypt_text(value))
 101      end
 102    end
 103  end