opensecret 0.0.960 → 0.0.962

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.
@@ -61,7 +61,7 @@ module OpenSecret
61
61
  log.info(x) { "os blowfish request to encrypt plain text with provided key." }
62
62
 
63
63
  block_txt = plain_text
64
- block_txt += OpenSecret::Cipher::TEXT_PADDER until block_txt.bytesize % OpenSecret::Blowfish::BLOWFISH_BLOCK_LEN == 0
64
+ block_txt += CryptIO::TEXT_PADDER until block_txt.bytesize % OpenSecret::Blowfish::BLOWFISH_BLOCK_LEN == 0
65
65
  raw_stretched_key = Digest::SHA256.digest(encryption_key)
66
66
 
67
67
  blowfish_encryptor = OpenSSL::Cipher.new(OpenSecret::Blowfish::BLOWFISH_CIPHER_ID).encrypt
@@ -113,7 +113,7 @@ module OpenSecret
113
113
  decrypt_tool.key = digested_key
114
114
 
115
115
  padded_plaintxt = decrypt_tool.update(cipher_text) << decrypt_tool.final
116
- pad_begin_index = padded_plaintxt.index OpenSecret::Cipher::TEXT_PADDER
116
+ pad_begin_index = padded_plaintxt.index CryptIO::TEXT_PADDER
117
117
  return padded_plaintxt if pad_begin_index.nil?
118
118
  return padded_plaintxt[ 0 .. (pad_begin_index-1) ]
119
119
 
@@ -82,11 +82,47 @@ module OpenSecret
82
82
  #
83
83
  # nil is reurned if no file can be found in the local mirror
84
84
  # at the configured path
85
+ #
86
+ # @raise [RuntimeError]
87
+ # unless the path exists in this coldstore and that path is
88
+ # a directory (as opposed to a file).
89
+ #
90
+ # @raise [ArgumentError]
91
+ # if more than one file match is made at the path specified.
85
92
  def read from_path
86
93
 
87
94
  frozen_filepath = File.join @store_path, from_path
88
- return nil unless File.exists? frozen_filepath
89
- return File.read frozen_filepath
95
+ frozen_dir_path = File.dirname(frozen_filepath)
96
+
97
+ log.info(x) { "Coldstore will search in folder [#{frozen_dir_path.hr_path}]" }
98
+
99
+ exists_msg = "Directory #{frozen_dir_path} does not exist in store."
100
+ is_dir_msg = "Path #{frozen_dir_path} should be a directory (not a file)."
101
+ raise RuntimeError, exists_msg unless File.exists? frozen_dir_path
102
+ raise RuntimeError, is_dir_msg unless File.directory? frozen_dir_path
103
+
104
+ full_filepath = ""
105
+ file_matched = false
106
+
107
+ Dir.glob("#{frozen_dir_path}/**/*.os.txt").each do |matched_path|
108
+
109
+ log.info(x) { "Coldstore search with [#{from_path}] has matched [#{matched_path.hr_path}]" }
110
+ log.info(x) { "Ignore directory at [#{matched_path.hr_path}]." } if File.directory? matched_path
111
+ next if File.directory? matched_path
112
+
113
+ two_match_msg = "More than one file matched. The second is #{matched_path}."
114
+ raise ArgumentError, two_match_msg if file_matched
115
+ file_matched = true
116
+
117
+ full_filepath = matched_path
118
+
119
+ end
120
+
121
+ no_file_msg = "Coldstore could not find path [#{from_path}] from [#{@store_path}]."
122
+ raise RuntimeError, no_file_msg unless file_matched
123
+
124
+ log.info(x) { "Coldstore matched exactly one envelope at [#{full_filepath.hr_path}]." }
125
+ return File.read full_filepath
90
126
 
91
127
  end
92
128
 
