opensecret 0.0.946 → 0.0.951

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f03e1b5d062560593f42736baf5a2af7794a4c0b
4
- data.tar.gz: ed65d8e10bd446f1413d9e0473b7291ec01f34a6
3
+ metadata.gz: ca35c2727f92f764b83fae65d656062b95520ad6
4
+ data.tar.gz: 260748f11554e881116e6efd8c4d44c0cdb06284
5
5
  SHA512:
6
- metadata.gz: 57989150d89ee5cc20d5950bd008b5bc97f4b23455dc690b66f791d1b3d1330a7550ce888715c73abf4bf43dd4ce80e409202c5393a7b32cc1bc41d75d97e047
7
- data.tar.gz: 842b02b7f3a2fbf99fdd3c9d4acbeeabcf16bed137894cf8d2ad1cc4aed54f6d39975c2d16714e3d8e16eb62bc9271d2a2a60bee2d6bd12c954bfeef0b71cb3b
6
+ metadata.gz: 10f94cba6fe468750401a38846641c9dddce2258601d981b1fb26e5b2e88c7fea27edb10264ee070d3d4920c6ada9470e0a7b4cb3178a5f5c2a07facb186db1a
7
+ data.tar.gz: 35aa0ff66488c53859c245c10ba2d3aae348b56df4df90d94963241b190b8065f39f20bbfb63c119159f25488b8262f69f847fd1a3e715d3fe8df13954cbc921
@@ -20,7 +20,7 @@ module OpenSecret
20
20
  # --
21
21
  def self.machine_key human_password_length, mix_ratio
22
22
 
23
- machine_raw_secret = engineer_password( human_password_length * ( mix_ratio + 1) )
23
+ machine_raw_secret = strong_key( human_password_length * ( mix_ratio + 1) )
24
24
  return machine_raw_secret[ 0..( human_password_length * mix_ratio - 1 ) ]
25
25
 
26
26
  end
@@ -30,7 +30,7 @@ module OpenSecret
30
30
  # -- Engineer a raw password that is similar (approximate) in
31
31
  # -- length to the integer parameter.
32
32
  # --
33
- def self.engineer_password approx_length
33
+ def self.strong_key approx_length
34
34
 
35
35
  non_alphanum = SecureRandom.urlsafe_base64(approx_length);
36
36
  return non_alphanum.delete("-_")
@@ -39,12 +39,24 @@ module OpenSecret
39
39
 
40
40
 
41
41
 
42
- # --
43
- # -- Get a viable machine password taking into account the human
44
- # -- password length and the specified mix_ratio.
45
- # --
46
- # -- machine password length = human password length * mix_ratio - 1
47
- # --
42
+ # Amalgamate the parameter passwords using a specific mix ratio. This method
43
+ # produces cryptographically stronger secrets than algorithms that simply
44
+ # concatenate two string keys together. If knowledge of one key were gained, this
45
+ # amalgamation algorithm still provides extremely strong protection even when
46
+ # one of the keys has a single digit length.
47
+ #
48
+ # This +length constraint formula+ binds the two input strings together with
49
+ # the integer mix ratio.
50
+ #
51
+ # <tt>machine password length = human password length * mix_ratio - 1</tt>
52
+ #
53
+ # @param human_password [String] the first password (shorter one) to amalgamate
54
+ # @param machine_password [String] the second password (longer one) to amalgamate
55
+ # @param mix_ratio [Fixnum] the mix ratio that must be respected by the
56
+ # previous two parameters.
57
+ # @return [String] an amalgamated (reproducible) union of the 2 parameter passwords
58
+ #
59
+ # @raise [ArgumentError] if the length constraint assertion does not hold true
48
60
  def self.get_amalgam_password human_password, machine_password, mix_ratio
49
61
 
50
62
  size_error_msg = "Human pass length times mix_ratio must equal machine pass length."
@@ -57,6 +57,27 @@ class String
57
57
  end
58
58
 
59
59
 
60
+ # To hex converts this string to hexadecimal form and returns
61
+ # the result leaving this string unchanged.
62
+ # @return [String] hexadecimal representation of this string
63
+ def to_hex
64
+
65
+ return self.unpack("H*").first
66
+
67
+ end
68
+
69
+
70
+ # From hex converts this (assumed) hexadecimal string back into
71
+ # its normal string form and returns the result leaving this string
72
+ # unchanged.
73
+ # @return [String] string that matches the hexadecimal representation
74
+ def from_hex
75
+
76
+ return [self].pack("H*")
77
+
78
+ end
79
+
80
+
60
81
  # Flatten (lower) a camel cased string and add periods to
61
82
  # denote separation where the capital letters used to be.
62
83
  #
@@ -78,11 +99,30 @@ class String
78
99
  # - in => BEAST
79
100
  # - out => b.e.a.s.t
80
101
  #
102
+ # == Flatten Class Names
103
+ #
104
+ # If the string comes in as a class name we can expect it to
105
+ # contain colons like the below examples.
106
+ # This::That
107
+ # ::That
108
+ # This::That::TheOther
109
+ #
110
+ # So we find the last index of a colon and then continue as per
111
+ # the above with flattening the string.
112
+ #
81
113
  # @return [String] a flatten (period separated) version of this camel cased string
82
114
  def do_flatten
83
115
 
116
+ to_flatten_str = self
117
+
118
+ last_colon_index = to_flatten_str.rindex ":"
119
+ ends_with_colon = to_flatten_str[-1].eql? ":"
120
+ unless ( last_colon_index.nil? || ends_with_colon )
121
+ to_flatten_str = to_flatten_str[ (last_colon_index+1) .. -1 ]
122
+ end
123
+
84
124
  snapped_str = ""
85
- self.each_char do |this_char|
125
+ to_flatten_str.each_char do |this_char|
86
126
  is_lower = "#{this_char}".is_all_lowercase?
87
127
  snapped_str += "." unless is_lower || snapped_str.empty?
