symmetric-encryption 0.9.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ce8b40ac71f3b255ea4947fe3a41ba51145b5188
4
+ data.tar.gz: de4ceb7712388671b92054ed66409e78ddcf21bd
5
+ SHA512:
6
+ metadata.gz: 83166719c8132a10e4108c6d8e3822b61dc02be4bcd0159a47d44a6f23ebc914b8ab5cf2b979cd7a4fffc413f6d0a1aa0b6e7f211afa2e4031173f72cf2c5ef4
7
+ data.tar.gz: 1c0917a0a784610aaa517b526374fed613883203bb0d9ff04f56c6182581af415f4b2b73adb81c15948e8a5e2c2ed17d83d5820f9ed47b75498c4863d79c8668
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ source :rubygems
2
+
3
+ group :test do
4
+ gem "shoulda"
5
+
6
+ gem "activerecord"
7
+ platforms :ruby do
8
+ gem 'sqlite3'
9
+ end
10
+
11
+ platforms :jruby do
12
+ gem 'jdbc-sqlite3'
13
+ gem 'activerecord-jdbcsqlite3-adapter'
14
+ end
15
+
16
+ gem "mongoid"
17
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,50 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activemodel (3.2.9)
5
+ activesupport (= 3.2.9)
6
+ builder (~> 3.0.0)
7
+ activerecord (3.2.9)
8
+ activemodel (= 3.2.9)
9
+ activesupport (= 3.2.9)
10
+ arel (~> 3.0.2)
11
+ tzinfo (~> 0.3.29)
12
+ activesupport (3.2.9)
13
+ i18n (~> 0.6)
14
+ multi_json (~> 1.0)
15
+ arel (3.0.2)
16
+ bourne (1.1.2)
17
+ mocha (= 0.10.5)
18
+ builder (3.0.4)
19
+ i18n (0.6.1)
20
+ metaclass (0.0.1)
21
+ mocha (0.10.5)
22
+ metaclass (~> 0.0.1)
23
+ mongoid (3.0.6)
24
+ activemodel (~> 3.1)
25
+ moped (~> 1.1)
26
+ origin (~> 1.0)
27
+ tzinfo (~> 0.3.22)
28
+ moped (1.2.5)
29
+ multi_json (1.5.0)
30
+ origin (1.0.9)
31
+ shoulda (3.3.2)
32
+ shoulda-context (~> 1.0.1)
33
+ shoulda-matchers (~> 1.4.1)
34
+ shoulda-context (1.0.1)
35
+ shoulda-matchers (1.4.2)
36
+ activesupport (>= 3.0.0)
37
+ bourne (~> 1.1.2)
38
+ sqlite3 (1.3.6)
39
+ tzinfo (0.3.35)
40
+
41
+ PLATFORMS
42
+ ruby
43
+
44
+ DEPENDENCIES
45
+ activerecord
46
+ activerecord-jdbcsqlite3-adapter
47
+ jdbc-sqlite3
48
+ mongoid
49
+ shoulda
50
+ sqlite3
data/README.md CHANGED
@@ -27,7 +27,7 @@ created, managed and further secured by System Administrators. This prevents
27
27
  developers having or needing to have access to the symmetric encryption keys
28
28
  * The Operating System security features limit access to the Symmetric Encryption
29
29
  key files to System Administrators and the userid under which the Rails application runs.
30
- * The files in which the Symmetric Encryption keys are stored are futher
30
+ * The files in which the Symmetric Encryption keys are stored are further
31
31
  encrypted using RSA 2048 bit encryption
32
32
 
33
33
  In order for anyone to decrypt the data being encrypted in the database, they
@@ -38,6 +38,15 @@ by the Operating System
38
38
  * The userid and password for the database to copy the encrypted data itself,
39
39
  or an unsecured copy or export of the database contents
40
40
 
41
+ A major feature of symmetric encryption is that it makes the encryption and decryption
42
+ automatically available when the Rails application is started. This includes all
43
+ rake tasks and the Rails console. In this way data can be encrypted or decrypted as
44
+ part of any rake task.
45
+
46
+ From a security perspective it is important then to properly secure the system so that
47
+ no hacker can switch to and run as the rails user and thereby gain access to the
48
+ encryption and decryption capabilities
49
+
41
50
  ## Features
42
51
 
43
52
  * Encryption of passwords in configuration files
@@ -59,37 +68,96 @@ are extended with encrypted_ behavior, rather than every object in the system
59
68
 
60
69
  ### Encryption Example
61
70
 
62
- SymmetricEncryption.encrypt "Sensitive data"
71
+ ```ruby
72
+ SymmetricEncryption.encrypt "Sensitive data"
73
+ ```
63
74
 
64
75
  ### Decryption Example
65
76
 
66
- SymmetricEncryption.decrypt "JqLJOi6dNjWI9kX9lSL1XQ==\n"
77
+ ```ruby
78
+ SymmetricEncryption.decrypt "JqLJOi6dNjWI9kX9lSL1XQ==\n"
79
+ ```
67
80
 
68
- ### Validation Example
81
+ ### ActiveRecord Example
82
+
83
+ ```ruby
84
+ class User < ActiveRecord::Base
85
+ # Requires table users to have a column called encrypted_bank_account_number
86
+ attr_encrypted :bank_account_number
87
+
88
+ # Requires table users to have a column called encrypted_social_security_number
89
+ attr_encrypted :social_security_number
90
+
91
+ validates :encrypted_bank_account_number, :symmetric_encryption => true
92
+ validates :encrypted_social_security_number, :symmetric_encryption => true
93
+ end
94
+
95
+ # Create a new user instance assigning a bank account number
96
+ user = User.new
97
+ user.bank_account_number = '12345'
98
+
99
+ # Saves the bank_account_number in the column encrypted_bank_account_number in
100
+ # encrypted form
101
+ user.save!
102
+
103
+ # Short example using create
104
+ User.create(:bank_account_number => '12345')
105
+ ```
106
+
107
+ ### Mongoid Example
69
108
 