@@ -0,0 +1,220 @@
1
+ #!/usr/bin/ruby
2
+ # coding: utf-8
3
+
4
+ module OpenSecret
5
+
6
+ # CryptIO concentrates on injecting and ingesting crypt properties into and
7
+ # out of a key/value dictionary as well as injecting and ingesting cryptographic
8
+ # materials into and out of text files.
9
+ #
10
+ # == Cryptographic Properties
11
+ #
12
+ # A crypt properties dictionary acts as <b>output from every encryption event</b>
13
+ # and <b>input to every decryption event</b>. The most common properties include
14
+ #
15
+ # - the symmetric key used for the encryption and decryption
16
+ # - the iv (initialization vector) that adds another dimension of strength
17
+ # - authorization data that thwarts switch attacks by tying context to content
18
+ # - the cipher algorithm, its implementation and its encryption strength
19
+ # - the various glue strings that allow related ciphertext to occupy a file
20
+ #
21
+ # == Why Pad?
22
+ #
23
+ # Many ciphers (like Blowfish) constrains plain text lengths to multiples
24
+ # of 8 (or 16) and a common <b>right pad with spaces</b> strategy is employed
25
+ # as a workaround. opensecret does it diferently.
26
+ #
27
+ # == Why isn't Space Padding Used?
28
+ #
29
+ # If opensecret padded plaintext (ending in one or more spaces) with
30
+ # spaces, the decrypt phase (after right stripping spaces) would return
31
+ # plain text string <b>shorter than the original</b>.
32
+ #
33
+ # == Why Unusual Padding and Separators
34
+ #
35
+ # Why does opensecret employ unusual strings for padding and separation.
36
+ #
37
+ # The separator string must be unusual to make it unlikely for it to occur in any
38
+ # of the map's key value pairs nor indeed the chunk of text being glued. Were
39
+ # this to happen, the separate and reconstitute phase may not accurately return
40
+ # the same two entities we are employed to unite.
41
+ #
42
+ # == So How is Padding Done?
43
+ #
44
+ # Instead of single space padding - opensecret uses an unlikely 7 character
45
+ # padder which is repeated until the multiple is reached.
46
+ #
47
+ # <tt><-|@|-></tt>
48
+ #
49
+ # == So How is Padding Done?
50
+ #
51
+ # The <b>padder length must be a prime number</b> or infinite loops could occur.
52
+ #
53
+ # If the padder string is likely to occur in the plain text, another
54
+ # padder (or strategy) should and could be employed.
55
+ #
56
+ class CryptIO
57
+
58
+
59
+ # The opensecret text padder. See the class description for an analysis
60
+ # of the use of this type of padder.
61
+ TEXT_PADDER = "<-|@|->"
62
+
63
+ # An unusual string that glues together an encryption dictionary and
64
+ # a chunk of base64 encoded and encrypted ciphertext.
65
+ # The string must be unusual enough to ensure it does not occur within
66
+ # the dictionary metadata keys or values.
67
+ INNER_GLUE_STRING = "\n<-|@| < || opensecret inner crypt material axis || > |@|->\n\n"
68
+
69
+ # An unusual string that glues together the asymmetrically encrypted outer
70
+ # encryption key with the outer crypted text.
71
+ OUTER_GLUE_STRING = "\n<-|@| < || opensecret outer crypt material axis || > |@|->\n\n"
72
+
73
+ # Text header for key-value pairs hash map that will be serialized.
74
+ DICT_HEADER_NAME = "crypt.properties"
75
+
76
+ # Name for the class of cipher employed.
77
+ DICT_CIPHER_NAME = "cipher.class"
78
+
79
+ # Name for the {Base64} encoded symmetric (lock/unlock) crypt key.
80
+ DICT_CRYPT_KEY = "encryption.key"
81
+
82
+ # Dictionary name for the encryption iv (initialization vector)
83
+ DICT_CRYPT_IV = "encryption.iv"
84
+
85
+ # Dictionary name for the Base64 (urlsafe) encoded plaintext digest.
86
+ DICT_TEXT_DIGEST = "plaintext.digest"
87
+
88
+
89
+ # Serialize and then unify a hash map and a textual chunk using
90
+ # a known but unusual separator string in a manner that protects
91
+ # content integrity during the serialize / deserialize process.
92
+ #
93
+ # This crypt serialization uses a specific "inner glue" as the
94
+ # string that separates the serialized key/value dictionary and
95
+ # the encoded textual block.
96
+ #
97
+ # @param hash_map [String]
98
+ # this hash (dictionary) will be serialized into INI formatted text
99
+ # using behaviour from {Hash} and {IniFile}.
100
+ #
101
+ # @param text_chunk [String]
102
+ # the usually Base64 encrypted textual block to be glued at the
103
+ # bottom of the returned block.
104
+ #
105
+ # @return [String] serialized and glued together result of map plus text
106
+ #
107
+ # @raise [ArgumentError]
108
+ # if the dictionary hash_map is either nil or empty.
109
+ def self.inner_crypt_serialize hash_map, text_chunk
110
+
111
+ nil_or_empty_hash = hash_map.nil? || hash_map.empty?
112
+ raise ArgumentError, "Cannot serialize nil or empty properties." if nil_or_empty_hash
113
+ ini_map = IniFile.new
114
+ ini_map[ DICT_HEADER_NAME ] = hash_map
115
+ return ini_map.to_s + INNER_GLUE_STRING + text_chunk
116
+
117
+ end
118
+
119
+
120
+ # Deserialize an opensecret formatted text which contains an
121
+ # encryption properties dictionary (serialized in INI format)
122
+ # and a Base64 encoded crypt block which is the subject of the
123
+ # encryption dictionary.
124
+ #
125
+ # The crypt serialization used a specific "inner glue" as the
126
+ # string that separates the serialized key/value dictionary and
127
+ # the encoded textual block. We now employ this glue to split
128
+ # the serialized dictionary from the textual block.
129
+ #
130
+ # @param hash_map [String]
131
+ # send an instantiated hash (dictionary) which will be populated
132
+ # by this deserialize operation. The dictionary propeties can
133
+ # then be used to decrypt the returned ciphertext.
134
+ #
135
+ # @param text_block [String]
136
+ # the first of a two-part amalgamation is a hash (dictionary) in
137
+ # INI serialized form and the second part is a Base64 encrypted
138
+ # textual block.
139
+ #
140
+ # The deserialized key/value pairs will be stuffed into the
141
+ # non nil (usually empty) hash map in the first parameter and
142
+ # the block (in the 2nd part) will be Base64 decoded and
143
+ # returned by this method.
144
+ #
145
+ # @return [String]
146
+ # The encoded block in the 2nd part of the 2nd parameter will be
147
+ # Base64 decoded and returned.
148
+ #
149
+ # @raise [ArgumentError]
150
+ # if the dictionary hash_map is either nil or empty. Also if
151
+ # the inner glue tying the two parts together is missing an
152
+ # {ArgumentError} will be thrown.
153
+ def self.inner_crypt_deserialize hash_map, text_block
154
+
155
+ raise ArgumentError, "Cannot populate a nil hash map." if hash_map.nil?
156
+ assert_contains_glue text_block, INNER_GLUE_STRING
157
+
158
+ serialized_map = text_block.split(INNER_GLUE_STRING).first.strip
159
+ encoded64_text = text_block.split(INNER_GLUE_STRING).last.strip
160
+ ini_props_hash = IniFile.new( :content => serialized_map )
161
+ encrypt_values = ini_props_hash[DICT_HEADER_NAME]
162
+
163
+ hash_map.merge!( encrypt_values )
164
+ return Base64.decode64( encoded64_text )
165
+
166
+ end
167
+
168
+
169
+ # Using an outer divider (glue) - attach the asymmetrically encrypted outer
170
+ # encryption key with the outer encrypted text.
171
+ #
172
+ # @param crypt_material_x [String] asymmetrically encrypted (encoded) outer encryption key
173
+ # @param crypt_material_y [String] symmetrically encrypted inner metadata and payload crypt
174
+ #
175
+ # @return [String] concatenated result of the two crypt materials and divider string
176
+ def self.outer_crypt_serialize crypt_material_x, crypt_material_y
177
+ return crypt_material_x + OUTER_GLUE_STRING + crypt_material_y
178
+ end
179
+
180
+
181
+ # Given two blocks of text that were bounded together by the
182
+ # {self.outer_crypt_serialize} method we must return either the
183
+ # first block (true) or the second (false).
184
+ #
185
+ # @param crypt_material [String]
186
+ # large block of text in two parts that is divided by the
187
+ # outer glue string.
188
+ #
189
+ # @param top_block [Boolean]
190
+ # if true the top (of the two) blocks will be returned
191
+ # otherwise the bottom block is returned.
192
+ #
193
+ # @return [String] either the first or second block of text
194
+ #
195
+ # @raise [ArgumentError]
196
+ # If the outer glue string tying the two parts together is
197
+ # missing an {ArgumentError} will be thrown.
198
+ def self.outer_crypt_deserialize os_material, top_block
199
+
200
+ assert_contains_glue os_material, OUTER_GLUE_STRING
201
+ return os_material.split(OUTER_GLUE_STRING).first.strip if top_block
202
+ return os_material.split(OUTER_GLUE_STRING).last.strip
203
+
204
+ end
205
+
206
+
207
+ private
208
+
209
+ def self.assert_contains_glue os_crypted_block, glue_string
210
+
211
+ no_glue_msg = "\nGlue string not in opensecret cipher block.\n#{glue_string}\n"
212
+ raise ArgumentError, no_glue_msg unless os_crypted_block.include? glue_string
213
+
214
+ end
215
+
216
+
217
+ end
218
+
219
+
220
+ end
@@ -44,6 +44,50 @@ module OpenSecret
44
44
  end