88
128
  snapped_str += this_char.downcase
@@ -1,6 +1,7 @@
1
1
 
2
2
  [global]
3
3
 
4
+ name = opensecret
4
5
  min.passwd.len = rb>> 6
5
6
  nickname = godzilla
6
7
  root.domain = devopswiki.co.uk
@@ -8,21 +9,31 @@ env.var.name = SECRET_MATERIAL
8
9
  ratio = rb>> 3
9
10
  bit.key.size = rb>> 8192
10
11
  key.cipher = rb>> OpenSSL::Cipher.new 'AES-256-CBC'
11
- secret.keyname = master.private.key.crypt.txt
12
- secret.keydir = rb>> OpenSession::Attributes.instance.get_value "opensecret", "safe"
13
- secret.keypath = rb>> File.join @s[:secret_keydir], @s[:secret_keyname]
12
+ secret.keydir = rb>> OpenSession::Attributes.instance.get_value @s[:name], "safe"
13
+ email.address = rb>> OpenSession::Attributes.instance.get_value @s[:name], "email"
14
+ safe.user = rb>> File.join @s[:secret_keydir], @s[:email_address]
15
+ master.dirname = master.keys
16
+ master.dirpath = rb>> File.join @s[:safe_user], @s[:master_dirname]
17
+ master.pub.name = master.public.key.x.os.txt
18
+ master.prv.name = master.private.key.x.os.txt
19
+ master.pub.key = rb>> File.join @s[:master_dirpath], @s[:master_pub_name]
20
+ master.prv.key = rb>> File.join @s[:master_dirpath], @s[:master_prv_name]
14
21
 
15
- repo.name = material_data
16
-
17
- ## local.gitrepo = rb>> File.join @i[:dir], @s[:repo_name]
22
+ machine.key.x = machine.key.x
23
+ separator.a = %$os$%
18
24
 
19
- ## public.gitrepo = https://www.eco-platform.co.uk/content/material.data.git
20
- ## public.dirname = public_keys
21
- ## public.keyroute = rb>> File.join @s[:root_domain], @s[:public_dirname]
22
- ## public.keydir = rb>> File.join @s[:local_gitrepo], @s[:public_keyroute]
23
- ## public.keyname = rb>> "public_key." + @s[:nickname] + dot + @s[:root_domain] + ".txt"
24
- ## public.keypath = rb>> File.join @s[:public_keydir], @s[:public_keyname]
25
+ repo.name = material_data
25
26
 
26
27
  prompt.1 = Enter a Robust Password
27
28
  prompt.2 = Re-enter that Password
28
29
 
30
+ [open]
31
+
32
+ open.name = session
33
+ open.dirname = session.material
34
+ open.dirpath = rb>> File.join @f[:global][:safe_user], @s[:open_dirname]
35
+ open.idlen = 9
36
+ open.keylen = 96
37
+ open.idname = session.id
38
+ open.keyname = session.key
39
+ open.pathname = session.path
@@ -6,9 +6,87 @@
6
6
  ## Trial and Error Scratch-Pad ##
7
7
  ## ########################### ##
8
8
 
9
- x = "messagess"
10
9
 
11
- x += "x" until x.bytesize % 8 == 0
10
+ class Trial
12
11
 
13
- puts "Now x string is [#{x}]."
14
- puts "x is now [#{x.length}] characters long."
12
+
13
+ def self.crypt
14
+
15
+ require 'openssl'
16
+ require "base64"
17
+
18
+ key = OpenSSL::PKey::RSA.new(8192)
19
+
20
+
21
+ payload = "55fff4c5895bb247676c6edd2307f17c665305457b3bcfcd985c398246b8780f54e337252c5407afd4895a5e3a2415fce5b703a483da3edc88739cb7787262a19d69fb9416f900fed797c046aaec83b8e15b14edb032ed76535def8ada77108936e5442a839d4078048ca01449a6acd7315c9b7a7b8802dba0c83eb4c13e21b1051efa77a420a3ffd3cbf1fa13182933a0503f23cce95b68787081f3af33c69049657bdbf1fd30d79f108d604faad1fbee198a3e2c1b28cdddf7ebb84b6b0c1d3e9b47665bd96d7df8407e11d00e4d9275e805c7b9e61b6739802d6d87ac8283ef92a593ed53db2096cd1dc9496307f40942cc3d54a7c864ede71e0b192ce152"
22
+
23
+ puts ""
24
+ puts "Payload size is #{payload.length}"
25
+ puts ""
26
+ puts ""
27
+ puts encrypted_string = key.public_encrypt( payload, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)
28
+ puts ""
29
+ puts base64text = Base64.encode64(encrypted_string)
30
+ puts ""
31
+ puts signature = key.sign(OpenSSL::Digest::SHA256.new, payload )
32
+ puts ""
33
+ puts hex_data = signature.unpack("H*").first
34
+ puts ""
35
+ puts "Length is #{hex_data.length}"
36
+ puts ""
37
+ puts key.public_key.verify(OpenSSL::Digest::SHA256.new, signature, payload)
38
+ puts ""
39
+ puts encrypted_string.unpack("H*").first
40
+ puts ""
41
+ puts key.private_decrypt(encrypted_string, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)
42
+ puts ""
43
+
44
+
45
+ end
46
+
47
+ =begin
48
+ ddGKDqfhF6HnkJuIdTECZk7J7E9xx9LiYRDywCdIuDxYQQs+if+3qxP37+ah
49
+ HwGYgjxpIjqS9slhLOveVexSeHUD4DCbjHW2AlMsaUxwoSY0UfgzrO+2LDG9
50
+ tyizUYA6n8a+vBzJqRFP2BW7/AxwP0jm0yADWwBOGFL1+g==
51
+
52
+ <-|@| < || opensecret outer crypt material axis || > |@|->
53
+
54
+ HNkUjWaFoI5dPTRUUymyf7uKMaXFhiIZaOq+ZYj4TWPN92qv6ANTd3pRvVa3
55
+ S+aQSOX7q3FkKIOc5yfWLushGAMSwidgH1kzLvocCf+SSWH5BY3zTb7NAGjW
56
+ =end
57
+
58
+ ### Trial.crypt
59
+ ### exit
60
+
61
+ def try
62
+
63
+ require "pp"
64
+ require "inifile"
65
+ new_map = { "string1" => "value1", "string2" => "value2" }
66
+
67
+ ini_pairs = IniFile.new
68
+ ini_pairs["dictionary"] = new_map
69
+
70
+ puts ""
71
+ puts ini_pairs.to_s
72
+ puts ""
73
+
74
+
75
+ puts "--------------------"
76
+ puts new_map
77
+ puts "--------------------"
78
+ puts "#{pp new_map}"
79
+ puts "--------------------"
80
+ puts "#{new_map.to_s}"
81
+ puts "--------------------"
82
+ puts ""
83
+
84
+ ## x = "messagess"
85
+ ## x += "x" until x.bytesize % 8 == 0
86
+
87
+ ## puts "Now x string is [#{x}]."
88
+ ## puts "x is now [#{x.length}] characters long."
89
+
90
+ end
91
+
92
+ end
@@ -54,6 +54,16 @@ class CliInterpreter < Thor
54
54
  end
