kms-tools 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|