45
45
 
46
46
 
47
+ # Unlock the {OpenSSL::PKey::RSA} private key and return the cipher object
48
+ # usable for asymmetric encryption, decryption, signing and signature
49
+ # verification use cases.
50
+ #
51
+ # The returned private key can be used to generate its twin public key
52
+ # and should be used to verify the same public key as (if) and when the
53
+ # need arises.
54
+ #
55
+ # @param locked_private_key [String]
56
+ # the locked up private key ciphertext
57
+ #
58
+ # @param unlock_key [String]
59
+ # the symmetric encryption key that can be used to unlock the private
60
+ # key ciphertext in the first parameter.
61
+ #
62
+ # @return [OpenSSL::PKey::RSA]
63
+ # return the {OpenSSL::PKey::RSA} private key that will be
64
+ # usable for asymmetric encryption, decryption, signing and signature
65
+ # verification.
66
+ def unlock_private_key locked_private_key, unlock_key
67
+ return OpenSSL::PKey::RSA.new locked_private_key, unlock_key
68
+ end
69
+
70
+
71
+ # Return the {OpenSSL::PKey::RSA} private key which is a cipher object
72
+ # usable for asymmetric encryption, decryption, signing and signature
73
+ # verification use cases.
74
+ #
75
+ # The returned private key can be used to generate its twin public key
76
+ # and should be used to verify the same public key as (if) and when the
77
+ # need arises.
78
+ #
79
+ # @param private_key_text [String]
80
+ # the private key plain text
81
+ #
82
+ # @return [OpenSSL::PKey::RSA]
83
+ # return the {OpenSSL::PKey::RSA} private key that will be
84
+ # usable for asymmetric encryption, decryption, signing and signature
85
+ # verification.
86
+ def to_private_key private_key_text
87
+ return OpenSSL::PKey::RSA.new private_key_text
88
+ end
89
+
90
+
47
91
  end
