opensecret 0.0.962 → 0.0.988

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +16 -10
  3. data/bin/opensecret +3 -4
  4. data/bin/ops +5 -0
  5. data/lib/extension/string.rb +114 -0
  6. data/lib/factbase/facts.opensecret.io.ini +9 -21
  7. data/lib/interprete/begin.rb +232 -0
  8. data/lib/interprete/cmd.rb +621 -0
  9. data/lib/{plugins/usecases/unlock.rb → interprete/export.rb} +25 -70
  10. data/lib/interprete/init.rb +205 -0
  11. data/lib/interprete/key.rb +119 -0
  12. data/lib/interprete/open.rb +148 -0
  13. data/lib/{plugins/usecases → interprete}/put.rb +19 -6
  14. data/lib/{plugins/usecases → interprete}/safe.rb +2 -1
  15. data/lib/{plugins/usecases/lock.rb → interprete/seal.rb} +24 -34
  16. data/lib/interprete/set.rb +46 -0
  17. data/lib/interprete/use.rb +43 -0
  18. data/lib/interpreter.rb +165 -0
  19. data/lib/keytools/binary.map.rb +245 -0
  20. data/lib/keytools/digester.rb +245 -0
  21. data/lib/keytools/doc.conversion.to.ones.and.zeroes.ruby +179 -0
  22. data/lib/keytools/doc.rsa.radix.binary-mapping.ruby +190 -0
  23. data/lib/keytools/doc.star.schema.strategy.txt +77 -0
  24. data/lib/keytools/doc.using.pbkdf2.kdf.ruby +95 -0
  25. data/lib/keytools/doc.using.pbkdf2.pkcs.ruby +266 -0
  26. data/lib/keytools/kdf.bcrypt.rb +180 -0
  27. data/lib/keytools/kdf.pbkdf2.rb +164 -0
  28. data/lib/keytools/key.data.rb +227 -0
  29. data/lib/keytools/key.derivation.rb +341 -0
  30. data/lib/keytools/key.module.rb +140 -0
  31. data/lib/keytools/key.rb +481 -0
  32. data/lib/logging/gem.logging.rb +1 -2
  33. data/lib/modules/cryptology.md +43 -0
  34. data/lib/{plugins/ciphers → modules/cryptology}/aes-256.rb +6 -0
  35. data/lib/{crypto → modules/cryptology}/amalgam.rb +6 -0
  36. data/lib/modules/cryptology/blowfish.rb +130 -0
  37. data/lib/modules/cryptology/cipher.rb +207 -0
  38. data/lib/modules/cryptology/collect.rb +118 -0
  39. data/lib/{plugins → modules/cryptology}/crypt.io.rb +5 -0
  40. data/lib/{crypto → modules/cryptology}/engineer.rb +7 -1
  41. data/lib/{crypto → modules/cryptology}/open.bcrypt.rb +0 -0
  42. data/lib/modules/mappers/collateral.rb +282 -0
  43. data/lib/modules/mappers/dictionary.rb +288 -0
  44. data/lib/modules/mappers/envelope.rb +127 -0
  45. data/lib/modules/mappers/settings.rb +170 -0
  46. data/lib/modules/storage/coldstore.rb +186 -0
  47. data/lib/{opensecret/plugins.io/git/git.flow.rb → modules/storage/git.store.rb} +11 -0
  48. data/lib/notepad/scratch.pad.rb +17 -0
  49. data/lib/session/fact.finder.rb +13 -0
  50. data/lib/session/require.gem.rb +5 -0
  51. data/lib/store-commands.txt +180 -0
  52. data/lib/version.rb +1 -1
  53. data/opensecret.gemspec +5 -6
  54. metadata +74 -29
  55. data/lib/crypto/blowfish.rb +0 -85
  56. data/lib/crypto/collect.rb +0 -140
  57. data/lib/crypto/verify.rb +0 -33
  58. data/lib/opensecret.rb +0 -236
  59. data/lib/plugins/cipher.rb +0 -203
  60. data/lib/plugins/ciphers/blowfish.rb +0 -126
  61. data/lib/plugins/coldstore.rb +0 -181
  62. data/lib/plugins/envelope.rb +0 -116
  63. data/lib/plugins/secrets.uc.rb +0 -94
  64. data/lib/plugins/usecase.rb +0 -239
  65. data/lib/plugins/usecases/init.rb +0 -145
  66. data/lib/plugins/usecases/open.rb +0 -108
  67. data/lib/session/attributes.rb +0 -279
  68. data/lib/session/dictionary.rb +0 -191
  69. data/lib/session/file.path.rb +0 -53
  70. data/lib/session/session.rb +0 -80