70
- class MyModel < ActiveRecord::Base
71
- validates :encrypted_ssn, :symmetric_encryption => true
72
- end
109
+ To encrypt a field in a Mongoid document, just add ":encrypted => true" at the end
110
+ of the field specifier. The field name must currently begin with "encrypted_"
73
111
 
74
- m = MyModel.new
75
- m.valid?
76
- # => false
77
- m.encrypted_ssn = SymmetricEncryption.encrypt('123456789')
78
- m.valid?
79
- # => true
112
+ ```ruby
113
+ # User model in Mongoid
114
+ class User
115
+ include Mongoid::Document
80
116
 
117
+ field :name, :type => String
118
+ field :encrypted_bank_account_number, :type => String, :encrypted => true
119
+ field :encrypted_social_security_number, :type => String, :encrypted => true
120
+ end
121
+
122
+ # Create a new user document
123
+ User.create(:bank_account_number => '12345')
124
+
125
+ # When finding a document, always use the encrypted form of the field name
126
+ user = User.where(:encrypted_bank_account_number => SymmetricEncryption.encrypt('12345')).first
127
+
128
+ # Fields can be accessed using their unencrypted names
129
+ puts user.bank_account_number
130
+ ```
131
+
132
+ ### Validation Example
133
+
134
+ ```ruby
135
+ class MyModel < ActiveRecord::Base
136
+ validates :encrypted_ssn, :symmetric_encryption => true
137
+ end
138
+
139
+ m = MyModel.new
140
+ m.valid?
141
+ # => false
142
+ m.encrypted_ssn = SymmetricEncryption.encrypt('123456789')
143
+ m.valid?
144
+ # => true
145
+ ```
81
146
  ### Encrypting Passwords in configuration files
82
147
 
83
148
  Passwords can be encrypted in any YAML configuration file.
84
149
 
85
150
  For example config/database.yml
86
151
 
87
- production:
88
- adapter: mysql
89
- host: db1w
90
- database: myapp_production
91
- username: admin
92
- password: <%= SymmetricEncryption.try_decrypt "JqLJOi6dNjWI9kX9lSL1XQ==\n" %>
152
+ ```yaml
153
+ ---
154
+ production:
155
+ adapter: mysql
156
+ host: db1w
157
+ database: myapp_production
158
+ username: admin
159
+ password: <%= SymmetricEncryption.try_decrypt "JqLJOi6dNjWI9kX9lSL1XQ==\n" %>
160
+ ```
93
161
 
94
162
  Note: Use SymmetricEncryption.try_decrypt method which will return nil if it
95
163
  fails to decrypt the value, which is essential when the encryption keys differ
@@ -98,54 +166,75 @@ Note: Use SymmetricEncryption.try_decrypt method which will return nil if it
98
166
  Note: In order for the above technique to work in other YAML configuration files
99
167
  the YAML file must be processed using ERB prior to passing to YAML. For example
100
168
 
169
+ ```ruby
101
170
  config_file = Rails.root.join('config', 'redis.yml')
102
171
  raise "redis config not found. Create a config file at: config/redis.yml" unless config_file.file?
103
172
 
104
173
  cfg = YAML.load(ERB.new(File.new(config_file).read).result)[Rails.env]
105
174
  raise("Environment #{Rails.env} not defined in redis.yml") unless cfg
175
+ ```
106
176
 
107
177
  ### Large File Encryption
108
178
 
109
179
  Example: Read and decrypt a line at a time from a file
110
180
 
111
- SymmetricEncryption::Reader.open('encrypted_file') do |file|
112
- file.each_line do |line|
113
- puts line
114
- end
115
- end
181
+ ```ruby
182
+ SymmetricEncryption::Reader.open('encrypted_file') do |file|
183
+ file.each_line do |line|
184
+ puts line
185
+ end
186
+ end
187
+ ```
116
188
 
117
189
  Example: Encrypt and write data to a file
118
190
 
119
- SymmetricEncryption::Writer.open('encrypted_file') do |file|
120
- file.write "Hello World\n"
121
- file.write "Keep this secret"
122
- end
191
+ ```ruby
192
+ SymmetricEncryption::Writer.open('encrypted_file') do |file|
193
+ file.write "Hello World\n"
194
+ file.write "Keep this secret"
195
+ end
196
+ ```
123
197
 
124
198
  Example: Compress, Encrypt and write data to a file
125
199
 
126
- SymmetricEncryption::Writer.open('encrypted_compressed.zip', :compress => true) do |file|
127
- file.write "Hello World\n"
128
- file.write "Compress this\n"
129
- file.write "Keep this safe and secure\n"
130
- end
200
+ ```ruby
201
+ SymmetricEncryption::Writer.open('encrypted_compressed.zip', :compress => true) do |file|
202
+ file.write "Hello World\n"
203
+ file.write "Compress this\n"
204
+ file.write "Keep this safe and secure\n"
205
+ end
206
+ ```
131
207
 
132
208
  ### Standalone test
133
209
 
134
210
  Before generating keys we can use SymmetricEncryption in a standalone test environment:
135
211
 
136
- # Use test encryption keys
137
- SymmetricEncryption.cipher = SymmetricEncryption::Cipher.new(
138
- :key => '1234567890ABCDEF1234567890ABCDEF',
139
- :iv => '1234567890ABCDEF',
140
- :cipher => 'aes-128-cbc'
141
- )
142
- encrypted = SymmetricEncryption.encrypt('hello world')
143
- puts SymmetricEncryption.decrypt(encrypted)
212
+ ```ruby
213
+ # Use test encryption keys
214
+ SymmetricEncryption.cipher = SymmetricEncryption::Cipher.new(
215
+ :key => '1234567890ABCDEF1234567890ABCDEF',
216
+ :iv => '1234567890ABCDEF',
217
+ :cipher => 'aes-128-cbc'
218
+ )
219
+ encrypted = SymmetricEncryption.encrypt('hello world')
220
+ puts SymmetricEncryption.decrypt(encrypted)
221
+ ```
222
+
223
+ ### Rake Tasks
224
+
225
+ For PCI compliance developers should not be the ones creating or encrypting
226
+ passwords. The following rake tasks can be used by system administrators to
227
+ generate and encrypt passwords for databases, or external web calls.
228
+ It is safe to pass the encrypted password for say MySQL to the developers
229
+ who can then put it in the config files which are kept in source control.
230
+
231
+ Generate a random password and display its encrypted form:
232
+
233
+ rake symmetric_encryption:random_password
144
234
 