48
92
 
49
93
 
@@ -88,12 +88,20 @@ module OpenSecret
88
88
  machine_key_x = Base64.urlsafe_encode64(
89
89
  Blowfish.new.encryptor(machine_key, machine_key_crypt_key)
90
90
  )
91
- public_key_64 = Base64.urlsafe_encode64 asymmetric_keys.public_key.to_pem
92
91
 
93
92
  OpenSession::Attributes.stash @c[:global][:name], @c[:global][:name], @c[:global][:machine_key_x], machine_key_x
94
93
  OpenSession::Attributes.stash @c[:global][:name], @c[:global][:name], @c[:global][:stamp_key], @c[:global][:stamp_23]
94
+
95
+
96
+ ## Change and write the public key to own file (see paper notes for naming direction)
97
+ ## Change and write the public key to own file (see paper notes for naming direction)
98
+ ## Change and write the public key to own file (see paper notes for naming direction)
99
+ public_key_64 = Base64.urlsafe_encode64 asymmetric_keys.public_key.to_pem
95
100
  OpenSession::Attributes.stash @c[:global][:name], @c[:global][:name], @c[:global][:publickey_id], public_key_64
96
101
 
102
+ ## not needed - produce public key from private key then validate with key in configuration.
103
+ ## not needed - produce public key from private key then validate with key in configuration.
104
+ ## not needed - produce public key from private key then validate with key in configuration.
97
105
  to_sign_segments = [ secured_keytext, public_key_64, @email_addr, @c[:global][:stamp_23] ]
98
106
  to_sign_packet = to_sign_segments.alphanumeric_union.concat_length