55
55
 
56
56
 
57
+ # Description of the open "wake-up" call.
58
+ desc "open", "open up a conduit for adding, subtracting and swapping secrets for a future commit."
59
+
60
+ # Open up a conduit from which we can add, subtract, update and list secrets
61
+ # before they are committed (and pushed) into permanent locked storage.
62
+ def open
63
+ OpenSecret::Open.new.flow_of_events
64
+ end
65
+
66
+
57
67
  # Description of the mandatory safe and (safe directory) configuration.
58
68
  desc "safe SAFE_DIR", "SAFE_DIR full path to the (ideally USB key) storage location"
59
69
 
@@ -50,7 +50,7 @@ module OpenSecret
50
50
  # - <tt>do_symmetric_encryption(plain_text)</tt> - resulting in ciphertext
51
51
  # - <tt>do_symmetric_decryption(ciphertext, encryption_dictionary)</tt> &raquo; plaintext
52
52
  #
53
- # and also set the <tt>@encryption_dictionary</tt> hash (map) of pertinent
53
+ # and also set the <tt>@dictionary</tt> hash (map) of pertinent
54
54
  # key/value pairs including the encryption algorithm, the encryption key and
55
55
  # the ciphertext signature to thwart any at-rest tampering.
56
56
  #
@@ -84,9 +84,36 @@ module OpenSecret
84
84
  #
85
85
  TEXT_PADDER = "<-|@|->"
86
86
 
87
+
88
+ # An unusual string that glues together an encryption dictionary and
89
+ # a chunk of base64 encoded and encrypted ciphertext.
90
+ # The string must be unusual enough to ensure it dos not occur within
91
+ # the dictionary metadata keys or values.
92
+ INNER_GLUE_STRING = "\n<-|@| < || opensecret inner crypt material axis || > |@|->\n\n"
93
+
94
+
95
+ # An unusual string that glues together the asymmetrically encrypted outer
96
+ # encryption key with the outer crypted text.
97
+ OUTER_GLUE_STRING = "\n<-|@| < || opensecret outer crypt material axis || > |@|->\n\n"
98
+
99
+
100
+ # Text header for key-value pairs hash map that will be serialized.
101
+ DICTIONARY = "dictionary"
102
+
103
+
87
104
  @@symmetric_cipher_keyname = "symmetric.cipher"
88
105
  @@encryption_key_keyname = "encryption.key"
89
- @@cipher_signature_keyname = "cipher.signature"
106
+ @@payload_signature_keyname = "payload.signature"
107
+
108
+
109
+ # The cipher constructor instantiates the encryption dictionary which
110
+ # will be collaboratively added to by the parent and child ciphers.
111
+ def initialize
112
+
113
+ @dictionary = {}
114
+
115
+ end
116
+
90
117
 
91
118
  # Ciphers use +symmetric algorithms+ to encrypt the given text, which
92
119
  # is then wrapped up along with the encryption key and other +metadata+
@@ -103,15 +130,55 @@ module OpenSecret
103
130
  # Every component in the pipeline bears the responsibility for nullifying
104
131
  # and rejecting malicious content.
105
132
  #
106
- # @param public_key [String] used for encrypting the key/metadata bundle
107
- # @param plain_text [String] the plain (or base64 encoded) text to encrypt
133
+ # @param public_key_text [String] textual portion of an {OpenSSL::PKey::RSA}
134
+ # public key that does not carry the private key as this method and its
135
+ # compatriots do not need to know the private key to do their work.
136
+ #
137
+ # @param payload_text [String] plaintext (or base64 encoded) text to encrypt
138
+ # @param payload_signature [String] signature of payload verifiable with public key
108
139
  #
109
140
  # @return [String] doubly (symmetric and asymmetric) encrypted cipher text
110
- def encrypt_it public_key, plain_text
141
+ def encrypt_it public_key_text, payload_text, payload_signature
142
+
143
+ asymmetric_key = OpenSSL::PKey::RSA.new public_key_text
144
+
145
+ signature_valid = asymmetric_key.verify(
146
+ OpenSSL::Digest::SHA256.new,
147
+ payload_signature,
148
+ payload_text
149
+ )
111
150
 