145
- ### Generating encrypted passwords
235
+ Encrypt a known value, such as a password:
146
236
 
147
- The following rake task can be used to generate encrypted passwords for the
148
- specified environment
237
+ rake symmetric_encryption:encrypt
149
238
 
150
239
  Note: Passwords must be encrypted in the environment in which they will be used.
151
240
  Since each environment should have its own symmetric encryption keys
@@ -155,7 +244,9 @@ Note: Passwords must be encrypted in the environment in which they will be used.
155
244
  ### Add to an existing Rails project
156
245
  Add the following line to Gemfile
157
246
 
158
- gem 'symmetric-encryption'
247
+ ```ruby
248
+ gem 'symmetric-encryption'
249
+ ```
159
250
 
160
251
  Install the Gem with bundler
161
252
 
@@ -244,8 +335,10 @@ one supplied in examples/symmetric-encryption.yml.
244
335
  At application startup, run the code below to initialize symmetric-encryption prior to
245
336
  attempting to encrypt or decrypt any data
246
337
 
247
- require 'symmetric-encryption'
248
- SymmetricEncryption.load!('config/symmetric-encryption.yml', 'production')
338
+ ```ruby
339
+ require 'symmetric-encryption'
340
+ SymmetricEncryption.load!('config/symmetric-encryption.yml', 'production')
341
+ ```
249
342
 
250
343
  Parameters:
251
344
 
@@ -254,8 +347,10 @@ Parameters:
254
347
 
255
348
  To manually generate the symmetric encryption keys, run the code below
256
349
 
257
- require 'symmetric-encryption'
258
- SymmetricEncryption.generate_symmetric_key_files('config/symmetric-encryption.yml', 'production')
350
+ ```ruby
351
+ require 'symmetric-encryption'
352
+ SymmetricEncryption.generate_symmetric_key_files('config/symmetric-encryption.yml', 'production')
353
+ ```
259
354
 
260
355
  Parameters:
261
356
 
@@ -280,87 +375,89 @@ use the same RSA Private key for gaining access to the Symmetric Encryption Keys
280
375
 
281
376
  Create a configuration file in config/symmetric-encryption.yml per the following example:
282
377
 
