opensecret 0.0.988 → 0.0.9925

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.
Files changed (62) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +56 -159
  3. data/bin/opensecret +2 -2
  4. data/bin/ops +17 -2
  5. data/lib/extension/string.rb +14 -16
  6. data/lib/{interpreter.rb → interprete.rb} +53 -29
  7. data/lib/keytools/binary.map.rb +49 -0
  8. data/lib/keytools/kdf.api.rb +249 -0
  9. data/lib/keytools/kdf.bcrypt.rb +64 -29
  10. data/lib/keytools/kdf.pbkdf2.rb +92 -83
  11. data/lib/keytools/kdf.scrypt.rb +190 -0
  12. data/lib/keytools/key.64.rb +326 -0
  13. data/lib/keytools/key.algo.rb +109 -0
  14. data/lib/keytools/key.api.rb +1281 -0
  15. data/lib/keytools/key.db.rb +265 -0
  16. data/lib/keytools/{key.module.rb → key.docs.rb} +55 -0
  17. data/lib/keytools/key.error.rb +110 -0
  18. data/lib/keytools/key.id.rb +271 -0
  19. data/lib/keytools/key.iv.rb +107 -0
  20. data/lib/keytools/key.local.rb +265 -0
  21. data/lib/keytools/key.mach.rb +248 -0
  22. data/lib/keytools/key.now.rb +402 -0
  23. data/lib/keytools/key.pair.rb +259 -0
  24. data/lib/keytools/key.pass.rb +120 -0
  25. data/lib/keytools/key.rb +428 -298
  26. data/lib/keytools/keydebug.txt +295 -0
  27. data/lib/logging/gem.logging.rb +3 -3
  28. data/lib/modules/cryptology/collect.rb +20 -0
  29. data/lib/session/require.gem.rb +1 -1
  30. data/lib/usecase/cmd.rb +417 -0
  31. data/lib/usecase/id.rb +36 -0
  32. data/lib/usecase/import.rb +174 -0
  33. data/lib/usecase/init.rb +78 -0
  34. data/lib/usecase/login.rb +70 -0
  35. data/lib/usecase/logout.rb +30 -0
  36. data/lib/usecase/open.rb +126 -0
  37. data/lib/{interprete → usecase}/put.rb +100 -47
  38. data/lib/usecase/read.rb +89 -0
  39. data/lib/{interprete → usecase}/safe.rb +0 -0
  40. data/lib/{interprete → usecase}/set.rb +0 -0
  41. data/lib/usecase/token.rb +111 -0
  42. data/lib/{interprete → usecase}/use.rb +0 -0
  43. data/lib/version.rb +1 -1
  44. data/opensecret.gemspec +4 -3
  45. metadata +39 -33
  46. data/lib/exception/cli.error.rb +0 -53
  47. data/lib/exception/errors/cli.errors.rb +0 -31
  48. data/lib/interprete/begin.rb +0 -232
  49. data/lib/interprete/cmd.rb +0 -621
  50. data/lib/interprete/export.rb +0 -163
  51. data/lib/interprete/init.rb +0 -205
  52. data/lib/interprete/key.rb +0 -119
  53. data/lib/interprete/open.rb +0 -148
  54. data/lib/interprete/seal.rb +0 -129
  55. data/lib/keytools/digester.rb +0 -245
  56. data/lib/keytools/key.data.rb +0 -227
  57. data/lib/keytools/key.derivation.rb +0 -341
  58. data/lib/modules/mappers/collateral.rb +0 -282
  59. data/lib/modules/mappers/envelope.rb +0 -127
  60. data/lib/modules/mappers/settings.rb +0 -170
  61. data/lib/notepad/scratch.pad.rb +0 -224
  62. data/lib/store-commands.txt +0 -180
