symmetric-encryption 3.4.0 → 3.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +102 -55
- data/Rakefile +13 -8
- data/lib/rails/generators/symmetric_encryption/config/config_generator.rb +1 -1
- data/lib/rails/generators/symmetric_encryption/heroku_config/templates/symmetric-encryption.yml +2 -2
- data/lib/rails/generators/symmetric_encryption/new_keys/new_keys_generator.rb +2 -2
- data/lib/symmetric_encryption.rb +7 -6
- data/lib/symmetric_encryption/cipher.rb +4 -4
- data/lib/symmetric_encryption/extensions/active_record/base.rb +6 -46
- data/lib/symmetric_encryption/extensions/mongo_mapper/plugins/encrypted_key.rb +129 -0
- data/lib/symmetric_encryption/{mongoid.rb → extensions/mongoid/encrypted.rb} +12 -46
- data/lib/symmetric_encryption/generator.rb +54 -0
- data/lib/symmetric_encryption/railtie.rb +3 -3
- data/lib/symmetric_encryption/railties/symmetric_encryption.rake +1 -1
- data/lib/symmetric_encryption/railties/symmetric_encryption_validator.rb +1 -1
- data/lib/symmetric_encryption/reader.rb +3 -3
- data/lib/symmetric_encryption/symmetric_encryption.rb +25 -15
- data/lib/symmetric_encryption/version.rb +1 -1
- data/lib/symmetric_encryption/writer.rb +4 -4
- data/test/active_record_test.rb +474 -0
- data/test/cipher_test.rb +15 -15
- data/test/config/mongo_mapper.yml +7 -0
- data/test/{field_encrypted_test.rb → mongo_mapper_test.rb} +68 -67
- data/test/mongoid_test.rb +535 -0
- data/test/reader_test.rb +10 -10
- data/test/symmetric_encryption_test.rb +27 -27
- data/test/test_db.sqlite3 +0 -0
- data/test/test_helper.rb +0 -1
- data/test/writer_test.rb +2 -2
- metadata +14 -8
- data/test/attr_encrypted_test.rb +0 -622
@@ -0,0 +1,129 @@
|
|
1
|
+
# Support Encryption and decryption of fields in MongoMapper
|
2
|
+
module MongoMapper
|
3
|
+
module Plugins
|
4
|
+
module EncryptedKey
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
COERCION_MAP = {
|
8
|
+
String => :string,
|
9
|
+
Integer => :integer,
|
10
|
+
Float => :float,
|
11
|
+
BigDecimal => :decimal,
|
12
|
+
DateTime => :datetime,
|
13
|
+
Time => :time,
|
14
|
+
Date => :date,
|
15
|
+
Boolean => :boolean,
|
16
|
+
Hash => :json
|
17
|
+
}
|
18
|
+
|
19
|
+
module ClassMethods
|
20
|
+
# MongoMapper::Document.encrypted_key
|
21
|
+
#
|
22
|
+
# Support automatic encryption and decryption of fields in MongoMapper
|
23
|
+
#
|
24
|
+
# Example:
|
25
|
+
#
|
26
|
+
# class Person
|
27
|
+
# include MongoMapper::Document
|
28
|
+
#
|
29
|
+
# key :name, String
|
30
|
+
# encrypted_key :social_security_number, String
|
31
|
+
# key :date_of_birth, Date
|
32
|
+
# encrypted_key :life_history, String, encrypted: { compress: true, random_iv: true }
|
33
|
+
#
|
34
|
+
# # Encrypted fields are _always_ stored in Mongo as a String
|
35
|
+
# # By specifying a type other than String, Symmetric Encryption will
|
36
|
+
# # perform the necessary conversions
|
37
|
+
# #
|
38
|
+
# # The following types are supported:
|
39
|
+
# # String
|
40
|
+
# # Integer
|
41
|
+
# # Float
|
42
|
+
# # BigDecimal
|
43
|
+
# # DateTime
|
44
|
+
# # Time
|
45
|
+
# # Date
|
46
|
+
# # Hash - (Stored as encrypted JSON in MongoDB)
|
47
|
+
# encrypted_key :age, Integer, encrypted: { random_iv: true }
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# The above document results in the following document in the Mongo collection 'persons':
|
51
|
+
# {
|
52
|
+
# "name" : "Joe",
|
53
|
+
# "encrypted_social_security_number" : "...",
|
54
|
+
# "age" : 21
|
55
|
+
# "encrypted_life_history" : "...",
|
56
|
+
# }
|
57
|
+
#
|
58
|
+
# Symmetric Encryption creates the getters and setters to be able to work with the field
|
59
|
+
# in it's decrypted form. For example
|
60
|
+
#
|
61
|
+
# Example:
|
62
|
+
# person = Person.where(encrypted_social_security_number: '...').first
|
63
|
+
#
|
64
|
+
# puts "Decrypted Social Security Number is: #{person.social_security_number}"
|
65
|
+
#
|
66
|
+
# # Or is the same as
|
67
|
+
# puts "Decrypted Social Security Number is: #{SymmetricEncryption.decrypt(person.encrypted_social_security_number)}"
|
68
|
+
#
|
69
|
+
# # Sets the encrypted_social_security_number to encrypted version
|
70
|
+
# person.social_security_number = "123456789"
|
71
|
+
#
|
72
|
+
# # Or, is equivalent to:
|
73
|
+
# person.encrypted_social_security_number = SymmetricEncryption.encrypt("123456789")
|
74
|
+
#
|
75
|
+
# Note: Only "String" types are currently supported for encryption
|
76
|
+
#
|
77
|
+
# Note: Unlike attr_encrypted finders must use the encrypted field name
|
78
|
+
# Invalid Example, does not work:
|
79
|
+
# person = Person.where(social_security_number: '123456789').first
|
80
|
+
#
|
81
|
+
# Valid Example:
|
82
|
+
# person = Person.where(encrypted_social_security_number: SymmetricEncryption.encrypt('123456789')).first
|
83
|
+
#
|
84
|
+
# Defines all the fields that are accessible on the Document
|
85
|
+
# For each field that is defined, a getter and setter will be
|
86
|
+
# added as an instance method to the Document.
|
87
|
+
#
|
88
|
+
# @example Define an encrypted key
|
89
|
+
# encrypted_key :social_security_number, String, encrypted: {compress: false, random_iv: false}
|
90
|
+
# encrypted_key :sensitive_text, String, encrypted: {compress: true, random_iv: true}
|
91
|
+
#
|
92
|
+
# @param [ Symbol ] name The name of the key.
|
93
|
+
# @param [ Object ] type The type of the key.
|
94
|
+
# @param [ Hash ] options The options to pass to the field, including any MongoMapper specific options
|
95
|
+
#
|
96
|
+
# @option options [ Hash ] :encrypted consists of:
|
97
|
+
# @option options [ Boolean ] :random_iv Whether the encrypted value should use a random IV every time the field is encrypted.
|
98
|
+
# @option options [ Boolean ] :compress Whether to compress this encrypted field
|
99
|
+
# @option options [ Symbol ] :encrypt_as Name of the encypted field in Mongo
|
100
|
+
#
|
101
|
+
# Some of the other regular MongoMapper options:
|
102
|
+
# :default, :alias, :field_name, :accessors, :abbr
|
103
|
+
#
|
104
|
+
# Note:
|
105
|
+
# Use MongoMapper's built-in support for :field_name to specify a different
|
106
|
+
# field name in MongoDB for the encrypted field from what is used via the model
|
107
|
+
#
|
108
|
+
def encrypted_key(key_name, type, full_options={})
|
109
|
+
full_options = full_options.is_a?(Hash) ? full_options.dup : {}
|
110
|
+
options = full_options.delete(:encrypted) || {}
|
111
|
+
# Support overriding the name of the decrypted attribute
|
112
|
+
encrypted_key_name = options.delete(:encrypt_as) || "encrypted_#{key_name}"
|
113
|
+
options[:type] = COERCION_MAP[type] unless [:yaml, :json].include?(options[:type])
|
114
|
+
|
115
|
+
raise "Invalid type: #{type.inspect}. Valid types: #{COERCION_MAP.keys.join(',')}" unless options[:type]
|
116
|
+
|
117
|
+
SymmetricEncryption::Generator.generate_decrypted_accessors(self, key_name, encrypted_key_name, options)
|
118
|
+
|
119
|
+
key(encrypted_key_name, String, full_options)
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
MongoMapper::Document.plugin(MongoMapper::Plugins::EncryptedKey)
|
129
|
+
MongoMapper::EmbeddedDocument.plugin(MongoMapper::Plugins::EncryptedKey)
|
@@ -15,17 +15,17 @@
|
|
15
15
|
# class Person
|
16
16
|
# include Mongoid::Document
|
17
17
|
#
|
18
|
-
# field :name, :
|
19
|
-
# field :encrypted_social_security_number, :
|
20
|
-
# field :date_of_birth, :
|
21
|
-
# field :encrypted_life_history, :
|
18
|
+
# field :name, type: String
|
19
|
+
# field :encrypted_social_security_number, type: String, encrypted: true
|
20
|
+
# field :date_of_birth, type: Date
|
21
|
+
# field :encrypted_life_history, type: String, encrypted: {compress: true, random_iv: true}
|
22
22
|
#
|
23
23
|
# # Encrypted fields are _always_ stored in Mongo as a String
|
24
24
|
# # To get the result back as an Integer, Symmetric Encryption can do the
|
25
25
|
# # necessary conversions by specifying the internal type as an option
|
26
26
|
# # to :encrypted
|
27
27
|
# # #see SymmetricEncryption::COERCION_TYPES for full list of types
|
28
|
-
# field :encrypted_age, :
|
28
|
+
# field :encrypted_age, type: String, encrypted: {type: :integer, random_iv: true}
|
29
29
|
# end
|
30
30
|
#
|
31
31
|
# The above document results in the following document in the Mongo collection 'persons':
|
@@ -40,7 +40,7 @@
|
|
40
40
|
# in it's unencrypted form. For example
|
41
41
|
#
|
42
42
|
# Example:
|
43
|
-
# person = Person.where(:
|
43
|
+
# person = Person.where(encrypted_social_security_number: '...').first
|
44
44
|
#
|
45
45
|
# puts "Decrypted Social Security Number is: #{person.social_security_number}"
|
46
46
|
#
|
@@ -57,18 +57,18 @@
|
|
57
57
|
#
|
58
58
|
# Note: Unlike attr_encrypted finders must use the encrypted field name
|
59
59
|
# Invalid Example, does not work:
|
60
|
-
# person = Person.where(:
|
60
|
+
# person = Person.where(social_security_number: '123456789').first
|
61
61
|
#
|
62
62
|
# Valid Example:
|
63
|
-
# person = Person.where(:
|
63
|
+
# person = Person.where(encrypted_social_security_number: SymmetricEncryption.encrypt('123456789')).first
|
64
64
|
#
|
65
65
|
# Defines all the fields that are accessible on the Document
|
66
66
|
# For each field that is defined, a getter and setter will be
|
67
67
|
# added as an instance method to the Document.
|
68
68
|
#
|
69
69
|
# @example Define a field.
|
70
|
-
# field :social_security_number, :
|
71
|
-
# field :sensitive_text, :
|
70
|
+
# field :social_security_number, type: String, encrypted: {compress: false, random_iv: false}
|
71
|
+
# field :sensitive_text, type: String, encrypted: {compress: true, random_iv: true}
|
72
72
|
#
|
73
73
|
# @param [ Symbol ] name The name of the field.
|
74
74
|
# @param [ Hash ] options The options to pass to the field.
|
@@ -92,6 +92,7 @@ Mongoid::Fields.option :encrypted do |model, field, options|
|
|
92
92
|
options = options.is_a?(Hash) ? options.dup : {}
|
93
93
|
encrypted_field_name = field.name
|
94
94
|
|
95
|
+
# Support overriding the name of the decrypted attribute
|
95
96
|
decrypted_field_name = options.delete(:decrypt_as)
|
96
97
|
if decrypted_field_name.nil? && encrypted_field_name.to_s.start_with?('encrypted_')
|
97
98
|
decrypted_field_name = encrypted_field_name.to_s['encrypted_'.length..-1]
|
@@ -101,42 +102,7 @@ Mongoid::Fields.option :encrypted do |model, field, options|
|
|
101
102
|
raise "SymmetricEncryption for Mongoid. Encryption enabled for field #{encrypted_field_name}. It must either start with 'encrypted_' or the option :decrypt_as must be supplied"
|
102
103
|
end
|
103
104
|
|
104
|
-
|
105
|
-
compress = options.delete(:compress) || false
|
106
|
-
type = options.delete(:type) || :string
|
107
|
-
raise "Invalid type: #{type.inspect}. Valid types: #{SymmetricEncryption::COERCION_TYPES.inspect}" unless SymmetricEncryption::COERCION_TYPES.include?(type)
|
108
|
-
|
109
|
-
options.each {|option| warn "Ignoring unknown option #{option.inspect} supplied to Mongoid :encrypted for #{model}##{field}"}
|
110
|
-
|
111
|
-
if model.const_defined?(:EncryptedAttributes, _search_ancestors = false)
|
112
|
-
mod = model.const_get(:EncryptedAttributes)
|
113
|
-
else
|
114
|
-
mod = model.const_set(:EncryptedAttributes, Module.new)
|
115
|
-
model.send(:include, mod)
|
116
|
-
end
|
117
|
-
|
118
|
-
# Generate getter and setter methods
|
119
|
-
mod.module_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
120
|
-
# Set the un-encrypted field
|
121
|
-
# Also updates the encrypted field with the encrypted value
|
122
|
-
# Freeze the decrypted field value so that it is not modified directly
|
123
|
-
def #{decrypted_field_name}=(value)
|
124
|
-
v = SymmetricEncryption::coerce(value, :#{type})
|
125
|
-
self.#{encrypted_field_name} = @stored_#{encrypted_field_name} = ::SymmetricEncryption.encrypt(v,#{random_iv},#{compress},:#{type})
|
126
|
-
@#{decrypted_field_name} = v.freeze
|
127
|
-
end
|
128
|
-
|
129
|
-
# Returns the decrypted value for the encrypted field
|
130
|
-
# The decrypted value is cached and is only decrypted if the encrypted value has changed
|
131
|
-
# If this method is not called, then the encrypted value is never decrypted
|
132
|
-
def #{decrypted_field_name}
|
133
|
-
if @stored_#{encrypted_field_name} != self.#{encrypted_field_name}
|
134
|
-
@#{decrypted_field_name} = ::SymmetricEncryption.decrypt(self.#{encrypted_field_name},version=nil,:#{type}).freeze
|
135
|
-
@stored_#{encrypted_field_name} = self.#{encrypted_field_name}
|
136
|
-
end
|
137
|
-
@#{decrypted_field_name}
|
138
|
-
end
|
139
|
-
EOS
|
105
|
+
SymmetricEncryption::Generator.generate_decrypted_accessors(model, decrypted_field_name, encrypted_field_name, options)
|
140
106
|
end
|
141
107
|
end
|
142
108
|
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module SymmetricEncryption
|
2
|
+
module Generator
|
3
|
+
# Common internal method for generating accessors for decrypted accessors
|
4
|
+
# Primarily used by extensions
|
5
|
+
def self.generate_decrypted_accessors(model, decrypted_name, encrypted_name, options)
|
6
|
+
|
7
|
+
random_iv = options.delete(:random_iv) || false
|
8
|
+
compress = options.delete(:compress) || false
|
9
|
+
type = options.delete(:type) || :string
|
10
|
+
|
11
|
+
# For backward compatibility
|
12
|
+
if options.delete(:marshal) == true
|
13
|
+
warn("The :marshal option has been deprecated in favor of :type. For example: attr_encrypted name, type: :yaml")
|
14
|
+
raise "Marshal is depreacted and cannot be used in conjunction with :type, just use :type. For #{params.inspect}" if type != :string
|
15
|
+
type = :yaml
|
16
|
+
end
|
17
|
+
|
18
|
+
options.each {|option| warn "Ignoring unknown option #{option.inspect} supplied when encrypting #{decrypted_name} with #{params.inspect}"}
|
19
|
+
|
20
|
+
raise "Invalid type: #{type.inspect}. Valid types: #{SymmetricEncryption::COERCION_TYPES.inspect}" unless SymmetricEncryption::COERCION_TYPES.include?(type)
|
21
|
+
|
22
|
+
if model.const_defined?(:EncryptedAttributes, _search_ancestors = false)
|
23
|
+
mod = model.const_get(:EncryptedAttributes)
|
24
|
+
else
|
25
|
+
mod = model.const_set(:EncryptedAttributes, Module.new)
|
26
|
+
model.send(:include, mod)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Generate getter and setter methods
|
30
|
+
mod.module_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
31
|
+
# Set the un-encrypted field
|
32
|
+
# Also updates the encrypted field with the encrypted value
|
33
|
+
# Freeze the decrypted field value so that it is not modified directly
|
34
|
+
def #{decrypted_name}=(value)
|
35
|
+
v = SymmetricEncryption::coerce(value, :#{type})
|
36
|
+
self.#{encrypted_name} = @stored_#{encrypted_name} = ::SymmetricEncryption.encrypt(v,#{random_iv},#{compress},:#{type})
|
37
|
+
@#{decrypted_name} = v.freeze
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns the decrypted value for the encrypted field
|
41
|
+
# The decrypted value is cached and is only decrypted if the encrypted value has changed
|
42
|
+
# If this method is not called, then the encrypted value is never decrypted
|
43
|
+
def #{decrypted_name}
|
44
|
+
if @stored_#{encrypted_name} != self.#{encrypted_name}
|
45
|
+
@#{decrypted_name} = ::SymmetricEncryption.decrypt(self.#{encrypted_name},version=nil,:#{type}).freeze
|
46
|
+
@stored_#{encrypted_name} = self.#{encrypted_name}
|
47
|
+
end
|
48
|
+
@#{decrypted_name}
|
49
|
+
end
|
50
|
+
|
51
|
+
EOS
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -8,9 +8,9 @@ module SymmetricEncryption #:nodoc:
|
|
8
8
|
# module MyApplication
|
9
9
|
# class Application < Rails::Application
|
10
10
|
# config.symmetric_encryption.cipher = SymmetricEncryption::Cipher.new(
|
11
|
-
# :
|
12
|
-
# :
|
13
|
-
# :
|
11
|
+
# key: '1234567890ABCDEF1234567890ABCDEF',
|
12
|
+
# iv: '1234567890ABCDEF',
|
13
|
+
# cipher_name: 'aes-128-cbc'
|
14
14
|
# )
|
15
15
|
# end
|
16
16
|
# end
|
@@ -66,7 +66,7 @@ namespace :symmetric_encryption do
|
|
66
66
|
if input_filename && output_filename
|
67
67
|
puts "\nEncrypting file: #{input_filename} and writing to: #{output_filename}\n\n"
|
68
68
|
::File.open(input_filename, 'rb') do |input_file|
|
69
|
-
SymmetricEncryption::Writer.open(output_filename, :
|
69
|
+
SymmetricEncryption::Writer.open(output_filename, compress: compress) do |output_file|
|
70
70
|
while !input_file.eof?
|
71
71
|
output_file.write(input_file.read(block_size))
|
72
72
|
end
|
@@ -63,15 +63,15 @@ module SymmetricEncryption
|
|
63
63
|
# end
|
64
64
|
#
|
65
65
|
# # Example: Read, Unencrypt and decompress data in a file
|
66
|
-
# SymmetricEncryption::Reader.open('encrypted_compressed.zip', :
|
66
|
+
# SymmetricEncryption::Reader.open('encrypted_compressed.zip', compress: true) do |file|
|
67
67
|
# file.each_line {|line| p line }
|
68
68
|
# end
|
69
69
|
#
|
70
70
|
# # Example: Reading from a CSV file
|
71
71
|
#
|
72
|
-
# require '
|
72
|
+
# require 'csv'
|
73
73
|
# begin
|
74
|
-
# csv =
|
74
|
+
# csv = CSV.new(SymmetricEncryption::Reader.open('csv_encrypted'))
|
75
75
|
# csv.each {|row| p row}
|
76
76
|
# ensure
|
77
77
|
# csv.close if csv
|
@@ -33,9 +33,9 @@ module SymmetricEncryption
|
|
33
33
|
# Example: For testing purposes the following test cipher can be used:
|
34
34
|
#
|
35
35
|
# SymmetricEncryption.cipher = SymmetricEncryption::Cipher.new(
|
36
|
-
# :
|
37
|
-
# :
|
38
|
-
# :
|
36
|
+
# key: '1234567890ABCDEF1234567890ABCDEF',
|
37
|
+
# iv: '1234567890ABCDEF',
|
38
|
+
# cipher: 'aes-128-cbc'
|
39
39
|
# )
|
40
40
|
def self.cipher=(cipher)
|
41
41
|
raise "Cipher must be similar to SymmetricEncryption::Ciphers" unless cipher.nil? || (cipher.respond_to?(:encrypt) && cipher.respond_to?(:decrypt))
|
@@ -311,7 +311,7 @@ module SymmetricEncryption
|
|
311
311
|
elsif !cipher_cfg[:iv]
|
312
312
|
iv = rsa_key.public_encrypt(key_pair[:iv])
|
313
313
|
puts "Generated new Symmetric Key for encryption. Set the IV environment variable in #{environment} to:"
|
314
|
-
puts ::Base64.encode64(
|
314
|
+
puts ::Base64.encode64(iv)
|
315
315
|
end
|
316
316
|
end
|
317
317
|
|
@@ -413,7 +413,7 @@ module SymmetricEncryption
|
|
413
413
|
if key_filename = config.delete(:key_filename)
|
414
414
|
raise "Missing mandatory config parameter :private_rsa_key when :key_filename is supplied" unless rsa
|
415
415
|
encrypted_key = begin
|
416
|
-
File.
|
416
|
+
File.open(key_filename, 'rb'){|f| f.read}
|
417
417
|
rescue Errno::ENOENT
|
418
418
|
puts "\nSymmetric Encryption key file: '#{key_filename}' not found or readable."
|
419
419
|
puts "To generate the keys for the first time run: rails generate symmetric_encryption:new_keys\n\n"
|
@@ -425,7 +425,7 @@ module SymmetricEncryption
|
|
425
425
|
if iv_filename = config.delete(:iv_filename)
|
426
426
|
raise "Missing mandatory config parameter :private_rsa_key when :iv_filename is supplied" unless rsa
|
427
427
|
encrypted_iv = begin
|
428
|
-
File.
|
428
|
+
File.open(iv_filename, 'rb'){|f| f.read} if iv_filename
|
429
429
|
rescue Errno::ENOENT
|
430
430
|
puts "\nSymmetric Encryption initialization vector file: '#{iv_filename}' not found or readable."
|
431
431
|
puts "To generate the keys for the first time run: rails generate symmetric_encryption:new_keys\n\n"
|
@@ -438,6 +438,11 @@ module SymmetricEncryption
|
|
438
438
|
raise "Missing mandatory config parameter :private_rsa_key when :encrypted_key is supplied" unless rsa
|
439
439
|
# Decode value first using encoding specified
|
440
440
|
encrypted_key = ::Base64.decode64(encrypted_key)
|
441
|
+
if !encrypted_key || encrypted_key.empty?
|
442
|
+
puts "\nSymmetric Encryption encrypted_key not found."
|
443
|
+
puts "To generate the keys for the first time run: rails generate symmetric_encryption:new_keys\n\n"
|
444
|
+
return
|
445
|
+
end
|
441
446
|
config[:key] = rsa.private_decrypt(encrypted_key)
|
442
447
|
end
|
443
448
|
|
@@ -445,6 +450,11 @@ module SymmetricEncryption
|
|
445
450
|
raise "Missing mandatory config parameter :private_rsa_key when :encrypted_iv is supplied" unless rsa
|
446
451
|
# Decode value first using encoding specified
|
447
452
|
encrypted_iv = ::Base64.decode64(encrypted_iv)
|
453
|
+
if !encrypted_key || encrypted_key.empty?
|
454
|
+
puts "\nSymmetric Encryption encrypted_iv not found."
|
455
|
+
puts "To generate the keys for the first time run: rails generate symmetric_encryption:new_keys\n\n"
|
456
|
+
return
|
457
|
+
end
|
448
458
|
config[:iv] = rsa.private_decrypt(encrypted_iv)
|
449
459
|
end
|
450
460
|
|
@@ -460,7 +470,7 @@ module SymmetricEncryption
|
|
460
470
|
# Coerce given value into given type
|
461
471
|
# Does not coerce json or yaml values
|
462
472
|
def self.coerce(value, type, from_type=nil)
|
463
|
-
return if value.nil?
|
473
|
+
return if value.nil? || (value.is_a?(String) && (value !~ /[^[:space:]]/))
|
464
474
|
|
465
475
|
from_type ||= value.class
|
466
476
|
case type
|
@@ -519,13 +529,13 @@ module SymmetricEncryption
|
|
519
529
|
end
|
520
530
|
|
521
531
|
COERCION_TYPE_MAP = {
|
522
|
-
:
|
523
|
-
:
|
524
|
-
:
|
525
|
-
:
|
526
|
-
:
|
527
|
-
:
|
528
|
-
:
|
532
|
+
string: String,
|
533
|
+
integer: Integer,
|
534
|
+
float: Float,
|
535
|
+
decimal: BigDecimal,
|
536
|
+
datetime: DateTime,
|
537
|
+
time: Time,
|
538
|
+
date: Date
|
529
539
|
}
|
530
540
|
|
531
541
|
# With Ruby 1.9 strings have encodings
|
@@ -534,4 +544,4 @@ module SymmetricEncryption
|
|
534
544
|
UTF8_ENCODING = Encoding.find("UTF-8")
|
535
545
|
end
|
536
546
|
|
537
|
-
end
|
547
|
+
end
|
@@ -83,17 +83,17 @@ module SymmetricEncryption
|
|
83
83
|
# end
|
84
84
|
#
|
85
85
|
# # Example: Compress, Encrypt and write data to a file
|
86
|
-
# SymmetricEncryption::Writer.open('encrypted_compressed.zip', :
|
86
|
+
# SymmetricEncryption::Writer.open('encrypted_compressed.zip', compress: true) do |file|
|
87
87
|
# file.write "Hello World\n"
|
88
88
|
# file.write "Compress this\n"
|
89
89
|
# file.write "Keep this safe and secure\n"
|
90
90
|
# end
|
91
91
|
#
|
92
92
|
# # Example: Writing to a CSV file
|
93
|
-
# require '
|
93
|
+
# require 'csv'
|
94
94
|
# begin
|
95
|
-
# # Must supply :row_sep for
|
96
|
-
# csv =
|
95
|
+
# # Must supply :row_sep for CSV otherwise it will attempt to read from and then rewind the file
|
96
|
+
# csv = CSV.new(SymmetricEncryption::Writer.open('csv_encrypted'), row_sep: "\n")
|
97
97
|
# csv << [1,2,3,4,5]
|
98
98
|
# ensure
|
99
99
|
# csv.close if csv
|