symmetric-encryption 3.8.3 → 3.9.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 +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
|