283
- #
284
- # Symmetric Encryption for Ruby
285
- #
286
- ---
287
- # For the development and test environments the test symmetric encryption keys
288
- # can be placed directly in the source code.
289
- # And therefore no RSA private key is required
290
- development: &development_defaults
291
- key: 1234567890ABCDEF1234567890ABCDEF
292
- iv: 1234567890ABCDEF
293
- cipher: aes-128-cbc
294
-
295
- test:
296
- <<: *development_defaults
297
-
298
- production:
299
- # Since the key to encrypt and decrypt with must NOT be stored along with the
300
- # source code, we only hold a RSA key that is used to unlock the file
301
- # containing the actual symmetric encryption key
302
- #
303
- # Sample RSA Key, DO NOT use this RSA key, generate a new one using
304
- # openssl genrsa 2048
305
- private_rsa_key: |
306
- -----BEGIN RSA PRIVATE KEY-----
307
- MIIEpAIBAAKCAQEAxIL9H/jYUGpA38v6PowRSRJEo3aNVXULNM/QNRpx2DTf++KH
308
- 6DcuFTFcNSSSxG9n4y7tKi755be8N0uwCCuOzvXqfWmXYjbLwK3Ib2vm0btpHyvA
309
- qxgqeJOOCxKdW/cUFLWn0tACUcEjVCNfWEGaFyvkOUuR7Ub9KfhbW9cZO3BxZMUf
310
- IPGlHl/gWyf484sXygd+S7cpDTRRzo9RjG74DwfE0MFGf9a1fTkxnSgeOJ6asTOy
311
- fp9tEToUlbglKaYGpOGHYQ9TV5ZsyJ9jRUyb4SP5wK2eK6dHTxTcHvT03kD90Hv4
312
- WeKIXv3WOjkwNEyMdpnJJfSDb5oquQvCNi7ZSQIDAQABAoIBAQCbzR7TUoBugU+e
313
- ICLvpC2wOYOh9kRoFLwlyv3QnH7WZFWRZzFJszYeJ1xr5etXQtyjCnmOkGAg+WOI
314
- k8GlOKOpAuA/PpB/leJFiYL4lBwU/PmDdTT0cdx6bMKZlNCeMW8CXGQKiFDOcMqJ
315
- 0uGtH5YD+RChPIEeFsJxnC8SyZ9/t2ra7XnMGiCZvRXIUDSEIIsRx/mOymJ7bL+h
316
- Lbp46IfXf6ZuIzwzoIk0JReV/r+wdmkAVDkrrMkCmVS4/X1wN/Tiik9/yvbsh/CL
317
- ztC55eSIEjATkWxnXfPASZN6oUfQPEveGH3HzNjdncjH/Ho8FaNMIAfFpBhhLPi9
318
- nG5sbH+BAoGBAOdoUyVoAA/QUa3/FkQaa7Ajjehe5MR5k6VtaGtcxrLiBjrNR7x+
319
- nqlZlGvWDMiCz49dgj+G1Qk1bbYrZLRX/Hjeqy5dZOGLMfgf9eKUmS1rDwAzBMcj
320
- M9jnnJEBx8HIlNzaR6wzp3GMd0rrccs660A8URvzkgo9qNbvMLq9vyUtAoGBANll
321
- SY1Iv9uaIz8klTXU9YzYtsfUmgXzw7K8StPdbEbo8F1J3JPJB4D7QHF0ObIaSWuf
322
- suZqLsvWlYGuJeyX2ntlBN82ORfvUdOrdrbDlmPyj4PfFVl0AK3U3Ai374DNrjKR
323
- hF6YFm4TLDaJhUjeV5C43kbE1N2FAMS9LYtPJ44NAoGAFDGHZ/E+aCLerddfwwun
324
- MBS6MnftcLPHTZ1RimTrNfsBXipBw1ItWEvn5s0kCm9X24PmdNK4TnhqHYaF4DL5
325
- ZjbQK1idEA2Mi8GGPIKJJ2x7P6I0HYiV4qy7fe/w1ZlCXE90B7PuPbtrQY9wO7Ll
326
- ipJ45X6I1PnyfOcckn8yafUCgYACtPAlgjJhWZn2v03cTbqA9nHQKyV/zXkyUIXd
327
- /XPLrjrP7ouAi5A8WuSChR/yx8ECRgrEM65Be3qBEtoGCB4AS1G0NcigM6qhKBFi
328
- VS0aMXr3+V8argcUIwJaWW/x+p2go48yXlJpLHPweeXe8mXEt4iM+QZte6p2yKQ4
329
- h9PGQQKBgQCqSydmXBnXGIVTp2sH/2GnpxLYnDBpcJE0tM8bJ42HEQQgRThIChsn
330
- PnGA91G9MVikYapgI0VYBHQOTsz8rTIUzsKwXG+TIaK+W84nxH5y6jUkjqwxZmAz
331
- r1URaMAun2PfAB4g2N/kEZTExgeOGqXjFhvvjdzl97ux2cTyZhaTXg==
332
- -----END RSA PRIVATE KEY-----
333
-
334
- # List Symmetric Key files in the order of current / latest first
335
- ciphers:
336
- -
337
- # Filename containing Symmetric Encryption Key encrypted using the
338
- # RSA public key derived from the private key above
339
- key_filename: /etc/rails/.rails.key
340
- iv_filename: /etc/rails/.rails.iv
341
-
342
- # Encryption cipher
343
- # Recommended values:
344
- # aes-256-cbc
345
- # 256 AES CBC Algorithm. Very strong
346
- # Ruby 1.8.7 MRI Approximately 100,000 encryptions or decryptions per second
347
- # JRuby 1.6.7 with Ruby 1.8.7 Approximately 22,000 encryptions or decryptions per second
348
- # aes-128-cbc
349
- # 128 AES CBC Algorithm. Less strong.
350
- # Ruby 1.8.7 MRI Approximately 100,000 encryptions or decryptions per second
351
- # JRuby 1.6.7 with Ruby 1.8.7 Approximately 22,000 encryptions or decryptions per second
352
- cipher: aes-256-cbc
353
-
354
- -
355
- # OPTIONAL:
356
- #
357
- # Any previous Symmetric Encryption Keys
358
- #
359
- # Only used when old data still exists that requires old decryption keys
360
- # to be used
361
- key_filename: /etc/rails/.rails_old.key
362
- iv_filename: /etc/rails/.rails_old.iv
363
- cipher: aes-256-cbc
378
+ ```yaml
379
+ #
380
+ # Symmetric Encryption for Ruby
381
+ #
382
+ ---
383
+ # For the development and test environments the test symmetric encryption keys
384
+ # can be placed directly in the source code.
385
+ # And therefore no RSA private key is required
386
+ development: &development_defaults
387
+ key: 1234567890ABCDEF1234567890ABCDEF
388
+ iv: 1234567890ABCDEF
389
+ cipher: aes-128-cbc
390
+
391
+ test:
392
+ <<: *development_defaults
393
+
394
+ production:
395
+ # Since the key to encrypt and decrypt with must NOT be stored along with the
396
+ # source code, we only hold a RSA key that is used to unlock the file
397
+ # containing the actual symmetric encryption key
398
+ #
399
+ # Sample RSA Key, DO NOT use this RSA key, generate a new one using
400
+ # openssl genrsa 2048
401
+ private_rsa_key: |
402
+ -----BEGIN RSA PRIVATE KEY-----
403
+ MIIEpAIBAAKCAQEAxIL9H/jYUGpA38v6PowRSRJEo3aNVXULNM/QNRpx2DTf++KH
404
+ 6DcuFTFcNSSSxG9n4y7tKi755be8N0uwCCuOzvXqfWmXYjbLwK3Ib2vm0btpHyvA
405
+ qxgqeJOOCxKdW/cUFLWn0tACUcEjVCNfWEGaFyvkOUuR7Ub9KfhbW9cZO3BxZMUf
406
+ IPGlHl/gWyf484sXygd+S7cpDTRRzo9RjG74DwfE0MFGf9a1fTkxnSgeOJ6asTOy
407
+ fp9tEToUlbglKaYGpOGHYQ9TV5ZsyJ9jRUyb4SP5wK2eK6dHTxTcHvT03kD90Hv4
408
+ WeKIXv3WOjkwNEyMdpnJJfSDb5oquQvCNi7ZSQIDAQABAoIBAQCbzR7TUoBugU+e
409
+ ICLvpC2wOYOh9kRoFLwlyv3QnH7WZFWRZzFJszYeJ1xr5etXQtyjCnmOkGAg+WOI
410
+ k8GlOKOpAuA/PpB/leJFiYL4lBwU/PmDdTT0cdx6bMKZlNCeMW8CXGQKiFDOcMqJ
411
+ 0uGtH5YD+RChPIEeFsJxnC8SyZ9/t2ra7XnMGiCZvRXIUDSEIIsRx/mOymJ7bL+h
412
+ Lbp46IfXf6ZuIzwzoIk0JReV/r+wdmkAVDkrrMkCmVS4/X1wN/Tiik9/yvbsh/CL
413
+ ztC55eSIEjATkWxnXfPASZN6oUfQPEveGH3HzNjdncjH/Ho8FaNMIAfFpBhhLPi9
414
+ nG5sbH+BAoGBAOdoUyVoAA/QUa3/FkQaa7Ajjehe5MR5k6VtaGtcxrLiBjrNR7x+
415
+ nqlZlGvWDMiCz49dgj+G1Qk1bbYrZLRX/Hjeqy5dZOGLMfgf9eKUmS1rDwAzBMcj
416
+ M9jnnJEBx8HIlNzaR6wzp3GMd0rrccs660A8URvzkgo9qNbvMLq9vyUtAoGBANll
417
+ SY1Iv9uaIz8klTXU9YzYtsfUmgXzw7K8StPdbEbo8F1J3JPJB4D7QHF0ObIaSWuf
418
+ suZqLsvWlYGuJeyX2ntlBN82ORfvUdOrdrbDlmPyj4PfFVl0AK3U3Ai374DNrjKR
419
+ hF6YFm4TLDaJhUjeV5C43kbE1N2FAMS9LYtPJ44NAoGAFDGHZ/E+aCLerddfwwun
420
+ MBS6MnftcLPHTZ1RimTrNfsBXipBw1ItWEvn5s0kCm9X24PmdNK4TnhqHYaF4DL5
421
+ ZjbQK1idEA2Mi8GGPIKJJ2x7P6I0HYiV4qy7fe/w1ZlCXE90B7PuPbtrQY9wO7Ll
422
+ ipJ45X6I1PnyfOcckn8yafUCgYACtPAlgjJhWZn2v03cTbqA9nHQKyV/zXkyUIXd
423
+ /XPLrjrP7ouAi5A8WuSChR/yx8ECRgrEM65Be3qBEtoGCB4AS1G0NcigM6qhKBFi
424
+ VS0aMXr3+V8argcUIwJaWW/x+p2go48yXlJpLHPweeXe8mXEt4iM+QZte6p2yKQ4
425
+ h9PGQQKBgQCqSydmXBnXGIVTp2sH/2GnpxLYnDBpcJE0tM8bJ42HEQQgRThIChsn
426
+ PnGA91G9MVikYapgI0VYBHQOTsz8rTIUzsKwXG+TIaK+W84nxH5y6jUkjqwxZmAz
427
+ r1URaMAun2PfAB4g2N/kEZTExgeOGqXjFhvvjdzl97ux2cTyZhaTXg==
428
+ -----END RSA PRIVATE KEY-----
429
+
430
+ # List Symmetric Key files in the order of current / latest first
431
+ ciphers:
432
+ -
433
+ # Filename containing Symmetric Encryption Key encrypted using the
434
+ # RSA public key derived from the private key above
435
+ key_filename: /etc/rails/.rails.key
436
+ iv_filename: /etc/rails/.rails.iv
437
+
438
+ # Encryption cipher
439
+ # Recommended values:
440
+ # aes-256-cbc
441
+ # 256 AES CBC Algorithm. Very strong
442
+ # Ruby 1.8.7 MRI Approximately 100,000 encryptions or decryptions per second
443
+ # JRuby 1.6.7 with Ruby 1.8.7 Approximately 22,000 encryptions or decryptions per second
444
+ # aes-128-cbc
445
+ # 128 AES CBC Algorithm. Less strong.
446
+ # Ruby 1.8.7 MRI Approximately 100,000 encryptions or decryptions per second
447
+ # JRuby 1.6.7 with Ruby 1.8.7 Approximately 22,000 encryptions or decryptions per second
448
+ cipher: aes-256-cbc
449
+
450
+ -
451
+ # OPTIONAL:
452
+ #
453
+ # Any previous Symmetric Encryption Keys
454
+ #
455
+ # Only used when old data still exists that requires old decryption keys
456
+ # to be used
457
+ key_filename: /etc/rails/.rails_old.key
458
+ iv_filename: /etc/rails/.rails_old.iv
459
+ cipher: aes-256-cbc
460
+ ```
364
461
 
