kms-tools 0.0.1
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 +7 -0
- data/.gitignore +7 -0
- data/.octopolo.yml +4 -0
- data/.soyuz.yml +13 -0
- data/.travis.yml +11 -0
- data/CHANGELOG.markdown +7 -0
- data/Gemfile +2 -0
- data/README.md +85 -0
- data/Rakefile +14 -0
- data/bin/kms-tools +44 -0
- data/kms-tools.gemspec +29 -0
- data/lib/kms-cli.rb +2 -0
- data/lib/kms-tools.rb +5 -0
- data/lib/kms-tools/base.rb +88 -0
- data/lib/kms-tools/cli/commands/decrypt.rb +15 -0
- data/lib/kms-tools/cli/commands/encrypt.rb +16 -0
- data/lib/kms-tools/cli/commands/list_aliases.rb +13 -0
- data/lib/kms-tools/cli/decrypt.rb +55 -0
- data/lib/kms-tools/cli/encrypt.rb +62 -0
- data/lib/kms-tools/cli/helpers.rb +30 -0
- data/lib/kms-tools/cli/output.rb +61 -0
- data/lib/kms-tools/decrypter.rb +82 -0
- data/lib/kms-tools/encrypted_file.rb +184 -0
- data/lib/kms-tools/encrypter.rb +96 -0
- data/lib/kms-tools/version.rb +3 -0
- data/spec/kms-tools/aws_mocks.rb +37 -0
- data/spec/kms-tools/base_spec.rb +83 -0
- data/spec/kms-tools/decrypter_spec.rb +95 -0
- data/spec/kms-tools/encrypted_file_spec.rb +14 -0
- data/spec/kms-tools/encrypter_spec.rb +91 -0
- data/spec/kms-tools/test_data.rb +11 -0
- data/spec/spec_helper.rb +26 -0
- metadata +202 -0
@@ -0,0 +1,62 @@
|
|
1
|
+
module KmsTools
|
2
|
+
# Namespace for CLI specfic classes in kms-tools
|
3
|
+
module CLI
|
4
|
+
# Class for handling encrypt operations from the CLI
|
5
|
+
class Encrypt
|
6
|
+
# Set up encryption handler
|
7
|
+
#
|
8
|
+
# @param [Hash] global_options
|
9
|
+
# @param [Hash] options
|
10
|
+
# @option global_options [String] :master_key Master key to use if provided by CLI options
|
11
|
+
# @option global_options [String] :profile AWS credential profile to us if provided by CLI options
|
12
|
+
# @option global_options [String] :region AWS region to use if provided by CLI options
|
13
|
+
# @option options [String] :data_key Existing data key to use if provided by CLI options
|
14
|
+
def initialize(global_options, options)
|
15
|
+
@enc = KmsTools::Encrypter.new(global_options)
|
16
|
+
@output = options[:output]
|
17
|
+
abort "You must specify a key alias as a flag when encrypting stdin!" unless STDIN.tty? || global_options[:k]
|
18
|
+
@enc.use_key_alias = Helpers.select_key(@enc) if @enc.master_key.nil?
|
19
|
+
end
|
20
|
+
|
21
|
+
# Handle encrypt command
|
22
|
+
#
|
23
|
+
# @param [String] source Plaintext source to encrypt. Can be a string for direct encryption or a path to a file to encrypt
|
24
|
+
# @return [String] Returns Base64 encoded ciphertext if a string is provided
|
25
|
+
# @return [String] Returns path to encrypted file if a source path is provided
|
26
|
+
def encrypt(source)
|
27
|
+
if File.file?(source)
|
28
|
+
save_path = encrypt_file(source)
|
29
|
+
Output.say("Encrypted file saved to: #{save_path}")
|
30
|
+
elsif source.is_a?(String)
|
31
|
+
encrypted_response = @enc.encrypt_string(source)
|
32
|
+
if STDIN.tty?
|
33
|
+
Output.say("Encrypted ciphertext (copy all text without surrounding whitespace):\n\n#{encrypted_response}\n\n")
|
34
|
+
else
|
35
|
+
print encrypted_response
|
36
|
+
end
|
37
|
+
else
|
38
|
+
raise "Unknown input to encrypt..."
|
39
|
+
end
|
40
|
+
|
41
|
+
# clear source from memory for good measure
|
42
|
+
source = nil
|
43
|
+
end
|
44
|
+
|
45
|
+
# Encrypt a file from source path
|
46
|
+
#
|
47
|
+
# @param [String] source path to file to encrypt
|
48
|
+
# @return [String] path to encrypted file
|
49
|
+
def encrypt_file(source)
|
50
|
+
ef = KmsTools::EncryptedFile.new(encrypter: @enc)
|
51
|
+
ef.create_from_file(source)
|
52
|
+
save_path = Helpers::get_save_path({
|
53
|
+
:prompt => "Save encrytped file to",
|
54
|
+
:suggested_path => File.absolute_path(source.sub File.extname(source), ".kms")
|
55
|
+
})
|
56
|
+
ef.save_encrypted(save_path)
|
57
|
+
save_path
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module KmsTools
|
2
|
+
module CLI
|
3
|
+
# General purpose helper functions for the CLI
|
4
|
+
class Helpers
|
5
|
+
|
6
|
+
# Prompts the user to select a key alias from a list of key aliases available to current credentials
|
7
|
+
#
|
8
|
+
# @param [Object] kms KMS client object
|
9
|
+
# @return [String] key alias
|
10
|
+
def self.select_key(kms)
|
11
|
+
Output.select_from_list("Choose which key alias to use as the base Customer Master Key:", kms.available_aliases)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Prompts the user for a path to save a file. Optionally providers a default suggestion.
|
15
|
+
#
|
16
|
+
# @param [Hash] params
|
17
|
+
# @option params [String] :prompt Prompt text to display
|
18
|
+
# @option params [String] :suggested_path Optional path to suggest to user and use a default if no additional input is given
|
19
|
+
# @return [String] path
|
20
|
+
def self.get_save_path(params)
|
21
|
+
prompt = params[:prompt].nil? ? "Save to" : params[:prompt]
|
22
|
+
prompt << " (#{params[:suggested_path]})" if params[:suggested_path]
|
23
|
+
prompt << ": "
|
24
|
+
entered_path = KmsTools::CLI::Output.ask(prompt, String)
|
25
|
+
entered_path.empty? ? params[:suggested_path] : entered_path
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'highline'
|
2
|
+
|
3
|
+
module KmsTools
|
4
|
+
module CLI
|
5
|
+
# Helper functions for terminal interaction
|
6
|
+
module Output
|
7
|
+
def self.terminal
|
8
|
+
HighLine.color_scheme = color_scheme
|
9
|
+
@@terminal ||= HighLine.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.color_scheme
|
13
|
+
@@color_scheme ||= HighLine::ColorScheme.new(
|
14
|
+
:normal => [],
|
15
|
+
:error => [:bold, :red],
|
16
|
+
:warning => [:bold, :yellow],
|
17
|
+
:verbose => [:bold, :magenta],
|
18
|
+
:debug => [:bold, :cyan],
|
19
|
+
:success => [:bold, :green],
|
20
|
+
:addition => [:bold, :green],
|
21
|
+
:removal => [:bold, :red],
|
22
|
+
:modification => [:bold, :yellow],
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.say(msg, log_style=:normal)
|
27
|
+
terminal.say format(msg, log_style)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.format(msg, log_style=:normal)
|
31
|
+
if $color
|
32
|
+
terminal.color(msg.to_s, log_style)
|
33
|
+
else
|
34
|
+
msg
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.say_verbose(msg)
|
39
|
+
terminal.say format(msg.to_s, 'verbose') if $verbose
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.say_debug(msg, log_style=:debug)
|
43
|
+
terminal.say format(msg.to_s, log_style) if $debug
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.ask(*args, &block)
|
47
|
+
terminal.ask(*args, &block)
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.select_from_list(prompt, options)
|
51
|
+
puts prompt
|
52
|
+
options.each_with_index do |key, index|
|
53
|
+
puts "#{index+1}. #{key}"
|
54
|
+
end
|
55
|
+
choice = Output.ask("? ", Integer) { |q| q.in = 1..options.length }
|
56
|
+
options[choice-1]
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module KmsTools
|
2
|
+
# Provides low-level decryption functionality for kms-tools
|
3
|
+
#
|
4
|
+
# @author Matt Kriegers
|
5
|
+
class Decrypter < KmsTools::Base
|
6
|
+
|
7
|
+
# Decrypt base64 encoded ciphertext that was encrypted directly with a customer master key
|
8
|
+
# @param str [String] Base64 encoded ciphertext
|
9
|
+
# @return [String] Binary plaintext
|
10
|
+
def decrypt_string(str)
|
11
|
+
kms.decrypt({:ciphertext_blob => from_64(str)}).plaintext
|
12
|
+
end
|
13
|
+
|
14
|
+
# Decrypt a blob using private keys
|
15
|
+
#
|
16
|
+
# @param [Hash] params
|
17
|
+
# @option params [String] :cipher OpenSSL cipher used for encryption
|
18
|
+
# @option params [String] :encrypted_key Encrypted private key
|
19
|
+
# @option params [String] :encrypted_iv Encrypted initialization vector
|
20
|
+
# @option params [String] :encrypted_data Ciphertext data blob
|
21
|
+
# @return [String] Binary plaintext
|
22
|
+
def decrypt_with_data_key(params)
|
23
|
+
cipher = OpenSSL::Cipher.new(params[:cipher])
|
24
|
+
cipher.decrypt
|
25
|
+
cipher.key = decrypt_string(params[:encrypted_key])
|
26
|
+
cipher.iv = decrypt_string(params[:encrypted_iv])
|
27
|
+
decrypted_data = cipher.update(params[:encrypted_data]) + cipher.final
|
28
|
+
|
29
|
+
raise "File integrity check failed!" unless integrity_verified?(decrypted_data, params[:checksum])
|
30
|
+
|
31
|
+
decrypted_data
|
32
|
+
end
|
33
|
+
|
34
|
+
# Decrypt a stream using private keys
|
35
|
+
#
|
36
|
+
# @param [Hash] params
|
37
|
+
# @option params [String] :cipher OpenSSL cipher used for encryption
|
38
|
+
# @option params [String] :encrypted_key Encrypted private key
|
39
|
+
# @option params [String] :encrypted_iv Encrypted initialization vector
|
40
|
+
# @option params [Stream] :in Input stream to read ciphertext data from
|
41
|
+
# @option params [Integer] :position Optional file position marking beginning of ciphertext
|
42
|
+
# @option params [Stream] :out Stream to to write plaintext output to
|
43
|
+
# @option params [String] :checksum Optional SHA1 checksum to verify integrity of decrypted data
|
44
|
+
def stream_decrypt_with_data_key(params)
|
45
|
+
# set up cipher
|
46
|
+
cipher = OpenSSL::Cipher.new(params[:cipher])
|
47
|
+
cipher.decrypt
|
48
|
+
cipher.key = decrypt_string(params[:encrypted_key])
|
49
|
+
cipher.iv = decrypt_string(params[:encrypted_iv])
|
50
|
+
|
51
|
+
sha1 = Digest::SHA1.new if params[:checksum]
|
52
|
+
|
53
|
+
# write the output stream
|
54
|
+
chunk = ""
|
55
|
+
params[:in].seek(params[:position], IO::SEEK_SET) if params[:position]
|
56
|
+
while params[:in].read(STREAM_CHUNK_SIZE, chunk)
|
57
|
+
decrypted_chunk = cipher.update(chunk)
|
58
|
+
sha1.update(decrypted_chunk) if params[:checksum]
|
59
|
+
params[:out] << decrypted_chunk
|
60
|
+
end
|
61
|
+
|
62
|
+
final = cipher.final
|
63
|
+
sha1.update(final) if params[:checksum]
|
64
|
+
|
65
|
+
if params[:checksum]
|
66
|
+
raise "Decrypted data stream failed checksum verification!" unless params[:checksum].eql? sha1.hexdigest
|
67
|
+
end
|
68
|
+
|
69
|
+
params[:out] << final
|
70
|
+
true
|
71
|
+
end
|
72
|
+
|
73
|
+
# Verify data blob against known hash
|
74
|
+
#
|
75
|
+
# @param [String] data Data to verify
|
76
|
+
# @param [String] checksum Known SHA1 hash
|
77
|
+
def integrity_verified?(data, checksum)
|
78
|
+
Digest::SHA1.hexdigest(data).eql? checksum
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,184 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'digest'
|
3
|
+
|
4
|
+
module KmsTools
|
5
|
+
# Interacts with files and streams for encryption and decryption of large blobs of data
|
6
|
+
#
|
7
|
+
# @author Matt Krieger
|
8
|
+
class EncryptedFile
|
9
|
+
# Number of bytes allocated at the beginning of a KMS file noting metadata size. 7 bytes limits metadata to 9.9 MB, which is way too much. Don't use that much.
|
10
|
+
META_SIZE_HEADER_LENGTH = 7
|
11
|
+
|
12
|
+
# Default cipher for local encryption
|
13
|
+
DEFAULT_CIPHER = 'aes-256-cbc'
|
14
|
+
|
15
|
+
# Minimum required metadata elements for a KMS file to be valid
|
16
|
+
KMS_REQUIRED_ELEMENTS = %i(encrypted_key encrypted_iv cipher original_extension checksum)
|
17
|
+
|
18
|
+
# Creats an EncryptedFile object.
|
19
|
+
#
|
20
|
+
# @param [Hash] options
|
21
|
+
# @option options [Object] :encrypter existing (Encrypter) object with options set
|
22
|
+
# @option options [String] :path Path to an encrypted file to load on initialization
|
23
|
+
def initialize(options = {})
|
24
|
+
@enc = options[:encrypter] || KmsTools::Encrypter.new
|
25
|
+
@dec = KmsTools::Decrypter.new
|
26
|
+
@kms_meta = {}
|
27
|
+
|
28
|
+
if options[:path]
|
29
|
+
if File.readable?(options[:path])
|
30
|
+
load_encrypted_file(options[:path])
|
31
|
+
else
|
32
|
+
raise "#{options[:path]} is not a readable!"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Generate metadata from a plaintext file and prepare for encryption
|
38
|
+
#
|
39
|
+
# @param [String] path Path to plaintext file
|
40
|
+
# @return [Hash] KMS file metadata
|
41
|
+
def create_from_file(path)
|
42
|
+
@decrypted_source = path
|
43
|
+
@kms_meta[:arn] = @enc.master_key_arn
|
44
|
+
@kms_meta[:checksum] = file_sha(path)
|
45
|
+
@kms_meta[:original_extension] = File.extname(path)
|
46
|
+
set_up_encryption_params
|
47
|
+
@kms_meta
|
48
|
+
end
|
49
|
+
|
50
|
+
# Read a KMS encrypted file and populate object metadata from file headers
|
51
|
+
#
|
52
|
+
# @param [String] path Path to encrypted file
|
53
|
+
# @return [Hash] KMS file metadata
|
54
|
+
def load_encrypted_file(path)
|
55
|
+
meta_size = IO.binread(path, META_SIZE_HEADER_LENGTH).to_i
|
56
|
+
kms_yaml = YAML::load(IO.binread(path, meta_size, META_SIZE_HEADER_LENGTH))
|
57
|
+
if is_valid_kms_file?(kms_yaml)
|
58
|
+
@kms_meta = kms_yaml
|
59
|
+
@encrypted_file_path = path
|
60
|
+
@encrypted_data_start = META_SIZE_HEADER_LENGTH + meta_size
|
61
|
+
else
|
62
|
+
raise "#{path} is not a valid KMS file!"
|
63
|
+
end
|
64
|
+
@kms_meta
|
65
|
+
end
|
66
|
+
|
67
|
+
# Get the encrypted key of the current file, generate a new one if not present
|
68
|
+
#
|
69
|
+
# @return [string] Base64 encoded encrypted data key
|
70
|
+
def encrypted_key
|
71
|
+
@kms_meta[:encrypted_key] ||= @enc.new_encrypted_key
|
72
|
+
end
|
73
|
+
|
74
|
+
# Get the encrypted initialization vector of the current file, generate a new one if not present
|
75
|
+
#
|
76
|
+
# @return [string] Base64 encoded encrypted data key
|
77
|
+
def encrypted_iv
|
78
|
+
@kms_meta[:encrypted_iv] ||= @enc.new_encrypted_key
|
79
|
+
end
|
80
|
+
|
81
|
+
# Get the original extension of the encrypted file
|
82
|
+
#
|
83
|
+
# @return [string] file extension
|
84
|
+
def original_extension
|
85
|
+
@kms_meta[:original_extension]
|
86
|
+
end
|
87
|
+
|
88
|
+
def encrypted_data
|
89
|
+
@kms_meta[:encrypted_data]
|
90
|
+
end
|
91
|
+
|
92
|
+
# Get the cipher used for the encrypted file or set the default
|
93
|
+
#
|
94
|
+
# @return [string] OpenSSL cipher
|
95
|
+
def cipher
|
96
|
+
@kms_meta[:cipher] ||= DEFAULT_CIPHER
|
97
|
+
end
|
98
|
+
|
99
|
+
# Get the SHA1 checksum of the decrypted data
|
100
|
+
#
|
101
|
+
# @return [string] hex encoded SHA1 checksum
|
102
|
+
def checksum
|
103
|
+
@kms_meta[:checksum]
|
104
|
+
end
|
105
|
+
|
106
|
+
# Generate encryption key, iv, and cipher if they do not exist
|
107
|
+
# @return [nil]
|
108
|
+
def set_up_encryption_params
|
109
|
+
encrypted_key
|
110
|
+
encrypted_iv
|
111
|
+
cipher
|
112
|
+
return nil
|
113
|
+
end
|
114
|
+
|
115
|
+
# Save encrypted data with KMS headers to the provided path
|
116
|
+
#
|
117
|
+
# @param [String] path Path to save encrypted file
|
118
|
+
# @return [Boolean] returns true on success
|
119
|
+
def save_encrypted(path)
|
120
|
+
kms_yaml = @kms_meta.to_yaml
|
121
|
+
meta_size = kms_yaml.bytesize.to_s.rjust(META_SIZE_HEADER_LENGTH, "0")
|
122
|
+
infile = File.open(@decrypted_source, 'rb')
|
123
|
+
outfile = File.open(path, 'wb+')
|
124
|
+
outfile << meta_size
|
125
|
+
outfile << kms_yaml
|
126
|
+
@enc.stream_encrypt_with_data_key({
|
127
|
+
in: infile,
|
128
|
+
out: outfile,
|
129
|
+
encrypted_iv: encrypted_iv,
|
130
|
+
encrypted_key: encrypted_key,
|
131
|
+
cipher: cipher
|
132
|
+
})
|
133
|
+
|
134
|
+
outfile.close
|
135
|
+
true
|
136
|
+
end
|
137
|
+
|
138
|
+
# Save decrypted data to the provided path
|
139
|
+
#
|
140
|
+
# @param [String] path Path to save decrypted file
|
141
|
+
# @return [Boolean] returns true on success
|
142
|
+
def save_decrypted(path)
|
143
|
+
path << @kms_meta[:original_extension] unless File.extname(path) == @kms_meta[:original_extension]
|
144
|
+
infile = File.open(@encrypted_file_path, 'rb')
|
145
|
+
outfile = File.open(path, 'wb+')
|
146
|
+
@dec.stream_decrypt_with_data_key({
|
147
|
+
in: infile,
|
148
|
+
position: @encrypted_data_start,
|
149
|
+
out: outfile,
|
150
|
+
encrypted_iv: encrypted_iv,
|
151
|
+
encrypted_key: encrypted_key,
|
152
|
+
cipher: cipher,
|
153
|
+
checksum: checksum
|
154
|
+
})
|
155
|
+
|
156
|
+
outfile.close
|
157
|
+
true
|
158
|
+
end
|
159
|
+
|
160
|
+
# Verify YAML header of a KMS file to encure necessary information is present to decrypt
|
161
|
+
#
|
162
|
+
# @param [Object] yaml object containing KMS metadata
|
163
|
+
# @return [Boolean]
|
164
|
+
def is_valid_kms_file?(yaml)
|
165
|
+
KMS_REQUIRED_ELEMENTS.all? { |e| yaml.has_key? e }
|
166
|
+
end
|
167
|
+
|
168
|
+
# Calculate SHA of a given file by chunks
|
169
|
+
#
|
170
|
+
# @param [String] path Path to file
|
171
|
+
# @return [String] Hex encoded SHA1 hash
|
172
|
+
def file_sha(path)
|
173
|
+
sha1 = Digest::SHA1.new
|
174
|
+
file = File.open(path,'rb')
|
175
|
+
chunk = ""
|
176
|
+
while file.read(STREAM_CHUNK_SIZE, chunk)
|
177
|
+
sha1.update(chunk)
|
178
|
+
end
|
179
|
+
|
180
|
+
sha1.hexdigest
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
184
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module KmsTools
|
2
|
+
# Provides low-level encryption functionality for kms-tools
|
3
|
+
#
|
4
|
+
# @author Matt Krieger
|
5
|
+
class Encrypter < KmsTools::Base
|
6
|
+
# Size limit for encrypting data directly using {http://docs.aws.amazon.com/sdkforruby/api/Aws/KMS/Client.html#encrypt-instance_method Aws::KMS::Client.encrypt}
|
7
|
+
STRING_SIZE_LIMIT = 4096
|
8
|
+
|
9
|
+
# Key spec to use by default unless overridden
|
10
|
+
DEFAULT_KEY_SPEC = 'AES_256'
|
11
|
+
|
12
|
+
# Encrypt a string up 4KB in size
|
13
|
+
# @param str [String] String to encrypt
|
14
|
+
# @return [String] Base64 encoded ciphertext
|
15
|
+
def encrypt_string(str)
|
16
|
+
to_s64(kms_encrypt(str).ciphertext_blob)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Call {http://docs.aws.amazon.com/sdkforruby/api/Aws/KMS/Client.html#encrypt-instance_method Aws::KMS::Client.encrypt} using object master_key
|
20
|
+
# @param str [String] String to encrypt
|
21
|
+
# @return [Object] {http://docs.aws.amazon.com/sdkforruby/api/Aws/KMS/Types/EncryptResponse.html Aws::KMS::Types::EncryptResponse}
|
22
|
+
def kms_encrypt(str)
|
23
|
+
kms.encrypt({:key_id => master_key, :plaintext => str})
|
24
|
+
end
|
25
|
+
|
26
|
+
# Encrypt a blob using private keys
|
27
|
+
#
|
28
|
+
# @param [Hash] params
|
29
|
+
# @option params [String] :cipher OpenSSL cipher to use for encryption
|
30
|
+
# @option params [String] :encrypted_key Encrypted private key
|
31
|
+
# @option params [String] :encrypted_iv Encrypted initialization vector
|
32
|
+
# @option params [String] :data Plaintext data blob
|
33
|
+
# @return [String] Binary encrypted ciphertext
|
34
|
+
def encrypt_with_data_key(params)
|
35
|
+
d = KmsTools::Decrypter.new()
|
36
|
+
cipher = OpenSSL::Cipher.new(params[:cipher])
|
37
|
+
cipher.encrypt
|
38
|
+
cipher.key = d.decrypt_string(params[:encrypted_key])
|
39
|
+
cipher.iv = d.decrypt_string(params[:encrypted_iv])
|
40
|
+
encrypted_data = cipher.update(params[:data]) + cipher.final
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
# Encrypt a stream using private keys
|
45
|
+
#
|
46
|
+
# @param [Hash] params
|
47
|
+
# @option params [String] :cipher OpenSSL cipher to use for encryption
|
48
|
+
# @option params [String] :encrypted_key Encrypted private key
|
49
|
+
# @option params [String] :encrypted_iv Encrypted initialization vector
|
50
|
+
# @option params [Stream] :in Input stream to read plaintext data from
|
51
|
+
# @option params [Stream] :out Stream to to write encrypted output to
|
52
|
+
def stream_encrypt_with_data_key(params)
|
53
|
+
d = KmsTools::Decrypter.new()
|
54
|
+
|
55
|
+
# set up cipher
|
56
|
+
cipher = OpenSSL::Cipher.new(params[:cipher])
|
57
|
+
cipher.encrypt
|
58
|
+
cipher.key = d.decrypt_string(params[:encrypted_key])
|
59
|
+
cipher.iv = d.decrypt_string(params[:encrypted_iv])
|
60
|
+
|
61
|
+
# write the output stream
|
62
|
+
buf = ""
|
63
|
+
params[:in].seek(params[:position], :SET) if params[:position]
|
64
|
+
while params[:in].read(STREAM_CHUNK_SIZE, buf)
|
65
|
+
params[:out] << cipher.update(buf)
|
66
|
+
end
|
67
|
+
params[:out] << cipher.final
|
68
|
+
|
69
|
+
# return true if nothing errored out
|
70
|
+
true
|
71
|
+
end
|
72
|
+
|
73
|
+
# Generate a data key to use for local symmetric encryption
|
74
|
+
# @return [Object] {http://docs.aws.amazon.com/sdkforruby/api/Aws/KMS/Types/GenerateDataKeyResponse.html Aws::KMS::Types::GenerateDataKeyResponse}
|
75
|
+
def new_key
|
76
|
+
kms.generate_data_key({
|
77
|
+
:key_id => master_key,
|
78
|
+
:key_spec => key_spec
|
79
|
+
})
|
80
|
+
end
|
81
|
+
|
82
|
+
# Generate Base64 encoded encrypted data key to use for local symmetric encryption
|
83
|
+
# @return [String] Base64 encoded encrypted data key
|
84
|
+
def new_encrypted_key
|
85
|
+
to_s64(new_key.ciphertext_blob)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Key spec that will be used for data key creation
|
89
|
+
# @return [String] {http://docs.aws.amazon.com/sdkforruby/api/Aws/KMS/Types/GenerateDataKeyRequest.html#key_spec-instance_method AWS Key Spec}
|
90
|
+
def key_spec
|
91
|
+
@key_spec ||= DEFAULT_KEY_SPEC
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|