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