99
107
  signature_string = Base64.urlsafe_encode64( asymmetric_keys.sign( OpenSSL::Digest::SHA256.new, to_sign_packet ) )
@@ -68,15 +68,15 @@ module OpenSecret
68
68
  def execute
69
69
 
70
70
  rel_filepath = OpenSession::Attributes.instance.get_value @@context_name, @c[:open][:open_name], @c[:open][:open_pathname]
71
- master_public_key = Base64.urlsafe_decode64( OpenSession::Attributes.instance.get_value @c[:global][:name], @c[:global][:name], "public.key" )
71
+ master_public_key = OpenSSL::PKey::RSA.new ( Base64.urlsafe_decode64( OpenSession::Attributes.instance.get_value @c[:global][:name], @c[:global][:name], "public.key" ) )
72
72
 
73
73
  main_store = ColdStore.new @c[:global][:store_mainpath]
74
74
  keys_store = ColdStore.new @c[:global][:store_keyspath]
75
75
 
76
76
  envelope = get_envelope
77
77
  asym_key = OpenSSL::PKey::RSA.new @c[:global][:bit_key_size]
78
- lockdown = Aes256.new.encrypt_it( asym_key.public_key.to_pem, envelope.to_json )
79
- lockedup = Aes256.new.encrypt_it( master_public_key, asym_key.export )
78
+ lockdown = Cipher.encrypt_it( asym_key.public_key, envelope.to_json )
79
+ lockedup = Cipher.encrypt_it( master_public_key, asym_key.export )
80
80
 
81
81
  ##### ###################################### #####
82
82
  ##### ###################################### #####
@@ -27,7 +27,7 @@ module OpenSecret
27
27
  #
28
28
  class Open < SecretsUseCase
29
29
 
30
- attr_writer :context_path
30
+ attr_writer :outer_path
31
31
  @@context_name = "opensecret"
32
32
 
33
33
  # Execute the <tt>open use case</tt> activities which precedes the ability to
@@ -69,9 +69,9 @@ module OpenSecret
69
69
  #
70
70
  def execute
71
71
 
72
- last_fwdslash_index = @context_path.rindex "/"
73
- folder_path = @context_path[0 .. last_fwdslash_index]
74
- file_word = @context_path[last_fwdslash_index .. -1]
72
+ last_fwdslash_index = @outer_path.rindex "/"
73
+ folder_path = @outer_path[0 .. last_fwdslash_index]
74
+ file_word = @outer_path[last_fwdslash_index .. -1]
75
75
 
76
76
  session_folder_path = File.join @p[:open_dirpath], folder_path
77
77
 
@@ -77,7 +77,7 @@ module OpenSecret
77
77
  @@context_name = "opensecret"
78
78
 
79
79
  # The <b>put use case</b> follows <b>open</b> and it adds secrets into an
80
- # <em>(encrypted at rest)</em> opened file. Put can be called many times to
80
+ # <em>(encrypted at rest)</em> envelope. Put can be called many times to
81
81
  # add secrets. Finally the <b>lock use case</b> commits all opened secrets
82
82
  # into the configured storage engines.
83
83
  #
