symmetric-encryption 4.2.1 → 4.4.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 +5 -7
- data/Rakefile +9 -9
- data/bin/symmetric-encryption +1 -1
- data/lib/symmetric-encryption.rb +1 -1
- data/lib/symmetric_encryption/{railties → active_record}/attr_encrypted.rb +16 -5
- data/lib/symmetric_encryption/active_record/encrypted_attribute.rb +37 -0
- data/lib/symmetric_encryption/cipher.rb +20 -14
- data/lib/symmetric_encryption/cli.rb +72 -54
- data/lib/symmetric_encryption/coerce.rb +3 -3
- data/lib/symmetric_encryption/config.rb +28 -27
- data/lib/symmetric_encryption/core.rb +25 -20
- data/lib/symmetric_encryption/encoder.rb +26 -8
- data/lib/symmetric_encryption/generator.rb +7 -3
- data/lib/symmetric_encryption/header.rb +24 -24
- data/lib/symmetric_encryption/key.rb +1 -1
- data/lib/symmetric_encryption/keystore/aws.rb +10 -13
- data/lib/symmetric_encryption/keystore/environment.rb +5 -5
- data/lib/symmetric_encryption/keystore/file.rb +27 -9
- data/lib/symmetric_encryption/keystore/gcp.rb +21 -18
- data/lib/symmetric_encryption/keystore/heroku.rb +1 -1
- data/lib/symmetric_encryption/keystore/memory.rb +3 -3
- data/lib/symmetric_encryption/keystore.rb +23 -23
- data/lib/symmetric_encryption/railtie.rb +12 -11
- data/lib/symmetric_encryption/railties/mongoid_encrypted.rb +5 -4
- data/lib/symmetric_encryption/railties/symmetric_encryption_validator.rb +1 -1
- data/lib/symmetric_encryption/reader.rb +13 -13
- data/lib/symmetric_encryption/rsa_key.rb +1 -1
- data/lib/symmetric_encryption/symmetric_encryption.rb +56 -36
- data/lib/symmetric_encryption/utils/aws.rb +8 -10
- data/lib/symmetric_encryption/utils/files.rb +3 -3
- data/lib/symmetric_encryption/utils/re_encrypt_files.rb +11 -11
- data/lib/symmetric_encryption/version.rb +1 -1
- data/lib/symmetric_encryption/writer.rb +20 -13
- data/lib/symmetric_encryption.rb +13 -9
- metadata +10 -10
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 17ec7e95cd640a1bc8b960bff9244557e3dcd58bb58744b054e4bb7ef95a051a
|
|
4
|
+
data.tar.gz: 36230ce36bf337f98d5cf70e45c5ed1658faeed8ce650cd9b4b7d12354a477df
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4d880e284b3aa211e2a4bdeb872ff294d8c8743eb033edcafd6ec7ee569da3390b12821e555b1efe98503b2e4c4c05d0380f5da6d09577dfcd57badc12c0bce2
|
|
7
|
+
data.tar.gz: 36453ff31c896a7b7359b66cd53d3777f71b6855d53d8f002a77d7af91e3fe21c1a346869c0414aecbe8cc92c7e93dd73701edaa751072df6dcdd9459dd74752
|
data/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# Symmetric Encryption
|
|
2
|
-
 ](https://rubygems.org/gems/symmetric-encryption) [](https://github.com/reidmorrison/symmetric-encryption/actions?query=workflow%3Abuild) [](https://rubygems.org/gems/symmetric-encryption) [](http://opensource.org/licenses/Apache-2.0) 
|
|
3
3
|
|
|
4
|
-
*
|
|
4
|
+
* https://encryption.rocketjob.io/
|
|
5
5
|
|
|
6
|
-
Transparently encrypt ActiveRecord,
|
|
6
|
+
Transparently encrypt ActiveRecord, and Mongoid attributes. Encrypt passwords in configuration files. Encrypt entire files at rest.
|
|
7
7
|
|
|
8
8
|
## Introduction
|
|
9
9
|
|
|
@@ -19,9 +19,7 @@ expose all the encryption algorithms supported by OpenSSL.
|
|
|
19
19
|
|
|
20
20
|
## Documentation
|
|
21
21
|
|
|
22
|
-
[Symmetric Encryption Guide](
|
|
23
|
-
|
|
24
|
-
[Reference Documentation](http://www.rubydoc.info/gems/symmetric-encryption/)
|
|
22
|
+
[Symmetric Encryption Guide](https://encryption.rocketjob.io/)
|
|
25
23
|
|
|
26
24
|
## Rocket Job
|
|
27
25
|
|
|
@@ -168,7 +166,7 @@ may have backward compatibility issues:
|
|
|
168
166
|
|
|
169
167
|
[Reid Morrison](https://github.com/reidmorrison)
|
|
170
168
|
|
|
171
|
-
[Contributors](https://github.com/
|
|
169
|
+
[Contributors](https://github.com/reidmorrison/symmetric-encryption/graphs/contributors)
|
|
172
170
|
|
|
173
171
|
## Versioning
|
|
174
172
|
|
data/Rakefile
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
# Setup bundler to avoid having to run bundle exec all the time.
|
|
2
|
-
require
|
|
3
|
-
require
|
|
2
|
+
require "rubygems"
|
|
3
|
+
require "bundler/setup"
|
|
4
4
|
|
|
5
|
-
require
|
|
6
|
-
require_relative
|
|
5
|
+
require "rake/testtask"
|
|
6
|
+
require_relative "lib/symmetric_encryption/version"
|
|
7
7
|
|
|
8
8
|
task :gem do
|
|
9
|
-
system
|
|
9
|
+
system "gem build symmetric-encryption.gemspec"
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
task publish: :gem do
|
|
13
13
|
system "git tag -a v#{SymmetricEncryption::VERSION} -m 'Tagging #{SymmetricEncryption::VERSION}'"
|
|
14
|
-
system
|
|
14
|
+
system "git push --tags"
|
|
15
15
|
system "gem push symmetric-encryption-#{SymmetricEncryption::VERSION}.gem"
|
|
16
16
|
system "rm symmetric-encryption-#{SymmetricEncryption::VERSION}.gem"
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
Rake::TestTask.new(:test) do |t|
|
|
20
|
-
t.pattern =
|
|
20
|
+
t.pattern = "test/**/*_test.rb"
|
|
21
21
|
t.verbose = true
|
|
22
22
|
t.warning = false
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
# By default run tests against all appraisals
|
|
26
|
-
if !ENV[
|
|
27
|
-
require
|
|
26
|
+
if !ENV["APPRAISAL_INITIALIZED"] && !ENV["TRAVIS"]
|
|
27
|
+
require "appraisal"
|
|
28
28
|
task default: :appraisal
|
|
29
29
|
else
|
|
30
30
|
task default: :test
|
data/bin/symmetric-encryption
CHANGED
data/lib/symmetric-encryption.rb
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "symmetric_encryption"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
module SymmetricEncryption
|
|
2
|
-
module
|
|
2
|
+
module ActiveRecord
|
|
3
3
|
module AttrEncrypted
|
|
4
4
|
def self.included(base)
|
|
5
5
|
base.extend ClassMethods
|
|
@@ -39,7 +39,7 @@ module SymmetricEncryption
|
|
|
39
39
|
# compression
|
|
40
40
|
# Note: Adds a 6 byte header prior to encoding, only if :random_iv is false
|
|
41
41
|
# Default: false
|
|
42
|
-
def attr_encrypted(*
|
|
42
|
+
def attr_encrypted(*attributes, random_iv: nil, type: :string, compress: false)
|
|
43
43
|
# Ensure ActiveRecord has created all its methods first
|
|
44
44
|
# Ignore failures since the table may not yet actually exist
|
|
45
45
|
begin
|
|
@@ -48,10 +48,21 @@ module SymmetricEncryption
|
|
|
48
48
|
nil
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
random_iv = true if random_iv.nil? && SymmetricEncryption.randomize_iv?
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
if random_iv.nil?
|
|
54
|
+
warn("attr_encrypted() no longer allows a default value for option `random_iv`. Add `random_iv: false` if it is required.")
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
attributes.each do |attribute|
|
|
58
|
+
SymmetricEncryption::Generator.generate_decrypted_accessors(
|
|
59
|
+
self,
|
|
60
|
+
attribute,
|
|
61
|
+
"encrypted_#{attribute}",
|
|
62
|
+
random_iv: random_iv,
|
|
63
|
+
type: type,
|
|
64
|
+
compress: compress
|
|
65
|
+
)
|
|
55
66
|
encrypted_attributes[attribute.to_sym] = "encrypted_#{attribute}".to_sym
|
|
56
67
|
end
|
|
57
68
|
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module SymmetricEncryption
|
|
2
|
+
module ActiveRecord
|
|
3
|
+
class EncryptedAttribute < ::ActiveModel::Type::String
|
|
4
|
+
def initialize(random_iv: true, compress: false, type: :string)
|
|
5
|
+
@random_iv = random_iv
|
|
6
|
+
@compress = compress
|
|
7
|
+
@encrypted_type = type
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def deserialize(value)
|
|
11
|
+
return if value.nil?
|
|
12
|
+
|
|
13
|
+
SymmetricEncryption.decrypt(value, type: encrypted_type)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def serialize(value)
|
|
17
|
+
return if value.nil?
|
|
18
|
+
|
|
19
|
+
SymmetricEncryption.encrypt(
|
|
20
|
+
value,
|
|
21
|
+
type: encrypted_type,
|
|
22
|
+
compress: compress,
|
|
23
|
+
random_iv: random_iv
|
|
24
|
+
)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
# Symmetric Encryption uses coercible gem to handle casting
|
|
30
|
+
def cast_value(value)
|
|
31
|
+
value
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
attr_reader :random_iv, :compress, :encrypted_type
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "openssl"
|
|
2
2
|
module SymmetricEncryption
|
|
3
3
|
# Hold all information related to encryption keys
|
|
4
4
|
# as well as encrypt and decrypt data using those keys.
|
|
@@ -12,7 +12,7 @@ module SymmetricEncryption
|
|
|
12
12
|
attr_writer :key
|
|
13
13
|
|
|
14
14
|
# Returns [Cipher] from a cipher config instance.
|
|
15
|
-
def self.from_config(cipher_name:
|
|
15
|
+
def self.from_config(cipher_name: "aes-256-cbc",
|
|
16
16
|
version: 0,
|
|
17
17
|
always_add_header: true,
|
|
18
18
|
encoding: :base64strict,
|
|
@@ -50,6 +50,8 @@ module SymmetricEncryption
|
|
|
50
50
|
# This is the recommended format since newlines in the values to
|
|
51
51
|
# SQL queries are cumbersome. Also the newline reformatting is unnecessary
|
|
52
52
|
# It is not the default for backward compatibility
|
|
53
|
+
# :base64urlsafe
|
|
54
|
+
# Same as base64strict except that base64urlsafe uses '-' instead of '+' and '_' instead of '/'.
|
|
53
55
|
# :base64
|
|
54
56
|
# Return as a base64 encoded string
|
|
55
57
|
# :base16
|
|
@@ -58,7 +60,7 @@ module SymmetricEncryption
|
|
|
58
60
|
# Return as raw binary data string. Note: String can contain embedded nulls
|
|
59
61
|
# Default: :base64strict
|
|
60
62
|
#
|
|
61
|
-
# version [
|
|
63
|
+
# version [Integer]
|
|
62
64
|
# Optional. The version number of this encryption key
|
|
63
65
|
# Used by SymmetricEncryption to select the correct key when decrypting data
|
|
64
66
|
# Valid Range: 0..255
|
|
@@ -72,7 +74,7 @@ module SymmetricEncryption
|
|
|
72
74
|
# Default: true
|
|
73
75
|
def initialize(key:,
|
|
74
76
|
iv: nil,
|
|
75
|
-
cipher_name:
|
|
77
|
+
cipher_name: "aes-256-cbc",
|
|
76
78
|
version: 0,
|
|
77
79
|
always_add_header: true,
|
|
78
80
|
encoding: :base64strict)
|
|
@@ -84,7 +86,9 @@ module SymmetricEncryption
|
|
|
84
86
|
@version = version.to_i
|
|
85
87
|
@always_add_header = always_add_header
|
|
86
88
|
|
|
87
|
-
|
|
89
|
+
return unless (@version > 255) || @version.negative?
|
|
90
|
+
|
|
91
|
+
raise(ArgumentError, "Cipher version has a valid range of 0 to 255. #{@version} is too high, or negative")
|
|
88
92
|
end
|
|
89
93
|
|
|
90
94
|
# Change the encoding
|
|
@@ -112,7 +116,7 @@ module SymmetricEncryption
|
|
|
112
116
|
# to convert it to a string
|
|
113
117
|
#
|
|
114
118
|
# random_iv [true|false]
|
|
115
|
-
# Whether the
|
|
119
|
+
# Whether the encrypted value should use a random IV every time the
|
|
116
120
|
# field is encrypted.
|
|
117
121
|
# Notes:
|
|
118
122
|
# * Setting random_iv to true will result in a different encrypted output for
|
|
@@ -131,7 +135,7 @@ module SymmetricEncryption
|
|
|
131
135
|
# * Should only be used for large strings since compression overhead and
|
|
132
136
|
# the overhead of adding the encryption header may exceed any benefits of
|
|
133
137
|
# compression
|
|
134
|
-
def encrypt(str, random_iv:
|
|
138
|
+
def encrypt(str, random_iv: SymmetricEncryption.randomize_iv?, compress: false, header: always_add_header)
|
|
135
139
|
return if str.nil?
|
|
136
140
|
|
|
137
141
|
str = str.to_s
|
|
@@ -167,7 +171,9 @@ module SymmetricEncryption
|
|
|
167
171
|
decrypted = binary_decrypt(decoded)
|
|
168
172
|
|
|
169
173
|
# Try to force result to UTF-8 encoding, but if it is not valid, force it back to Binary
|
|
170
|
-
|
|
174
|
+
unless decrypted.force_encoding(SymmetricEncryption::UTF8_ENCODING).valid_encoding?
|
|
175
|
+
decrypted.force_encoding(SymmetricEncryption::BINARY_ENCODING)
|
|
176
|
+
end
|
|
171
177
|
|
|
172
178
|
decrypted
|
|
173
179
|
end
|
|
@@ -180,7 +186,7 @@ module SymmetricEncryption
|
|
|
180
186
|
#
|
|
181
187
|
# Returned string is UTF8 encoded except for encoding :none
|
|
182
188
|
def encode(binary_string)
|
|
183
|
-
return binary_string if binary_string.nil? || (binary_string ==
|
|
189
|
+
return binary_string if binary_string.nil? || (binary_string == "")
|
|
184
190
|
|
|
185
191
|
encoder.encode(binary_string)
|
|
186
192
|
end
|
|
@@ -190,7 +196,7 @@ module SymmetricEncryption
|
|
|
190
196
|
#
|
|
191
197
|
# Returned string is Binary encoded
|
|
192
198
|
def decode(encoded_string)
|
|
193
|
-
return encoded_string if encoded_string.nil? || (encoded_string ==
|
|
199
|
+
return encoded_string if encoded_string.nil? || (encoded_string == "")
|
|
194
200
|
|
|
195
201
|
encoder.decode(encoded_string)
|
|
196
202
|
end
|
|
@@ -246,7 +252,7 @@ module SymmetricEncryption
|
|
|
246
252
|
# Default: `always_add_header`
|
|
247
253
|
#
|
|
248
254
|
# See #encrypt to encrypt and encode the result as a string.
|
|
249
|
-
def binary_encrypt(str, random_iv:
|
|
255
|
+
def binary_encrypt(str, random_iv: SymmetricEncryption.randomize_iv?, compress: false, header: always_add_header)
|
|
250
256
|
return if str.nil?
|
|
251
257
|
|
|
252
258
|
string = str.to_s
|
|
@@ -316,8 +322,8 @@ module SymmetricEncryption
|
|
|
316
322
|
|
|
317
323
|
openssl_cipher = ::OpenSSL::Cipher.new(header.cipher_name || cipher_name)
|
|
318
324
|
openssl_cipher.decrypt
|
|
319
|
-
openssl_cipher.key
|
|
320
|
-
if (iv
|
|
325
|
+
openssl_cipher.key = header.key || @key
|
|
326
|
+
if (iv = header.iv || @iv)
|
|
321
327
|
openssl_cipher.iv = iv
|
|
322
328
|
end
|
|
323
329
|
result = openssl_cipher.update(data)
|
|
@@ -327,7 +333,7 @@ module SymmetricEncryption
|
|
|
327
333
|
|
|
328
334
|
# Returns the magic header after applying the encoding in this cipher
|
|
329
335
|
def encoded_magic_header
|
|
330
|
-
@encoded_magic_header ||= encoder.encode(SymmetricEncryption::Header::MAGIC_HEADER).delete(
|
|
336
|
+
@encoded_magic_header ||= encoder.encode(SymmetricEncryption::Header::MAGIC_HEADER).delete("=").strip
|
|
331
337
|
end
|
|
332
338
|
|
|
333
339
|
# Returns [String] object represented as a string, filtering out the key
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
require
|
|
2
|
-
require
|
|
1
|
+
require "optparse"
|
|
2
|
+
require "fileutils"
|
|
3
3
|
module SymmetricEncryption
|
|
4
4
|
class CLI
|
|
5
5
|
attr_reader :key_path, :app_name, :encrypt, :config_file_path,
|
|
@@ -16,11 +16,11 @@ module SymmetricEncryption
|
|
|
16
16
|
|
|
17
17
|
def initialize(argv)
|
|
18
18
|
@version = current_version
|
|
19
|
-
@environment = ENV[
|
|
20
|
-
@config_file_path = File.expand_path(ENV[
|
|
21
|
-
@app_name =
|
|
19
|
+
@environment = ENV["SYMMETRIC_ENCRYPTION_ENV"] || ENV["RACK_ENV"] || ENV["RAILS_ENV"] || "development"
|
|
20
|
+
@config_file_path = File.expand_path(ENV["SYMMETRIC_ENCRYPTION_CONFIG"] || "config/symmetric-encryption.yml")
|
|
21
|
+
@app_name = "symmetric-encryption"
|
|
22
22
|
@key_path = "#{ENV['HOME']}/.symmetric-encryption"
|
|
23
|
-
@cipher_name =
|
|
23
|
+
@cipher_name = "aes-256-cbc"
|
|
24
24
|
@rolling_deploy = false
|
|
25
25
|
@prompt = false
|
|
26
26
|
@show_version = false
|
|
@@ -34,7 +34,7 @@ module SymmetricEncryption
|
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
def run!
|
|
37
|
-
raise(ArgumentError,
|
|
37
|
+
raise(ArgumentError, "Cannot cleanup keys and rotate keys at the same time") if cleanup_keys && rotate_keys
|
|
38
38
|
|
|
39
39
|
if show_version
|
|
40
40
|
puts "Symmetric Encryption v#{VERSION}"
|
|
@@ -70,11 +70,11 @@ module SymmetricEncryption
|
|
|
70
70
|
end
|
|
71
71
|
|
|
72
72
|
def parser
|
|
73
|
-
@parser
|
|
73
|
+
@parser ||= OptionParser.new do |opts|
|
|
74
74
|
opts.banner = <<~BANNER
|
|
75
75
|
Symmetric Encryption v#{VERSION}
|
|
76
76
|
|
|
77
|
-
For more information, see: https://rocketjob.
|
|
77
|
+
For more information, see: https://encryption.rocketjob.io/
|
|
78
78
|
|
|
79
79
|
Note:
|
|
80
80
|
It is recommended to backup the current configuration file, or place it in version control before running
|
|
@@ -83,113 +83,129 @@ module SymmetricEncryption
|
|
|
83
83
|
symmetric-encryption [options]
|
|
84
84
|
BANNER
|
|
85
85
|
|
|
86
|
-
opts.on
|
|
86
|
+
opts.on "-e", "--encrypt [FILE_NAME]", "Encrypt a file, or read from stdin if no file name is supplied." do |file_name|
|
|
87
87
|
@encrypt = file_name || STDIN
|
|
88
88
|
end
|
|
89
89
|
|
|
90
|
-
opts.on
|
|
90
|
+
opts.on "-d", "--decrypt [FILE_NAME]", "Decrypt a file, or read from stdin if no file name is supplied." do |file_name|
|
|
91
91
|
@decrypt = file_name || STDIN
|
|
92
92
|
end
|
|
93
93
|
|
|
94
|
-
opts.on
|
|
94
|
+
opts.on "-o", "--output FILE_NAME",
|
|
95
|
+
"Write encrypted or decrypted file to this file, otherwise output goes to stdout." do |file_name|
|
|
95
96
|
@output_file_name = file_name
|
|
96
97
|
end
|
|
97
98
|
|
|
98
|
-
opts.on
|
|
99
|
+
opts.on "-P", "--prompt", "When encrypting or decrypting, prompt for a string encrypt or decrypt." do
|
|
99
100
|
@prompt = true
|
|
100
101
|
end
|
|
101
102
|
|
|
102
|
-
opts.on
|
|
103
|
+
opts.on "-z", "--compress", "Compress encrypted output file. [Default for encrypting files]" do
|
|
103
104
|
@compress = true
|
|
104
105
|
end
|
|
105
106
|
|
|
106
|
-
opts.on
|
|
107
|
+
opts.on "-Z", "--no-compress", "Does not compress the output file. [Default for encrypting strings]" do
|
|
107
108
|
@compress = false
|
|
108
109
|
end
|
|
109
110
|
|
|
110
|
-
opts.on
|
|
111
|
+
opts.on "-E", "--env ENVIRONMENT",
|
|
112
|
+
"Environment to use in the config file. Default: SYMMETRIC_ENCRYPTION_ENV || RACK_ENV || RAILS_ENV || 'development'" do |environment|
|
|
111
113
|
@environment = environment
|
|
112
114
|
end
|
|
113
115
|
|
|
114
|
-
opts.on
|
|
116
|
+
opts.on "-c", "--config CONFIG_FILE_PATH",
|
|
117
|
+
"File name & path to the Symmetric Encryption configuration file. Default: config/symmetric-encryption.yml or Env var: `SYMMETRIC_ENCRYPTION_CONFIG`" do |path|
|
|
115
118
|
@config_file_path = path
|
|
116
119
|
end
|
|
117
120
|
|
|
118
|
-
opts.on
|
|
121
|
+
opts.on "-m", "--migrate", "Migrate configuration file to new format." do
|
|
119
122
|
@migrate = true
|
|
120
123
|
end
|
|
121
124
|
|
|
122
|
-
opts.on
|
|
123
|
-
|
|
125
|
+
opts.on "-r", "--re-encrypt [PATTERN]",
|
|
126
|
+
'ReEncrypt all files matching the pattern. Default: "**/*.{yml,rb}"' do |pattern|
|
|
127
|
+
@re_encrypt = pattern || "**/*.{yml,rb}"
|
|
124
128
|
end
|
|
125
129
|
|
|
126
|
-
opts.on
|
|
130
|
+
opts.on "-n", "--new-password [SIZE]",
|
|
131
|
+
"Generate a new random password using only characters that are URL-safe base64. Default size is 22." do |size|
|
|
127
132
|
@random_password = (size || 22).to_i
|
|
128
133
|
end
|
|
129
134
|
|
|
130
|
-
opts.on
|
|
135
|
+
opts.on "-g", "--generate", "Generate a new configuration file and encryption keys for every environment." do |config|
|
|
131
136
|
@generate = config
|
|
132
137
|
end
|
|
133
138
|
|
|
134
|
-
opts.on
|
|
135
|
-
|
|
139
|
+
opts.on "-s", "--keystore heroku|environment|file|aws|gcp",
|
|
140
|
+
"Which keystore to use during generation or re-encryption." do |keystore|
|
|
141
|
+
@keystore = (keystore || "file").downcase.to_sym
|
|
136
142
|
end
|
|
137
143
|
|
|
138
|
-
opts.on
|
|
139
|
-
|
|
144
|
+
opts.on "-B", "--regions [us-east-1,us-east-2,us-west-1,us-west-2]",
|
|
145
|
+
"AWS KMS Regions to encrypt data key with." do |regions|
|
|
146
|
+
@regions = regions.to_s.split(",").collect(&:strip) if regions
|
|
140
147
|
end
|
|
141
148
|
|
|
142
|
-
opts.on
|
|
149
|
+
opts.on "-K", "--key-path KEY_PATH",
|
|
150
|
+
"Output path in which to write generated key files. Default: ~/.symmetric-encryption" do |path|
|
|
143
151
|
@key_path = path
|
|
144
152
|
end
|
|
145
153
|
|
|
146
|
-
opts.on
|
|
154
|
+
opts.on "-a", "--app-name NAME",
|
|
155
|
+
"Application name to use when generating a new configuration. Default: symmetric-encryption" do |name|
|
|
147
156
|
@app_name = name
|
|
148
157
|
end
|
|
149
158
|
|
|
150
|
-
opts.on
|
|
151
|
-
|
|
159
|
+
opts.on "-S", "--environments ENVIRONMENTS",
|
|
160
|
+
"Comma separated list of environments for which to generate the config file. Default: development,test,release,production" do |environments|
|
|
161
|
+
@environments = environments.split(",").collect(&:strip).collect(&:to_sym)
|
|
152
162
|
end
|
|
153
163
|
|
|
154
|
-
opts.on
|
|
164
|
+
opts.on "-C", "--cipher-name NAME",
|
|
165
|
+
"Name of the cipher to use when generating a new config file, or when rotating keys. Default: aes-256-cbc" do |name|
|
|
155
166
|
@cipher_name = name
|
|
156
167
|
end
|
|
157
168
|
|
|
158
|
-
opts.on
|
|
169
|
+
opts.on "-R", "--rotate-keys",
|
|
170
|
+
"Generates a new encryption key version, encryption key files, and updates the configuration file." do
|
|
159
171
|
@rotate_keys = true
|
|
160
172
|
end
|
|
161
173
|
|
|
162
|
-
opts.on
|
|
174
|
+
opts.on "-U", "--rotate-kek",
|
|
175
|
+
"Replace the existing key encrypting keys only, the data encryption key is not changed, and updates the configuration file." do
|
|
163
176
|
@rotate_kek = true
|
|
164
177
|
end
|
|
165
178
|
|
|
166
|
-
opts.on
|
|
179
|
+
opts.on "-D", "--rolling-deploy",
|
|
180
|
+
"During key rotation, support a rolling deploy by placing the new key second in the list so that it is not activated yet." do
|
|
167
181
|
@rolling_deploy = true
|
|
168
182
|
end
|
|
169
183
|
|
|
170
|
-
opts.on
|
|
184
|
+
opts.on "-A", "--activate-key", "Activates the key by moving the key with the highest version to the top." do
|
|
171
185
|
@activate_key = true
|
|
172
186
|
end
|
|
173
187
|
|
|
174
|
-
opts.on
|
|
188
|
+
opts.on "-X", "--cleanup-keys",
|
|
189
|
+
"Removes all encryption keys, except the one with the highest version from the configuration file." do
|
|
175
190
|
@cleanup_keys = true
|
|
176
191
|
end
|
|
177
192
|
|
|
178
|
-
opts.on
|
|
193
|
+
opts.on "-V", "--key-version NUMBER",
|
|
194
|
+
"Encryption key version to use when encrypting or re-encrypting. Default: (Current global version)." do |number|
|
|
179
195
|
@version = number.to_i
|
|
180
196
|
end
|
|
181
197
|
|
|
182
|
-
opts.on
|
|
198
|
+
opts.on "-L", "--ciphers", "List available OpenSSL ciphers." do
|
|
183
199
|
puts "OpenSSL v#{OpenSSL::VERSION}. Available Ciphers:"
|
|
184
200
|
puts OpenSSL::Cipher.ciphers.join("\n")
|
|
185
201
|
exit
|
|
186
202
|
end
|
|
187
203
|
|
|
188
|
-
opts.on
|
|
204
|
+
opts.on "-v", "--version", "Display Symmetric Encryption version." do
|
|
189
205
|
@show_version = true
|
|
190
206
|
end
|
|
191
207
|
|
|
192
|
-
opts.on(
|
|
208
|
+
opts.on("-h", "--help", "Prints this help.") do
|
|
193
209
|
puts opts
|
|
194
210
|
exit
|
|
195
211
|
end
|
|
@@ -212,7 +228,7 @@ module SymmetricEncryption
|
|
|
212
228
|
|
|
213
229
|
config_file_does_not_exist!
|
|
214
230
|
self.environments ||= %i[development test release production]
|
|
215
|
-
args
|
|
231
|
+
args = {
|
|
216
232
|
app_name: app_name,
|
|
217
233
|
environments: environments,
|
|
218
234
|
cipher_name: cipher_name
|
|
@@ -237,7 +253,8 @@ module SymmetricEncryption
|
|
|
237
253
|
end
|
|
238
254
|
|
|
239
255
|
config = Config.read_file(config_file_path)
|
|
240
|
-
SymmetricEncryption::Keystore.rotate_keys!(config, environments: environments || [], app_name: app_name,
|
|
256
|
+
SymmetricEncryption::Keystore.rotate_keys!(config, environments: environments || [], app_name: app_name,
|
|
257
|
+
rolling_deploy: rolling_deploy, keystore: keystore)
|
|
241
258
|
Config.write_file(config_file_path, config)
|
|
242
259
|
puts "Existing configuration file updated with new keys: #{config_file_path}"
|
|
243
260
|
end
|
|
@@ -255,7 +272,7 @@ module SymmetricEncryption
|
|
|
255
272
|
next if environments && !environments.include?(env.to_sym)
|
|
256
273
|
next unless ciphers = cfg[:ciphers]
|
|
257
274
|
|
|
258
|
-
highest
|
|
275
|
+
highest = ciphers.max_by { |i| i[:version] }
|
|
259
276
|
ciphers.clear
|
|
260
277
|
ciphers << highest
|
|
261
278
|
end
|
|
@@ -270,7 +287,7 @@ module SymmetricEncryption
|
|
|
270
287
|
next if environments && !environments.include?(env.to_sym)
|
|
271
288
|
next unless ciphers = cfg[:ciphers]
|
|
272
289
|
|
|
273
|
-
highest
|
|
290
|
+
highest = ciphers.max_by { |i| i[:version] }
|
|
274
291
|
ciphers.delete(highest)
|
|
275
292
|
ciphers.unshift(highest)
|
|
276
293
|
end
|
|
@@ -280,7 +297,8 @@ module SymmetricEncryption
|
|
|
280
297
|
end
|
|
281
298
|
|
|
282
299
|
def encrypt_file(input_file_name)
|
|
283
|
-
SymmetricEncryption::Writer.encrypt(source: input_file_name, target: output_file_name || STDOUT, compress: compress,
|
|
300
|
+
SymmetricEncryption::Writer.encrypt(source: input_file_name, target: output_file_name || STDOUT, compress: compress,
|
|
301
|
+
version: version)
|
|
284
302
|
end
|
|
285
303
|
|
|
286
304
|
def decrypt_file(input_file_name)
|
|
@@ -289,22 +307,22 @@ module SymmetricEncryption
|
|
|
289
307
|
|
|
290
308
|
def decrypt_string
|
|
291
309
|
begin
|
|
292
|
-
require
|
|
310
|
+
require "highline"
|
|
293
311
|
rescue LoadError
|
|
294
312
|
puts("\nPlease install gem highline before using the command line task to decrypt an entered string.\n gem install \"highline\"\n\n")
|
|
295
313
|
exit(-2)
|
|
296
314
|
end
|
|
297
315
|
|
|
298
|
-
encrypted = HighLine.new.ask(
|
|
316
|
+
encrypted = HighLine.new.ask("Enter the value to decrypt:")
|
|
299
317
|
text = SymmetricEncryption.cipher(version).decrypt(encrypted)
|
|
300
318
|
|
|
301
319
|
puts("\n\nEncrypted: #{encrypted}")
|
|
302
|
-
output_file_name ? File.open(output_file_name,
|
|
320
|
+
output_file_name ? File.open(output_file_name, "wb") { |f| f << text } : puts("Decrypted: #{text}\n\n")
|
|
303
321
|
end
|
|
304
322
|
|
|
305
323
|
def encrypt_string
|
|
306
324
|
begin
|
|
307
|
-
require
|
|
325
|
+
require "highline"
|
|
308
326
|
rescue LoadError
|
|
309
327
|
puts("\nPlease install gem highline before using the command line task to encrypt an entered string.\n gem install \"highline\"\n\n")
|
|
310
328
|
exit(-2)
|
|
@@ -313,14 +331,14 @@ module SymmetricEncryption
|
|
|
313
331
|
value2 = 0
|
|
314
332
|
|
|
315
333
|
while value1 != value2
|
|
316
|
-
value1 = HighLine.new.ask(
|
|
317
|
-
value2 = HighLine.new.ask(
|
|
334
|
+
value1 = HighLine.new.ask("Enter the value to encrypt:") { |q| q.echo = "*" }
|
|
335
|
+
value2 = HighLine.new.ask("Re-enter the value to encrypt:") { |q| q.echo = "*" }
|
|
318
336
|
|
|
319
|
-
puts(
|
|
337
|
+
puts("Values do not match, please try again") if value1 != value2
|
|
320
338
|
end
|
|
321
339
|
compress = false if compress.nil?
|
|
322
340
|
encrypted = SymmetricEncryption.cipher(version).encrypt(value1, compress: compress)
|
|
323
|
-
output_file_name ? File.open(output_file_name,
|
|
341
|
+
output_file_name ? File.open(output_file_name, "wb") { |f| f << encrypted } : puts("\n\nEncrypted: #{encrypted}\n\n")
|
|
324
342
|
end
|
|
325
343
|
|
|
326
344
|
def gen_random_password(size)
|
|
@@ -328,7 +346,7 @@ module SymmetricEncryption
|
|
|
328
346
|
puts("\nGenerated Password: #{p}")
|
|
329
347
|
encrypted = SymmetricEncryption.encrypt(p)
|
|
330
348
|
puts("Encrypted: #{encrypted}\n\n")
|
|
331
|
-
File.open(output_file_name,
|
|
349
|
+
File.open(output_file_name, "wb") { |f| f << encrypted } if output_file_name
|
|
332
350
|
end
|
|
333
351
|
|
|
334
352
|
def current_version
|
|
@@ -14,7 +14,7 @@ module SymmetricEncryption
|
|
|
14
14
|
# Coerce given value into given type
|
|
15
15
|
# Does not coerce json or yaml values
|
|
16
16
|
def self.coerce(value, type, from_type = nil)
|
|
17
|
-
return value if value.nil? || (value ==
|
|
17
|
+
return value if value.nil? || (value == "")
|
|
18
18
|
|
|
19
19
|
from_type ||= value.class
|
|
20
20
|
case type
|
|
@@ -32,7 +32,7 @@ module SymmetricEncryption
|
|
|
32
32
|
# Note: if the type is :string, then the value is returned as is, and the
|
|
33
33
|
# coercible gem is not used at all.
|
|
34
34
|
def self.coerce_from_string(value, type)
|
|
35
|
-
return value if value.nil? || (value ==
|
|
35
|
+
return value if value.nil? || (value == "")
|
|
36
36
|
|
|
37
37
|
case type
|
|
38
38
|
when :string
|
|
@@ -50,7 +50,7 @@ module SymmetricEncryption
|
|
|
50
50
|
# Note: if the type is :string, and value is not nil, then #to_s is called
|
|
51
51
|
# on the value and the coercible gem is not used at all.
|
|
52
52
|
def self.coerce_to_string(value, type)
|
|
53
|
-
return value if value.nil? || (value ==
|
|
53
|
+
return value if value.nil? || (value == "")
|
|
54
54
|
|
|
55
55
|
case type
|
|
56
56
|
when :string
|