symmetric-encryption 0.7.2 → 0.8.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 +66 -102
- data/examples/symmetric-encryption.yml +16 -17
- data/lib/rails/generators/symmetric_encryption/config/config_generator.rb +22 -0
- data/lib/rails/generators/symmetric_encryption/config/templates/symmetric-encryption.yml +50 -0
- data/lib/rails/generators/symmetric_encryption/new_keys/new_keys_generator.rb +14 -0
- data/lib/symmetric_encryption/cipher.rb +7 -3
- data/lib/symmetric_encryption/railtie.rb +8 -4
- data/lib/symmetric_encryption/railties/symmetric_encryption.rake +0 -5
- data/lib/symmetric_encryption/symmetric_encryption.rb +48 -24
- data/lib/symmetric_encryption/version.rb +1 -1
- data/test/attr_encrypted_test.rb +2 -2
- data/test/config/symmetric-encryption.yml +4 -0
- data/test/field_encrypted_test.rb +5 -5
- data/test/symmetric_encryption_test.rb +32 -1
- metadata +7 -4
data/README.md
CHANGED
@@ -138,97 +138,34 @@ specified environment
|
|
138
138
|
Note: Passwords must be encrypted in the environment in which they will be used.
|
139
139
|
Since each environment should have its own symmetric encryption keys
|
140
140
|
|
141
|
-
##
|
141
|
+
## Installation
|
142
142
|
|
143
|
-
|
144
|
-
|
145
|
-
## Configuration
|
146
|
-
|
147
|
-
### Generating the RSA Private key
|
143
|
+
### Add to an existing Rails project
|
144
|
+
Add the following line to Gemfile
|
148
145
|
|
149
|
-
|
150
|
-
encryption.
|
146
|
+
gem 'symmetric-encryption'
|
151
147
|
|
152
|
-
|
148
|
+
Install the Gem with bundler
|
153
149
|
|
154
|
-
|
150
|
+
bundle install
|
155
151
|
|
156
|
-
|
152
|
+
## Rails Configuration
|
157
153
|
|
158
154
|
### Creating the configuration file
|
159
155
|
|
160
|
-
|
156
|
+
The configuration file contains the path to the production encryption key files.
|
157
|
+
Generally in development and test the files are not created, so supply the full path
|
158
|
+
to these files in production. Once the config file has been generated it can be
|
159
|
+
modified as needed.
|
161
160
|
|
162
|
-
|
163
|
-
# Symmetric Encryption for Ruby
|
164
|
-
#
|
165
|
-
---
|
166
|
-
# For the development and test environments the test symmetric encryption keys
|
167
|
-
# can be placed directly in the source code.
|
168
|
-
# And therefore no RSA private key is required
|
169
|
-
development: &development_defaults
|
170
|
-
key: 1234567890ABCDEF1234567890ABCDEF
|
171
|
-
iv: 1234567890ABCDEF
|
172
|
-
cipher: aes-128-cbc
|
161
|
+
Generate the configuration file:
|
173
162
|
|
174
|
-
|
175
|
-
<<: *development_defaults
|
163
|
+
rails generate symmetric_encryption:config /etc/rails/keys
|
176
164
|
|
177
|
-
|
178
|
-
|
179
|
-
# source code, we only hold a RSA key that is used to unlock the file
|
180
|
-
# containing the actual symmetric encryption key
|
181
|
-
#
|
182
|
-
# Sample RSA Key, DO NOT use this RSA key, generate a new one using
|
183
|
-
# openssl genrsa 2048
|
184
|
-
private_rsa_key: |
|
185
|
-
-----BEGIN RSA PRIVATE KEY-----
|
186
|
-
MIIEpAIBAAKCAQEAxIL9H/jYUGpA38v6PowRSRJEo3aNVXULNM/QNRpx2DTf++KH
|
187
|
-
6DcuFTFcNSSSxG9n4y7tKi755be8N0uwCCuOzvXqfWmXYjbLwK3Ib2vm0btpHyvA
|
188
|
-
qxgqeJOOCxKdW/cUFLWn0tACUcEjVCNfWEGaFyvkOUuR7Ub9KfhbW9cZO3BxZMUf
|
189
|
-
IPGlHl/gWyf484sXygd+S7cpDTRRzo9RjG74DwfE0MFGf9a1fTkxnSgeOJ6asTOy
|
190
|
-
fp9tEToUlbglKaYGpOGHYQ9TV5ZsyJ9jRUyb4SP5wK2eK6dHTxTcHvT03kD90Hv4
|
191
|
-
WeKIXv3WOjkwNEyMdpnJJfSDb5oquQvCNi7ZSQIDAQABAoIBAQCbzR7TUoBugU+e
|
192
|
-
ICLvpC2wOYOh9kRoFLwlyv3QnH7WZFWRZzFJszYeJ1xr5etXQtyjCnmOkGAg+WOI
|
193
|
-
k8GlOKOpAuA/PpB/leJFiYL4lBwU/PmDdTT0cdx6bMKZlNCeMW8CXGQKiFDOcMqJ
|
194
|
-
0uGtH5YD+RChPIEeFsJxnC8SyZ9/t2ra7XnMGiCZvRXIUDSEIIsRx/mOymJ7bL+h
|
195
|
-
Lbp46IfXf6ZuIzwzoIk0JReV/r+wdmkAVDkrrMkCmVS4/X1wN/Tiik9/yvbsh/CL
|
196
|
-
ztC55eSIEjATkWxnXfPASZN6oUfQPEveGH3HzNjdncjH/Ho8FaNMIAfFpBhhLPi9
|
197
|
-
nG5sbH+BAoGBAOdoUyVoAA/QUa3/FkQaa7Ajjehe5MR5k6VtaGtcxrLiBjrNR7x+
|
198
|
-
nqlZlGvWDMiCz49dgj+G1Qk1bbYrZLRX/Hjeqy5dZOGLMfgf9eKUmS1rDwAzBMcj
|
199
|
-
M9jnnJEBx8HIlNzaR6wzp3GMd0rrccs660A8URvzkgo9qNbvMLq9vyUtAoGBANll
|
200
|
-
SY1Iv9uaIz8klTXU9YzYtsfUmgXzw7K8StPdbEbo8F1J3JPJB4D7QHF0ObIaSWuf
|
201
|
-
suZqLsvWlYGuJeyX2ntlBN82ORfvUdOrdrbDlmPyj4PfFVl0AK3U3Ai374DNrjKR
|
202
|
-
hF6YFm4TLDaJhUjeV5C43kbE1N2FAMS9LYtPJ44NAoGAFDGHZ/E+aCLerddfwwun
|
203
|
-
MBS6MnftcLPHTZ1RimTrNfsBXipBw1ItWEvn5s0kCm9X24PmdNK4TnhqHYaF4DL5
|
204
|
-
ZjbQK1idEA2Mi8GGPIKJJ2x7P6I0HYiV4qy7fe/w1ZlCXE90B7PuPbtrQY9wO7Ll
|
205
|
-
ipJ45X6I1PnyfOcckn8yafUCgYACtPAlgjJhWZn2v03cTbqA9nHQKyV/zXkyUIXd
|
206
|
-
/XPLrjrP7ouAi5A8WuSChR/yx8ECRgrEM65Be3qBEtoGCB4AS1G0NcigM6qhKBFi
|
207
|
-
VS0aMXr3+V8argcUIwJaWW/x+p2go48yXlJpLHPweeXe8mXEt4iM+QZte6p2yKQ4
|
208
|
-
h9PGQQKBgQCqSydmXBnXGIVTp2sH/2GnpxLYnDBpcJE0tM8bJ42HEQQgRThIChsn
|
209
|
-
PnGA91G9MVikYapgI0VYBHQOTsz8rTIUzsKwXG+TIaK+W84nxH5y6jUkjqwxZmAz
|
210
|
-
r1URaMAun2PfAB4g2N/kEZTExgeOGqXjFhvvjdzl97ux2cTyZhaTXg==
|
211
|
-
-----END RSA PRIVATE KEY-----
|
165
|
+
Note: Ignore the warning about "Symmetric Encryption config not found" since it is
|
166
|
+
being generated
|
212
167
|
|
213
|
-
|
214
|
-
ciphers:
|
215
|
-
-
|
216
|
-
# Filename containing Symmetric Encryption Key encrypted using the
|
217
|
-
# RSA public key derived from the private key above
|
218
|
-
key_filename: /etc/rails/.rails.key
|
219
|
-
iv_filename: /etc/rails/.rails.iv
|
220
|
-
|
221
|
-
# Encryption cipher
|
222
|
-
# Recommended values:
|
223
|
-
# aes-256-cbc
|
224
|
-
# 256 AES CBC Algorithm. Very strong
|
225
|
-
# Ruby 1.8.7 MRI Approximately 100,000 encryptions or decryptions per second
|
226
|
-
# JRuby 1.6.7 with Ruby 1.8.7 Approximately 22,000 encryptions or decryptions per second
|
227
|
-
# aes-128-cbc
|
228
|
-
# 128 AES CBC Algorithm. Less strong.
|
229
|
-
# Ruby 1.8.7 MRI Approximately 100,000 encryptions or decryptions per second
|
230
|
-
# JRuby 1.6.7 with Ruby 1.8.7 Approximately 22,000 encryptions or decryptions per second
|
231
|
-
cipher: aes-256-cbc
|
168
|
+
#### Save to version control
|
232
169
|
|
233
170
|
This configuration file should be checked into the source code control system.
|
234
171
|
It does Not include the Symmetric Encryption keys. They will be generated in the
|
@@ -236,22 +173,44 @@ next step.
|
|
236
173
|
|
237
174
|
### Generating and securing the Symmetric Encryption keys
|
238
175
|
|
176
|
+
Once development and testing is complete we need to generate secure encryption
|
177
|
+
key files for production. It is recommended that the step below be run on only
|
178
|
+
one of the production servers. The generated key files must then be copied to
|
179
|
+
all the production web servers.
|
180
|
+
|
181
|
+
Note: Do not run this step more than once, otherwise new keys will be generated
|
182
|
+
and any encrypted data will no longer be accessible.
|
183
|
+
|
184
|
+
Note: Do not run this step on more than one server in each environment otherwise
|
185
|
+
each server will be encrypting with it's own key and the servers will not be able
|
186
|
+
to decrypt data encrypted on another server. Just copy the generated files to each
|
187
|
+
server
|
188
|
+
|
239
189
|
The symmetric encryption key consists of the key itself and an optional
|
240
190
|
initialization vector.
|
241
191
|
|
242
|
-
To generate the keys run the following Rake task in each environment:
|
192
|
+
To generate the keys run the following Rake task once only in each environment:
|
243
193
|
|
244
|
-
|
194
|
+
rails generate symmetric_encryption:new_keys production
|
245
195
|
|
246
196
|
Replace 'production' as necessary for each environment.
|
247
197
|
|
248
198
|
Make sure that the current user has read and write access to the folder listed
|
249
|
-
in the
|
199
|
+
in the config file option key_filename.
|
200
|
+
|
201
|
+
Note: Ignore the warning about the key files "not found or readable" since they
|
202
|
+
are being generated
|
250
203
|
|
251
204
|
Once the Symmetric Encryption keys have been generated, secure them further by
|
252
|
-
making the files read-only to the Rails user and not readable by any other user
|
205
|
+
making the files read-only to the Rails user and not readable by any other user.
|
206
|
+
Change ownership of the keys to the rails user and only give it access to read the key files:
|
207
|
+
|
208
|
+
chown rails /etc/rails/keys/*
|
209
|
+
chmod 0400 /etc/rails/keys/*
|
253
210
|
|
254
|
-
|
211
|
+
Change 'rails' above to the userid under which your Rails processes are run
|
212
|
+
and update the path to the one supplied when generating the config file or
|
213
|
+
look in the config file itself
|
255
214
|
|
256
215
|
When running multiple Rails servers in a particular environment copy the same
|
257
216
|
key files to every server in that environment. I.e. All Rails servers in each
|
@@ -261,8 +220,16 @@ Note: The generate step above must only be run once in each environment
|
|
261
220
|
|
262
221
|
## Using in non-Rails environments
|
263
222
|
|
264
|
-
|
265
|
-
|
223
|
+
SymmetricEncryption can also be used in non-Rails environment.
|
224
|
+
|
225
|
+
Install SymmetricEncryption
|
226
|
+
|
227
|
+
gem install symmetric-encryption
|
228
|
+
|
229
|
+
Manually create a symmetric-encryption.yml configuration file based on the
|
230
|
+
one supplied in examples/symmetric-encryption.yml.
|
231
|
+
|
232
|
+
At application startup, run the code below to initialize symmetric-encryption prior to
|
266
233
|
attempting to encrypt or decrypt any data
|
267
234
|
|
268
235
|
require 'symmetric-encryption'
|
@@ -309,8 +276,8 @@ Create a configuration file in config/symmetric-encryption.yml per the following
|
|
309
276
|
# can be placed directly in the source code.
|
310
277
|
# And therefore no RSA private key is required
|
311
278
|
development: &development_defaults
|
312
|
-
key:
|
313
|
-
iv:
|
279
|
+
key: 1234567890ABCDEF1234567890ABCDEF
|
280
|
+
iv: 1234567890ABCDEF
|
314
281
|
cipher: aes-128-cbc
|
315
282
|
|
316
283
|
test:
|
@@ -358,7 +325,7 @@ Create a configuration file in config/symmetric-encryption.yml per the following
|
|
358
325
|
# Filename containing Symmetric Encryption Key encrypted using the
|
359
326
|
# RSA public key derived from the private key above
|
360
327
|
key_filename: /etc/rails/.rails.key
|
361
|
-
iv_filename:
|
328
|
+
iv_filename: /etc/rails/.rails.iv
|
362
329
|
|
363
330
|
# Encryption cipher
|
364
331
|
# Recommended values:
|
@@ -380,10 +347,17 @@ Create a configuration file in config/symmetric-encryption.yml per the following
|
|
380
347
|
# Only used when old data still exists that requires old decryption keys
|
381
348
|
# to be used
|
382
349
|
key_filename: /etc/rails/.rails_old.key
|
383
|
-
iv_filename:
|
384
|
-
cipher:
|
350
|
+
iv_filename: /etc/rails/.rails_old.iv
|
351
|
+
cipher: aes-256-cbc
|
385
352
|
|
386
|
-
##
|
353
|
+
## Future Enhancements
|
354
|
+
|
355
|
+
* Ability to randomly generate a new initialization vector (iv) with every
|
356
|
+
encryption and put the iv in the encrypted data as its header
|
357
|
+
|
358
|
+
* With file encryption randomly generate a new key and initialization vector (iv) with every
|
359
|
+
file encryption and put the key and iv in the encrypted data as its header which
|
360
|
+
is encrypted using the global key and iv
|
387
361
|
|
388
362
|
Submit an issue ticket to request any of the following features:
|
389
363
|
|
@@ -395,16 +369,6 @@ Submit an issue ticket to request any of the following features:
|
|
395
369
|
data exceeds some predefined size. And automatically decompressing the data
|
396
370
|
during decryption
|
397
371
|
|
398
|
-
* Make attr_encrypted auto-detect the encrypted column type and Base64 encode
|
399
|
-
when type is CHAR and store as binary when type is BINARY or BLOB
|
400
|
-
|
401
|
-
* Create rake task / generator to generate a sample configuration file
|
402
|
-
with a new RSA Private key already in it
|
403
|
-
|
404
|
-
* Ability to change SymmetricEncryption configuration options from custom
|
405
|
-
Rails initializers, rather than having everything in the config file.
|
406
|
-
For example config.symmetric_encryption.cipher = 'aes-128-cbc'
|
407
|
-
|
408
372
|
Meta
|
409
373
|
----
|
410
374
|
|
@@ -68,6 +68,21 @@ production:
|
|
68
68
|
# JRuby 1.6.7 with Ruby 1.8.7 Approximately 22,000 encryptions or decryptions per second
|
69
69
|
cipher: aes-256-cbc
|
70
70
|
|
71
|
+
# Set the way the encrypted data is encoded:
|
72
|
+
# base64
|
73
|
+
# Encrypted data is returned in base64 encoding format
|
74
|
+
# Symmetric::Encryption.decrypt will also base64 decode any data prior
|
75
|
+
# to decrypting it
|
76
|
+
# base64strict
|
77
|
+
# As base64 except that does not contain any newlines
|
78
|
+
# This is the recommended setting
|
79
|
+
# none
|
80
|
+
# Encrypted data is returned as raw binary
|
81
|
+
# Although smaller than base64 it cannot be stored in MySQL text columns
|
82
|
+
# It can only be held in binary columns such as BINARY or BLOB
|
83
|
+
# Default: base64
|
84
|
+
encoding: base64strict
|
85
|
+
|
71
86
|
# FUTURE ENHANCEMENT:
|
72
87
|
#
|
73
88
|
# By adding a version indicator all encrypted data will include
|
@@ -86,23 +101,6 @@ production:
|
|
86
101
|
# Default: 0
|
87
102
|
#version: 0
|
88
103
|
|
89
|
-
# FUTURE ENHANCEMENT:
|
90
|
-
#
|
91
|
-
# Set the way the encrypted data is encoded:
|
92
|
-
# base64
|
93
|
-
# Encrypted data is returned in base64 encoding format
|
94
|
-
# Symmetric::Encryption.decrypt will also base64 decode any data prior
|
95
|
-
# to decrypting it
|
96
|
-
# base64withoutsuffix
|
97
|
-
# As base64 except that the trailing newline is removed after base64
|
98
|
-
# encoding
|
99
|
-
# binary
|
100
|
-
# Encrypted data is returned as raw binary
|
101
|
-
# Although smaller than base64 it cannot be stored in MySQL text columns
|
102
|
-
# It can only be held in binary columns such as BINARY or BLOB
|
103
|
-
# Default: base64withoutsuffix
|
104
|
-
#encoding: base64withoutsuffix
|
105
|
-
|
106
104
|
# OPTIONAL:
|
107
105
|
#
|
108
106
|
# Any previous Symmetric Encryption Keys
|
@@ -112,3 +110,4 @@ production:
|
|
112
110
|
- key_filename: /etc/rails/.rails_old.key
|
113
111
|
iv_filename: /etc/rails/.rails_old.iv
|
114
112
|
cipher: aes-256-cbc
|
113
|
+
encoding: base64strict
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module SymmetricEncryption
|
2
|
+
module Generators
|
3
|
+
class ConfigGenerator < Rails::Generators::Base
|
4
|
+
desc "Creates a SymmetricEncryption configuration file at config/symmetric-encryption.yml"
|
5
|
+
|
6
|
+
argument :key_path, :type => :string, :optional => false
|
7
|
+
|
8
|
+
def self.source_root
|
9
|
+
@_symmetric_encryption_source_root ||= File.expand_path("../templates", __FILE__)
|
10
|
+
end
|
11
|
+
|
12
|
+
def app_name
|
13
|
+
Rails::Application.subclasses.first.parent.to_s.underscore
|
14
|
+
end
|
15
|
+
|
16
|
+
def create_config_file
|
17
|
+
template 'symmetric-encryption.yml', File.join('config', "symmetric-encryption.yml")
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
#
|
2
|
+
# Symmetric Encryption for Ruby
|
3
|
+
#
|
4
|
+
---
|
5
|
+
# For the development and test environments the test symmetric encryption keys
|
6
|
+
# can be placed directly in the source code.
|
7
|
+
# And therefore no RSA private key is required
|
8
|
+
development: &development_defaults
|
9
|
+
key: 1234567890ABCDEF1234567890ABCDEF
|
10
|
+
iv: 1234567890ABCDEF
|
11
|
+
cipher: aes-128-cbc
|
12
|
+
|
13
|
+
test:
|
14
|
+
<<: *development_defaults
|
15
|
+
|
16
|
+
release:
|
17
|
+
# Since the key to encrypt and decrypt with must NOT be stored along with the
|
18
|
+
# source code, we only hold a RSA key that is used to unlock the file
|
19
|
+
# containing the actual symmetric encryption key
|
20
|
+
private_rsa_key: |
|
21
|
+
<%= OpenSSL::PKey::RSA.generate(2048).to_s.collect { |line| " #{line}" }.join('') %>
|
22
|
+
|
23
|
+
# List Symmetric Key files in the order of current / latest first
|
24
|
+
ciphers:
|
25
|
+
-
|
26
|
+
# Filename containing Symmetric Encryption Key encrypted using the
|
27
|
+
# RSA public key derived from the private key above
|
28
|
+
key_filename: <%= File.join(key_path, "#{app_name}_release.key") %>
|
29
|
+
iv_filename: <%= File.join(key_path, "#{app_name}_release.iv") %>
|
30
|
+
cipher: aes-256-cbc
|
31
|
+
# Base64 encode encrypted data without newlines
|
32
|
+
encoding: base64strict
|
33
|
+
|
34
|
+
production:
|
35
|
+
# Since the key to encrypt and decrypt with must NOT be stored along with the
|
36
|
+
# source code, we only hold a RSA key that is used to unlock the file
|
37
|
+
# containing the actual symmetric encryption key
|
38
|
+
private_rsa_key: |
|
39
|
+
<%= OpenSSL::PKey::RSA.generate(2048).to_s.collect { |line| " #{line}" }.join('') %>
|
40
|
+
|
41
|
+
# List Symmetric Key files in the order of current / latest first
|
42
|
+
ciphers:
|
43
|
+
-
|
44
|
+
# Filename containing Symmetric Encryption Key encrypted using the
|
45
|
+
# RSA public key derived from the private key above
|
46
|
+
key_filename: <%= File.join(key_path, "#{app_name}_production.key") %>
|
47
|
+
iv_filename: <%= File.join(key_path, "#{app_name}_production.iv") %>
|
48
|
+
cipher: aes-256-cbc
|
49
|
+
# Base64 encode encrypted data without newlines
|
50
|
+
encoding: base64strict
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module SymmetricEncryption
|
2
|
+
module Generators
|
3
|
+
class NewKeysGenerator < Rails::Generators::Base
|
4
|
+
desc "Generate new Symmetric key and initialization vector based on values in config/symmetric-encryption.yml"
|
5
|
+
|
6
|
+
argument :environment, :type => :string, :optional => false
|
7
|
+
|
8
|
+
def create_config_file
|
9
|
+
SymmetricEncryption.generate_symmetric_key_files(File.join('config', "symmetric-encryption.yml"), environment)
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -7,10 +7,11 @@ module SymmetricEncryption
|
|
7
7
|
# threads at the same time without needing an instance of Cipher per thread
|
8
8
|
class Cipher
|
9
9
|
# Cipher to use for encryption and decryption
|
10
|
-
attr_reader :cipher, :version
|
10
|
+
attr_reader :cipher, :version, :version
|
11
|
+
attr_accessor :encoding
|
11
12
|
|
12
|
-
#
|
13
|
-
|
13
|
+
# Available encodings
|
14
|
+
ENCODINGS = [:none, :base64, :base64strict]
|
14
15
|
|
15
16
|
# Generate a new Symmetric Key pair
|
16
17
|
#
|
@@ -43,6 +44,9 @@ module SymmetricEncryption
|
|
43
44
|
@iv = parms[:iv]
|
44
45
|
@cipher = parms[:cipher] || 'aes-256-cbc'
|
45
46
|
@version = parms[:version]
|
47
|
+
@encoding = (parms[:encoding] || :base64).to_sym
|
48
|
+
|
49
|
+
raise("Invalid Encoding: #{@encoding}") unless ENCODINGS.include?(@encoding)
|
46
50
|
end
|
47
51
|
|
48
52
|
# AES Symmetric Encryption of supplied string
|
@@ -7,10 +7,14 @@ module SymmetricEncryption #:nodoc:
|
|
7
7
|
# @example Set up configuration in the Rails app.
|
8
8
|
# module MyApplication
|
9
9
|
# class Application < Rails::Application
|
10
|
-
# config.symmetric_encryption.cipher =
|
10
|
+
# config.symmetric_encryption.cipher = SymmetricEncryption::Cipher.new(
|
11
|
+
# :key => '1234567890ABCDEF1234567890ABCDEF',
|
12
|
+
# :iv => '1234567890ABCDEF',
|
13
|
+
# :cipher => 'aes-128-cbc'
|
14
|
+
# )
|
11
15
|
# end
|
12
16
|
# end
|
13
|
-
|
17
|
+
config.symmetric_encryption = ::SymmetricEncryption
|
14
18
|
|
15
19
|
rake_tasks do
|
16
20
|
load "symmetric_encryption/railties/symmetric_encryption.rake"
|
@@ -33,8 +37,8 @@ module SymmetricEncryption #:nodoc:
|
|
33
37
|
if config_file.file?
|
34
38
|
::SymmetricEncryption.load!(config_file, Rails.env)
|
35
39
|
else
|
36
|
-
puts "\nSymmetric Encryption config not found.
|
37
|
-
|
40
|
+
puts "\nSymmetric Encryption config not found."
|
41
|
+
puts "To generate one for the first time: rails generate symmetric_encryption:config\n\n"
|
38
42
|
end
|
39
43
|
end
|
40
44
|
|
@@ -23,11 +23,6 @@ namespace :symmetric_encryption do
|
|
23
23
|
puts "\nEncrypted: #{SymmetricEncryption.encrypt(password1)}\n\n"
|
24
24
|
end
|
25
25
|
|
26
|
-
desc 'Generate new Symmetric key and initialization vector. Example: RAILS_ENV=production rake symmetric_encryption:generate_symmetric_keys'
|
27
|
-
task :generate_symmetric_keys do
|
28
|
-
SymmetricEncryption.generate_symmetric_key_files
|
29
|
-
end
|
30
|
-
|
31
26
|
desc 'Generate a random password and display its encrypted form. Example: rake symmetric_encryption:random_password'
|
32
27
|
task :random_password => :environment do
|
33
28
|
p = SymmetricEncryption.random_password
|
@@ -65,13 +65,19 @@ module SymmetricEncryption
|
|
65
65
|
#
|
66
66
|
def self.decrypt(str)
|
67
67
|
raise "Call SymmetricEncryption.load! or SymmetricEncryption.cipher= prior to encrypting or decrypting data" unless @@cipher
|
68
|
-
|
68
|
+
|
69
|
+
# Decode data first based on encoding setting
|
70
|
+
case @@cipher.encoding
|
71
|
+
when :base64, :base64strict
|
72
|
+
str = ::Base64.decode64(str) if str
|
73
|
+
end
|
74
|
+
|
69
75
|
begin
|
70
|
-
@@cipher.decrypt(
|
76
|
+
@@cipher.decrypt(str)
|
71
77
|
rescue OpenSSL::Cipher::CipherError => exc
|
72
78
|
@@secondary_ciphers.each do |cipher|
|
73
79
|
begin
|
74
|
-
return cipher.decrypt(
|
80
|
+
return cipher.decrypt(str)
|
75
81
|
rescue OpenSSL::Cipher::CipherError
|
76
82
|
end
|
77
83
|
end
|
@@ -87,11 +93,18 @@ module SymmetricEncryption
|
|
87
93
|
raise "Call SymmetricEncryption.load! or SymmetricEncryption.cipher= prior to encrypting or decrypting data" unless @@cipher
|
88
94
|
|
89
95
|
# Encrypt data as a binary string
|
90
|
-
result = @@cipher.encrypt(str)
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
96
|
+
if result = @@cipher.encrypt(str)
|
97
|
+
# Now encode data based on encoding setting
|
98
|
+
case @@cipher.encoding
|
99
|
+
when :base64
|
100
|
+
# Base 64 Encoding of binary data
|
101
|
+
::Base64.encode64(result)
|
102
|
+
when :base64strict
|
103
|
+
::Base64.encode64(result).gsub(/\n/, '')
|
104
|
+
else
|
105
|
+
result
|
106
|
+
end
|
107
|
+
end
|
95
108
|
end
|
96
109
|
|
97
110
|
# Invokes decrypt
|
@@ -117,11 +130,9 @@ module SymmetricEncryption
|
|
117
130
|
def self.encrypted?(encrypted_data)
|
118
131
|
raise "Call SymmetricEncryption.load! or SymmetricEncryption.cipher= prior to encrypting or decrypting data" unless @@cipher
|
119
132
|
|
120
|
-
# First make sure Base64 encoded data still ends with "\n" since it could be used in a key field somewhere
|
121
|
-
return false unless encrypted_data.end_with?("\n")
|
122
|
-
|
123
133
|
# For now have to decrypt it fully
|
124
|
-
|
134
|
+
result = try_decrypt(encrypted_data)
|
135
|
+
!(result.nil? || result == '')
|
125
136
|
end
|
126
137
|
|
127
138
|
# Load the Encryption Configuration from a YAML file
|
@@ -142,11 +153,7 @@ module SymmetricEncryption
|
|
142
153
|
else
|
143
154
|
private_rsa_key = config[:private_rsa_key]
|
144
155
|
@@cipher, *@@secondary_ciphers = config[:ciphers].collect do |cipher_conf|
|
145
|
-
cipher_from_encrypted_files(
|
146
|
-
private_rsa_key,
|
147
|
-
cipher_conf[:cipher],
|
148
|
-
cipher_conf[:key_filename],
|
149
|
-
cipher_conf[:iv_filename])
|
156
|
+
cipher_from_encrypted_files(private_rsa_key, cipher_conf)
|
150
157
|
end
|
151
158
|
end
|
152
159
|
|
@@ -164,7 +171,7 @@ module SymmetricEncryption
|
|
164
171
|
# and initilization vector .iv
|
165
172
|
# which is encrypted with the above Public key
|
166
173
|
#
|
167
|
-
#
|
174
|
+
# Existing key files will be renamed if present
|
168
175
|
def self.generate_symmetric_key_files(filename=nil, environment=nil)
|
169
176
|
config = read_config(filename, environment)
|
170
177
|
cipher_cfg = config[:ciphers].first
|
@@ -239,6 +246,7 @@ module SymmetricEncryption
|
|
239
246
|
:cipher => cipher_cfg['cipher'] || default_cipher,
|
240
247
|
:key_filename => key_filename,
|
241
248
|
:iv_filename => iv_filename,
|
249
|
+
:encoding => cipher_cfg['encoding']
|
242
250
|
}
|
243
251
|
end
|
244
252
|
|
@@ -271,18 +279,34 @@ module SymmetricEncryption
|
|
271
279
|
# iv_filename
|
272
280
|
# Optional. Name of file containing symmetric key initialization vector
|
273
281
|
# encrypted using the public key matching the supplied private_key
|
274
|
-
def self.cipher_from_encrypted_files(private_rsa_key,
|
282
|
+
def self.cipher_from_encrypted_files(private_rsa_key, cipher_conf)
|
275
283
|
# Load Encrypted Symmetric keys
|
276
|
-
|
277
|
-
|
284
|
+
key_filename = cipher_conf[:key_filename]
|
285
|
+
encrypted_key = begin
|
286
|
+
File.read(key_filename)
|
287
|
+
rescue Errno::ENOENT
|
288
|
+
puts "\nSymmetric Encryption key file: '#{key_filename}' not found or readable."
|
289
|
+
puts "To generate the keys for the first time run: rails generate symmetric_encryption:new_keys\n\n"
|
290
|
+
return
|
291
|
+
end
|
292
|
+
|
293
|
+
iv_filename = cipher_conf[:iv_filename]
|
294
|
+
encrypted_iv = begin
|
295
|
+
File.read(iv_filename) if iv_filename
|
296
|
+
rescue Errno::ENOENT
|
297
|
+
puts "\nSymmetric Encryption initialization vector file: '#{iv_filename}' not found or readable."
|
298
|
+
puts "To generate the keys for the first time run: rails generate symmetric_encryption:new_keys\n\n"
|
299
|
+
return
|
300
|
+
end
|
278
301
|
|
279
302
|
# Decrypt Symmetric Keys
|
280
303
|
rsa = OpenSSL::PKey::RSA.new(private_rsa_key)
|
281
304
|
iv = rsa.private_decrypt(encrypted_iv) if iv_filename
|
282
305
|
Cipher.new(
|
283
|
-
:key
|
284
|
-
:iv
|
285
|
-
:cipher
|
306
|
+
:key => rsa.private_decrypt(encrypted_key),
|
307
|
+
:iv => iv,
|
308
|
+
:cipher => cipher_conf[:cipher],
|
309
|
+
:encoding => cipher_conf[:encoding]
|
286
310
|
)
|
287
311
|
end
|
288
312
|
|
data/test/attr_encrypted_test.rb
CHANGED
@@ -51,10 +51,10 @@ class AttrEncryptedTest < Test::Unit::TestCase
|
|
51
51
|
|
52
52
|
setup do
|
53
53
|
@bank_account_number = "1234567890"
|
54
|
-
@bank_account_number_encrypted = "L94ArJeFlJrZp6SYsvoOGA
|
54
|
+
@bank_account_number_encrypted = "L94ArJeFlJrZp6SYsvoOGA=="
|
55
55
|
|
56
56
|
@social_security_number = "987654321"
|
57
|
-
@social_security_number_encrypted = "S+8X1NRrqdfEIQyFHVPuVA
|
57
|
+
@social_security_number_encrypted = "S+8X1NRrqdfEIQyFHVPuVA=="
|
58
58
|
|
59
59
|
@user = User.new(
|
60
60
|
# Encrypted Attribute
|
@@ -39,9 +39,13 @@ test:
|
|
39
39
|
- key_filename: /Users/rmorrison/Sandbox/symmetric-encryption/test/config/test_new.key
|
40
40
|
iv_filename: /Users/rmorrison/Sandbox/symmetric-encryption/test/config/test_new.iv
|
41
41
|
cipher: aes-128-cbc
|
42
|
+
# Base64 encode encrypted data without newlines
|
43
|
+
encoding: base64strict
|
42
44
|
|
43
45
|
# Previous Symmetric Encryption Key
|
44
46
|
- key_filename: /Users/rmorrison/Sandbox/symmetric-encryption/test/config/test_secondary_1.key
|
45
47
|
iv_filename: /Users/rmorrison/Sandbox/symmetric-encryption/test/config/test_secondary_1.iv
|
46
48
|
cipher: aes-128-cbc
|
49
|
+
# Base64 encode encrypted data without newlines
|
50
|
+
encoding: base64
|
47
51
|
|
@@ -39,19 +39,19 @@ class FieldEncryptedTest < Test::Unit::TestCase
|
|
39
39
|
context 'the SymmetricEncryption Library' do
|
40
40
|
setup do
|
41
41
|
@bank_account_number = "1234567890"
|
42
|
-
@bank_account_number_encrypted = "L94ArJeFlJrZp6SYsvoOGA
|
42
|
+
@bank_account_number_encrypted = "L94ArJeFlJrZp6SYsvoOGA=="
|
43
43
|
|
44
44
|
@social_security_number = "987654321"
|
45
|
-
@social_security_number_encrypted = "S+8X1NRrqdfEIQyFHVPuVA
|
45
|
+
@social_security_number_encrypted = "S+8X1NRrqdfEIQyFHVPuVA=="
|
46
46
|
|
47
47
|
@integer = 32768
|
48
|
-
@integer_encrypted = "FA3smFQEKqB/ITv+A0xACg
|
48
|
+
@integer_encrypted = "FA3smFQEKqB/ITv+A0xACg=="
|
49
49
|
|
50
50
|
@float = 0.9867
|
51
|
-
@float_encrypted = "z7Pwt2JDp74d+u0IXFAdrQ
|
51
|
+
@float_encrypted = "z7Pwt2JDp74d+u0IXFAdrQ=="
|
52
52
|
|
53
53
|
@date = Date.parse('20120320')
|
54
|
-
@date_encrypted = "WTkSPHo5ApSSHBJMxxWt2A
|
54
|
+
@date_encrypted = "WTkSPHo5ApSSHBJMxxWt2A=="
|
55
55
|
|
56
56
|
# #TODO Intercept passing in attributes to create etc.
|
57
57
|
@user = MongoidUser.new(
|
@@ -24,11 +24,42 @@ class SymmetricEncryptionTest < Test::Unit::TestCase
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
context '
|
27
|
+
context 'Base64 encoding tests' do
|
28
28
|
setup do
|
29
29
|
@social_security_number = "987654321"
|
30
30
|
@social_security_number_encrypted = "S+8X1NRrqdfEIQyFHVPuVA==\n"
|
31
31
|
@social_security_number_encrypted_with_secondary_1 = "D1UCu38pqJ3jc0GvwJHiow==\n"
|
32
|
+
@encoding = SymmetricEncryption.cipher.encoding
|
33
|
+
SymmetricEncryption.cipher.encoding = :base64
|
34
|
+
end
|
35
|
+
|
36
|
+
teardown do
|
37
|
+
SymmetricEncryption.cipher.encoding = @encoding
|
38
|
+
end
|
39
|
+
|
40
|
+
should "encrypt simple string" do
|
41
|
+
assert_equal @social_security_number_encrypted, SymmetricEncryption.encrypt(@social_security_number)
|
42
|
+
end
|
43
|
+
|
44
|
+
should "decrypt string" do
|
45
|
+
assert_equal @social_security_number, SymmetricEncryption.decrypt(@social_security_number_encrypted)
|
46
|
+
end
|
47
|
+
|
48
|
+
should "determine if string is encrypted" do
|
49
|
+
assert_equal true, SymmetricEncryption.encrypted?(@social_security_number_encrypted)
|
50
|
+
assert_equal false, SymmetricEncryption.encrypted?(@social_security_number)
|
51
|
+
end
|
52
|
+
|
53
|
+
should "decrypt with secondary key when first one fails" do
|
54
|
+
assert_equal @social_security_number, SymmetricEncryption.decrypt(@social_security_number_encrypted)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'Base64Strict tests' do
|
59
|
+
setup do
|
60
|
+
@social_security_number = "987654321"
|
61
|
+
@social_security_number_encrypted = "S+8X1NRrqdfEIQyFHVPuVA=="
|
62
|
+
@social_security_number_encrypted_with_secondary_1 = "D1UCu38pqJ3jc0GvwJHiow=="
|
32
63
|
end
|
33
64
|
|
34
65
|
should "encrypt simple string" do
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 8
|
8
|
+
- 0
|
9
|
+
version: 0.8.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Reid Morrison
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2012-08-
|
17
|
+
date: 2012-08-28 00:00:00 -04:00
|
18
18
|
default_executable:
|
19
19
|
dependencies: []
|
20
20
|
|
@@ -32,6 +32,9 @@ files:
|
|
32
32
|
- csv_encrypted
|
33
33
|
- csv_encrypted_zip
|
34
34
|
- examples/symmetric-encryption.yml
|
35
|
+
- lib/rails/generators/symmetric_encryption/config/config_generator.rb
|
36
|
+
- lib/rails/generators/symmetric_encryption/config/templates/symmetric-encryption.yml
|
37
|
+
- lib/rails/generators/symmetric_encryption/new_keys/new_keys_generator.rb
|
35
38
|
- lib/symmetric-encryption.rb
|
36
39
|
- lib/symmetric_encryption/cipher.rb
|
37
40
|
- lib/symmetric_encryption/extensions/active_record/base.rb
|