@@ -0,0 +1,208 @@
1
+ #!/usr/bin/ruby
2
+
3
+ module OpenSecret
4
+
5
+ require 'openssl'
6
+
7
+ # The <tt>unlock use case</tt> moves doubly encrypted material <b>from the frozen</b>
8
+ # (key and crypt) stores, <b>into an (encrypted) session envelope</b>.
9
+ #
10
+ # Material within the auspices of the session envelope can be manipulated by commands
11
+ # like {OpenSecret::Put} and remove and also read by commands like peep, look and update.
12
+ #
13
+ # <b>Unlock | Pre-Conditions</b>
14
+ #
15
+ # To deliver on its core promise of moving the encrypted (key and crypt) stores
16
+ # to an encrypted session envelope, <b>unlock</b> expects
17
+ #
18
+ # - the local key and crypt stores to be pulled (refreshed) from remote
19
+ # - the destination session path to either be empty (or)
20
+ # - a populated session path containing equivalent data (ie cannot be overwritten)
21
+ # - both the human (agent) password and workstation key to be correct
22
+ #
23
+ # <b>Unlock | Alternate Flows</b>
24
+ #
25
+ # This use case requires the human (agent) password unless the <tt>--no-human-password</tt>
26
+ # flag was posted along with the <tt>init</tt> command. In this instance an agent password
27
+ # will have been generated and encrypted with the user's home tree.
28
+ #
29
+ # <b>Unlock | Observable Value</b>
30
+ #
31
+ # The observable value proffered by unlock is
32
+ #
33
+ # - validating the existence of the requested secret path
34
+ # - validation of the human password and workstation key
35
+ # - the keys and crypt at the paths are decrypted
36
+ # - the session envelope is stuffed with the crypted material
37
+ # - an encrypted session envelope (post-stuffing)
38
+ #
39
+ # @example
40
+ #
41
+ # These use case steps are implemented and ready to go.
42
+ #
43
+ # $ opensecret open geo/countries
44
+ # $ opensecret put uganda/capital kampala
45
+ # $ opensecret put kenya/capital nairobi
46
+ # $ opensecret put france/capital paris
47
+ # $ opensecret put france/population 23000000
48
+ # $ opensecret lock
49
+ # $ opensecret unlock geo/countries --with=asdfasdf
50
+ #
51
+ # Below are future examples with use cases like list and print
52
+ # which curently have not been implemented.
53
+ #
54
+ # $ opensecret init bobby@example.com --with="hUM4n-0pen$3cr3t"
55
+ #
56
+ # $ opensecret open my/gadgets
57
+ #
58
+ # $ opensecret put laptop/login/username bob
59
+ # $ opensecret put laptop/login/password bob$_p455w0rd
60
+ # $ opensecret put iphone/pin 8529
61
+ #
62
+ # $ opensecret lock
63
+ # $ opensecret list
64
+ #
65
+ # $ opensecret unlock my/gadgets --with="hUM4n-0pen$3cr3t"
66
+ # $ opensecret print
67
+ #
68
+ # $ opensecret put wifi/ssid Virgin-HGPAS
69
+ # $ opensecret put wifi/password SDBLJHGPASDFA1234ZNF
70
+ #
71
+ # $ opensecret print
72
+ # $ opensecret lock
73
+ #
74
+ class Unlock < SecretsUseCase
75
+
76
+ attr_writer :outer_path, :master_p4ss
77
+ @@context_name = "opensecret"
78
+
79
+
80
+ # The <tt>lock use case</tt> is called after {OpenSecret::Open} and {OpenSecret::Put}
81
+ # and its effect is to dispatch the doubly encrypted materrial to the configured storage
82
+ # platform, be it Git, S3, SSH or just an accessible file-system.
83
+ #
84
+ # <b>Main Flow of Events</b>
85
+ #
86
+ # To seal the envelope built up by put, file and add amongst others requires
87
+ # that we
88
+ #
89
+ # - get the encrypted envelope
90
+ # - create a strong asymmetric key
91
+ # - lock the envelope using opensecret's double encrypt modus operandi
92
+ # - place the doubly encrypted result into the crypt store
93
+ # - lock the asymmetric key again with opensecret's double encrypt modus operandi
94
+ # - place the doubly encrypted result into the key store
95
+ #
96
+ # The second double lock of the crypted envelope is done with the public key
97
+ # aspect of an asymmetric key created here.
98
+ #
99
+ # The second double lock of the crypted private key (created here) is done with
100
+ # the master public key created in the {Init.execute} use case main flow.
101
+ #
102
+ # <b>Lock | Observable Value</b>
103
+ #
104
+ # The observable value after the lock use case has completed entails
105
+ #
106
+ # - a doubly encrypted data envelope placed in the backend store
107
+ # - a doubly encrypted private key placed in the frontend store
108
+ # - both stores sync'd with off-machine Git (S3, ...) mirrors
109
+ # - deletion of the (encrypted) envelope {Open}ed and stuffed with {Put}
110
+ # - deletion of {Open}ed session data to locate and decrypt envelope
111
+ def execute
112
+
113
+ main_store = ColdStore.new @c[:global][:store_mainpath]
114
+ keys_store = ColdStore.new @c[:global][:store_keyspath]
115
+
116
+ keys_crypt = keys_store.read @outer_path
117
+ main_crypt = main_store.read @outer_path
118
+
119
+ unless @master_p4ss
120
+ @master_p4ss = Collect.secret_text(
121
+ @c[:global][:min_passwd_len],
122
+ false,
123
+ "Enter Master Password "
124
+ )
125
+ end
126
+
127
+ workstation_rawkey = OpenSession::Attributes.instance.get_value @c[:global][:name], @c[:global][:name], @c[:global][:machine_key_x]
128
+ original_timestamp = OpenSession::Attributes.instance.get_value @c[:global][:name], @c[:global][:name], @c[:global][:stamp_key]
129
+ workstation_cipher = Base64.urlsafe_decode64( workstation_rawkey )
130
+ crypt_key_segments = [ @master_p4ss, @c[:global][:separator_a], @email_addr, @c[:global][:separator_a], original_timestamp ]
131
+ workstation_lock_x = crypt_key_segments.alphanumeric_union.concat_length
132
+
133
+ workstation_string = Blowfish.new.decryptor workstation_cipher, workstation_lock_x
134
+ private_key_lock_x = Amalgam.passwords @master_p4ss, workstation_string, @c[:global][:ratio]
135
+ private_key_cipher = File.read @c[:global][:master_prv_key]
136
+ private_key_object = unlock_private_key( private_key_cipher, private_key_lock_x )
137
+
138
+ string_private_key = Cipher.decrypt_it( private_key_object, keys_crypt )
139
+ plain_message_text = Cipher.decrypt_it( to_private_key(string_private_key), main_crypt )
140
+
141
+ puts ""
142
+ puts "==== ======================================= ===="
143
+ puts "==== The Exported Plain Text Structured Data ===="
144
+ puts "==== ======================================= ===="
145
+ puts ""
146
+ puts plain_message_text
147
+ puts ""
148
+ puts ""
149
+ puts JSON.pretty_generate( JSON.parse( plain_message_text ) )
150
+ puts ""
151
+
152
+ exit
153
+
154
+ #############################################################################################
155
+ #############################################################################################
156
+
157
+ rel_filepath = OpenSession::Attributes.instance.get_value @@context_name, @c[:open][:open_name], @c[:open][:open_pathname]
158
+ master_public_key = Base64.urlsafe_decode64( OpenSession::Attributes.instance.get_value @c[:global][:name], @c[:global][:name], "public.key" )
159
+
160
+
161
+ #############################################################################################
162
+ #############################################################################################
163
+
164
+ =begin
165
+ Crypto.print_secret_env_var @p[:env_var_name], machine_key
166
+ GitFlow.do_clone_repo @p[:public_gitrepo], @p[:local_gitrepo]
167
+ FileUtils.mkdir_p @p[:public_keydir]
168
+ File.write @p[:public_keypath], public_key_text
169
+ GitFlow.push @p[:local_gitrepo], @p[:public_keyname], @c[:time][:stamp]
170
+ =end
171
+
172
+
173
+ # key4_pem = File.read 'private.secure.pem'
174
+ # pass_phrase = 'superduperpasswordistoBeENTEREDRIGHT1234HereandRightNOW'
175
+ # key4 = OpenSSL::PKey::RSA.new key4_pem, pass_phrase
176
+ # decrypted_text = key4.private_decrypt(Base64.urlsafe_decode64(encrypted_string))
177
+
178
+ # print "\nHey we have done the decryption.\n", "\n"
179
+ # print decrypted_text, "\n"
180
+
181
+ #############################################################################################
182
+ #############################################################################################
183
+
184
+ end
185
+
186
+
187
+ # Perform pre-conditional validations in preparation to executing the main flow
188
+ # of events for this use case. This method may throw the below exceptions.
189
+ #
190
+ # @raise [SafeDirNotConfigured] if the safe's url has not been configured
191
+ # @raise [EmailAddrNotConfigured] if the email address has not been configured
192
+ # @raise [StoreUrlNotConfigured] if the crypt store url is not configured
193
+ def pre_validation
194
+
195
+ @email_addr = OpenSession::Attributes.instance.get_value @@context_name, @@context_name, "email"
196
+ email_configured = !@email_addr.nil? && !@email_addr.empty? && @email_addr.length > 4
197
+ @err_msg = "viable [email address] not configured. Try =>] opensecret email joe@example.com"
198
+ raise EmailAddrNotConfigured.new @err_msg, @email_addr unless email_configured
199
+
200
+ end
201
+
202
+
203
+ end
204
+
205
+
206
+ end
207
+
208
+