@@ -1,148 +0,0 @@
1
- #!/usr/bin/ruby
2
-
3
- module OpenSecret
4
-
5
- require 'openssl'
6
-
7
- # The <tt>open use case</tt> allows us to add (put), subtract (del)ete, change
8
- # (update) and list the secrets within an envelope (outer path) at a given
9
- # position (inner path), whether that envelope exists or not.
10
- #
11
- # Also see the <b>reopen</b> command which only differs from open in that it
12
- # fails if the path specified does not exist in either the sealed or session
13
- # envelopes.
14
- #
15
- # == The Open Path Parameter
16
- #
17
- # Open must be called with a single <b>path</b> parameter with an optional
18
- # single colon separating the outer (path to envelope) from the inner (path
19
- # within envelope).
20
- #
21
- # ops open aws.credentials:s3reader
22
- #
23
- # The outer and inner paths can contain forward slashes that segment the path.
24
- #
25
- # ops open production/aws.credentials:s3/s3reader
26
- # ops put access_key ABCD1234
27
- # ops put secret_key FGHIJ56789
28
- # ops put region_key eu-central-1
29
- # ops seal
30
- #
31
- #
32
- # == Before Opening a Path
33
- #
34
- # To open a path these conditions must be true.
35
- #
36
- # - the OPS_KEY environment variable must have been set for the session
37
- # - either <tt>ops begin</tt> or <tt>ops init</tt> must have been issued
38
- # - the external drive (eg usb key) must be configured and accessible
39
- #
40
- #
41
- # == After Opening a Path
42
- #
43
- # After a path is opened we can
44
- #
45
- # - <tt>open</tt> to relative or absolutely change the path
46
- # - <tt>put</tt> key/value data
47
- # - <tt>add</tt> a single value
48
- # - <tt>drop</tt> the value at the opened path
49
- # - <tt>mod</tt> change (modify) value at path
50
- # - <tt>seal</tt> to permanently write opened envelopes
51
- #
52
- # == Observable Value
53
- #
54
- # $ opensecret open home/wifi
55
- #
56
- # The observable value delivered by +[open]+ boils down to
57
- #
58
- # - an openkey (eg asdfx1234) and corresponding open encryption key
59
- # - open encryption key written to <tt>~/.opensecret/open.keys/asdfx1234.x.txt</tt>
60
- # - the opened path (ending in filename) written to session.cache base in [safe]
61
- # - the INI string (were the file to be decrypted) would look like the below
62
- #
63
- # [session]
64
- # base.path = home/wifi
65
- #
66
- class Open < Command
67
-
68
- attr_writer :open_path
69
-
70
- # The activities performed by the executing open use case is to
71
- #
72
- def execute
73
-
74
- instantiate_collateral
75
- @domain_name = @collateral.domain_name
76
-
77
- param_outer_path = @open_path.split(":").first
78
- param_inner_path = @open_path.split(":").last
79
-
80
- index = get_session_dictionary
81
- index.put OUTER_PATH, param_outer_path
82
- index.put INNER_PATH, param_inner_path
83
-
84
- index.write( create_session_dict_lock )
85
-
86
- puts ""
87
- puts index.to_s
88
- puts ""
89
-
90
- exit
91
-
92
-
93
-
94
- last_fwdslash_index = param_outer_path.rindex "/"
95
- folder_path = param_outer_path[0 .. last_fwdslash_index]
96
- file_word = param_outer_path[last_fwdslash_index .. -1]
97
-
98
- session_tree_dir = @collateral.session_envelopes_path
99
- session_folder_path = File.join session_tree_dir, folder_path
100
-
101
- FileUtils.mkdir_p session_folder_path
102
- open_id = ToolBelt::Engineer.strong_key @p[:open_idlen]
103
- open_key = ToolBelt::Engineer.strong_key @p[:open_keylen]
104
-
105
- file_name = file_word + ".#{open_id}.os.txt"
106
- file_key = File.join folder_path, file_name
107
-
108
- Mapper::Settings.write @p[:open_name], @p[:open_idname], open_id
109
- Mapper::Settings.write @p[:open_name], @p[:open_keyname], open_key
110
- Mapper::Settings.write @p[:open_name], @p[:open_pathname], file_key
111
-
112
- puts ""
113
- puts "---------------------------"
114
- puts "success | envelope opened"
115
- puts "---------------------------"
116
- puts ""
117
- puts "envelope path => #{param_outer_path}"
118
- puts "envelope file => #{nickname file_key}"
119
- puts "time [opened] => #{@c[:global][:stamp_23]}"
120
- puts ""
121
- puts "------------------"
122
- puts "now put secrets"
123
- puts "------------------"
124
- puts ""
125
- puts "ops put virgin/ssid VM68256973"
126
- puts "ops put virgin/password Wn5lsfixjfy"
127
- puts ""
128
-
129
-
130
- end
131
-
132
-
133
- # Perform pre-conditional validations in preparation to executing the main flow
134
- # of events for this use case. This method may throw the below exceptions.
135
- #
136
- # @raise [SafeDirNotConfigured] if the safe's url has not been configured
137
- # @raise [EmailAddrNotConfigured] if the email address has not been configured
138
- # @raise [StoreUrlNotConfigured] if the crypt store url is not configured
139
- def pre_validation
140
-
141
-
142
- end
143
-
144
-
145
- end
146
-
147
-
148
- end
@@ -1,129 +0,0 @@
1
- #!/usr/bin/ruby
2
-
3
- module OpenSecret
4
-
5
- require 'openssl'
6
-
7
- # The <tt>lock use case</tt> is called after {OpenSecret::Open} and {OpenSecret::Put}
8
- # and its effect is to dispatch the doubly encrypted materrial to the configured storage
9
- # platform, be it Git, S3, SSH or just an accessible file-system.
10
- #
11
- # The 3 core scenarios that this lock use case is equiped to handle are
12
- #
13
- # - a new source that is as yet uncommitted
14
- # - updating (overwriting) an existing source
15
- # - requiring the destination to be deleted
16
- #
17
- # <b>Lock | Observable Value</b>
18
- #
19
- # The observable value after the lock use case has completed entails
20
- #
21
- # - a doubly encrypted data envelope placed in the backend store
22
- # - a doubly encrypted private key placed in the frontend store
23
- # - both stores sync'd with off-machine Git (S3, ...) mirrors
24
- # - deletion of the (encrypted) envelope {Open}ed and stuffed with {Put}
25
- # - deletion of {Open}ed session data to locate and decrypt envelope
26
- #
27
- # @example
28
- #
29
- # $ ops seal
30
- #
31
- class Seal < Command
32
-
33
- attr_writer :envelope_path
34
-
35
- # The <tt>lock use case</tt> is called after {OpenSecret::Open} and {OpenSecret::Put}
36
- # and its effect is to dispatch the doubly encrypted materrial to the configured storage
37
- # platform, be it Git, S3, SSH or just an accessible file-system.
38
- #
39
- # <b>Main Flow of Events</b>
40
- #
41
- # To seal the envelope built up by put, file and add amongst others requires
42
- # that we
43
- #
44
- # - get the encrypted envelope
45
- # - create a strong asymmetric key
46
- # - lock the envelope using opensecret's double encrypt modus operandi
47
- # - place the doubly encrypted result into the crypt store
48
- # - lock the asymmetric key again with opensecret's double encrypt modus operandi
49
- # - place the doubly encrypted result into the key store
50
- #
51
- # The second double lock of the crypted envelope is done with the public key
52
- # aspect of an asymmetric key created here.
53
- #
54
- # The second double lock of the crypted private key (created here) is done with
55
- # the master public key created in the {Init.execute} use case main flow.
56
- #
57
- # <b>Lock | Observable Value</b>
58
- #
59
- # The observable value after the lock use case has completed entails
60
- #
61
- # - a doubly encrypted data envelope placed in the backend store
62
- # - a doubly encrypted private key placed in the frontend store
63
- # - both stores sync'd with off-machine Git (S3, ...) mirrors
64
- # - deletion of the (encrypted) envelope {Open}ed and stuffed with {Put}
65
- # - deletion of {Open}ed session data to locate and decrypt envelope
66
- def execute
67
-
68
- instantiate_collateral
69
-
70
- rel_filepath = Mapper::Settings.read @c[:open][:open_name], @c[:open][:open_pathname]
71
- master_public_key = OpenSSL::PKey::RSA.new ( @collateral.read_public_key )
72
-
73
- keys_store = Store::ColdStore.new( @collateral.frontend_keystore_path )
74
- main_store = Store::ColdStore.new( @collateral.backend_cryptstore_path )
75
-
76
- envelope = get_envelope
77
- asym_key = OpenSSL::PKey::RSA.new @c[:global][:bit_key_size]
78
- lockdown = ToolBelt::Cipher.encrypt_it( asym_key.public_key, envelope.to_json )
79
- lockedup = ToolBelt::Cipher.encrypt_it( master_public_key, asym_key.export )
80
-
81
- ##### ###################################### #####
82
- ##### ###################################### #####
83
- ### Now put the CRYPTS into [Cold] Storage ###
84
- ##### ###################################### #####
85
- ##### ###################################### #####
86
-
87
- keys_store.write lockedup, rel_filepath
88
- main_store.write lockdown, rel_filepath
89
-
90
- puts ""
91
- puts "================================================================="
92
- puts "[Lock] => Now DELETE the session files and configured variables."
93
- puts "================================================================="
94
- puts ""
95
-
96
-
97
- end
98
-
99
-
100
- # Perform pre-conditional validations in preparation to executing the main flow
101
- # of events for this use case. This method may throw the below exceptions.
102
- #
103
- # @raise [SafeDirNotConfigured] if the safe's url has not been configured
104
- # @raise [EmailAddrNotConfigured] if the email address has not been configured
105
- # @raise [StoreUrlNotConfigured] if the crypt store url is not configured
106
- def pre_validation
107
-
108
-
109
- end
110
-
111
-
112
- end
113
-
114
-
115
- end
116
-
117
-
118
- #############################################################################################
119
- #############################################################################################
120
-
121
- =begin
122
- GitFlow.do_clone_repo @p[:public_gitrepo], @p[:local_gitrepo]
123
- FileUtils.mkdir_p @p[:public_keydir]
124
- File.write @p[:public_keypath], public_key_text
125
- GitFlow.push @p[:local_gitrepo], @p[:public_keyname], @c[:time][:stamp]
126
- =end
127
-
128
- #############################################################################################
129
- #############################################################################################
@@ -1,245 +0,0 @@
1
- #!/usr/bin/ruby
2
-
3
- module OpenKey
4
-
5
- # If you have a possibly weak human password that you need to either store
6
- # or derive a symmetric encryption key from - you use this digester.
7
- #
8
- # You can safely store the resulting key confident that no known method exists
9
- # of deriving the original password from the key. The digester uses the
10
- # most recent SHA512 bit hashing algorithm - twice - to mince the key into
11
- # something worthless to everyone, but the password originator.
12
- #
13
- # This key digester knows how to apply one-way functions that dessimate a
14
- # (possibly weak) human generated (password) string.
15
- #
16
- # It should be initialized with a nonce like the count of nanoseconds
17
- # since the current second (for low throughput systems).
18
- #
19
- # ==How to Use the Digester
20
- #
21
- # <b><em>Generating the Hashed Key</em></b>
22
- #
23
- # To use the digester you instantiate it with a nonce and then call
24
- # the generate method with a possibly weak human key that is required
25
- # to contain a minimum of 6 characters.
26
- #
27
- # The 6 characters excludes any leading or trailing whitespace.
28
- # keydigester = Digester.new "nonce"
29
- # the_key = keydigester.generate "human_k3y"
30
- # output_iv = keydigester.encrypted_iv
31
- #
32
- # You then read off the encrypted iv (initialization vector).
33
- #
34
- # <b><em>Re-generating the Hashed Key</em></b>
35
- #
36
- # To retrieve the same key (perhaps many moons later), you instantiate
37
- # another Digester providing the same nonce you gave to the generate
38
- # method. You then supply the encrypted iv that you pulled out during
39
- # the generate step.
40
- # keydigester = Digester.new "nonce"
41
- # keydigester.encrypted_iv = "axbxcxdx1x2x3x4x"
42
- # the_key = keydigester.regenerate "human_k3y"
43
- #
44
- # Now when you regenerate the key - you have the original.
45
- #
46
- #
47
- # @example
48
- # keydigester = Digester.new "nonce"
49
- # the_key = keydigester.generate "human_k3y"
50
- # output_iv = keydigester.encrypted_iv
51
- #
52
- # keydigester = Digester.new "nonce"
53
- # keydigester.encrypted_iv = "axbxcxdx1x2x3x4x"
54
- # the_key = keydigester.regenerate "human_k3y"
55
- class Digester
56
-
57
- attr_accessor :encrypted_iv
58
-
59
- # The golden ratio is the relationship between the human password and the
60
- # strengthening amalgam. Two is perhaps too small, three or four is perfect
61
- # to strengthen human generated keys whose median tends to gravitate at
62
- # around 12 characters.
63
- AMALGAM_GOLDEN_RATIO = 3
64
-
65
- # The inner nonce provides a salt of sorts to help with randomizing the
66
- # keys and protecting them from pre-configured rainbow tables.
67
- INNER_NONCE = "9]w/t$=ON@mUf(+_SoY"
68
-
69
- # The minimum length tolerated for the assumed human provided password.
70
- # This number excludes any leading or trailing whitespace which should
71
- # be removed before length examination is performed.
72
- MIN_HUMAN_KEY_LENGTH = 6
73
-
74
-
75
- # Initialize this key digester with a nonce like the count of nanoseconds
76
- # since the current second (for low throughput systems).
77
- #
78
- # Note that the same nonce must be provided in order to produce the same
79
- # key from calling either {Digester.generate} or {Digester.regenerate}.
80
- #
81
- # @param the_nonce [String]
82
- # the nonce can be the count of nanoseconds since the current second
83
- # (for low throughput systems).
84
- #
85
- # @raise [ArgumentError]
86
- # raise an error if the nonce is empty, or consists only of whitespace
87
- # or is too short.
88
- def initialize the_nonce
89
-
90
- @nonce = the_nonce.strip.reverse
91
-
92
- raise ArgumentError, "The nonce contains only whitespace." if @nonce.empty?
93
- raise ArgumentError, "The nonce is too short." if @nonce.length < MIN_HUMAN_KEY_LENGTH
94
-
95
- end
96
-
97
-
98
- # Generate a viciously unretrievable nor reversable string from a possible
99
- # weak key provided by a human being.
100
- #
101
- # Due to the fickle nature of human beings we use an amalgam key to frustrate
102
- # attempts to derive the original through rainbow tables and replay attacks.
103
- #
104
- # <b>Getting the Initialization Vector</b>
105
- #
106
- # After calling this method the encrypted initialization vector generated
107
- # must be stored and re-provided to the {Digester.regenerate} method as
108
- # and when required.
109
- #
110
- # @example
111
- # keydigester = Digester.new "nonce"
112
- # the_key = keydigester.generate "human_k3y"
113
- # output_iv = keydigester.encrypted_iv
114
- #
115
- # @param human_p4ss [String]
116
- #
117
- # the key provided by a human being which cannot be less than six
118
- # characters in length. Between 24 and 32 apparently random characters
119
- # involving upper case letters, digits and punctuators.
120
- #
121
- # Leading and trailing whitespace is removed from the string if found.
122
- #
123
- # @raise [ArgumentError] if the (possibly) human sourced password is too short
124
- def generate human_p4ss
125
-
126
- human_key = human_p4ss.strip.reverse
127
- raise ArgumentError, "The password contains only whitespace." if human_key.empty?
128
- raise ArgumentError, "The password is too short." if human_key.length < MIN_HUMAN_KEY_LENGTH
129
-
130
- machine_key = OpenSecret::ToolBelt::Engineer.machine_key human_key.length, AMALGAM_GOLDEN_RATIO
131
- snippet = human_key[ human_key.length - MIN_HUMAN_KEY_LENGTH .. -1 ]
132
-
133
- iv_key = [ INNER_NONCE, snippet, @nonce ].join
134
- @encrypted_iv = machine_key.encrypt_url_encode( iv_key )
135
-
136
- return hashed_outcome human_key, machine_key
137
-
138
- end
139
-
140
-
141
- # Regenerate the viciously unretrievable nor reversable string that has been
142
- # generated from a possible weak key provided by a human being.
143
- #
144
- # The difference between this and the {Digester.generate} method is that
145
- # the encrypted initialization vector is provided here. This must first be
146
- # decrypted before being fed back into the numerical mincer.
147
- #
148
- # The same nonce must also be provided in the constructor.
149
- #
150
- # <b>Setting the Initialization Vector</b>
151
- #
152
- # Before calling this method the encrypted initialization vector generated
153
- # by the generate method needs to be faithfully returned.
154
- #
155
- # @example
156
- #
157
- # keydigester = Digester.new "nonce"
158
- # keydigester.encrypted_iv = "axbxcxdx1x2x3x4x"
159
- # the_key = keydigester.regenerate "human_k3y"
160
- #
161
- # @param human_p4ss [String]
162
- #
163
- # the key provided by a human being which cannot be less than six
164
- # characters in length. Between 24 and 32 apparently random characters
165
- # involving upper case letters, digits and punctuators.
166
- #
167
- # Leading and trailing whitespace is removed from the string if found.
168
- #
169
- # @raise [ArgumentError]
170
- # If the human sourced password is too short.
171
- # Or if it consists solely of whitespace.
172
- def regenerate human_p4ss
173
-
174
- human_key = human_p4ss.strip.reverse
175
- raise ArgumentError, "The password contains only whitespace." if human_key.empty?
176
- raise ArgumentError, "The password is too short." if human_key.length < MIN_HUMAN_KEY_LENGTH
177
-
178
- snippet = human_key[ human_key.length - MIN_HUMAN_KEY_LENGTH .. -1 ]
179
- iv_key = [ INNER_NONCE, snippet, @nonce ].join
180
- machine_key = @encrypted_iv.url_decode_decrypt( iv_key )
181
-
182
- return hashed_outcome human_key, machine_key
183
-
184
- end
185
-
186
-
187
- # This digester alphanumeric hasher employs the SHA512 digest algorithm
188
- # to gnash the parameter key and then Base64 encode the result.
189
- #
190
- # This method removes any non alpha-numeric characeters after a url safe
191
- # base 64 encoding and thus guarantees that the resultant string will
192
- # not contain
193
- #
194
- # - any equals signs
195
- # - any hyphens
196
- # - any underscores
197
- #
198
- # It is safe to use this method when a result must be stored in environment
199
- # variables or other forms (like INI) where an equals sign is frowned upon.
200
- #
201
- # That said, this method should not be used if one wants to return to the
202
- # pre base64 encoded character sequence. By mashing away the non-alphanums
203
- # it mashes away any realistic hope of a determinant return to the raw
204
- # hashed value.
205
- #
206
- # @param hash_me [String]
207
- # use a one-way function to mush me into a form that is repeatable but
208
- # non-returnable to the original input.
209
- #
210
- # @return [String]
211
- # The SHA512 mashed version of the parameter key which is Base64 encoded
212
- # (using the url safe variant) and the result stripped of any non alpha
213
- # numeric characters.
214
- #
215
- def self.alphanum_hash hash_me
216
- return self.alphanum_encoder( OpenSSL::Digest::SHA512.digest( hash_me ) )
217
- end
218
-
219
-
220
- def self.mash hash_me, max_length
221
- raise ArgumentError, "Max length #{max_length} is unacceptable." if max_length < 32
222
- return self.alphanum_encoder( OpenSSL::Digest::SHA512.digest( hash_me ) )[0 .. (max_length-1)]
223
- end
224
-
225
-
226
- private
227
-
228
-
229
- def self.alphanum_encoder encode_this
230
- return Base64.urlsafe_encode64( encode_this ).delete("=\\-_")
231
- end
232
-
233
-
234
- def hashed_outcome the_human_key, the_machine_key
235
- amalgam_key = OpenSecret::ToolBelt::Amalgam.passwords the_human_key, the_machine_key, AMALGAM_GOLDEN_RATIO
236
- level1_hash = Digester.alphanum_encoder( OpenSSL::Digest::SHA512.digest( amalgam_key ) )
237
- level2_hash = Digester.alphanum_encoder( OpenSSL::Digest::SHA512.digest( @nonce + level1_hash ) )
238
- return level2_hash
239
- end
240
-
241
-
242
- end
243
-
244
-
245
- end