112
- symmetric_ciphertext = do_symmetric_encryption plain_text
113
- plain_paraphernalia = glue @encryption_dictionary, symmetric_ciphertext
114
- return do_asymmetric_encryption public_key, plain_paraphernalia
151
+ raise ArgumentError, "Payload not verified by the signature." unless signature_valid
152
+ @dictionary[@@payload_signature_keyname] = payload_signature.to_hex
153
+ crypted_payload = do_symmetric_encryption payload_text
154
+
155
+ unified_material = unify_hash_and_text crypted_payload
156
+ blowfish_cryptor = Blowfish.new
157
+ outer_crypt_key = OpenSecret::Engineer.strong_key( 128 )
158
+ crypted_material = blowfish_cryptor.do_encrypt_with_key unified_material, outer_crypt_key
159
+ crypted_cryptkey = do_asymmetric_encryption public_key_text, outer_crypt_key
160
+ locked_up_string = unify_text_and_text crypted_cryptkey, crypted_material
161
+
162
+ return locked_up_string
163
+
164
+ end
165
+
166
+
167
+ # Thismethod takes the textual public key lacking the private key portion
168
+ # as it is not needed, and encrypts the secret text with it.
169
+ # It returns a Base64 encoded version of they encrypted text.
170
+ #
171
+ # The public key text must be compatible with {OpenSSL::PKey::RSA} as the
172
+ # class will be instantiated using the public key text.
173
+ #
174
+ # @param public_key_text [String] the textual portion of an RSA public key
175
+ # @param secret_text [String] secret text to encrypt with the public key
176
+ #
177
+ # @return [String] a Base64 encoded version of the encrypted secret text
178
+ def do_asymmetric_encryption public_key_text, secret_text
179
+
180
+ asymmetric_encrypt_key = OpenSSL::PKey::RSA.new public_key_text
181
+ Base64.encode64( asymmetric_encrypt_key.public_encrypt( secret_text[0..1012] ) )
115
182
 
116
183
  end
117
184
 
@@ -140,6 +207,62 @@ module OpenSecret
140
207
  end
141
208
 
142
209
 
210
+ # Serialize and then unite a hash map and a textual chunk using
211
+ # a known but unusual separator string in a manner that protects
212
+ # the content integrity during the serialize and extraction phases.
213
+ #
214
+ # == Why an Unusual Separator String
215
+ #
216
+ # The separator string must be unusual to make it unlikely for it
217
+ # to occur in any of the map's key value pairs nor indeed the chunk
218
+ # of text being glued. Were this to happen, the separate and reconstitute
219
+ # phase may not accurately return the same two entities we are employed
220
+ # to unite.
221
+ #
222
+ # == Hash (Map) Contents
223
+ #
224
+ # The map contents will effectively be serialized in a simplistic
225
+ # manner therefore the keys should all be strings and the value
226
+ # types restricted to
227
+ #
228
+ # - strings
229
+ # - integers and/or floating point numbers
230
+ # - booleans
231
+ #
232
+ # Binary text is not allowed neither in the map or the text chunk.
233
+ # Any binary should be base64 encoded before being passed to us.
234
+ #
235
+ # @param text_chunk [String] the text chunk to be glued at the bottom
236
+ #
237
+ # @return [String] serialized and glued together result of map plus text
238
+ def unify_hash_and_text text_chunk
239
+
240
+ nil_or_empty_hash = @dictionary.nil? || @dictionary.empty?
241
+ raise ArgumentError, "Cannot unify nil or empty metadata." if nil_or_empty_hash
242
+
243
+ ini_map = IniFile.new
244
+ ini_map[ DICTIONARY ] = @dictionary
245
+
246
+ return ini_map.to_s + INNER_GLUE_STRING + text_chunk
247
+
248
+ end
249
+
250
+
251
+
252
+ # Using an outer divider (glue) - attach the asymmetrically encrypted outer
253
+ # encryption key with the outer encrypted text.
254
+ #
255
+ # @param crypt_material_x [String] asymmetrically encrypted (encoded) outer encryption key
256
+ # @param crypt_material_y [String] symmetrically encrypted inner metadata and payload crypt
257
+ #
258
+ # @return [String] concatenated result of the two crypt materials and divider string
259
+ def unify_text_and_text crypt_material_x, crypt_material_y
260
+
261
+ return crypt_material_x + OUTER_GLUE_STRING + crypt_material_y
262
+
263
+ end
264
+
265
+
143
266
 
144
267
  def encrypt_usecase public_key, secret_path, stores, plain_text
145
268
 
@@ -28,7 +28,7 @@ module OpenSecret
28
28
  # - <tt>do_symmetric_encryption(plain_text)</tt> - resulting in ciphertext
29
29
  # - <tt>do_symmetric_decryption(ciphertext, encryption_dictionary)</tt> &raquo; plaintext
30
30
  #
31
- # and it also sets the <tt>@encryption_dictionary</tt> hash (map) of pertinent
31
+ # and it also sets the <tt>@dictionary</tt> hash (map) of pertinent
32
32
  # key/value pairs including the +encryption algorithm+ and +encryption key+.
33
33
  #
34
34
  # That's It. Cipher children can rely on the {OpenSecret::Cipher} parent to
@@ -41,7 +41,7 @@ module OpenSecret
41
41
  # Use the AES 256 bit block cipher and a robust strong random key plus
42
42
  # initialization vector (IV) to symmetrically encrypt the plain text.
43
43
  #
44
- # Add these key/value pairs to @encryption_dictionary instance map.
44
+ # Add these key/value pairs to @dictionary instance map.
45
45
  #
46
46
  # - <tt>symmetric.cipher</tt> - the algorithm used to encrypt and decrypt
47
47
  # - <tt>encryption.key</tt> - hex encoded key for encrypting and decrypting
@@ -54,15 +54,13 @@ module OpenSecret
54
54
  @cipher_name = "aes-256-cbc"
55
55
 
56
56
  crypt_cipher = OpenSSL::Cipher.new @cipher_name
57
- crypt_cipher.encrypt( plain_text )
57
+ crypt_cipher.encrypt
58
58
 
