| 
									
										
										
										
											2011-02-26 13:09:25 +00:00
										 |  |  | # Redmine - project management software | 
					
						
							| 
									
										
										
										
											2013-01-12 09:29:31 +00:00
										 |  |  | # Copyright (C) 2006-2013  Jean-Philippe Lang | 
					
						
							| 
									
										
										
										
											2011-02-26 13:09:25 +00:00
										 |  |  | # | 
					
						
							|  |  |  | # This program is free software; you can redistribute it and/or | 
					
						
							|  |  |  | # modify it under the terms of the GNU General Public License | 
					
						
							|  |  |  | # as published by the Free Software Foundation; either version 2 | 
					
						
							|  |  |  | # of the License, or (at your option) any later version. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | # but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  | # GNU General Public License for more details. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  | # along with this program; if not, write to the Free Software | 
					
						
							|  |  |  | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module Redmine | 
					
						
							|  |  |  |   module Ciphering | 
					
						
							| 
									
										
										
										
											2011-09-01 00:48:43 +00:00
										 |  |  |     def self.included(base) | 
					
						
							| 
									
										
										
										
											2011-02-26 13:09:25 +00:00
										 |  |  |       base.extend ClassMethods | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2011-09-01 00:48:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-26 13:09:25 +00:00
										 |  |  |     class << self | 
					
						
							|  |  |  |       def encrypt_text(text) | 
					
						
							| 
									
										
										
										
											2011-11-29 19:47:51 +00:00
										 |  |  |         if cipher_key.blank? || text.blank? | 
					
						
							| 
									
										
										
										
											2011-02-26 13:09:25 +00:00
										 |  |  |           text | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           c = OpenSSL::Cipher::Cipher.new("aes-256-cbc") | 
					
						
							|  |  |  |           iv = c.random_iv | 
					
						
							|  |  |  |           c.encrypt | 
					
						
							|  |  |  |           c.key = cipher_key | 
					
						
							|  |  |  |           c.iv = iv | 
					
						
							|  |  |  |           e = c.update(text.to_s) | 
					
						
							|  |  |  |           e << c.final | 
					
						
							|  |  |  |           "aes-256-cbc:" + [e, iv].map {|v| Base64.encode64(v).strip}.join('--') | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2011-09-01 00:48:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-26 13:09:25 +00:00
										 |  |  |       def decrypt_text(text) | 
					
						
							|  |  |  |         if text && match = text.match(/\Aaes-256-cbc:(.+)\Z/) | 
					
						
							| 
									
										
										
										
											2011-11-11 14:04:33 +00:00
										 |  |  |           if cipher_key.blank? | 
					
						
							|  |  |  |             logger.error "Attempt to decrypt a ciphered text with no cipher key configured in config/configuration.yml" if logger | 
					
						
							|  |  |  |             return text | 
					
						
							|  |  |  |           end | 
					
						
							| 
									
										
										
										
											2011-02-26 13:09:25 +00:00
										 |  |  |           text = match[1] | 
					
						
							|  |  |  |           c = OpenSSL::Cipher::Cipher.new("aes-256-cbc") | 
					
						
							|  |  |  |           e, iv = text.split("--").map {|s| Base64.decode64(s)} | 
					
						
							|  |  |  |           c.decrypt | 
					
						
							|  |  |  |           c.key = cipher_key | 
					
						
							|  |  |  |           c.iv = iv | 
					
						
							|  |  |  |           d = c.update(e) | 
					
						
							|  |  |  |           d << c.final | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           text | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2011-09-01 00:48:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-26 13:09:25 +00:00
										 |  |  |       def cipher_key | 
					
						
							|  |  |  |         key = Redmine::Configuration['database_cipher_key'].to_s | 
					
						
							|  |  |  |         key.blank? ? nil : Digest::SHA256.hexdigest(key) | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2011-11-11 14:04:33 +00:00
										 |  |  |        | 
					
						
							|  |  |  |       def logger | 
					
						
							| 
									
										
										
										
											2011-11-11 14:40:49 +00:00
										 |  |  |         Rails.logger | 
					
						
							| 
									
										
										
										
											2011-11-11 14:04:33 +00:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2011-02-26 13:09:25 +00:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2011-09-01 00:48:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-26 13:09:25 +00:00
										 |  |  |     module ClassMethods | 
					
						
							|  |  |  |       def encrypt_all(attribute) | 
					
						
							|  |  |  |         transaction do | 
					
						
							|  |  |  |           all.each do |object| | 
					
						
							|  |  |  |             clear = object.send(attribute) | 
					
						
							|  |  |  |             object.send "#{attribute}=", clear | 
					
						
							| 
									
										
										
										
											2012-04-25 17:17:49 +00:00
										 |  |  |             raise(ActiveRecord::Rollback) unless object.save(:validation => false) | 
					
						
							| 
									
										
										
										
											2011-02-26 13:09:25 +00:00
										 |  |  |           end | 
					
						
							|  |  |  |         end ? true : false | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2011-09-01 00:48:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-26 13:09:25 +00:00
										 |  |  |       def decrypt_all(attribute) | 
					
						
							|  |  |  |         transaction do | 
					
						
							|  |  |  |           all.each do |object| | 
					
						
							|  |  |  |             clear = object.send(attribute) | 
					
						
							| 
									
										
										
										
											2012-04-25 17:17:49 +00:00
										 |  |  |             object.send :write_attribute, attribute, clear | 
					
						
							|  |  |  |             raise(ActiveRecord::Rollback) unless object.save(:validation => false) | 
					
						
							| 
									
										
										
										
											2011-02-26 13:09:25 +00:00
										 |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end ? true : false | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2011-09-01 00:48:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-26 13:09:25 +00:00
										 |  |  |     private | 
					
						
							| 
									
										
										
										
											2011-09-01 00:48:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-26 13:09:25 +00:00
										 |  |  |     # Returns the value of the given ciphered attribute | 
					
						
							|  |  |  |     def read_ciphered_attribute(attribute) | 
					
						
							|  |  |  |       Redmine::Ciphering.decrypt_text(read_attribute(attribute)) | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2011-09-01 00:48:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-26 13:09:25 +00:00
										 |  |  |     # Sets the value of the given ciphered attribute | 
					
						
							|  |  |  |     def write_ciphered_attribute(attribute, value) | 
					
						
							|  |  |  |       write_attribute(attribute, Redmine::Ciphering.encrypt_text(value)) | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | end |