symmetric-encryption 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +41 -11
- data/Rakefile +3 -3
- data/lib/symmetric-encryption.rb +10 -7
- data/lib/symmetric_encryption/cipher.rb +114 -0
- data/lib/{symmetric → symmetric_encryption}/extensions/active_record/base.rb +4 -7
- data/lib/{symmetric → symmetric_encryption}/extensions/mongoid/fields.rb +19 -10
- data/lib/{symmetric → symmetric_encryption}/railtie.rb +4 -4
- data/lib/{symmetric → symmetric_encryption}/railties/symmetric_encryption.rake +5 -5
- data/lib/{symmetric/railties/symmetric_encrypted_validator.rb → symmetric_encryption/railties/symmetric_encryption_validator.rb} +4 -4
- data/lib/symmetric_encryption/reader.rb +221 -0
- data/lib/symmetric_encryption/symmetric_encryption.rb +280 -0
- data/lib/symmetric_encryption/version.rb +4 -0
- data/lib/symmetric_encryption/writer.rb +132 -0
- data/nbproject/private/private.xml +14 -1
- data/symmetric-encryption-0.2.0.gem +0 -0
- data/symmetric-encryption-0.4.0.gem +0 -0
- data/test/attr_encrypted_test.rb +7 -7
- data/test/cipher_test.rb +8 -13
- data/test/field_encrypted_test.rb +3 -3
- data/test/reader_test.rb +76 -0
- data/test/symmetric_encryption_test.rb +53 -0
- data/test/writer_test.rb +56 -0
- metadata +20 -15
- data/lib/symmetric/cipher.rb +0 -184
- data/lib/symmetric/encryption.rb +0 -262
- data/lib/symmetric/version.rb +0 -4
- data/symmetric-encryption-0.3.0.gem +0 -0
- data/symmetric-encryption-0.3.1.gem +0 -0
- data/test/encryption_test.rb +0 -51
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
7
|
+
- 5
|
8
8
|
- 0
|
9
|
-
version: 0.
|
9
|
+
version: 0.5.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Reid Morrison
|
@@ -14,11 +14,11 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2012-
|
17
|
+
date: 2012-04-05 00:00:00 -04:00
|
18
18
|
default_executable:
|
19
19
|
dependencies: []
|
20
20
|
|
21
|
-
description:
|
21
|
+
description: SymmetricEncryption supports encrypting ActiveRecord data, Mongoid data, passwords in configuration files, encrypting and decrypting of large files through streaming
|
22
22
|
email:
|
23
23
|
- reidmo@gmail.com
|
24
24
|
executables: []
|
@@ -29,15 +29,17 @@ extra_rdoc_files: []
|
|
29
29
|
|
30
30
|
files:
|
31
31
|
- examples/symmetric-encryption.yml
|
32
|
-
- lib/symmetric/cipher.rb
|
33
|
-
- lib/symmetric/encryption.rb
|
34
|
-
- lib/symmetric/extensions/active_record/base.rb
|
35
|
-
- lib/symmetric/extensions/mongoid/fields.rb
|
36
|
-
- lib/symmetric/railtie.rb
|
37
|
-
- lib/symmetric/railties/symmetric_encrypted_validator.rb
|
38
|
-
- lib/symmetric/railties/symmetric_encryption.rake
|
39
|
-
- lib/symmetric/version.rb
|
40
32
|
- lib/symmetric-encryption.rb
|
33
|
+
- lib/symmetric_encryption/cipher.rb
|
34
|
+
- lib/symmetric_encryption/extensions/active_record/base.rb
|
35
|
+
- lib/symmetric_encryption/extensions/mongoid/fields.rb
|
36
|
+
- lib/symmetric_encryption/railtie.rb
|
37
|
+
- lib/symmetric_encryption/railties/symmetric_encryption.rake
|
38
|
+
- lib/symmetric_encryption/railties/symmetric_encryption_validator.rb
|
39
|
+
- lib/symmetric_encryption/reader.rb
|
40
|
+
- lib/symmetric_encryption/symmetric_encryption.rb
|
41
|
+
- lib/symmetric_encryption/version.rb
|
42
|
+
- lib/symmetric_encryption/writer.rb
|
41
43
|
- LICENSE.txt
|
42
44
|
- nbproject/private/config.properties
|
43
45
|
- nbproject/private/private.properties
|
@@ -47,8 +49,9 @@ files:
|
|
47
49
|
- nbproject/project.xml
|
48
50
|
- Rakefile
|
49
51
|
- README.md
|
50
|
-
- symmetric-encryption-0.
|
51
|
-
- symmetric-encryption-0.
|
52
|
+
- symmetric-encryption-0.2.0.gem
|
53
|
+
- symmetric-encryption-0.4.0.gem
|
54
|
+
- symmetric-encryption-0.5.0.gem
|
52
55
|
- test/attr_encrypted_test.rb
|
53
56
|
- test/cipher_test.rb
|
54
57
|
- test/config/database.yml
|
@@ -58,8 +61,10 @@ files:
|
|
58
61
|
- test/config/test_new.key
|
59
62
|
- test/config/test_secondary_1.iv
|
60
63
|
- test/config/test_secondary_1.key
|
61
|
-
- test/encryption_test.rb
|
62
64
|
- test/field_encrypted_test.rb
|
65
|
+
- test/reader_test.rb
|
66
|
+
- test/symmetric_encryption_test.rb
|
67
|
+
- test/writer_test.rb
|
63
68
|
has_rdoc: true
|
64
69
|
homepage: https://github.com/ClarityServices/symmetric-encryption
|
65
70
|
licenses: []
|
data/lib/symmetric/cipher.rb
DELETED
@@ -1,184 +0,0 @@
|
|
1
|
-
require 'base64'
|
2
|
-
require 'openssl'
|
3
|
-
require 'zlib'
|
4
|
-
|
5
|
-
module Symmetric
|
6
|
-
|
7
|
-
# Hold all information related to encryption keys
|
8
|
-
# as well as encrypt and decrypt data using those keys
|
9
|
-
#
|
10
|
-
# Cipher is thread safe so that the same instance can be called by multiple
|
11
|
-
# threads at the same time without needing an instance of Cipher per thread
|
12
|
-
class Cipher
|
13
|
-
# Cipher to use for encryption and decryption
|
14
|
-
attr_reader :cipher
|
15
|
-
|
16
|
-
# Future Use:
|
17
|
-
# attr_accessor :encoding, :version
|
18
|
-
|
19
|
-
# Generate a new Symmetric Key pair
|
20
|
-
#
|
21
|
-
# Returns a hash containing a new random symmetric_key pair
|
22
|
-
# consisting of a :key and :iv.
|
23
|
-
# The cipher is also included for compatibility with the Cipher initializer
|
24
|
-
def self.random_key_pair(cipher = 'aes-256-cbc', generate_iv = true)
|
25
|
-
openssl_cipher = OpenSSL::Cipher.new(cipher)
|
26
|
-
openssl_cipher.encrypt
|
27
|
-
|
28
|
-
{
|
29
|
-
:key => openssl_cipher.random_key,
|
30
|
-
:iv => generate_iv ? openssl_cipher.random_iv : nil,
|
31
|
-
:cipher => cipher
|
32
|
-
}
|
33
|
-
end
|
34
|
-
|
35
|
-
# Create a Symmetric::Key for encryption and decryption purposes
|
36
|
-
#
|
37
|
-
# Parameters:
|
38
|
-
# :key
|
39
|
-
# The Symmetric Key to use for encryption and decryption
|
40
|
-
# :iv
|
41
|
-
# Optional. The Initialization Vector to use with Symmetric Key
|
42
|
-
# :cipher
|
43
|
-
# Optional. Encryption Cipher to use
|
44
|
-
# Default: aes-256-cbc
|
45
|
-
def initialize(parms={})
|
46
|
-
raise "Missing mandatory parameter :key" unless @key = parms[:key]
|
47
|
-
@iv = parms[:iv]
|
48
|
-
@cipher = parms[:cipher] || 'aes-256-cbc'
|
49
|
-
end
|
50
|
-
|
51
|
-
# AES Symmetric Encryption of supplied string
|
52
|
-
# Returns result as a Base64 encoded string
|
53
|
-
# Returns nil if the supplied str is nil
|
54
|
-
# Returns "" if it is a string and it is empty
|
55
|
-
def encrypt(str)
|
56
|
-
return str if str.nil? || (str.is_a?(String) && str.empty?)
|
57
|
-
::Base64.encode64(crypt(:encrypt, str))
|
58
|
-
end
|
59
|
-
|
60
|
-
# AES Symmetric Decryption of supplied string
|
61
|
-
# Returns decrypted string
|
62
|
-
# Returns nil if the supplied str is nil
|
63
|
-
# Returns "" if it is a string and it is empty
|
64
|
-
def decrypt(str)
|
65
|
-
return str if str.nil? || (str.is_a?(String) && str.empty?)
|
66
|
-
crypt(:decrypt, ::Base64.decode64(str))
|
67
|
-
end
|
68
|
-
|
69
|
-
# The minimum length for an encrypted string
|
70
|
-
def min_encrypted_length
|
71
|
-
@min_encrypted_length ||= encrypt('1').length
|
72
|
-
end
|
73
|
-
|
74
|
-
# Returns [true|false] a best effort determination as to whether the supplied
|
75
|
-
# string is encrypted or not, without incurring the penalty of actually
|
76
|
-
# decrypting the supplied data
|
77
|
-
# Parameters:
|
78
|
-
# encrypted_data: Encrypted string
|
79
|
-
def encrypted?(encrypted_data)
|
80
|
-
# Simple checks first
|
81
|
-
return false if (encrypted_data.length < min_encrypted_length) || (!encrypted_data.end_with?("\n"))
|
82
|
-
# For now have to decrypt it fully
|
83
|
-
begin
|
84
|
-
decrypt(encrypted_data) ? true : false
|
85
|
-
rescue
|
86
|
-
false
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
# Return a new random key using the configured cipher
|
91
|
-
# Useful for generating new symmetric keys
|
92
|
-
def random_key
|
93
|
-
::OpenSSL::Cipher::Cipher.new(@cipher).random_key
|
94
|
-
end
|
95
|
-
|
96
|
-
protected
|
97
|
-
|
98
|
-
# Some of these methods are for future use to handle binary data, etc..
|
99
|
-
|
100
|
-
# Binary encrypted data includes this magic header so that we can quickly
|
101
|
-
# identify binary data versus base64 encoded data that does not have this header
|
102
|
-
unless defined? MAGIC_HEADER
|
103
|
-
MAGIC_HEADER = '@EnC'
|
104
|
-
MAGIC_HEADER_SIZE = MAGIC_HEADER.size
|
105
|
-
end
|
106
|
-
|
107
|
-
# AES Symmetric Encryption of supplied string
|
108
|
-
# Returns result as a binary encrypted string
|
109
|
-
# Returns nil if the supplied str is nil or empty
|
110
|
-
# Parameters
|
111
|
-
# compress => Whether to compress the supplied string using zip before
|
112
|
-
# encrypting
|
113
|
-
# true | false
|
114
|
-
# Default false
|
115
|
-
def self.encrypt_binary(str, compress=false)
|
116
|
-
return nil if str.nil? || (str.is_a?(String) && str.empty?)
|
117
|
-
# Bit Layout
|
118
|
-
# 15 => Compressed?
|
119
|
-
# 0..14 => Version number of encryption key/algorithm currently 0
|
120
|
-
flags = 0 # Same as 0b0000_0000_0000_0000
|
121
|
-
# If the data is to be compressed before being encrypted, set the flag and
|
122
|
-
# compress using zlib. Only compress if data is greater than 15 chars
|
123
|
-
str = str.to_s unless str.is_a?(String)
|
124
|
-
if compress && str.length > 15
|
125
|
-
flags |= 0b1000_0000_0000_0000
|
126
|
-
begin
|
127
|
-
ostream = StringIO.new
|
128
|
-
gz = ::Zlib::GzipWriter.new(ostream)
|
129
|
-
gz.write(str)
|
130
|
-
str = ostream.string
|
131
|
-
ensure
|
132
|
-
gz.close
|
133
|
-
end
|
134
|
-
end
|
135
|
-
return nil unless encrypted = self.crypt(:encrypt, str)
|
136
|
-
# Resulting buffer consists of:
|
137
|
-
# '@EnC'
|
138
|
-
# unsigned short (32 bits) in little endian format for flags above
|
139
|
-
# 'actual encrypted buffer data'
|
140
|
-
"#{MAGIC_HEADER}#{[flags].pack('v')}#{encrypted}"
|
141
|
-
end
|
142
|
-
|
143
|
-
# AES Symmetric Decryption of supplied Binary string
|
144
|
-
# Returns decrypted string
|
145
|
-
# Returns nil if the supplied str is nil
|
146
|
-
# Returns "" if it is a string and it is empty
|
147
|
-
def self.decrypt_binary(str)
|
148
|
-
return str if str.nil? || (str.is_a?(String) && str.empty?)
|
149
|
-
str = str.to_s unless str.is_a?(String)
|
150
|
-
encrypted = if str.starts_with? MAGIC_HEADER
|
151
|
-
# Remove header and extract flags
|
152
|
-
header, flags = str.unpack(@@unpack ||= "A#{MAGIC_HEADER_SIZE}v")
|
153
|
-
# Uncompress if data is compressed and remove header
|
154
|
-
if flags & 0b1000_0000_0000_0000
|
155
|
-
begin
|
156
|
-
gz = ::Zlib::GzipReader.new(StringIO.new(str[MAGIC_HEADER_SIZE,-1]))
|
157
|
-
gz.read
|
158
|
-
ensure
|
159
|
-
gz.close
|
160
|
-
end
|
161
|
-
else
|
162
|
-
str[MAGIC_HEADER_SIZE,-1]
|
163
|
-
end
|
164
|
-
else
|
165
|
-
::Base64.decode64(str)
|
166
|
-
end
|
167
|
-
crypt(:decrypt, encrypted)
|
168
|
-
end
|
169
|
-
|
170
|
-
# Creates a new OpenSSL::Cipher with every call so that this call
|
171
|
-
# is thread-safe
|
172
|
-
def crypt(cipher_method, string) #:nodoc:
|
173
|
-
openssl_cipher = ::OpenSSL::Cipher.new(self.cipher)
|
174
|
-
openssl_cipher.send(cipher_method)
|
175
|
-
raise "Encryption.key must be set before calling Encryption encrypt or decrypt" unless @key
|
176
|
-
openssl_cipher.key = @key
|
177
|
-
openssl_cipher.iv = @iv if @iv
|
178
|
-
result = openssl_cipher.update(string.to_s)
|
179
|
-
result << openssl_cipher.final
|
180
|
-
end
|
181
|
-
|
182
|
-
end
|
183
|
-
|
184
|
-
end
|
data/lib/symmetric/encryption.rb
DELETED
@@ -1,262 +0,0 @@
|
|
1
|
-
require 'base64'
|
2
|
-
require 'openssl'
|
3
|
-
require 'zlib'
|
4
|
-
require 'yaml'
|
5
|
-
|
6
|
-
module Symmetric
|
7
|
-
|
8
|
-
# Encrypt using 256 Bit AES CBC symmetric key and initialization vector
|
9
|
-
# The symmetric key is protected using the private key below and must
|
10
|
-
# be distributed separately from the application
|
11
|
-
class Encryption
|
12
|
-
|
13
|
-
# Defaults
|
14
|
-
@@cipher = nil
|
15
|
-
@@secondary_ciphers = []
|
16
|
-
|
17
|
-
# Set the Primary Symmetric Cipher to be used
|
18
|
-
def self.cipher=(cipher)
|
19
|
-
raise "Cipher must be similar to Symmetric::Ciphers" unless cipher.respond_to?(:encrypt) && cipher.respond_to?(:decrypt) && cipher.respond_to?(:encrypted?)
|
20
|
-
@@cipher = cipher
|
21
|
-
end
|
22
|
-
|
23
|
-
# Returns the Primary Symmetric Cipher being used
|
24
|
-
def self.cipher
|
25
|
-
@@cipher
|
26
|
-
end
|
27
|
-
|
28
|
-
# Set the Secondary Symmetric Ciphers Array to be used
|
29
|
-
def self.secondary_ciphers=(secondary_ciphers)
|
30
|
-
raise "secondary_ciphers must be a collection" unless secondary_ciphers.respond_to? :each
|
31
|
-
secondary_ciphers.each do |cipher|
|
32
|
-
raise "secondary_ciphers can only consist of Symmetric::Ciphers" unless cipher.respond_to?(:encrypt) && cipher.respond_to?(:decrypt) && cipher.respond_to?(:encrypted?)
|
33
|
-
end
|
34
|
-
@@secondary_ciphers = secondary_ciphers
|
35
|
-
end
|
36
|
-
|
37
|
-
# Returns the Primary Symmetric Cipher being used
|
38
|
-
def self.secondary_ciphers
|
39
|
-
@@secondary_ciphers
|
40
|
-
end
|
41
|
-
|
42
|
-
# AES Symmetric Decryption of supplied string
|
43
|
-
# Returns decrypted string
|
44
|
-
# Returns nil if the supplied str is nil
|
45
|
-
# Returns "" if it is a string and it is empty
|
46
|
-
#
|
47
|
-
# Note: If secondary ciphers are supplied in the configuration file the
|
48
|
-
# first key will be used to decrypt 'str'. If it fails each cipher in the
|
49
|
-
# order supplied will be tried.
|
50
|
-
# It is slow to try each cipher in turn, so should be used during migrations
|
51
|
-
# only
|
52
|
-
#
|
53
|
-
# Raises: OpenSSL::Cipher::CipherError when 'str' was not encrypted using
|
54
|
-
# the supplied key and iv
|
55
|
-
#
|
56
|
-
def self.decrypt(str)
|
57
|
-
raise "Call Symmetric::Encryption.load! or Symmetric::Encryption.cipher= prior to encrypting or decrypting data" unless @@cipher
|
58
|
-
begin
|
59
|
-
@@cipher.decrypt(str)
|
60
|
-
rescue OpenSSL::Cipher::CipherError => exc
|
61
|
-
@@secondary_ciphers.each do |cipher|
|
62
|
-
begin
|
63
|
-
return cipher.decrypt(str)
|
64
|
-
rescue OpenSSL::Cipher::CipherError
|
65
|
-
end
|
66
|
-
end
|
67
|
-
raise exc
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
# AES Symmetric Encryption of supplied string
|
72
|
-
# Returns result as a Base64 encoded string
|
73
|
-
# Returns nil if the supplied str is nil
|
74
|
-
# Returns "" if it is a string and it is empty
|
75
|
-
def self.encrypt(str)
|
76
|
-
raise "Call Symmetric::Encryption.load! or Symmetric::Encryption.cipher= prior to encrypting or decrypting data" unless @@cipher
|
77
|
-
@@cipher.encrypt(str)
|
78
|
-
end
|
79
|
-
|
80
|
-
# Invokes decrypt
|
81
|
-
# Returns decrypted String
|
82
|
-
# Return nil if it fails to decrypt a String
|
83
|
-
#
|
84
|
-
# Useful for example when decoding passwords encrypted using a key from a
|
85
|
-
# different environment. I.e. We cannot decode production passwords
|
86
|
-
# in the test or development environments but still need to be able to load
|
87
|
-
# YAML config files that contain encrypted development and production passwords
|
88
|
-
def self.try_decrypt(str)
|
89
|
-
raise "Call Symmetric::Encryption.load! or Symmetric::Encryption.cipher= prior to encrypting or decrypting data" unless @@cipher
|
90
|
-
begin
|
91
|
-
decrypt(str)
|
92
|
-
rescue OpenSSL::Cipher::CipherError
|
93
|
-
nil
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
# Returns [true|false] a best effort determination as to whether the supplied
|
98
|
-
# string is encrypted or not, without incurring the penalty of actually
|
99
|
-
# decrypting the supplied data
|
100
|
-
# Parameters:
|
101
|
-
# encrypted_data: Encrypted string
|
102
|
-
def self.encrypted?(encrypted_data)
|
103
|
-
raise "Call Symmetric::Encryption.load! or Symmetric::Encryption.cipher= prior to encrypting or decrypting data" unless @@cipher
|
104
|
-
@@cipher.encrypted?(encrypted_data)
|
105
|
-
end
|
106
|
-
|
107
|
-
# Load the Encryption Configuration from a YAML file
|
108
|
-
# filename:
|
109
|
-
# Name of file to read.
|
110
|
-
# Mandatory for non-Rails apps
|
111
|
-
# Default: Rails.root/config/symmetric-encryption.yml
|
112
|
-
# environment:
|
113
|
-
# Which environments config to load. Usually: production, development, etc.
|
114
|
-
# Default: Rails.env
|
115
|
-
def self.load!(filename=nil, environment=nil)
|
116
|
-
config = read_config(filename, environment)
|
117
|
-
|
118
|
-
# Check for hard coded key, iv and cipher
|
119
|
-
if config[:key]
|
120
|
-
@@cipher = Cipher.new(config)
|
121
|
-
@@secondary_ciphers = []
|
122
|
-
else
|
123
|
-
private_rsa_key = config[:private_rsa_key]
|
124
|
-
@@cipher, *@@secondary_ciphers = config[:ciphers].collect do |cipher_conf|
|
125
|
-
cipher_from_encrypted_files(
|
126
|
-
private_rsa_key,
|
127
|
-
cipher_conf[:cipher],
|
128
|
-
cipher_conf[:key_filename],
|
129
|
-
cipher_conf[:iv_filename])
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
true
|
134
|
-
end
|
135
|
-
|
136
|
-
# Future: Generate private key in config file generator
|
137
|
-
#new_key = OpenSSL::PKey::RSA.generate(2048)
|
138
|
-
|
139
|
-
# Generate new random symmetric keys for use with this Encryption library
|
140
|
-
#
|
141
|
-
# Note: Only the current Encryption key settings are used
|
142
|
-
#
|
143
|
-
# Creates Symmetric Key .key
|
144
|
-
# and initilization vector .iv
|
145
|
-
# which is encrypted with the above Public key
|
146
|
-
#
|
147
|
-
# Warning: Existing files will be overwritten
|
148
|
-
def self.generate_symmetric_key_files(filename=nil, environment=nil)
|
149
|
-
config = read_config(filename, environment)
|
150
|
-
cipher_cfg = config[:ciphers].first
|
151
|
-
key_filename = cipher_cfg[:key_filename]
|
152
|
-
iv_filename = cipher_cfg[:iv_filename]
|
153
|
-
cipher = cipher_cfg[:cipher]
|
154
|
-
|
155
|
-
raise "The configuration file must contain a 'private_rsa_key' parameter to generate symmetric keys" unless config[:private_rsa_key]
|
156
|
-
rsa_key = OpenSSL::PKey::RSA.new(config[:private_rsa_key])
|
157
|
-
|
158
|
-
# Generate a new Symmetric Key pair
|
159
|
-
key_pair = Symmetric::Cipher.random_key_pair(cipher || 'aes-256-cbc', !iv_filename.nil?)
|
160
|
-
|
161
|
-
# Save symmetric key after encrypting it with the private RSA key, backing up existing files if present
|
162
|
-
File.rename(key_filename, "#{key_filename}.#{Time.now.to_i}") if File.exist?(key_filename)
|
163
|
-
File.open(key_filename, 'wb') {|file| file.write( rsa_key.public_encrypt(key_pair[:key]) ) }
|
164
|
-
|
165
|
-
if iv_filename
|
166
|
-
File.rename(iv_filename, "#{iv_filename}.#{Time.now.to_i}") if File.exist?(iv_filename)
|
167
|
-
File.open(iv_filename, 'wb') {|file| file.write( rsa_key.public_encrypt(key_pair[:iv]) ) }
|
168
|
-
end
|
169
|
-
puts("Generated new Symmetric Key for encryption. Please copy #{key_filename} and #{iv_filename} to the other web servers in #{environment}.")
|
170
|
-
end
|
171
|
-
|
172
|
-
# Generate a 22 character random password
|
173
|
-
def self.random_password
|
174
|
-
Base64.encode64(OpenSSL::Cipher.new('aes-128-cbc').random_key)[0..-4]
|
175
|
-
end
|
176
|
-
|
177
|
-
protected
|
178
|
-
|
179
|
-
# Returns the Encryption Configuration
|
180
|
-
#
|
181
|
-
# Read the configuration from the YAML file and return in the latest format
|
182
|
-
#
|
183
|
-
# filename:
|
184
|
-
# Name of file to read.
|
185
|
-
# Mandatory for non-Rails apps
|
186
|
-
# Default: Rails.root/config/symmetric-encryption.yml
|
187
|
-
# environment:
|
188
|
-
# Which environments config to load. Usually: production, development, etc.
|
189
|
-
def self.read_config(filename=nil, environment=nil)
|
190
|
-
config = YAML.load_file(filename || File.join(Rails.root, "config", "symmetric-encryption.yml"))[environment || Rails.env]
|
191
|
-
|
192
|
-
# Default cipher
|
193
|
-
default_cipher = config['cipher'] || 'aes-256-cbc'
|
194
|
-
cfg = {}
|
195
|
-
|
196
|
-
# Hard coded symmetric_key? - Dev / Testing use only!
|
197
|
-
if symmetric_key = (config['key'] || config['symmetric_key'])
|
198
|
-
raise "Symmetric::Encryption Cannot hard code Production encryption keys in #{filename}" if (environment || Rails.env) == 'production'
|
199
|
-
cfg[:key] = symmetric_key
|
200
|
-
cfg[:iv] = config['iv'] || config['symmetric_iv']
|
201
|
-
cfg[:cipher] = default_cipher
|
202
|
-
|
203
|
-
elsif ciphers = config['ciphers']
|
204
|
-
raise "Missing mandatory config parameter 'private_rsa_key'" unless cfg[:private_rsa_key] = config['private_rsa_key']
|
205
|
-
|
206
|
-
cfg[:ciphers] = ciphers.collect do |cipher_cfg|
|
207
|
-
key_filename = cipher_cfg['key_filename'] || cipher_cfg['symmetric_key_filename']
|
208
|
-
raise "Missing mandatory 'key_filename' for environment:#{environment} in #{filename}" unless key_filename
|
209
|
-
iv_filename = cipher_cfg['iv_filename'] || cipher_cfg['symmetric_iv_filename']
|
210
|
-
{
|
211
|
-
:cipher => cipher_cfg['cipher'] || default_cipher,
|
212
|
-
:key_filename => key_filename,
|
213
|
-
:iv_filename => iv_filename,
|
214
|
-
}
|
215
|
-
end
|
216
|
-
|
217
|
-
else
|
218
|
-
# Migrate old format config
|
219
|
-
raise "Missing mandatory config parameter 'private_rsa_key'" unless cfg[:private_rsa_key] = config['private_rsa_key']
|
220
|
-
cfg[:ciphers] = [ {
|
221
|
-
:cipher => default_cipher,
|
222
|
-
:key_filename => config['symmetric_key_filename'],
|
223
|
-
:iv_filename => config['symmetric_iv_filename'],
|
224
|
-
} ]
|
225
|
-
end
|
226
|
-
|
227
|
-
cfg
|
228
|
-
end
|
229
|
-
|
230
|
-
# Returns an instance of Symmetric::Cipher initialized from keys
|
231
|
-
# stored in files
|
232
|
-
#
|
233
|
-
# Raises an Exception on failure
|
234
|
-
#
|
235
|
-
# Parameters:
|
236
|
-
# cipher
|
237
|
-
# Encryption cipher for the symmetric encryption key
|
238
|
-
# private_key
|
239
|
-
# Key used to unlock file containing the actual symmetric key
|
240
|
-
# key_filename
|
241
|
-
# Name of file containing symmetric key encrypted using the public
|
242
|
-
# key matching the supplied private_key
|
243
|
-
# iv_filename
|
244
|
-
# Optional. Name of file containing symmetric key initialization vector
|
245
|
-
# encrypted using the public key matching the supplied private_key
|
246
|
-
def self.cipher_from_encrypted_files(private_rsa_key, cipher, key_filename, iv_filename = nil)
|
247
|
-
# Load Encrypted Symmetric keys
|
248
|
-
encrypted_key = File.read(key_filename)
|
249
|
-
encrypted_iv = File.read(iv_filename) if iv_filename
|
250
|
-
|
251
|
-
# Decrypt Symmetric Keys
|
252
|
-
rsa = OpenSSL::PKey::RSA.new(private_rsa_key)
|
253
|
-
iv = rsa.private_decrypt(encrypted_iv) if iv_filename
|
254
|
-
Cipher.new(
|
255
|
-
:key => rsa.private_decrypt(encrypted_key),
|
256
|
-
:iv => iv,
|
257
|
-
:cipher => cipher
|
258
|
-
)
|
259
|
-
end
|
260
|
-
|
261
|
-
end
|
262
|
-
end
|