365
462
  ## Future Enhancements
366
463
 
data/Rakefile CHANGED
@@ -2,6 +2,7 @@ lib = File.expand_path('../lib/', __FILE__)
2
2
  $:.unshift lib unless $:.include?(lib)
3
3
 
4
4
  require 'rubygems'
5
+ require 'rubygems/package'
5
6
  require 'rake/clean'
6
7
  require 'rake/testtask'
7
8
  require 'date'
@@ -20,9 +21,10 @@ task :gem do |t|
20
21
  s.summary = "Symmetric Encryption for Ruby, and Ruby on Rails"
21
22
  s.description = "SymmetricEncryption supports encrypting ActiveRecord data, Mongoid data, passwords in configuration files, encrypting and decrypting of large files through streaming"
22
23
  s.files = FileList["./**/*"].exclude(/.gem$/, /.log$/,/^nbproject/).map{|f| f.sub(/^\.\//, '')}
24
+ s.license = "Apache License V2.0"
23
25
  s.has_rdoc = true
24
26
  end
25
- Gem::Builder.new(gemspec).build
27
+ Gem::Package.build gemspec
26
28
  end
27
29
 
28
30
  desc "Run Test Suite"
@@ -11,7 +11,7 @@ module SymmetricEncryption
11
11
  attr_accessor :encoding
12
12
 
13
13
  # Available encodings
14
- ENCODINGS = [:none, :base64, :base64strict]
14
+ ENCODINGS = [:none, :base64, :base64strict, :base16]
15
15
 
16
16
  # Generate a new Symmetric Key pair
17
17
  #
@@ -51,7 +51,9 @@ module SymmetricEncryption
51
51
  # It is not the default for backward compatibility
52
52
  # :base64
53
53
  # Return as a base64 encoded string
54
- # :binary
54
+ # :base16
55
+ # Return as a Hex encoded string
56
+ # :none
55
57
  # Return as raw binary data string. Note: String can contain embedded nulls
56
58
  # Default: :base64
57
59
  # Recommended: :base64strict
@@ -69,45 +71,53 @@ module SymmetricEncryption
69
71
  raise("Invalid Encoding: #{@encoding}") unless ENCODINGS.include?(@encoding)
70
72
  end
71
73
 
72
- # AES Symmetric Encryption of supplied string
74
+ # Encryption of supplied string
73
75
  # The String is encoded to UTF-8 prior to encryption
74
76
  #
75
- # Returns result as a Base64 encoded string
77
+ # Returns result as an encoded string if encode is true
76
78
  # Returns nil if the supplied str is nil
77
79
  # Returns "" if it is a string and it is empty
78
80
  if defined?(Encoding)
79
- def encrypt(str)
81
+ def encrypt(str, encode = true)
80
82
  return if str.nil?
81
83
  buf = str.to_s.encode(SymmetricEncryption::UTF8_ENCODING)
82
84
  return str if buf.empty?
83
- crypt(:encrypt, buf)
85
+ encrypted = crypt(:encrypt, buf)
86
+ encode ? self.encode(encrypted) : encrypted
84
87
  end
85
88
  else
86
- def encrypt(str)
89
+ def encrypt(str, encode = true)
87
90
  return if str.nil?
88
91
  buf = str.to_s
89
92
  return str if buf.empty?
90
- crypt(:encrypt, buf)
93
+ encrypted = crypt(:encrypt, buf)
94
+ encode ? self.encode(encrypted) : encrypted
91
95
  end
92
96
  end
93
97
 
94
- # AES Symmetric Decryption of supplied string
95
- # The encoding of the supplied string is ignored since it must be binary data
98
+ # Decryption of supplied string
99
+ #
100
+ # Decodes string first if decode is true
101
+ #
96
102
  # Returns a UTF-8 encoded, decrypted string
97
103
  # Returns nil if the supplied str is nil
98
104
  # Returns "" if it is a string and it is empty
99
105
  if defined?(Encoding)
100
- def decrypt(str)
101
- return if str.nil?
102
- buf = str.to_s.force_encoding(SymmetricEncryption::BINARY_ENCODING)
103
- return str if buf.empty?
106
+ def decrypt(str, decode = true)
107
+ decoded = self.decode(str) if decode
108
+ return unless decoded
109
+
110
+ buf = decoded.to_s.force_encoding(SymmetricEncryption::BINARY_ENCODING)
111
+ return decoded if buf.empty?
104
112
  crypt(:decrypt, buf).force_encoding(SymmetricEncryption::UTF8_ENCODING)
105
113
  end
106
114
  else
107
- def decrypt(str)
108
- return if str.nil?
109
- buf = str.to_s
110
- return str if buf.empty?
115
+ def decrypt(str, decode = true)
116
+ decoded = self.decode(str) if decode
117
+ return unless decoded
118
+
119
+ buf = decoded.to_s
120
+ return decoded if buf.empty?
111
121
  crypt(:decrypt, buf)
112
122
  end
113
123
  end
@@ -123,6 +133,40 @@ module SymmetricEncryption
123
133
  ::OpenSSL::Cipher::Cipher.new(@cipher).block_size
124
134
  end
125
135
 
136
+ # Encode the supplied string using the encoding in this cipher instance
137
+ # Returns nil if the supplied string is nil
138
+ # Note: No encryption or decryption is performed
139
+ def encode(binary_string)
140
+ return unless binary_string
141
+
142
+ # Now encode data based on encoding setting
143
+ case encoding
144
+ when :base64
145
+ ::Base64.encode64(binary_string)
146
+ when :base64strict
147
+ ::Base64.encode64(binary_string).gsub(/\n/, '')
148
+ when :base16
149
+ binary_string.to_s.unpack('H*').first
150
+ else
151
+ binary_string
152
+ end
153
+ end
154
+
155
+ # Decode the supplied string using the encoding in this cipher instance
156
+ # Note: No encryption or decryption is performed
157
+ def decode(encoded_string)
158
+ return unless encoded_string
159
+
160
+ case encoding
161
+ when :base64, :base64strict
162
+ ::Base64.decode64(encoded_string)
163
+ when :base16
164
+ [encoded_string].pack('H*')
165
+ else
166
+ encoded_string
167
+ end
168
+ end
169
+
126
170
  protected
127
171
 
128
172
  # Only for use by Symmetric::EncryptedStream
@@ -66,12 +66,7 @@ module SymmetricEncryption
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
+ # Decode and then decrypt supplied string
75
70
  begin
76
71
  @@cipher.decrypt(str)
77
72
  rescue OpenSSL::Cipher::CipherError => exc
@@ -92,19 +87,8 @@ module SymmetricEncryption
92
87
  def self.encrypt(str)
93
88
  raise "Call SymmetricEncryption.load! or SymmetricEncryption.cipher= prior to encrypting or decrypting data" unless @@cipher
94
89
 
95
- # Encrypt data as a binary string
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
90
+ # Encrypt and then encode the supplied string
91
+ @@cipher.encrypt(str)
108
92
  end
109
93
 
110
94
  # Invokes decrypt
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module SymmetricEncryption #:nodoc
3
- VERSION = "0.9.1"
3
+ VERSION = "1.0.0"
4
4
  end
@@ -1,3 +1,3 @@
1
1
  file.reference.symmetry-lib=/Users/rmorrison/Sandbox/symmetry/lib
2
2
  file.reference.symmetry-test=/Users/rmorrison/Sandbox/symmetry/test
3
- platform.active=Ruby_0
3
+ platform.active=Ruby
@@ -14,7 +14,4 @@
14
14
  <line>60</line>
15
15
  </file>
16
16
  </editor-bookmarks>
17
- <open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/1">
18
- <file>file:/Users/rmorrison/Sandbox/symmetric-encryption/lib/symmetric_encryption/extensions/active_record/base.rb</file>
19
- </open-files>
20
17
  </project-private>
data/test/cipher_test.rb CHANGED
@@ -13,16 +13,18 @@ class CipherTest < Test::Unit::TestCase
13
13
 
14
14
  should "allow setting the cipher" do
15
15
  cipher = SymmetricEncryption::Cipher.new(
16
- :cipher => 'aes-128-cbc',
17
- :key => '1234567890ABCDEF1234567890ABCDEF',
18
- :iv => '1234567890ABCDEF'
16
+ :cipher => 'aes-128-cbc',
17
+ :key => '1234567890ABCDEF1234567890ABCDEF',
18
+ :iv => '1234567890ABCDEF',
19
+ :encoding => :none
19
20
  )
20
21
  assert_equal 'aes-128-cbc', cipher.cipher
21
22
  end
22
23
 
23
24
  should "not require an iv" do
24
25
  cipher = SymmetricEncryption::Cipher.new(
25
- :key => '1234567890ABCDEF1234567890ABCDEF'
26
+ :key => '1234567890ABCDEF1234567890ABCDEF',
27
+ :encoding => :none
26
28
  )
27
29
  result = "\302<\351\227oj\372\3331\310\260V\001\v'\346"
28
30
  # Note: This test fails on JRuby 1.7 RC1 since it's OpenSSL
@@ -35,9 +37,10 @@ class CipherTest < Test::Unit::TestCase
35
37
 
36
38
  should "throw an exception on bad data" do
37
39
  cipher = SymmetricEncryption::Cipher.new(
38
- :cipher => 'aes-128-cbc',
39
- :key => '1234567890ABCDEF1234567890ABCDEF',
40
- :iv => '1234567890ABCDEF'
40
+ :cipher => 'aes-128-cbc',
41
+ :key => '1234567890ABCDEF1234567890ABCDEF',
42
+ :iv => '1234567890ABCDEF',
43
+ :encoding => :none
41
44
  )
42
45
  assert_raise OpenSSL::Cipher::CipherError do
43
46
  cipher.decrypt('bad data')
@@ -49,8 +52,9 @@ class CipherTest < Test::Unit::TestCase
49
52
  context 'with configuration' do
50
53
  setup do
51
54
  @cipher = SymmetricEncryption::Cipher.new(
52
- :key => '1234567890ABCDEF1234567890ABCDEF',
53
- :iv => '1234567890ABCDEF'
55
+ :key => '1234567890ABCDEF1234567890ABCDEF',
56
+ :iv => '1234567890ABCDEF',
57
+ :encoding => :none
54
58
  )
55
59
  @social_security_number = "987654321"
56
60
 
@@ -1,7 +1,5 @@
1
1
  test:
2
- database: symmetric_encryption_test
3
- username: root
4
- password:
5
- encoding: utf8
6
- adapter: mysql
7
- host: 127.0.0.1
2
+ adapter: sqlite3
3
+ database: test/test_db.sqlite3
4
+ pool: 5
5
+ timeout: 5000
data/test/reader_test.rb CHANGED
@@ -22,7 +22,7 @@ class ReaderTest < Test::Unit::TestCase
22
22
  ]
23
23
  @data_str = @data.inject('') {|sum,str| sum << str}
24
24
  @data_len = @data_str.length
25
- @data_encrypted = SymmetricEncryption.cipher.encrypt(@data_str)
25
+ @data_encrypted = SymmetricEncryption.cipher.encrypt(@data_str, false)
26
26
  end
27
27
 
28
28
  should "decrypt from string stream as a single read" do
@@ -12,9 +12,9 @@ SymmetricEncryption.load!(File.join(File.dirname(__FILE__), 'config', 'symmetric
12
12
  # Unit Test for SymmetricEncryption
13
13
  #
14
14
  class SymmetricEncryptionTest < Test::Unit::TestCase
15
- context 'initialized' do
15
+ context 'SymmetricEncryption' do
16
16
 
17
- context 'SymmetricEncryption configuration' do
17
+ context 'configuration' do
18
18
  setup do
19
19
  @config = SymmetricEncryption.send(:read_config, File.join(File.dirname(__FILE__), 'config', 'symmetric-encryption.yml'), 'test')
20
20
  end
@@ -24,61 +24,51 @@ class SymmetricEncryptionTest < Test::Unit::TestCase
24
24
  end
25
25
  end
26
26
 
27
- context 'Base64 encoding tests' do
28
- setup do
29
- @social_security_number = "987654321"
30
- @social_security_number_encrypted = "S+8X1NRrqdfEIQyFHVPuVA==\n"
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)
27
+ SymmetricEncryption::Cipher::ENCODINGS.each do |encoding|
28
+ context "encoding: #{encoding}" do
29
+ setup do
30
+ @social_security_number = "987654321"
31
+ @social_security_number_encrypted =
32
+ case encoding
33
+ when :base64
34
+ "S+8X1NRrqdfEIQyFHVPuVA==\n"
35
+ when :base64strict
36
+ "S+8X1NRrqdfEIQyFHVPuVA=="
37
+ when :base16
38
+ "4bef17d4d46ba9d7c4210c851d53ee54"
39
+ when :none
40
+ "K\xEF\x17\xD4\xD4k\xA9\xD7\xC4!\f\x85\x1DS\xEET".force_encoding(Encoding.find("binary"))
41
+ else
42
+ raise "Add test for encoding: #{encoding}"
43
+ end
44
+ @social_security_number_encrypted_with_secondary_1 = "D1UCu38pqJ3jc0GvwJHiow==\n"
45
+ @encoding = SymmetricEncryption.cipher.encoding
46
+ SymmetricEncryption.cipher.encoding = encoding
47
+ end
48
+
49
+ teardown do
50
+ SymmetricEncryption.cipher.encoding = @encoding
51
+ end
52
+
53
+ should "encrypt simple string" do
54
+ assert_equal @social_security_number_encrypted, SymmetricEncryption.encrypt(@social_security_number)
55
+ end
56
+
57
+ should "decrypt string" do
58
+ assert_equal @social_security_number, SymmetricEncryption.decrypt(@social_security_number_encrypted)
59
+ end
60
+
61
+ should "determine if string is encrypted" do
62
+ assert_equal true, SymmetricEncryption.encrypted?(@social_security_number_encrypted)
63
+ assert_equal false, SymmetricEncryption.encrypted?(@social_security_number)
64
+ end
65
+
66
+ should "decrypt with secondary key when first one fails" do
67
+ assert_equal @social_security_number, SymmetricEncryption.decrypt(@social_security_number_encrypted_with_secondary_1)
68
+ end
55
69
  end
56
70
  end
57
71
 
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=="
63
- end
64
-
65
- should "encrypt simple string" do
66
- assert_equal @social_security_number_encrypted, SymmetricEncryption.encrypt(@social_security_number)
67
- end
68
-
69
- should "decrypt string" do
70
- assert_equal @social_security_number, SymmetricEncryption.decrypt(@social_security_number_encrypted)
71
- end
72
-
73
- should "determine if string is encrypted" do
74
- assert_equal true, SymmetricEncryption.encrypted?(@social_security_number_encrypted)
75
- assert_equal false, SymmetricEncryption.encrypted?(@social_security_number)
76
- end
77
-
78
- should "decrypt with secondary key when first one fails" do
79
- assert_equal @social_security_number, SymmetricEncryption.decrypt(@social_security_number_encrypted)
80
- end
81
- end
82
72
  end
83
73
 
84
74
  end
Binary file
data/test/writer_test.rb CHANGED
@@ -22,7 +22,7 @@ class EncryptionWriterTest < Test::Unit::TestCase
22
22
  ]
23
23
  @data_str = @data.inject('') {|sum,str| sum << str}
24
24
  @data_len = @data_str.length
25
- @data_encrypted = SymmetricEncryption.cipher.encrypt(@data_str)
25
+ @data_encrypted = SymmetricEncryption.cipher.encrypt(@data_str, false)
26
26
  @filename = '._test'
27
27
  end
28
28
 
metadata CHANGED
@@ -1,15 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: symmetric-encryption
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.1
5
- prerelease:
4
+ version: 1.0.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Reid Morrison
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-11-05 00:00:00.000000000 Z
11
+ date: 2013-03-07 00:00:00.000000000 Z
13
12
  dependencies: []
14
13
  description: SymmetricEncryption supports encrypting ActiveRecord data, Mongoid data,
15
14
  passwords in configuration files, encrypting and decrypting of large files through
@@ -20,11 +19,17 @@ executables: []
20
19
  extensions: []
21
20
  extra_rdoc_files: []
22
21
  files:
22
+ - Gemfile
23
+ - Gemfile.lock
24
+ - LICENSE.txt
25
+ - README.md
26
+ - Rakefile
23
27
  - examples/symmetric-encryption.yml
24
28
  - lib/rails/generators/symmetric_encryption/config/config_generator.rb
25
29
  - lib/rails/generators/symmetric_encryption/config/templates/symmetric-encryption.yml
26
30
  - lib/rails/generators/symmetric_encryption/new_keys/new_keys_generator.rb
27
31
  - lib/symmetric-encryption.rb
32
+ - lib/symmetric_encryption.rb
28
33
  - lib/symmetric_encryption/cipher.rb
29
34
  - lib/symmetric_encryption/extensions/active_record/base.rb
30
35
  - lib/symmetric_encryption/extensions/mongoid/fields.rb
@@ -35,16 +40,13 @@ files:
35
40
  - lib/symmetric_encryption/symmetric_encryption.rb
36
41
  - lib/symmetric_encryption/version.rb
37
42
  - lib/symmetric_encryption/writer.rb
38
- - lib/symmetric_encryption.rb
39
- - LICENSE.txt
40
43
  - nbproject/private/config.properties
41
44
  - nbproject/private/private.properties
42
45
  - nbproject/private/private.xml
43
46
  - nbproject/private/rake-d.txt
44
47
  - nbproject/project.properties
45
48
  - nbproject/project.xml
46
- - Rakefile
47
- - README.md
49
+ - test.rb
48
50
  - test/attr_encrypted_test.rb
49
51
  - test/cipher_test.rb
50
52
  - test/config/database.yml
@@ -58,30 +60,30 @@ files:
58
60
  - test/field_encrypted_test.rb
59
61
  - test/reader_test.rb
60
62
  - test/symmetric_encryption_test.rb
63
+ - test/test_db.sqlite3
61
64
  - test/writer_test.rb
62
- - test.rb
63
65
  homepage: https://github.com/ClarityServices/symmetric-encryption
64
- licenses: []
66
+ licenses:
67
+ - Apache License V2.0
68
+ metadata: {}
65
69
  post_install_message:
66
70
  rdoc_options: []
67
71
  require_paths:
68
72
  - lib
69
73
  required_ruby_version: !ruby/object:Gem::Requirement
70
- none: false
71
74
  requirements:
72
- - - ! '>='
75
+ - - '>='
73
76
  - !ruby/object:Gem::Version
74
77
  version: '0'
75
78
  required_rubygems_version: !ruby/object:Gem::Requirement
76
- none: false
77
79
  requirements:
78
- - - ! '>='
80
+ - - '>='
79
81
  - !ruby/object:Gem::Version
80
82
  version: '0'
81
83
  requirements: []
82
84
  rubyforge_project:
83
- rubygems_version: 1.8.24
85
+ rubygems_version: 2.0.2
84
86
  signing_key:
85
- specification_version: 3
87
+ specification_version: 4
86
88
  summary: Symmetric Encryption for Ruby, and Ruby on Rails
87
89
  test_files: []