symmetric-encryption 3.8.3 → 3.9.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.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/Rakefile +16 -16
- data/examples/symmetric-encryption.yml +33 -38
- data/lib/rails/generators/symmetric_encryption/config/templates/symmetric-encryption.yml +10 -14
- data/lib/rails/generators/symmetric_encryption/heroku_config/templates/symmetric-encryption.yml +28 -25
- data/lib/symmetric_encryption.rb +14 -6
- data/lib/symmetric_encryption/cipher.rb +151 -130
- data/lib/symmetric_encryption/config.rb +0 -1
- data/lib/symmetric_encryption/encoder.rb +79 -0
- data/lib/symmetric_encryption/extensions/active_record/base.rb +94 -134
- data/lib/symmetric_encryption/extensions/mongo_mapper/plugins/encrypted_key.rb +3 -89
- data/lib/symmetric_encryption/key_encryption_key.rb +32 -0
- data/lib/symmetric_encryption/railtie.rb +3 -3
- data/lib/symmetric_encryption/symmetric_encryption.rb +41 -8
- data/lib/symmetric_encryption/utils/re_encrypt_config_files.rb +82 -0
- data/lib/symmetric_encryption/version.rb +1 -1
- data/test/active_record_test.rb +149 -140
- data/test/cipher_test.rb +98 -6
- data/test/config/{mongoid_v5.yml → mongoid.yml} +0 -0
- data/test/config/symmetric-encryption.yml +4 -10
- data/test/config/test_new.key +2 -2
- data/test/encoder_test.rb +61 -0
- data/test/mongoid_test.rb +12 -22
- data/test/reader_test.rb +16 -11
- data/test/symmetric_encryption_test.rb +23 -3
- data/test/test_db.sqlite3 +0 -0
- data/test/test_helper.rb +2 -16
- data/test/writer_test.rb +1 -5
- metadata +11 -12
- data/test/config/mongoid_v2.yml +0 -6
- data/test/config/mongoid_v3.yml +0 -9
- data/test/mongo_mapper_test.rb +0 -599
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fad0434ee0b203f85088bc62492c16d2365a284c
|
4
|
+
data.tar.gz: c8cd4796787faa48be52155d75e1e312f627b38d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 59fe734623957ac4abed7b6b94786153a793947528d6b857612f418c6fa151947076b8802b5fe901bc2a1d0bad02aa79aa6790951b0671d054e4274ea09a29cc
|
7
|
+
data.tar.gz: 72270dd87fd4e16616b31e7d173facffc2da383c6f0719c0cc76bb9e353d0b33f1179c419af24f36c4ac108e6279b695202163884c01d0d97fe7f770688223b2
|
data/README.md
CHANGED
@@ -33,8 +33,8 @@ Fully supports Symmetric Encryption to encrypt data in flight and at rest while
|
|
33
33
|
|
34
34
|
Symmetric Encryption works with the following Ruby VMs:
|
35
35
|
|
36
|
-
- Ruby 2.1
|
37
|
-
- JRuby
|
36
|
+
- Ruby 2.1 and higher.
|
37
|
+
- JRuby 9.1 and higher.
|
38
38
|
|
39
39
|
## Upgrading to SymmetricEncryption V3
|
40
40
|
|
data/Rakefile
CHANGED
@@ -1,8 +1,9 @@
|
|
1
|
-
|
2
|
-
require '
|
1
|
+
# Setup bundler to avoid having to run bundle exec all the time.
|
2
|
+
require 'rubygems'
|
3
|
+
require 'bundler/setup'
|
3
4
|
|
4
|
-
|
5
|
-
|
5
|
+
require 'rake/testtask'
|
6
|
+
require_relative 'lib/symmetric_encryption/version'
|
6
7
|
|
7
8
|
task :gem do
|
8
9
|
system 'gem build symmetric-encryption.gemspec'
|
@@ -15,17 +16,16 @@ task :publish => :gem do
|
|
15
16
|
system "rm symmetric-encryption-#{SymmetricEncryption::VERSION}.gem"
|
16
17
|
end
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
t.verbose = true
|
23
|
-
end
|
24
|
-
|
25
|
-
# For mongoid
|
26
|
-
ENV['RACK_ENV'] = 'test'
|
27
|
-
|
28
|
-
Rake::Task['functional'].invoke
|
19
|
+
Rake::TestTask.new(:test) do |t|
|
20
|
+
t.pattern = 'test/**/*_test.rb'
|
21
|
+
t.verbose = true
|
22
|
+
t.warning = false
|
29
23
|
end
|
30
24
|
|
31
|
-
|
25
|
+
# By default run tests against all appraisals
|
26
|
+
if !ENV["APPRAISAL_INITIALIZED"] && !ENV["TRAVIS"]
|
27
|
+
require 'appraisal'
|
28
|
+
task default: :appraisal
|
29
|
+
else
|
30
|
+
task default: :test
|
31
|
+
end
|
@@ -4,9 +4,9 @@
|
|
4
4
|
---
|
5
5
|
# For the development and test environments the test symmetric encryption keys
|
6
6
|
# can be placed directly in the source code.
|
7
|
-
# And therefore no
|
7
|
+
# And therefore no key encryption key is required
|
8
8
|
development: &development_defaults
|
9
|
-
key:
|
9
|
+
key: 1234567890ABCDEF
|
10
10
|
iv: 1234567890ABCDEF
|
11
11
|
cipher: aes-128-cbc
|
12
12
|
|
@@ -14,12 +14,12 @@ test:
|
|
14
14
|
<<: *development_defaults
|
15
15
|
|
16
16
|
production:
|
17
|
-
# Since the key
|
18
|
-
# source code,
|
19
|
-
# containing the actual symmetric encryption key
|
17
|
+
# Since the encryption key must NOT be stored along with the
|
18
|
+
# source code, only store the key encryption key here.
|
20
19
|
#
|
21
|
-
#
|
22
|
-
#
|
20
|
+
# Test Key encryption key, DO NOT use this key, generate a new one using
|
21
|
+
# SymmetricEncryption::KeyEncryptionKey.generate
|
22
|
+
# Or use the rails generator to create a new config file as described in the readme
|
23
23
|
private_rsa_key: |
|
24
24
|
-----BEGIN RSA PRIVATE KEY-----
|
25
25
|
MIIEpAIBAAKCAQEAxIL9H/jYUGpA38v6PowRSRJEo3aNVXULNM/QNRpx2DTf++KH
|
@@ -49,11 +49,11 @@ production:
|
|
49
49
|
r1URaMAun2PfAB4g2N/kEZTExgeOGqXjFhvvjdzl97ux2cTyZhaTXg==
|
50
50
|
-----END RSA PRIVATE KEY-----
|
51
51
|
|
52
|
-
# List Symmetric Key Ciphers in the order of current /
|
52
|
+
# List Symmetric Key Ciphers in the order of current / newest first
|
53
53
|
ciphers:
|
54
|
-
|
55
|
-
#
|
56
|
-
|
54
|
+
-
|
55
|
+
# Name of the file containing the encrypted key and iv.
|
56
|
+
key_filename: /etc/rails/.rails.key
|
57
57
|
iv_filename: /etc/rails/.rails.iv
|
58
58
|
|
59
59
|
# Encryption cipher
|
@@ -83,31 +83,26 @@ production:
|
|
83
83
|
# Default: base64
|
84
84
|
encoding: base64strict
|
85
85
|
|
86
|
-
#
|
87
|
-
#
|
88
|
-
#
|
89
|
-
|
90
|
-
|
91
|
-
#
|
92
|
-
#
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
86
|
+
# Version of this key so that when a new key is supplied, old encrypted data can be decrypted
|
87
|
+
# using the correct key.
|
88
|
+
# Increment this version with every time a new key is generated.
|
89
|
+
version: 2
|
90
|
+
|
91
|
+
# Highly Recommended to always set this to true.
|
92
|
+
# Add a header to every encrypted message.
|
93
|
+
always_add_header: true
|
94
|
+
|
95
|
+
# OPTIONAL:
|
96
|
+
#
|
97
|
+
# Any previous Symmetric Encryption Keys
|
98
|
+
#
|
99
|
+
# Only used when old data still exists that requires old decryption keys
|
100
|
+
# to be used
|
101
|
+
-
|
102
|
+
key_filename: /etc/rails/.rails_old.key
|
103
|
+
iv_filename: /etc/rails/.rails_old.iv
|
104
|
+
cipher: aes-256-cbc
|
105
|
+
encoding: base64strict
|
106
|
+
version: 1
|
107
|
+
always_add_header: true
|
103
108
|
|
104
|
-
# OPTIONAL:
|
105
|
-
#
|
106
|
-
# Any previous Symmetric Encryption Keys
|
107
|
-
#
|
108
|
-
# Only used when old data still exists that requires old decryption keys
|
109
|
-
# to be used
|
110
|
-
- key_filename: /etc/rails/.rails_old.key
|
111
|
-
iv_filename: /etc/rails/.rails_old.iv
|
112
|
-
cipher: aes-256-cbc
|
113
|
-
encoding: base64strict
|
@@ -4,9 +4,9 @@
|
|
4
4
|
---
|
5
5
|
# For the development and test environments the test symmetric encryption keys
|
6
6
|
# can be placed directly in the source code.
|
7
|
-
# And therefore no
|
7
|
+
# And therefore no key encryption key is required
|
8
8
|
development: &development_defaults
|
9
|
-
key:
|
9
|
+
key: 1234567890ABCDEF
|
10
10
|
iv: 1234567890ABCDEF
|
11
11
|
cipher_name: aes-128-cbc
|
12
12
|
encoding: :base64strict
|
@@ -16,17 +16,15 @@ test:
|
|
16
16
|
<<: *development_defaults
|
17
17
|
|
18
18
|
release:
|
19
|
-
# Since the key
|
20
|
-
# source code,
|
21
|
-
# containing the actual symmetric encryption key
|
19
|
+
# Since the encryption key must NOT be stored along with the
|
20
|
+
# source code, only store the key encryption key here.
|
22
21
|
private_rsa_key: |
|
23
|
-
<%=
|
22
|
+
<%= SymmetricEncryption::KeyEncryptionKey.generate.each_line.collect { |line| " #{line}" }.join('') %>
|
24
23
|
|
25
24
|
# List Symmetric Key files in the order of current / latest first
|
26
25
|
ciphers:
|
27
26
|
-
|
28
|
-
#
|
29
|
-
# RSA public key derived from the private key above
|
27
|
+
# Name of the file containing the encrypted key and iv.
|
30
28
|
key_filename: <%= File.join(key_path, "#{app_name}_release.key") %>
|
31
29
|
iv_filename: <%= File.join(key_path, "#{app_name}_release.iv") %>
|
32
30
|
cipher_name: aes-256-cbc
|
@@ -35,17 +33,15 @@ release:
|
|
35
33
|
always_add_header: true
|
36
34
|
|
37
35
|
production:
|
38
|
-
# Since the key
|
39
|
-
# source code,
|
40
|
-
# containing the actual symmetric encryption key
|
36
|
+
# Since the encryption key must NOT be stored along with the
|
37
|
+
# source code, only store the key encryption key here.
|
41
38
|
private_rsa_key: |
|
42
|
-
<%=
|
39
|
+
<%= SymmetricEncryption::KeyEncryptionKey.generate.each_line.collect { |line| " #{line}" }.join('') %>
|
43
40
|
|
44
41
|
# List Symmetric Key files in the order of current / latest first
|
45
42
|
ciphers:
|
46
43
|
-
|
47
|
-
#
|
48
|
-
# RSA public key derived from the private key above
|
44
|
+
# Name of the file containing the encrypted key and iv.
|
49
45
|
key_filename: <%= File.join(key_path, "#{app_name}_production.key") %>
|
50
46
|
iv_filename: <%= File.join(key_path, "#{app_name}_production.iv") %>
|
51
47
|
cipher_name: aes-256-cbc
|
data/lib/rails/generators/symmetric_encryption/heroku_config/templates/symmetric-encryption.yml
CHANGED
@@ -4,9 +4,9 @@
|
|
4
4
|
---
|
5
5
|
# For the development and test environments the test symmetric encryption keys
|
6
6
|
# can be placed directly in the source code.
|
7
|
-
# And therefore no
|
7
|
+
# And therefore no key encryption key is required
|
8
8
|
development: &development_defaults
|
9
|
-
key:
|
9
|
+
key: 1234567890ABCDEF
|
10
10
|
iv: 1234567890ABCDEF
|
11
11
|
cipher_name: aes-128-cbc
|
12
12
|
encoding: :base64strict
|
@@ -15,60 +15,63 @@ test:
|
|
15
15
|
<<: *development_defaults
|
16
16
|
|
17
17
|
<%
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
encrypted_key =
|
18
|
+
rsa_key = SymmetricEncryption::KeyEncryptionKey.generate
|
19
|
+
cipher_conf = SymmetricEncryption::Cipher.generate_random_keys(private_rsa_key: rsa_key, encrypted_key: '', encrypted_iv: '')
|
20
|
+
cipher_name = cipher_conf[:cipher_name]
|
21
|
+
encrypted_iv = cipher_conf[:encrypted_iv]
|
22
|
+
encrypted_key = cipher_conf[:encrypted_key]
|
23
23
|
|
24
24
|
puts "\n\n********************************************************************************"
|
25
25
|
puts "Add the release environment key to Heroku: (Optional)\n\n"
|
26
26
|
puts " heroku config:add RELEASE_KEY1=#{encrypted_key}\n\n"
|
27
|
+
puts "\n\n********************************************************************************"
|
28
|
+
puts "Add the release environment key to Heroku: (Optional)\n\n"
|
29
|
+
puts " heroku config:add RELEASE_IV1=#{encrypted_iv}\n\n"
|
27
30
|
-%>
|
28
31
|
release:
|
29
|
-
#
|
30
|
-
#
|
31
|
-
# containing the actual symmetric encryption key
|
32
|
+
# Key encryption key
|
33
|
+
# Key used to secure the encryption key when it is stored in a file or encrypted.
|
32
34
|
private_rsa_key: |
|
33
|
-
<%= rsa_key.
|
35
|
+
<%= rsa_key.each_line.collect { |line| " #{line}" }.join('') %>
|
34
36
|
|
35
37
|
# List Symmetric Key files in the order of current / latest first
|
36
38
|
ciphers:
|
37
39
|
-
|
38
40
|
# Filename containing Symmetric Encryption Key encrypted using the
|
39
|
-
#
|
41
|
+
# key encryption key above (private_rsa_key).
|
40
42
|
encrypted_key: "<%= '<' + "%= ENV['RELEASE_KEY1'] %" + '>' %>"
|
41
|
-
|
43
|
+
encrypted_iv: "<%= '<' + "%= ENV['RELEASE_IV1'] %" + '>' %>"
|
42
44
|
cipher_name: <%= cipher_name %>
|
43
45
|
encoding: :base64strict
|
44
46
|
version: 1
|
45
47
|
always_add_header: true
|
46
48
|
|
47
49
|
<%
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
encrypted_key =
|
50
|
+
rsa_key = SymmetricEncryption::KeyEncryptionKey.generate
|
51
|
+
cipher_conf = SymmetricEncryption::Cipher.generate_random_keys(private_rsa_key: rsa_key, encrypted_key: '', encrypted_iv: '')
|
52
|
+
cipher_name = cipher_conf[:cipher_name]
|
53
|
+
encrypted_iv = cipher_conf[:encrypted_iv]
|
54
|
+
encrypted_key = cipher_conf[:encrypted_key]
|
53
55
|
|
54
56
|
puts "Add the production key to Heroku:\n\n"
|
55
57
|
puts " heroku config:add PRODUCTION_KEY1=#{encrypted_key}\n\n"
|
56
58
|
puts "********************************************************************************\n\n\n"
|
59
|
+
puts "Add the production key to Heroku:\n\n"
|
60
|
+
puts " heroku config:add PRODUCTION_IV1=#{encrypted_iv}\n\n"
|
61
|
+
puts "********************************************************************************\n\n\n"
|
57
62
|
-%>
|
58
63
|
production:
|
59
|
-
# Since the key
|
60
|
-
# source code,
|
61
|
-
# containing the actual symmetric encryption key
|
64
|
+
# Since the encryption key must NOT be stored along with the
|
65
|
+
# source code, only store the key encryption key here.
|
62
66
|
private_rsa_key: |
|
63
|
-
<%= rsa_key.
|
67
|
+
<%= rsa_key.each_line.collect { |line| " #{line}" }.join('') %>
|
64
68
|
|
65
69
|
# List Symmetric Key files in the order of current / latest first
|
66
70
|
ciphers:
|
67
71
|
-
|
68
|
-
#
|
69
|
-
# RSA public key derived from the private key above
|
72
|
+
# Encrypted key is supplied via an environment variable.
|
70
73
|
encrypted_key: "<%= '<' + "%= ENV['PRODUCTION_KEY1'] %" + '>' %>"
|
71
|
-
|
74
|
+
encrypted_iv: "<%= '<' + "%= ENV['PRODUCTION_IV1'] %" + '>' %>"
|
72
75
|
cipher_name: <%= cipher_name %>
|
73
76
|
encoding: :base64strict
|
74
77
|
version: 1
|
data/lib/symmetric_encryption.rb
CHANGED
@@ -10,11 +10,16 @@ require 'symmetric_encryption/exception'
|
|
10
10
|
|
11
11
|
#@formatter:off
|
12
12
|
module SymmetricEncryption
|
13
|
-
autoload :Coerce,
|
14
|
-
autoload :Config,
|
15
|
-
autoload :
|
16
|
-
autoload :
|
17
|
-
autoload :
|
13
|
+
autoload :Coerce, 'symmetric_encryption/coerce'
|
14
|
+
autoload :Config, 'symmetric_encryption/config'
|
15
|
+
autoload :Encoder, 'symmetric_encryption/encoder'
|
16
|
+
autoload :KeyEncryptionKey, 'symmetric_encryption/key_encryption_key'
|
17
|
+
autoload :Reader, 'symmetric_encryption/reader'
|
18
|
+
autoload :Writer, 'symmetric_encryption/writer'
|
19
|
+
autoload :Generator, 'symmetric_encryption/generator'
|
20
|
+
module Utils
|
21
|
+
autoload :ReEncryptConfigFiles, 'symmetric_encryption/re_encrypt_config_files'
|
22
|
+
end
|
18
23
|
end
|
19
24
|
#@formatter:on
|
20
25
|
|
@@ -25,4 +30,7 @@ if defined?(ActiveRecord::Base) && !defined?(AttrEncrypted::Version)
|
|
25
30
|
end
|
26
31
|
require 'symmetric_encryption/railties/symmetric_encryption_validator' if defined?(ActiveModel)
|
27
32
|
require 'symmetric_encryption/extensions/mongoid/encrypted' if defined?(Mongoid)
|
28
|
-
|
33
|
+
if defined?(MongoMapper)
|
34
|
+
warn 'MongoMapper support is deprecated. Consider upgrading to Mongoid.'
|
35
|
+
require 'symmetric_encryption/extensions/mongo_mapper/plugins/encrypted_key'
|
36
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
|
+
require 'openssl'
|
1
2
|
module SymmetricEncryption
|
2
|
-
|
3
3
|
# Hold all information related to encryption keys
|
4
4
|
# as well as encrypt and decrypt data using those keys
|
5
5
|
#
|
@@ -7,11 +7,9 @@ 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
|
-
|
11
|
-
|
12
|
-
|
13
|
-
# Available encodings
|
14
|
-
ENCODINGS = [:none, :base64, :base64strict, :base16]
|
10
|
+
attr_accessor :cipher_name, :version, :iv, :always_add_header
|
11
|
+
attr_reader :encoder, :encoding
|
12
|
+
attr_writer :key
|
15
13
|
|
16
14
|
# Backward compatibility
|
17
15
|
alias_method :cipher, :cipher_name
|
@@ -52,48 +50,104 @@ module SymmetricEncryption
|
|
52
50
|
}
|
53
51
|
end
|
54
52
|
|
55
|
-
# Generate new randomized keys and generate key and iv files if supplied
|
56
|
-
# Overwrites key files for the current environment
|
57
|
-
#
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
53
|
+
# Generate new randomized keys and generate key and iv files if supplied.
|
54
|
+
# Overwrites key files for the current environment.
|
55
|
+
#
|
56
|
+
# Parameters
|
57
|
+
# :key_filename
|
58
|
+
# Name of file that will contain the symmetric key encrypted using the public
|
59
|
+
# key from the private_rsa_key.
|
60
|
+
# Or,
|
61
|
+
# :encrypted_key
|
62
|
+
# Symmetric key encrypted using the public key from the private_rsa_key
|
63
|
+
# and then Base64 encoded
|
64
|
+
#
|
65
|
+
# Note:
|
66
|
+
# If :key_filename and :encrypted_key are not supplied then a new :key will be returned.
|
67
|
+
# :key is the Symmetric Key to use for encryption and decryption.
|
68
|
+
#
|
69
|
+
#
|
70
|
+
# :iv_filename
|
71
|
+
# Name of file containing symmetric key initialization vector
|
72
|
+
# encrypted using the public key from the private_rsa_key
|
73
|
+
# Deprecated: It is _not_ necessary to encrypt the initialization vector (IV)
|
74
|
+
# Or,
|
75
|
+
# :encrypted_iv
|
76
|
+
# Initialization vector encrypted using the public key from the private_rsa_key
|
77
|
+
# and then Base64 encoded
|
78
|
+
# Deprecated: It is _not_ necessary to encrypt the initialization vector (IV)
|
79
|
+
#
|
80
|
+
# Note:
|
81
|
+
# If :iv_filename and :encrypted_iv are not supplied then a new :iv will be returned.
|
82
|
+
# :key is the Initialization Vector to use with Symmetric Key.
|
83
|
+
#
|
84
|
+
#
|
85
|
+
# private_rsa_key [String]
|
86
|
+
# Key encryption key.
|
87
|
+
# To generate a new one: SymmetricEncryption::KeyEncryptionKey.generate
|
88
|
+
# Required if :key_filename, :encrypted_key, :iv_filename, or :encrypted_iv is supplied
|
89
|
+
#
|
90
|
+
# :cipher_name [String]
|
91
|
+
# Encryption Cipher to use.
|
92
|
+
# Default: aes-256-cbc
|
93
|
+
#
|
94
|
+
# :encoding [Symbol]
|
95
|
+
# :base64strict
|
96
|
+
# Return as a base64 encoded string that does not include additional newlines
|
97
|
+
# This is the recommended format since newlines in the values to
|
98
|
+
# SQL queries are cumbersome. Also the newline reformatting is unnecessary
|
99
|
+
# It is not the default for backward compatibility
|
100
|
+
# :base64
|
101
|
+
# Return as a base64 encoded string
|
102
|
+
# :base16
|
103
|
+
# Return as a Hex encoded string
|
104
|
+
# :none
|
105
|
+
# Return as raw binary data string. Note: String can contain embedded nulls
|
106
|
+
# Default: :base64strict
|
107
|
+
def self.generate_random_keys(params = {})
|
108
|
+
params = params.dup
|
109
|
+
private_rsa_key = params.delete(:private_rsa_key)
|
110
|
+
cipher_name = params.delete(:cipher_name) || 'aes-256-cbc'
|
111
|
+
encoding = params.delete(:encoding) || :base64strict
|
112
|
+
unless private_rsa_key
|
113
|
+
[:key_filename, :encrypted_key, :iv_filename, :encrypted_iv].each do |key|
|
114
|
+
raise(SymmetricEncryption::ConfigError, "When :#{key} is supplied, :private_rsa_key is required.") if params.include?(key)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
key_encryption_key = KeyEncryptionKey.new(private_rsa_key) if private_rsa_key
|
119
|
+
cipher_conf = {cipher_name: cipher_name, encoding: encoding}
|
120
|
+
|
121
|
+
key_pair = SymmetricEncryption::Cipher.random_key_pair(cipher_name)
|
122
|
+
key = key_pair[:key]
|
123
|
+
iv = key_pair[:iv]
|
124
|
+
|
125
|
+
if file_name = params.delete(:key_filename)
|
126
|
+
cipher_conf[:key_filename] = file_name
|
127
|
+
encrypted_key = key_encryption_key.encrypt(key)
|
128
|
+
write_to_file(file_name, encrypted_key)
|
129
|
+
elsif params.delete(:encrypted_key)
|
130
|
+
encrypted_key = key_encryption_key.encrypt(key)
|
131
|
+
cipher_conf[:encrypted_key] = SymmetricEncryption::Encoder[encoding].encode(encrypted_key)
|
132
|
+
else
|
133
|
+
params.delete(:key)
|
134
|
+
cipher_conf[:key] = SymmetricEncryption::Encoder[encoding].encode(key.to_s)
|
80
135
|
end
|
81
136
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
elsif
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
puts "heroku config:add #{environment.upcase}_KEY1=#{encrypted_iv}"
|
93
|
-
puts
|
94
|
-
puts 'Otherwise, set the :encrypted_iv value to:'
|
95
|
-
puts encrypted_iv
|
137
|
+
if file_name = params.delete(:iv_filename)
|
138
|
+
cipher_conf[:iv_filename] = file_name
|
139
|
+
encrypted_iv = key_encryption_key.encrypt(iv)
|
140
|
+
write_to_file(file_name, encrypted_iv)
|
141
|
+
elsif params.delete(:encrypted_iv)
|
142
|
+
encrypted_iv = key_encryption_key.encrypt(iv)
|
143
|
+
cipher_conf[:encrypted_iv] = SymmetricEncryption::Encoder[encoding].encode(encrypted_iv)
|
144
|
+
else
|
145
|
+
params.delete(:iv)
|
146
|
+
cipher_conf[:iv] = SymmetricEncryption::Encoder[encoding].encode(iv.to_s)
|
96
147
|
end
|
148
|
+
|
149
|
+
raise(ArgumentError, "SymmetricEncryption::Cipher Invalid options #{params.inspect}") if params.size > 0
|
150
|
+
cipher_conf
|
97
151
|
end
|
98
152
|
|
99
153
|
# Create a Symmetric::Key for encryption and decryption purposes
|
@@ -114,15 +168,15 @@ module SymmetricEncryption
|
|
114
168
|
# Optional. The Initialization Vector to use with Symmetric Key
|
115
169
|
# Highly Recommended as it is the input into the CBC algorithm
|
116
170
|
# Or,
|
117
|
-
# Note: The following 2 options are deprecated since it is _not_ necessary
|
118
|
-
# to encrypt the initialization vector (IV)
|
119
171
|
# :iv_filename
|
120
172
|
# Name of file containing symmetric key initialization vector
|
121
173
|
# encrypted using the public key from the private_rsa_key
|
174
|
+
# Deprecated: It is _not_ necessary to encrypt the initialization vector (IV)
|
122
175
|
# Or,
|
123
176
|
# :encrypted_iv
|
124
177
|
# Initialization vector encrypted using the public key from the private_rsa_key
|
125
178
|
# and then Base64 encoded
|
179
|
+
# Deprecated: It is _not_ necessary to encrypt the initialization vector (IV)
|
126
180
|
#
|
127
181
|
# :cipher_name [String]
|
128
182
|
# Optional. Encryption Cipher to use
|
@@ -157,41 +211,57 @@ module SymmetricEncryption
|
|
157
211
|
# Recommended: true
|
158
212
|
#
|
159
213
|
# private_rsa_key [String]
|
160
|
-
#
|
161
|
-
#
|
214
|
+
# Key encryption key.
|
215
|
+
# To generate a new one: SymmetricEncryption::KeyEncryptionKey.generate
|
216
|
+
# Required if :key_filename, :encrypted_key, :iv_filename, or :encrypted_iv is supplied
|
162
217
|
def initialize(params={})
|
163
218
|
params = params.dup
|
164
219
|
@cipher_name = params.delete(:cipher_name) || params.delete(:cipher) || 'aes-256-cbc'
|
165
220
|
@version = params.delete(:version)
|
166
221
|
@always_add_header = params.delete(:always_add_header) || false
|
167
|
-
|
168
|
-
|
169
|
-
# To decrypt encrypted key or iv files
|
222
|
+
self.encoding = (params.delete(:encoding) || :base64).to_sym
|
170
223
|
private_rsa_key = params.delete(:private_rsa_key)
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
elsif file_name = params.delete(:key_filename)
|
176
|
-
@key = read_from_file(file_name, rsa)
|
177
|
-
elsif encrypted_key = params.delete(:encrypted_key)
|
178
|
-
@key = decrypt_key(encrypted_key, rsa)
|
224
|
+
unless private_rsa_key
|
225
|
+
[:key_filename, :encrypted_key, :iv_filename, :encrypted_iv].each do |key|
|
226
|
+
raise(SymmetricEncryption::ConfigError, "When :#{key} is supplied, :private_rsa_key is required.") if params.include?(key)
|
227
|
+
end
|
179
228
|
end
|
180
229
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
230
|
+
key_encryption_key = KeyEncryptionKey.new(private_rsa_key) if private_rsa_key
|
231
|
+
@key =
|
232
|
+
if key = params.delete(:key)
|
233
|
+
key
|
234
|
+
elsif file_name = params.delete(:key_filename)
|
235
|
+
encrypted_key = self.class.read_from_file(file_name)
|
236
|
+
key_encryption_key.decrypt(encrypted_key)
|
237
|
+
elsif encrypted_key = params.delete(:encrypted_key)
|
238
|
+
binary = self.encoder.decode(encrypted_key)
|
239
|
+
key_encryption_key.decrypt(binary)
|
240
|
+
else
|
241
|
+
raise(ArgumentError, 'Missing mandatory parameter :key, :key_filename, or :encrypted_key')
|
242
|
+
end
|
243
|
+
|
244
|
+
@iv =
|
245
|
+
if iv = params.delete(:iv)
|
246
|
+
iv
|
247
|
+
elsif file_name = params.delete(:iv_filename)
|
248
|
+
encrypted_iv = self.class.read_from_file(file_name)
|
249
|
+
key_encryption_key.decrypt(encrypted_iv)
|
250
|
+
elsif encrypted_iv = params.delete(:encrypted_iv)
|
251
|
+
binary = self.encoder.decode(encrypted_iv)
|
252
|
+
key_encryption_key.decrypt(binary)
|
253
|
+
end
|
188
254
|
|
189
|
-
raise(ArgumentError, 'Missing mandatory parameter :key, :key_filename, or :encrypted_key') unless @key
|
190
|
-
raise(ArgumentError, "Invalid Encoding: #{@encoding}") unless ENCODINGS.include?(@encoding)
|
191
255
|
raise(ArgumentError, "Cipher version has a valid range of 0 to 255. #{@version} is too high, or negative") if (@version.to_i > 255) || (@version.to_i < 0)
|
192
256
|
raise(ArgumentError, "SymmetricEncryption::Cipher Invalid options #{params.inspect}") if params.size > 0
|
193
257
|
end
|
194
258
|
|
259
|
+
# Change the encoding
|
260
|
+
def encoding=(encoding)
|
261
|
+
@encoder = SymmetricEncryption::Encoder[encoding]
|
262
|
+
@encoding = encoding
|
263
|
+
end
|
264
|
+
|
195
265
|
# Encrypt and then encode a string
|
196
266
|
#
|
197
267
|
# Returns data encrypted and then encoded according to the encoding setting
|
@@ -277,21 +347,7 @@ module SymmetricEncryption
|
|
277
347
|
# Returned string is UTF8 encoded except for encoding :none
|
278
348
|
def encode(binary_string)
|
279
349
|
return binary_string if binary_string.nil? || (binary_string == '')
|
280
|
-
|
281
|
-
# Now encode data based on encoding setting
|
282
|
-
case encoding
|
283
|
-
when :base64
|
284
|
-
encoded_string = ::Base64.encode64(binary_string)
|
285
|
-
encoded_string.force_encoding(SymmetricEncryption::UTF8_ENCODING)
|
286
|
-
when :base64strict
|
287
|
-
encoded_string = ::Base64.encode64(binary_string).gsub(/\n/, '')
|
288
|
-
encoded_string.force_encoding(SymmetricEncryption::UTF8_ENCODING)
|
289
|
-
when :base16
|
290
|
-
encoded_string = binary_string.to_s.unpack('H*').first
|
291
|
-
encoded_string.force_encoding(SymmetricEncryption::UTF8_ENCODING)
|
292
|
-
else
|
293
|
-
binary_string
|
294
|
-
end
|
350
|
+
encoder.encode(binary_string)
|
295
351
|
end
|
296
352
|
|
297
353
|
# Decode the supplied string using the encoding in this cipher instance
|
@@ -300,17 +356,7 @@ module SymmetricEncryption
|
|
300
356
|
# Returned string is Binary encoded
|
301
357
|
def decode(encoded_string)
|
302
358
|
return encoded_string if encoded_string.nil? || (encoded_string == '')
|
303
|
-
|
304
|
-
case encoding
|
305
|
-
when :base64, :base64strict
|
306
|
-
decoded_string = ::Base64.decode64(encoded_string)
|
307
|
-
decoded_string.force_encoding(SymmetricEncryption::BINARY_ENCODING)
|
308
|
-
when :base16
|
309
|
-
decoded_string = [encoded_string].pack('H*')
|
310
|
-
decoded_string.force_encoding(SymmetricEncryption::BINARY_ENCODING)
|
311
|
-
else
|
312
|
-
encoded_string
|
313
|
-
end
|
359
|
+
encoder.decode(encoded_string)
|
314
360
|
end
|
315
361
|
|
316
362
|
# Return a new random key using the configured cipher_name
|
@@ -548,44 +594,19 @@ module SymmetricEncryption
|
|
548
594
|
|
549
595
|
attr_reader :key
|
550
596
|
|
551
|
-
# Read the
|
552
|
-
def read_from_file(file_name
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
puts "\nSymmetric Encryption key file: '#{file_name}' not found or readable."
|
559
|
-
puts "To generate the keys for the first time run: bin/rails generate symmetric_encryption:new_keys production\n\n"
|
560
|
-
end
|
597
|
+
# Read from the file, raising an exception if it is not found
|
598
|
+
def self.read_from_file(file_name)
|
599
|
+
File.open(file_name, 'rb') { |f| f.read }
|
600
|
+
rescue Errno::ENOENT => exc
|
601
|
+
puts "\nSymmetric Encryption key file: '#{file_name}' not found or readable."
|
602
|
+
puts "To generate the keys for the first time run: bin/rails generate symmetric_encryption:new_keys production\n\n"
|
603
|
+
raise(exc)
|
561
604
|
end
|
562
605
|
|
563
|
-
#
|
564
|
-
|
565
|
-
def self.write_to_file(file_name, key, rsa)
|
566
|
-
raise(SymmetricEncryption::ConfigError, 'Missing mandatory config parameter :private_rsa_key when filename key is used') unless rsa
|
606
|
+
# Write to the supplied filename, backing up the existing file if present
|
607
|
+
def self.write_to_file(file_name, data)
|
567
608
|
File.rename(file_name, "#{file_name}.#{Time.now.to_i}") if File.exist?(file_name)
|
568
|
-
File.open(file_name, 'wb') { |file| file.write(
|
569
|
-
end
|
570
|
-
|
571
|
-
# Read the encrypted key from file
|
572
|
-
def decrypt_key(encrypted_key, rsa)
|
573
|
-
raise(SymmetricEncryption::ConfigError, 'Missing mandatory config parameter :private_rsa_key when encrypted key is supplied') unless rsa
|
574
|
-
|
575
|
-
# Decode value first using encoding specified
|
576
|
-
encrypted_key = ::Base64.decode64(encrypted_key)
|
577
|
-
if !encrypted_key || encrypted_key.empty?
|
578
|
-
puts "\nSymmetric Encryption encrypted_key not found."
|
579
|
-
puts "To generate the keys for the first time run: rails generate symmetric_encryption:new_keys\n\n"
|
580
|
-
else
|
581
|
-
rsa.private_decrypt(encrypted_key)
|
582
|
-
end
|
583
|
-
end
|
584
|
-
|
585
|
-
# Returns [String] encrypted form of supplied key
|
586
|
-
def encrypt_key(key, rsa)
|
587
|
-
raise(SymmetricEncryption::ConfigError, 'Missing mandatory config parameter :private_rsa_key when encrypted key is supplied') unless rsa
|
588
|
-
::Base64.encode64(rsa.public_encrypt(key))
|
609
|
+
File.open(file_name, 'wb') { |file| file.write(data) }
|
589
610
|
end
|
590
611
|
|
591
612
|
end
|