@@ -1,126 +0,0 @@
1
- #!/usr/bin/ruby
2
- # coding: utf-8
3
-
4
- module OpenSecret
5
-
6
- # Blowfish is a symmetric encryption cipher which inherits extends the
7
- # {OpenSecret::Cipher} base class in order to implement plug and play
8
- # symmetric encryption.
9
- #
10
- # Blowfish is still uncrackable - however its successor (TwoFish) has
11
- # been reinforced to counter the growth of super-computer brute force
12
- # resources.
13
- class Blowfish < OpenSecret::Cipher
14
-
15
-
16
- # The blowfish cipher id constant is used to +initialize+
17
- # an {OpenSSL::Cipher} class instance.
18
- BLOWFISH_CIPHER_ID = "BF-ECB"
19
-
20
-
21
- # Blowfish constrains the length of +incoming plain text+ forcing it
22
- # to be a multiple of eight (8).
23
- BLOWFISH_BLOCK_LEN = 8
24
-
25
-
26
- # Encrypt the (plain) text parameter using the symmetric encryption key
27
- # specified in the second parameter and return the base64 encoded
28
- # representation of the cipher text.
29
- #
30
- # Blowfish is a block cipher meaning it needs both the key and the plain
31
- # text inputted to conform to a divisible block length.
32
- #
33
- # Don't worry about this block length requirement as this encrption method
34
- # takes care of it and its sister method {self.decryptor} will also perform
35
- # the correct reversal activities to give you back the original plain text.
36
- #
37
- # {Base64.urlsafe_encode64} facilitates the ciphertext encoding returning text that
38
- # is safe to write to a file.
39
- #
40
- # @param plain_text [String]
41
- # This parameter should be the non-nil text to encrypt using Blowfish.
42
- # Before encryption the text will be padded using a text string from
43
- # the {OpenSecret::Cipher::TEXT_PADDER} constant until it results in
44
- # a string with the required block length.
45
- #
46
- # @param encryption_key [String]
47
- # send a long strong unencoded key which does not have to be a multiple of
48
- # eight even though the algorithm demands it. Before the encryption this key
49
- # will be passed through a digest using behaviour from {Digest::SHA256.digest}
50
- #
51
- # This behaviour returns a key whose length is a multiple of eight.
52
- #
53
- # @return [String] base64 representation of blowfish crypted ciphertext
54
- #
55
- # @raise [OpenSSL::Cipher::CipherError]
56
- # An (encryption) <tt>key length too short</tt> error is raised for short keys.
57
- def encryptor plain_text, encryption_key
58
-
59
- shortkey_msg = "The #{encryption_key.length} character encryption key is too short."
60
- raise ArgumentError, shortkey_msg unless encryption_key.length > 8
61
- log.info(x) { "os blowfish request to encrypt plain text with provided key." }
62
-
63
- block_txt = plain_text
64
- block_txt += CryptIO::TEXT_PADDER until block_txt.bytesize % OpenSecret::Blowfish::BLOWFISH_BLOCK_LEN == 0
65
- raw_stretched_key = Digest::SHA256.digest(encryption_key)
66
-
67
- blowfish_encryptor = OpenSSL::Cipher.new(OpenSecret::Blowfish::BLOWFISH_CIPHER_ID).encrypt
68
- blowfish_encryptor.key = raw_stretched_key
69
- return blowfish_encryptor.update(block_txt) << blowfish_encryptor.final
70
-
71
- end
72
-
73
-
74
- # Decrypt the cipher text parameter using the symmetric decryption key
75
- # specified in the second parameter. The cipher text is expected to have
76
- # already been decoded if necessary.
77
- #
78
- # Its okay to use a bespoke encryptor - just ensure you encode the result
79
- # and override the padding constant.
80
- #
81
- # Blowfish is a block cipher meaning it needs both the key and the plain
82
- # text inputted to conform to a divisible block length.
83
- #
84
- # Don't worry about this block length requirement as this decrption method
85
- # takes care of the reversing the activities carried out by {self.encryptor}.
86
- #
87
- # @param cipher_text [String]
88
- # This incoming cipher text should already be encoded but it
89
- # will <b>chomped and stripped upon receipt</b> followed by
90
- # decryption using the Blowfish algorithm.
91
- #
92
- # @param decryption_key [String]
93
- # Send the same key that was used during the encryption phase. The encryption
94
- # phase passed the key through the {Digest::SHA256.digest} digest so here
95
- # the decryption does the exact same thing.
96
- #
97
- # The digest processing guarantees a symmetric key whose length conforms to
98
- # the multiple of eight block length requirement.
99
- #
100
- # @return [String]
101
- # After decoding and decryption the plain text string will still be padded,
102
- # +but not with spaces+. The unlikely to occur padding string constant used
103
- # is the {OpenSecret::Cipher::TEXT_PADDER}.
104
- #
105
- # If the plaintext ended with spaces these would be preserved. After padder
106
- # removal any trailing spaces will be preserved in the returned plain text.
107
- #
108
- def decryptor cipher_text, decryption_key
109
-
110
- digested_key = Digest::SHA256.digest decryption_key
111
-
112
- decrypt_tool = OpenSSL::Cipher.new(OpenSecret::Blowfish::BLOWFISH_CIPHER_ID).decrypt
113
- decrypt_tool.key = digested_key
114
-
115
- padded_plaintxt = decrypt_tool.update(cipher_text) << decrypt_tool.final
116
- pad_begin_index = padded_plaintxt.index CryptIO::TEXT_PADDER
117
- return padded_plaintxt if pad_begin_index.nil?
118
- return padded_plaintxt[ 0 .. (pad_begin_index-1) ]
119
-
120
- end
121
-
122
-
123
- end
124
-
125
-
126
- end
@@ -1,181 +0,0 @@
1
- #!/usr/bin/ruby
2
- # coding: utf-8
3
-
4
- module OpenSecret
5
-
6
- # Cold storage can sync repositories with a <b>bias during conflicts</b>
7
- # either to the <em>remote repository</em> <b>when pulling</b>, and then
8
- # conversely to the <em>local reposiory</em> <b>when pushing</b>.
9
- #
10
- # In between the sync operations a ColdStore can create, read, update and
11
- # delete to and from the local mirror.
12
- #
13
- # == ColdStore | Use Cases
14
- #
15
- # Any <b>self-respecting coldstore</b> must, after initialization, provide
16
- # some basic (and mandatory) behaviour.
17
- #
18
- # These include
19
- #
20
- # - <b>read</b> - reading text from a (possibly unavailable) frozen path
21
- # - <b>write</b> - writing text (effectively freezing it) to a path
22
- # - <b>pull</b> - sync with a <b>collision bias</b> that favours the remote mirror
23
- # - <b>push</b> - sync with a <b>collision bias</b> that favours the local mirror
24
- #
25
- # <b>Cold Storage</b> is borrowed from BitCoin and represents offline storage
26
- # for keys and crypts. opensecret separates keys and crypts so that you can
27
- # transfer and share secrets by moving keys (not the crypts).
28
- #
29
- # == Houses and Gold Bullion
30
- #
31
- # You don't carry houses or gold bullion around to rent, share or transfer
32
- # their ownership.
33
- #
34
- # You copy keys to rent secrets and when the tenure is up (or you change your
35
- # mind) you revoke access with a metaphorical lock change.
36
- #
37
- # opensecret embodies concepts like an owner who rents as opposed to a change
38
- # in ownership.
39
- #
40
- # == trade secrets | commoditizing secrets
41
- #
42
- # opensecret is a conduit through which secrets can be bought and sold.
43
- #
44
- # It commoditizes secrets so that they can be owned, traded, leased and
45
- # auctioned. Options to acquire or relinquish them at set prices can easily
46
- # be taken out.
47
- class ColdStore
48
-
49
- # @param base_path [String]
50
- # path to the store's (mirror) base directory.
51
- # If the denoted directory does not exist an attempt will be made to
52
- # create it. If a file exists at this path an error will be thrown.
53
- #
54
- # @param domain [String]
55
- # the domain is an identifier (and namespace) denoting which opensecret
56
- # "account" is being accessed. opensecret allows the creation and use of
57
- # multiple domains.
58
- def initialize local_path
59
-
60
- @store_path = local_path
61
- FileUtils.mkdir_p @store_path
62
-
63
- end
64
-
65
-
66
- # Read the file frozen (in this store mirror) at this path and
67
- # return its contents.
68
- #
69
- # Coldstores are usually frozen offline (offmachine) so for this
70
- # to work the {ColdStore.pull} behaviour must have executed to
71
- # create a local store mirror. This method reads from that mirror.
72
- #
73
- # @param from_path [String]
74
- # read the file frozen at this path and return its contents
75
- # so that the defreeze process can begin.
76
- #
77
- # This path is relative to the base of the store defined in
78
- # the constructor.
79
- #
80
- # @return [String]
81
- # return the text frozen in a file at the denoted local path
82
- #
83
- # nil is reurned if no file can be found in the local mirror
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.
92
- def read from_path
93
-
94
- frozen_filepath = File.join @store_path, from_path
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
126
-
127
- end
128
-
129
-
130
- # Write (freeze) the text into a file at the denoted path. The
131
- # folder path will be created if need be.
132
- #
133
- # Coldstores are usually frozen offline (offmachine) so after
134
- # this method completes the {ColdStore.push} behaviour must be
135
- # executed to synchronize the local coldstore freezer with the
136
- # remote mirror.
137
- #
138
- # @param this_text [String]
139
- # this is the text that needs to be frozen into the local and
140
- # subsequently the remote coldstore freezer.
141
- #
142
- # @param to_path [String]
143
- # write the text (effectively freezing it) into the file at
144
- # this path. An attempt will be made to put down the necessary
145
- # directory structure.
146
- #
147
- # This path is relative to the base of the store defined in
148
- # the constructor.
149
- def write this_text, to_path
150
-
151
- freeze_filepath = File.join @store_path, to_path
152
-
153
- log.info(x) { "ColdStore freezing #{this_text.length} characters of worthless text."}
154
- log.info(x) { "ColdStore freeze file path => #{freeze_filepath.hr_path}"}
155
-
156
- FileUtils.mkdir_p(File.dirname(freeze_filepath))
157
- File.write freeze_filepath, this_text
158
-
159
- end
160
-
161
-
162
- private
163
-
164
- # @todo - write sync (with a local bias during conflicts)
165
- # The open up to the public (published) api.
166
- def push
167
-
168
-
169
- end
170
-
171
- # @todo - write sync (with a rmote bias during conflicts)
172
- # The open up to the public (published) api.
173
- def pull
174
-
175
- end
176
-
177
-
178
- end
179
-
180
-
181
- end
@@ -1,116 +0,0 @@
1
- #!/usr/bin/ruby
2
- # coding: utf-8
3
-
4
- module OpenSecret
5
-
6
- require 'json'
7
-
8
- # An envelope knows how to manipulate a JSON backed data structure
9
- # (put, add etc) <b>after reading and then decrypting it</b> from a
10
- # file and <b>before encrypting and then writing it</b> to a file.
11
- #
12
- # It provides behaviour to which we can create, append (add), update
13
- # (change), read parts and delete essentially two structures
14
- #
15
- # - a collection of name/value pairs
16
- # - an ordered list of values
17
- #
18
- # == JSON is Not Exposed in the Interface
19
- #
20
- # An envelope doesn't expose the data format used in the implementation
21
- # allowing this to be changed seamlessly to YAMl or other formats.
22
- #
23
- # == Symmetric Encryption and Decryption
24
- #
25
- # An envelope supports operations to <b>read from</b> and <b>write to</b>
26
- # a known filepath and with a symmetric key it can
27
- #
28
- # - decrypt <b>after reading from</b> a file and
29
- # - encrypt <b>before writing to</b> a (the same) file
30
- #
31
- # == Hashes as the Primary Data Structure
32
- #
33
- # Envelope extends {Hash} as the core data structure for holding
34
- #
35
- # - strings
36
- # - arrays
37
- # - other hashes
38
- # - booleans
39
- # - integers and floats
40
- class Envelope < Hash
41
-
42
-
43
- # Read and inject into this envelope, the data structure found in a
44
- # file at the path specified in the first parameter.
45
- #
46
- # Symmetric cryptography is mandatory for the envelope so we must
47
- # <b>encrypt before writing</b> and <b>decrypt after reading</b>.
48
- #
49
- # An argument error will result if a suitable key is not provided.
50
- #
51
- # If the file does not exist (denoting the first read) all this method
52
- # does is to stash the filepath as an instance variable and igore the
53
- # decryption key which can be nil (or ommitted).
54
- #
55
- # @param the_filepath [String]
56
- # absolute path to the file which acts as the persistent mirror to
57
- # this data structure envelope.
58
- #
59
- # @param decryption_key [String]
60
- # encryption at rest is a given so this mandatory parameter must
61
- # contain a robust symmetric decryption key. The key will be used
62
- # for decryption after the read and it will not linger (ie not cached
63
- # as an instance variable).
64
- #
65
- # @raise [ArgumentError] if the decryption key is not robust enough.
66
- def read the_filepath, decryption_key = nil
67
-
68
- @filepath = the_filepath
69
- return unless File.exists? @filepath
70
-
71
- cipher_text = Base64.decode64( File.read( @filepath ).strip )
72
- plain_text = OpenSecret::Blowfish.new.decryptor( cipher_text, decryption_key )
73
-
74
- puts ""
75
- puts "=== ============================"
76
- puts "=== Envelope After Decryption"
77
- puts "=== ============================"
78
- puts plain_text
79
- puts "=== ============================"
80
- puts ""
81
-
82
- data_structure = JSON.parse plain_text
83
- self.merge! data_structure
84
-
85
- end
86
-
87
-
88
- # Write the data in this envelope hash map into a file-system
89
- # backed mirror whose path was specified in the {self.read} method.
90
- #
91
- # Technology for encryption at rest is supported by this dictionary
92
- # and to this aim, please endeavour to post a robust symmetric
93
- # encryption key.
94
- #
95
- # Calling this {self.write} method when the file at the prescribed path
96
- # does not exist results in the directory structure being created
97
- # (if necessary) and then the encrypted file being written.
98
- #
99
- # @param encryption_key [String]
100
- # encryption at rest is a given so this mandatory parameter must
101
- # contain a robust symmetric encryption key. The symmetric key will
102
- # be used for the decryption after the read. Note that the decryption
103
- # key does not linger meaning it isn't cached in an instance variable.
104
- def write encryption_key
105
-
106
- FileUtils.mkdir_p(File.dirname(@filepath))
107
- cipher_text = Base64.encode64 Blowfish.new.encryptor( self.to_json, encryption_key )
108
- File.write @filepath, cipher_text
109
-
110
- end
111
-
112
-
113
- end
114
-
115
-
116
- end
@@ -1,94 +0,0 @@
1
- #!/usr/bin/ruby
2
- # coding: utf-8
3
-
4
- module OpenSecret
5
-
6
- # The parent OpenSecret use case is designed to be extended by the cli
7
- # (command line) use cases like {OpenSecret::Open}, {OpenSecret::Put} and
8
- # {OpenSecret::Lock} because it describes behaviour common to at least two
9
- # (but usually more) of the use cases.
10
- #
11
- # == Behaviour Reuse
12
- #
13
- # Behaviour that is reusable by any use case fits within {OpenSession::UseCase}
14
- # whilst behaviour common to two or more {OpenSecret} use cases belongs here.
15
- # Therefore the only behaviour in the named use case is detailed and must belong
16
- # solely to it.
17
- #
18
- # == Fact Reuse
19
- #
20
- # Fact evaluation rules are born with reuse in mind. <b>Use case facts</b>
21
- # are evaluated when they belong to either the class or its parent or any
22
- # ancestors.
23
- class SecretsUseCase < OpenSession::UseCase
24
-
25
- @@context_name = "opensecret"
26
-
27
- # Get the envelope that <b>was opened</b> by the open command but
28
- # <b>not locked</b> with the lock command.
29
- #
30
- # @return [Envelope]
31
- # return the Envelope that has been opened. The state carried alongside an
32
- # open envelope is an id, an encryption key and a filepath all inside the
33
- # userhome configuration file.
34
- def get_envelope
35
-
36
- encrypt_key = OpenSession::Attributes.instance.get_value @@context_name, @c[:open][:open_name], @c[:open][:open_keyname]
37
- rel_filepath = OpenSession::Attributes.instance.get_value @@context_name, @c[:open][:open_name], @c[:open][:open_pathname]
38
-
39
- put_filepath = File.join @c[:open][:open_dirpath], rel_filepath
40
- the_envelope = Envelope.new
41
- the_envelope.read put_filepath, encrypt_key
42
- return the_envelope
43
-
44
- end
45
-
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
-
91
- end
92
-
93
-
94
- end