opensecret 0.0.988 → 0.0.9925

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