59
- @encryption_dictionary = {
60
- @@symmetric_cipher_keyname => @cipher_name,
61
- @@encryption_key_keyname => crypt_cipher.random_key.unpack("H*").first,
62
- @@initialize_vector_keyname => crypt_cipher.random_iv.unpack("H*").first
63
- }
59
+ @dictionary[@@symmetric_cipher_keyname] = @cipher_name
60
+ @dictionary[@@encryption_key_keyname] = crypt_cipher.random_key.to_hex
61
+ @dictionary[@@initialize_vector_keyname] = crypt_cipher.random_iv.to_hex
64
62
 
65
- Base64.encode64( crypt_cipher.update + crypt_cipher.final )
63
+ return Base64.encode64( crypt_cipher.update( plain_text ) + crypt_cipher.final )
66
64
 
67
65
  end
68
66
 
@@ -73,7 +71,7 @@ module OpenSecret
73
71
  #
74
72
  # == Pre-Condition | Encryption Dictionary
75
73
  #
76
- # This method requires the <tt>@encryption_dictionary</tt> instance
74
+ # This method requires the <tt>@dictionary</tt> instance
77
75
  # variable to have been set and to contain (amongst others)
78
76
  #
79
77
  # - the <tt>encryption.key</tt> - hex encoded key for encrypting and decrypting
@@ -24,7 +24,7 @@ module OpenSecret
24
24
 
25
25
 
26
26
  # This method provides the Blowfish algorithm but we reserve the
27
- # right to enforce upon it - an encryption key of our choosing.
27
+ # right to enforce upon it an encryption key of our choosing.
28
28
  #
29
29
  # The key length need not be a multiple of 8 - however it is advisable
30
30
  # to use {Digest::SHA256.digest} to produce a strong 32 character key.
@@ -68,13 +68,13 @@ module OpenSecret
68
68
  log.info(x) { "os blowfish request to encrypt plain text with provided key." }
69
69
 
70
70
  block_txt = plain_text
71
- block_txt += ::Cipher::TEXT_PADDER until block_txt.bytesize % OpenSecret::Blowfish::BLOWFISH_BLOCK_LEN == 0
71
+ block_txt += OpenSecret::Cipher::TEXT_PADDER until block_txt.bytesize % OpenSecret::Blowfish::BLOWFISH_BLOCK_LEN == 0
72
72
  raw_stretched_key = Digest::SHA256.digest(encryption_key)
73
73
 
74
74
  blowfish_encryptor = OpenSSL::Cipher.new(OpenSecret::Blowfish::BLOWFISH_CIPHER_ID).encrypt
75
75
  blowfish_encryptor.key = raw_stretched_key
76
76
 
77
- Base64.encode64( blowfish_encryptor.update(block_txt) << blowfish_encryptor.final )
77
+ return Base64.encode64( blowfish_encryptor.update(block_txt) << blowfish_encryptor.final )
78
78
 
79
79
  end
80
80
 
@@ -51,14 +51,13 @@ module OpenSession
51
51
 
52
52
  pre_validation
53
53
 
54
- rescue OpenError::Error => e
54
+ rescue OpenError::CliError => e
55
55
 
56
56
  puts ""
57
57
  puts "Your command did not complete successfully."
58
58
  puts "Pre validation checks failed."
59
59
  puts ""
60
60
  puts " => #{e.message}"
61
- #### puts " => #{e.culprit}"
62
61
  puts ""
63
62
  abort e.message
64
63
  end
@@ -80,7 +79,7 @@ module OpenSession
80
79
 
81
80
  post_validation
82
81
 
83
- rescue OpenError::Error => e
82
+ rescue OpenError::CliError => e
84
83
 
85
84
  puts ""
86
85
  puts "Your command did not complete successfully."
@@ -197,6 +196,7 @@ module OpenSession
197
196
  return if is_pre_init_usecase
198
197
 
199
198
  @ucid_str = self.class.name.do_flatten
199
+ log.info(x) { "Usecase class [self.class.name] converted to => #{@ucid_str}" }
200
200
  @ucid_sym = @ucid_str.gsub(".", "_").to_sym
201
201
 
202
202
  OpenSession::FactFind.instance.instantiate @ucid_str
@@ -204,9 +204,12 @@ module OpenSession
204
204
 
205
205
  @c = OpenSession::FactFind.instance.f
206
206
  @i = OpenSession::FactFind.instance.i
207
- @p = OpenSession::FactFind.instance.f[@ucid_str]
207
+ @p = OpenSession::FactFind.instance.f[@ucid_sym]
208
+
209
+ log.info(x) { "assimilated [#{@p.length}] facts specific to the [#{@ucid_str}] use case." }
208
210
 
209
211
  @time_stamp = OpenSession::Stamp.instance
212
+
210
213
  =begin
211
214
  @eco_id_str = SnapFlat.do self.class.name
212
215
  @eco_id_sym = @eco_id_str.gsub(".", "_").to_sym
@@ -48,22 +48,24 @@ module OpenSecret
48
48
  # So in preparation to execute its modus operandi encryption,
49
49
  # decryption and (if required) transportation use cases opensecret will
50
50
  #
51
+ # - @todo copy the attributes file to the safestore AND delete it.
51
52
  # - +collect the human password+ (twice), verify robustness (and throw away asap)
52
53
  # - +manufacture workstation key+ that will be encrypted b4 it rests on machine
53
54
  # - +create amalgamated human/workstation password+ for locking the private key
54
55
  # - +create a long cryptographically strong symmetric encryption key+
55
56
  # - +encrypt workstation key+ into <tt>.opensecret/<email>/workstation.key.osx.txt</tt>
56
-
57
57
  # - +encrypt workstation encryption key+ with human password and email address
58
- # - then write into <tt>safe</tt> under <tt>machine.password.key.cipher.txt</tt>
58
+ # - then write into the workstation opensecret config file under <tt>machine.key.crypt</tt>
59
+ # - @todo write machine.key.cipher copy the attributes file to the safestore AND delete it.
59
60
  # - +create a super 8,192 bit private/public key pair+
