opensecret 0.0.960 → 0.0.962

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