60
- # - use +amalgamated password to encrypt the private key+
61
- # - write to <tt><SAFE>/<email>/master.keys/master.private.key.crypt.txt</tt>
61
+ # - use +amalgamated password with AES 256 RSA to encrypt the private key+
62
+ # - write to <tt><SAFE>/<email>/master.keys/master.private.key.x.os.txt</tt>
63
+ # - use the +amalgamated password with Blowfish to encrypt the public key+
64
+ # - write to <tt><SAFE>/<email>/master.keys/master.public.key.x.os.txt</tt>
65
+
62
66
  # - +create robust salt+ for hashing the path to the (crypted) keys and ciphers
63
67
  # - use +public key to encrypt the salt+
64
68
  # - write crypted salt to <tt><SAFE>/<email>/master.keys/master.path.salt.crypt.txt</tt>
65
- # - now +use the public key to encrypt itself+
66
- # - write public key crypt to <tt><SAFE>/<email>/master.keys/master.public.key.crypt.txt</tt>
67
69
  # - +create the cryptographic keystore+ inside the safe
68
70
  #
69
71
  # Variables should be first zeroed and then deleted immediately after their last use.
@@ -105,32 +107,47 @@ module OpenSecret
105
107
  amalgam_key = Amalgam.passwords human_password, machine_key, @c[:global][:ratio]
106
108
  asymmetric_keys = OpenSSL::PKey::RSA.new @c[:global][:bit_key_size]
107
109
  secured_keytext = asymmetric_keys.export @c[:global][:key_cipher], amalgam_key
108
- public_key_text = asymmetric_keys.public_key.to_pem
109
110
 
110
- machine_key_crypt_key = human_password + "%$os$%" + @email_addr
111
+ machine_key_crypt_key = human_password + @c[:global][:separator_a] + @email_addr
111
112
  blowfish_cipher = OpenSecret::Blowfish.new()
112
- machine_key_crypted = blowfish_cipher.do_encrypt_with_key machine_key, machine_key_crypt_key
113
+ machine_key_x = blowfish_cipher.do_encrypt_with_key machine_key, machine_key_crypt_key
114
+
115
+ OpenSession::Attributes.stash @c[:global][:name], @c[:global][:machine_key_x], machine_key_x
116
+ FileUtils.mkdir_p @c[:global][:master_dirpath]
117
+ File.write @c[:global][:master_prv_key], secured_keytext
118
+
119
+ public_key_text = asymmetric_keys.public_key.to_pem
120
+ public_key_crypt = Blowfish.new.do_encrypt_with_key public_key_text, amalgam_key
121
+ File.write @c[:global][:master_pub_key], public_key_crypt
122
+
123
+ payload_signature = asymmetric_keys.sign( OpenSSL::Digest::SHA256.new, public_key_text )
124
+
125
+ big_crypted_block = Aes256.new.encrypt_it(
126
+ public_key_text,
127
+ public_key_text,
128
+ payload_signature
129
+ )
113
130
 
114
131
  puts ""
115
- puts "public key => #{public_key_text}"
116
- puts "Carry on development in init.rb"
132
+ puts "=============="
133
+ puts "Crypted Block"
134
+ puts "=============="
117
135
  puts ""
118
- puts "Machine Key Plain Text => #{machine_key}"
119
- puts "Machine Key Crypt Key => #{machine_key_crypt_key}"
120
- puts "Machine Key Cipher Text => #{machine_key_crypted}"
136
+ puts "#{big_crypted_block}"
137
+ puts ""
138
+ puts ""
139
+ puts "Carry on development in init.rb"
121
140
  puts ""
122
- exit
123
-
124
141
 
125
- Dir.mkdir @p[:secret_keydir] unless File.exists? @p[:secret_keydir]
126
- File.write @p[:secret_keypath], secured_keytext
127
142
 
143
+ =begin
128
144
  Crypto.print_secret_env_var @p[:env_var_name], machine_key
129
-
130
145
  GitFlow.do_clone_repo @p[:public_gitrepo], @p[:local_gitrepo]
131
146
  FileUtils.mkdir_p @p[:public_keydir]
132
147
  File.write @p[:public_keypath], public_key_text
133
148
  GitFlow.push @p[:local_gitrepo], @p[:public_keyname], @c[:time][:stamp]
149
+ =end
150
+
134
151
 
135
152
  # exit
136
153
  # key4_pem = File.read 'private.secure.pem'
@@ -142,7 +159,6 @@ module OpenSecret
142
159
  # print decrypted_text, "\n"
143
160
 
144
161
 
145
-
146
162
  end
147
163
 
148
164
 
@@ -0,0 +1,177 @@
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 and list
8
+ # the secrets in a file (whether it exists or not). The file can then be locked.
9
+ # Lookout for the reopen command.
10
+ #
11
+ # If the file to open already exists a --with option (giving the master-secret)
12
+ # must be provided.
13
+ #
14
+ # == Observable Value
15
+ #
16
+ # $ opensecret open home/wifi
17
+ #
18
+ # The observable value delivered by +[open]+ boils down to
19
+ #
20
+ # - an openkey (eg asdfx1234) and corresponding open encryption key
21
+ # - open encryption key written to <tt>~/.opensecret/open.keys/asdfx1234.x.txt</tt>
22
+ # - the opened path (ending in filename) written to session.cache base in [safe]
23
+ # - the INI string (were the file to be decrypted) would look like the below
24
+ #
25
+ # [session]
26
+ # base.path = home/wifi
27
+ #
28
+ class Open < OpenSession::UseCase
29
+
30
+ @@context_name = "opensecret"
31
+
32
+ # Execute the <tt>open use case</tt> activities which precedes the ability to
33
+ # to add (put), subtract (del)ete and list the secrets into the opened session file.
34
+ # The file can then be locked (committed and pushed to permanent crypted stores).
35
+ #
36
+ # If the file to open already exists a --with option (giving the master-secret)
37
+ # must be provided.
38
+ #
39
+ # == Observable Value
40
+ #
41
+ # $ opensecret open home/wifi
42
+ #
43
+ # The observable value delivered by +[open]+ boils down to
44
+ #
45
+ # - a provisioned openkey (eg asdfx1234) and corresponding open encryption key
46
+ # - open encryption key written to <tt>~/.opensecret/open.keys/asdfx1234.x.txt</tt>
47
+ # - the opened path (ending in filename) written to session.cache base in [safe]
48
+ # - the INI string (were the file to be decrypted) would look like the below
49
+ #
50
+ # [session]
51
+ # base.path = home/wifi
52
+ #
53
+ # @example
54
+ # home/wifi can be simply populated like this.
55
+ #
56
+ # $ opensecret put bt/ssid g034gdf3455
57
+ # $ opensecret put bt/password HRAsyf324g4DF
58
+ #
59
+ # $ opensecret put virgin.media/ssid 345SDFS
60
+ # $ opensecret put virgin.media/password HlksHRd043NjPO
61
+ #
62
+ # $ opensecret file virgin.media/contract /home/joe/downloads/vm.contract.pdf
63
+ #
64
+ # To encrypt (lock-down) these secrets we simply issue
65
+ #
66
+ # $ opensecret close
67
+ #
68
+ def execute
69
+
70
+ FileUtils.mkdir_p @p[:open_dirpath]
71
+ open_id = Engineer.strong_key @p[:open_idlen]
72
+ open_key = Engineer.strong_key @p[:open_keylen]
73
+
74
+ OpenSession::Attributes.stash @p[:open_name], @p[:open_idname], open_id
75
+ OpenSession::Attributes.stash @p[:open_name], @p[:open_keyname], open_key
76
+ OpenSession::Attributes.stash @p[:open_name], @p[:open_pathname], open_path
77
+
78
+
79
+ exit
80
+
81
+
82
+ human_password = Collect.secret_text(
83
+ @c[:global][:min_passwd_len],
84
+ true,
85
+ @c[:global][:prompt_1],
86
+ @c[:global][:prompt_2]
87
+ )
88
+
89
+ machine_key = Engineer.machine_key human_password.length, @c[:global][:ratio]
90
+ amalgam_key = Amalgam.passwords human_password, machine_key, @c[:global][:ratio]
91
+ asymmetric_keys = OpenSSL::PKey::RSA.new @c[:global][:bit_key_size]
92
+ secured_keytext = asymmetric_keys.export @c[:global][:key_cipher], amalgam_key
93
+
94
+ machine_key_crypt_key = human_password + @c[:global][:separator_a] + @email_addr
95
+ blowfish_cipher = OpenSecret::Blowfish.new()
96
+ machine_key_x = blowfish_cipher.do_encrypt_with_key machine_key, machine_key_crypt_key
97
+
98
+ OpenSession::Attributes.stash @c[:global][:name], @c[:global][:machine_key_x], machine_key_x
99
+ FileUtils.mkdir_p @c[:global][:master_dirpath]
100
+ File.write @c[:global][:master_prv_key], secured_keytext
101
+
102
+ public_key_text = asymmetric_keys.public_key.to_pem
103
+ public_key_crypt = Blowfish.new.do_encrypt_with_key public_key_text, amalgam_key
104
+ File.write @c[:global][:master_pub_key], public_key_crypt
105
+
106
+ payload_signature = asymmetric_keys.sign( OpenSSL::Digest::SHA256.new, public_key_text )
107
+
108
+ big_crypted_block = Aes256.new.encrypt_it(
109
+ public_key_text,
110
+ public_key_text,
111
+ payload_signature
112
+ )
113
+
114
+ puts ""
115
+ puts "=============="
116
+ puts "Crypted Block"
117
+ puts "=============="
118
+ puts ""
119
+ puts "#{big_crypted_block}"
120
+ puts ""
121
+ puts ""
122
+ puts "Carry on development in init.rb"
123
+ puts ""
124
+
125
+
126
+ =begin
127
+ Crypto.print_secret_env_var @p[:env_var_name], machine_key
128
+ GitFlow.do_clone_repo @p[:public_gitrepo], @p[:local_gitrepo]
129
+ FileUtils.mkdir_p @p[:public_keydir]
130
+ File.write @p[:public_keypath], public_key_text
131
+ GitFlow.push @p[:local_gitrepo], @p[:public_keyname], @c[:time][:stamp]
132
+ =end
133
+
134
+
135
+ # exit
136
+ # key4_pem = File.read 'private.secure.pem'
137
+ # pass_phrase = 'superduperpasswordistoBeENTEREDRIGHT1234HereandRightNOW'
138
+ # key4 = OpenSSL::PKey::RSA.new key4_pem, pass_phrase
139
+ # decrypted_text = key4.private_decrypt(Base64.decode64(encrypted_string))
140
+
141
+ # print "\nHey we have done the decryption.\n", "\n"
142
+ # print decrypted_text, "\n"
143
+
144
+
145
+ end
146
+
147
+
148
+ # Perform pre-conditional validations in preparation to executing the main flow
149
+ # of events for this use case. This method may throw the below exceptions.
150
+ #
151
+ # @raise [SafeDirNotConfigured] if the safe's url has not been configured
152
+ # @raise [EmailAddrNotConfigured] if the email address has not been configured
153
+ # @raise [StoreUrlNotConfigured] if the crypt store url is not configured
154
+ def pre_validation
155
+
156
+ @safe_path = OpenSession::Attributes.instance.get_value @@context_name, "safe"
157
+ safe_configured = File.exists?( @safe_path ) && File.directory?( @safe_path )
158
+ @err_msg = "[safe] storage not yet configured. Try =>] opensecret safe /folder/path"
159
+ raise SafeDirNotConfigured.new @err_msg, @safe_path unless safe_configured
160
+
161
+ @email_addr = OpenSession::Attributes.instance.get_value @@context_name, "email"
162
+ email_configured = !@email_addr.nil? && !@email_addr.empty? && @email_addr.length > 4
163
+ @err_msg = "viable [email address] not configured. Try =>] opensecret email joe@example.com"
164
+ raise EmailAddrNotConfigured.new @err_msg, @email_addr unless email_configured
165
+
166
+ @store_url = OpenSession::Attributes.instance.get_value @@context_name, "store"
167
+ store_configured = !@store_url.nil? && !@store_url.empty? && @store_url.length > 0
168
+ @err_msg = "crypt [store url] not configured. Try =>] opensecret store /path/to/crypt"
169
+ raise StoreUrlNotConfigured.new @err_msg, @store_url unless store_configured
170
+
171
+ end
172
+
173
+
174
+ end
175
+
176
+
177
+ end
@@ -0,0 +1,145 @@
1
+
2
+ ==============================================================================================
3
+
4
+ open office/laptop
5
+ (or pull)
6
+
7
+ put login/username=myname
8
+ put login/password=mysecret
9
+ list
10
+ put disk/password=anothersecret
11
+ swap disk/password=bettersecret
12
+
13
+ lock
14
+ (or push)
15
+ ==============================================================================================
16
+
17
+
18
+ open office/laptop --with=asdfasdflkhlkh
19
+ (or pull)
20
+
21
+ list
22
+ get login
23
+ get disk
24
+ trash disk
25
+ list
26
+ get login/password
27
+
28
+ lock
29
+ (or push)
30
+ ==============================================================================================
31
+
32
+
33
+ lock <<path/to/a/file.txt>> ## locks (encrypts) the file in-place | you must delete it
34
+ lock <<path/to/a/folder>> --zip ## zips and encrypts folder (in-place) | you must delete it
35
+
36
+ ==============================================================================================
37
+
38
+ Command => open office/laptop
39
+
40
+ Effect1 => Creates in-memory INI string (see below) and writes (in effect2) to file
41
+ Effect2 => Creates a an openkey eg asdfa234234234sfss and a long password.
42
+ Effect3 => Creates a file ../<<email>>/opened.files/office/laptop.asdfa234234234sfss.x.txt
43
+ Effect4 => Puts long password in $HOME/.opensecret/session.keys/asdfa234234234sfss.x.txt
44
+
45
+ -------------------------------------
46
+ in-memory INI string
47
+ -------------------------------------
48
+ [opensecret]
49
+
50
+ secret.path = office/laptop
51
+ -------------------------------------
52
+
53
+ Assert => no office/laptop exists before opening (if so prompt user to => trash office/laptop
54
+
55
+ ==============================================================================================
56
+
57
+ Command => open office/laptop/login/fullname="Mr Blobby"
58
+
59
+ Effect1 => Creates in-memory INI string (see below) and writes (in effect2) to file
60
+ Effect2 => Creates a file ../<<email>>/opened.files/office/laptop.asdfa234234234sfss.x.txt
61
+ Effect3 => With its encrypt-key in $HOME/.opensecret/session.keys/asdfa234234234sfss.x.txt
62
+
63
+ -------------------------------------
64
+ in-memory INI string
65
+ -------------------------------------
66
+ [opensecret]
67
+
68
+ secret.path = office/laptop
69
+
70
+ [login]
71
+ fullname = Mr Blobby
72
+ -------------------------------------
73
+
74
+ Assert => no office/laptop exists before opening (if so prompt user to => trash office/laptop
75
+
76
+
77
+
78
+ inner_key
79
+ outer_key
80
+ filename
81
+ foldername
82
+ office/room2/rack6/server4/username
83
+
84
+
85
+
86
+
87
+ open
88
+
89
+ get session id as time string
90
+ use
91
+
92
+
93
+
94
+
95
+ close
96
+
97
+
98
+
99
+
100
+
101
+ lock wifi/password
102
+
103
+ [keys]
104
+ wifi = asdff234523
105
+ password = dfgsdfgsfg
106
+
107
+
108
+ asdff234523/dfgsdfgsfg
109
+
110
+ [home]
111
+
112
+ wifi=asdfasd
113
+ alarm=fdghdfg
114
+ safe1=3456hjk3h45
115
+ safe2=2n34lijss
116
+
117
+ ======================================
118
+
119
+ in asdfasd (wifi)
120
+
121
+ [home/wifi]
122
+
123
+ ssid = 3452454
124
+ password = 2452345
125
+
126
+
127
+ office/room2/rack6/server4/username
128
+ office/accounts/sage
129
+ office/alarm/pin
130
+ office/gmail/username
131
+
132
+
133
+ [office]
134
+
135
+ room2 = asddf345
136
+ accounts = 9o8udfg
137
+ alarm = 345ljdfg
138
+ gmail = ldf2345
139
+
140
+
141
+ [office/room2]
142
+
143
+ rack6 = asdf234
144
+
145
+ [office/room2]
@@ -1,3 +1,3 @@
1
1
  module OpenSecret
2
- VERSION = "0.0.946"
2
+ VERSION = "0.0.951"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: opensecret
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.946
4
+ version: 0.0.951
5
5
  platform: ruby
6
6
  authors:
7
7
  - Apollo Akora
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-02-23 00:00:00.000000000 Z
11
+ date: 2018-02-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: inifile
@@ -143,12 +143,14 @@ files:
143
143
  - lib/plugins/usecase.rb
144
144
  - lib/plugins/usecases/init.rb
145
145
  - lib/plugins/usecases/on.rb
146
+ - lib/plugins/usecases/open.rb
146
147
  - lib/plugins/usecases/safe.rb
147
148
  - lib/session/attributes.rb
148
149
  - lib/session/fact.finder.rb
149
150
  - lib/session/require.gem.rb
150
151
  - lib/session/time.stamp.rb
151
152
  - lib/session/user.home.rb
153
+ - lib/using.txt
152
154
  - lib/version.rb
153
155
  - opensecret.gemspec
154
156
  homepage: https://www.eco-platform.co.uk