opensecret 0.0.957 → 0.0.959
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.
- checksums.yaml +4 -4
- data/lib/factbase/facts.opensecret.io.ini +0 -2
- data/lib/notepad/blow.rb +16 -4
- data/lib/opensecret.rb +9 -0
- data/lib/plugins/cipher.rb +25 -23
- data/lib/plugins/ciphers/aes-256.rb +16 -12
- data/lib/plugins/ciphers/blowfish.rb +7 -10
- data/lib/plugins/envelope.rb +116 -0
- data/lib/plugins/secrets.uc.rb +50 -0
- data/lib/plugins/usecases/init.rb +9 -7
- data/lib/plugins/usecases/lock.rb +77 -93
- data/lib/plugins/usecases/open.rb +1 -1
- data/lib/plugins/usecases/put.rb +18 -18
- data/lib/plugins/usecases/safe.rb +1 -1
- data/lib/session/dictionary.rb +5 -5
- data/lib/using.txt +2 -0
- data/lib/version.rb +1 -1
- data/opensecret.gemspec +2 -2
- metadata +4 -30
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ced0dc3656c2318960d7c747cd24e8eacb189224
|
4
|
+
data.tar.gz: dcca8f54f93da21ef00d6fbbdba0e8975ac7ddca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 219cd0fe00537778fb1364d6a214856bea94be3196e399177bbcbd912ffab087dda9bb01fb906ad1fd7f078f15f27b9d1c24d82894fb1790f592e838487aa10e
|
7
|
+
data.tar.gz: 2ba3881642795bf29de00431cbd7926b664b3d0a0031f18eb17b2dc5d79d282f8df7ccb32559720e614be52229e2ec8eb59b924282b88596960ab10fa52bc8cf
|
@@ -16,10 +16,8 @@ master.dirname = master.keys
|
|
16
16
|
master.dirpath = rb>> File.join @s[:safe_user], @s[:master_dirname]
|
17
17
|
|
18
18
|
master.sig.file = master.signature.os.txt
|
19
|
-
########### -----> master.pub.name = master.public.key.os.txt
|
20
19
|
master.prv.name = master.private.key.xx.txt
|
21
20
|
master.sig.path = rb>> File.join @s[:master_dirpath], @s[:master_sig_file]
|
22
|
-
########### -----> master.pub.key = rb>> File.join @s[:master_dirpath], @s[:master_pub_name]
|
23
21
|
master.prv.key = rb>> File.join @s[:master_dirpath], @s[:master_prv_name]
|
24
22
|
|
25
23
|
stamp.key = stamp
|
data/lib/notepad/blow.rb
CHANGED
@@ -9,6 +9,18 @@
|
|
9
9
|
|
10
10
|
class Trial
|
11
11
|
|
12
|
+
def self.ciphername
|
13
|
+
|
14
|
+
require 'openssl'
|
15
|
+
require "base64"
|
16
|
+
|
17
|
+
crypt_cipher = OpenSSL::Cipher::AES256.new(:CBC)
|
18
|
+
puts "Cipher Name => #{crypt_cipher.class.name}"
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
Trial.ciphername
|
23
|
+
|
12
24
|
|
13
25
|
def self.certify
|
14
26
|
|
@@ -82,7 +94,7 @@ payload = "55fff4c5895bb247676c6edd2307f17c665305457b3bcfcd985c398246b8780f54e33
|
|
82
94
|
puts ""
|
83
95
|
puts encrypted_string = key.public_encrypt( payload, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)
|
84
96
|
puts ""
|
85
|
-
puts base64text = Base64.
|
97
|
+
puts base64text = Base64.urlsafe_encode64(encrypted_string)
|
86
98
|
puts ""
|
87
99
|
puts signature = key.sign(OpenSSL::Digest::SHA256.new, payload )
|
88
100
|
puts ""
|
@@ -112,8 +124,8 @@ payload = "55fff4c5895bb247676c6edd2307f17c665305457b3bcfcd985c398246b8780f54e33
|
|
112
124
|
context_string_dirty = secured_privatekey + public_key_text + email_address + time_stamp
|
113
125
|
context_string_clean = context_string_dirty.delete("^A-Za-z0-9")
|
114
126
|
context_string_clean += context_string_clean.length.to_s
|
115
|
-
#### context_signature_str = Base64.
|
116
|
-
context_signature_str = Base64.
|
127
|
+
#### context_signature_str = Base64.urlsafe_encode64(second_key.sign OpenSSL::Digest::SHA256.new, context_string_clean)
|
128
|
+
context_signature_str = Base64.urlsafe_encode64(key.sign OpenSSL::Digest::SHA256.new, context_string_clean)
|
117
129
|
|
118
130
|
|
119
131
|
## --------------------------------------------------------------------------------------------
|
@@ -121,7 +133,7 @@ payload = "55fff4c5895bb247676c6edd2307f17c665305457b3bcfcd985c398246b8780f54e33
|
|
121
133
|
|
122
134
|
reinstated_key = OpenSSL::PKey::RSA.new "#{public_key_text}"
|
123
135
|
### reinstated_key = OpenSSL::PKey::RSA.new "#{second_public_key_text}"
|
124
|
-
raw_signature_text = Base64.
|
136
|
+
raw_signature_text = Base64.urlsafe_decode64(context_signature_str)
|
125
137
|
is_valid = reinstated_key.public_key.verify OpenSSL::Digest::SHA256.new, raw_signature_text, (context_string_clean)
|
126
138
|
raise ArgumentError, "Keys not validated" unless is_valid
|
127
139
|
|
data/lib/opensecret.rb
CHANGED
@@ -56,6 +56,15 @@ class CliInterpreter < Thor
|
|
56
56
|
end
|
57
57
|
|
58
58
|
|
59
|
+
# Description of the lock use case command line call.
|
60
|
+
desc "lock", "Lock away the (secret stuffed) envelope into key and crypt stores."
|
61
|
+
|
62
|
+
# Lock away the (secret stuffed) envelope into key and crypt stores.
|
63
|
+
def lock
|
64
|
+
OpenSecret::Lock.new.flow_of_events
|
65
|
+
end
|
66
|
+
|
67
|
+
|
59
68
|
# Description of the open "wake-up" call.
|
60
69
|
desc "open CONTEXT_PATH", "CONTEXT_PATH context path to the family of secrets to be created."
|
61
70
|
|
data/lib/plugins/cipher.rb
CHANGED
@@ -28,7 +28,6 @@ module OpenSecret
|
|
28
28
|
# with a powerful symmetric encryption algorithm which could be any one of the
|
29
29
|
# leading ciphers such as TwoFish or the Advanced Encryption Standard (AES).
|
30
30
|
#
|
31
|
-
#
|
32
31
|
# == How to Implement a Cipher
|
33
32
|
#
|
34
33
|
# Extend this base class to inherit lots of +unexciting+ functionality
|
@@ -100,10 +99,23 @@ module OpenSecret
|
|
100
99
|
# Text header for key-value pairs hash map that will be serialized.
|
101
100
|
DICTIONARY = "dictionary"
|
102
101
|
|
102
|
+
# Name for the class of cipher employed.
|
103
|
+
DICT_CIPHER_NAME = "cipher.class"
|
104
|
+
|
105
|
+
# Name for the {Base64} encoded symmetric (lock/unlock) crypt key.
|
106
|
+
DICT_CRYPT_KEY = "encryption.key"
|
107
|
+
|
108
|
+
# Name for the {Base64} encoded plain text digest.
|
109
|
+
DICT_PLAINTEXT_DIGEST = "plaintext.digest"
|
110
|
+
|
111
|
+
# Name for the {Base64} encoded crypt material digest.
|
112
|
+
DICT_MATERIAL_DIGEST = "cipher.digest"
|
103
113
|
|
104
|
-
|
105
|
-
|
106
|
-
|
114
|
+
# Name for the plain text initialization vector (iv).
|
115
|
+
DICT_INIT_VECTOR = "crypt.init.vector"
|
116
|
+
|
117
|
+
# Name for the {Base64} encoded crypted cipher text.
|
118
|
+
DICT_CIPHER_TEXT = "cipher.text"
|
107
119
|
|
108
120
|
|
109
121
|
# The cipher constructor instantiates the encryption dictionary which
|
@@ -131,40 +143,30 @@ module OpenSecret
|
|
131
143
|
# and rejecting malicious content.
|
132
144
|
#
|
133
145
|
# @param public_key_text [String] textual portion of an {OpenSSL::PKey::RSA}
|
134
|
-
# public key
|
135
|
-
#
|
146
|
+
# public key. There is no need for an asymmetric encryption agent to know
|
147
|
+
# the asymmetic private key.
|
136
148
|
#
|
137
149
|
# @param payload_text [String] plaintext (or base64 encoded) text to encrypt
|
138
|
-
# @param payload_signature [String] signature of payload verifiable with public key
|
139
150
|
#
|
140
151
|
# @return [String] doubly (symmetric and asymmetric) encrypted cipher text
|
141
|
-
def encrypt_it public_key_text, payload_text
|
142
|
-
|
143
|
-
asymmetric_key = OpenSSL::PKey::RSA.new public_key_text
|
152
|
+
def encrypt_it public_key_text, payload_text
|
144
153
|
|
145
|
-
signature_valid = asymmetric_key.verify(
|
146
|
-
OpenSSL::Digest::SHA256.new,
|
147
|
-
payload_signature,
|
148
|
-
payload_text
|
149
|
-
)
|
150
|
-
|
151
|
-
raise ArgumentError, "Payload not verified by the signature." unless signature_valid
|
152
|
-
@dictionary[@@payload_signature_keyname] = payload_signature.to_hex
|
153
154
|
crypted_payload = do_symmetric_encryption payload_text
|
154
155
|
|
156
|
+
######### puts JSON.pretty_generate(@dictionary)
|
157
|
+
|
155
158
|
unified_material = unify_hash_and_text crypted_payload
|
156
|
-
blowfish_cryptor = Blowfish.new
|
157
159
|
outer_crypt_key = OpenSecret::Engineer.strong_key( 128 )
|
158
|
-
crypted_material = blowfish_cryptor.encryptor unified_material, outer_crypt_key
|
159
160
|
crypted_cryptkey = do_asymmetric_encryption public_key_text, outer_crypt_key
|
160
|
-
|
161
|
+
crypted_material = Base64.encode64(Blowfish.new.encryptor unified_material, outer_crypt_key)
|
162
|
+
locked_ciphertxt = unify_text_and_text crypted_cryptkey, crypted_material
|
161
163
|
|
162
|
-
return
|
164
|
+
return locked_ciphertxt
|
163
165
|
|
164
166
|
end
|
165
167
|
|
166
168
|
|
167
|
-
#
|
169
|
+
# This method takes the textual public key lacking the private key portion
|
168
170
|
# as it is not needed, and encrypts the secret text with it.
|
169
171
|
# It returns a Base64 encoded version of they encrypted text.
|
170
172
|
#
|
@@ -7,7 +7,7 @@ module OpenSecret
|
|
7
7
|
# {OpenSecret::Cipher} base class in order to implement plug and play
|
8
8
|
# symmetric encryption.
|
9
9
|
#
|
10
|
-
# == Aes256 Symmetric Encrypt/Decrypt
|
10
|
+
# == Aes256 Symmetric Encrypt/Decrypt
|
11
11
|
#
|
12
12
|
# To facilitate decryption - this cipher produces a key/value pair
|
13
13
|
# dictionary which will be stored along with the ciphertext itself.
|
@@ -51,16 +51,20 @@ module OpenSecret
|
|
51
51
|
# @return [String] the symmetrically encrypted cipher text
|
52
52
|
def do_symmetric_encryption plain_text
|
53
53
|
|
54
|
-
|
55
|
-
|
56
|
-
crypt_cipher = OpenSSL::Cipher.new @cipher_name
|
54
|
+
crypt_cipher = OpenSSL::Cipher::AES256.new(:CBC)
|
57
55
|
crypt_cipher.encrypt
|
58
56
|
|
59
|
-
@dictionary[
|
60
|
-
@dictionary[
|
61
|
-
@dictionary[
|
57
|
+
@dictionary[DICT_CIPHER_NAME] = crypt_cipher.class.name
|
58
|
+
@dictionary[DICT_CRYPT_KEY] = Base64.urlsafe_encode64 crypt_cipher.random_key
|
59
|
+
@dictionary[DICT_INIT_VECTOR] = Base64.urlsafe_encode64 crypt_cipher.random_iv
|
60
|
+
@dictionary[DICT_PLAINTEXT_DIGEST] = Base64.urlsafe_encode64(Digest::SHA256.digest(plain_text))
|
61
|
+
|
62
|
+
cipher_text = crypt_cipher.update( plain_text ) + crypt_cipher.final
|
63
|
+
|
64
|
+
@dictionary[DICT_CIPHER_TEXT] = Base64.urlsafe_encode64( cipher_text )
|
65
|
+
@dictionary[DICT_MATERIAL_DIGEST] = Base64.urlsafe_encode64(Digest::SHA256.digest(cipher_text))
|
62
66
|
|
63
|
-
return
|
67
|
+
return cipher_text
|
64
68
|
|
65
69
|
end
|
66
70
|
|
@@ -69,7 +73,7 @@ module OpenSecret
|
|
69
73
|
# and initialization vector (iv) sitting in the encryption_dictionary,
|
70
74
|
# to symmetrically decrypt the parameter cipher text.
|
71
75
|
#
|
72
|
-
# == Pre-Condition | Encryption
|
76
|
+
# == Pre-Condition | Encryption ...
|
73
77
|
#
|
74
78
|
# This method requires the <tt>@dictionary</tt> instance
|
75
79
|
# variable to have been set and to contain (amongst others)
|
@@ -112,7 +116,7 @@ crypt_text += encode_cipher.update line5
|
|
112
116
|
crypt_text += encode_cipher.update line6
|
113
117
|
crypt_text += encode_cipher.update line7
|
114
118
|
crypt_text += encode_cipher.final
|
115
|
-
coded_crypt_text = Base64.
|
119
|
+
coded_crypt_text = Base64.urlsafe_encode64(crypt_text)
|
116
120
|
|
117
121
|
puts ""
|
118
122
|
puts "The key is #{hex_key}"
|
@@ -133,13 +137,13 @@ puts "========================"
|
|
133
137
|
puts ""
|
134
138
|
puts ""
|
135
139
|
|
136
|
-
unencoded_crypt_text = Base64.
|
140
|
+
unencoded_crypt_text = Base64.urlsafe_decode64(coded_crypt_text)
|
137
141
|
decode_cipher = OpenSSL::Cipher.new('aes-256-cbc')
|
138
142
|
|
139
143
|
decode_cipher.decrypt
|
140
144
|
decode_cipher.key = [hex_key].pack("H*")
|
141
145
|
decode_cipher.iv = [hex_iv].pack("H*")
|
142
|
-
first_part = decode_cipher.update( Base64.
|
146
|
+
first_part = decode_cipher.update( Base64.urlsafe_decode64(coded_crypt_text) )
|
143
147
|
second_part = ""
|
144
148
|
second_part << decode_cipher.final
|
145
149
|
|
@@ -34,7 +34,7 @@ module OpenSecret
|
|
34
34
|
# takes care of it and its sister method {self.decryptor} will also perform
|
35
35
|
# the correct reversal activities to give you back the original plain text.
|
36
36
|
#
|
37
|
-
# {Base64.
|
37
|
+
# {Base64.urlsafe_encode64} facilitates the ciphertext encoding returning text that
|
38
38
|
# is safe to write to a file.
|
39
39
|
#
|
40
40
|
# @param plain_text [String]
|
@@ -66,16 +66,14 @@ module OpenSecret
|
|
66
66
|
|
67
67
|
blowfish_encryptor = OpenSSL::Cipher.new(OpenSecret::Blowfish::BLOWFISH_CIPHER_ID).encrypt
|
68
68
|
blowfish_encryptor.key = raw_stretched_key
|
69
|
-
|
70
|
-
|
71
|
-
return Base64.encode64( encrypted_lines ).chomp
|
69
|
+
return blowfish_encryptor.update(block_txt) << blowfish_encryptor.final
|
72
70
|
|
73
71
|
end
|
74
72
|
|
75
73
|
|
76
74
|
# Decrypt the cipher text parameter using the symmetric decryption key
|
77
|
-
# specified in the second parameter. The cipher text is expected to
|
78
|
-
#
|
75
|
+
# specified in the second parameter. The cipher text is expected to have
|
76
|
+
# already been decoded if necessary.
|
79
77
|
#
|
80
78
|
# Its okay to use a bespoke encryptor - just ensure you encode the result
|
81
79
|
# and override the padding constant.
|
@@ -87,8 +85,8 @@ module OpenSecret
|
|
87
85
|
# takes care of the reversing the activities carried out by {self.encryptor}.
|
88
86
|
#
|
89
87
|
# @param cipher_text [String]
|
90
|
-
# This incoming cipher text should be encoded
|
91
|
-
#
|
88
|
+
# This incoming cipher text should already be encoded but it
|
89
|
+
# will <b>chomped and stripped upon receipt</b> followed by
|
92
90
|
# decryption using the Blowfish algorithm.
|
93
91
|
#
|
94
92
|
# @param decryption_key [String]
|
@@ -109,13 +107,12 @@ module OpenSecret
|
|
109
107
|
#
|
110
108
|
def decryptor cipher_text, decryption_key
|
111
109
|
|
112
|
-
decoded_text = Base64.decode64(cipher_text.chomp.strip)
|
113
110
|
digested_key = Digest::SHA256.digest decryption_key
|
114
111
|
|
115
112
|
decrypt_tool = OpenSSL::Cipher.new(OpenSecret::Blowfish::BLOWFISH_CIPHER_ID).decrypt
|
116
113
|
decrypt_tool.key = digested_key
|
117
114
|
|
118
|
-
padded_plaintxt = decrypt_tool.update(
|
115
|
+
padded_plaintxt = decrypt_tool.update(cipher_text) << decrypt_tool.final
|
119
116
|
pad_begin_index = padded_plaintxt.index OpenSecret::Cipher::TEXT_PADDER
|
120
117
|
return padded_plaintxt if pad_begin_index.nil?
|
121
118
|
return padded_plaintxt[ 0 .. (pad_begin_index-1) ]
|
@@ -0,0 +1,116 @@
|
|
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
|
+
# Write the data in this envelope hash map into a file-system
|
44
|
+
# backed mirror whose path was specified in the {self.read} method.
|
45
|
+
#
|
46
|
+
# Technology for encryption at rest is supported by this dictionary
|
47
|
+
# and to this aim, please endeavour to post a robust symmetric
|
48
|
+
# encryption key.
|
49
|
+
#
|
50
|
+
# Calling this {self.write} method when the file at the prescribed path
|
51
|
+
# does not exist results in the directory structure being created
|
52
|
+
# (if necessary) and then the encrypted file being written.
|
53
|
+
#
|
54
|
+
# @param encryption_key [String]
|
55
|
+
# encryption at rest is a given so this mandatory parameter must
|
56
|
+
# contain a robust symmetric encryption key. The symmetric key will
|
57
|
+
# be used for the decryption after the read. Note that the decryption
|
58
|
+
# key does not linger meaning it isn't cached in an instance variable.
|
59
|
+
def write encryption_key
|
60
|
+
|
61
|
+
FileUtils.mkdir_p(File.dirname(@filepath))
|
62
|
+
cipher_text = Base64.encode64 Blowfish.new.encryptor( self.to_json, encryption_key )
|
63
|
+
File.write @filepath, cipher_text
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
# Read and inject into this envelope, the data structure found in a
|
69
|
+
# file at the path specified in the first parameter.
|
70
|
+
#
|
71
|
+
# Symmetric cryptography is mandatory for the envelope so we must
|
72
|
+
# <b>encrypt before writing</b> and <b>decrypt after reading</b>.
|
73
|
+
#
|
74
|
+
# An argument error will result if a suitable key is not provided.
|
75
|
+
#
|
76
|
+
# If the file does not exist (denoting the first read) all this method
|
77
|
+
# does is to stash the filepath as an instance variable and igore the
|
78
|
+
# decryption key which can be nil (or ommitted).
|
79
|
+
#
|
80
|
+
# @param the_filepath [String]
|
81
|
+
# absolute path to the file which acts as the persistent mirror to
|
82
|
+
# this data structure envelope.
|
83
|
+
#
|
84
|
+
# @param decryption_key [String]
|
85
|
+
# encryption at rest is a given so this mandatory parameter must
|
86
|
+
# contain a robust symmetric decryption key. The key will be used
|
87
|
+
# for decryption after the read and it will not linger (ie not cached
|
88
|
+
# as an instance variable).
|
89
|
+
#
|
90
|
+
# @raise [ArgumentError] if the decryption key is not robust enough.
|
91
|
+
def read the_filepath, decryption_key = nil
|
92
|
+
|
93
|
+
@filepath = the_filepath
|
94
|
+
return unless File.exists? @filepath
|
95
|
+
|
96
|
+
cipher_text = Base64.decode64( File.read( @filepath ).strip )
|
97
|
+
plain_text = OpenSecret::Blowfish.new.decryptor( cipher_text, decryption_key )
|
98
|
+
|
99
|
+
puts ""
|
100
|
+
puts "=== ============================"
|
101
|
+
puts "=== Envelope After Decryption"
|
102
|
+
puts "=== ============================"
|
103
|
+
puts plain_text
|
104
|
+
puts "=== ============================"
|
105
|
+
puts ""
|
106
|
+
|
107
|
+
data_structure = JSON.parse plain_text
|
108
|
+
self.merge! data_structure
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
end
|
@@ -0,0 +1,50 @@
|
|
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
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
end
|
@@ -32,7 +32,7 @@ module OpenSecret
|
|
32
32
|
#
|
33
33
|
# <b>opensecret</b> thwarts this by continual verification against an
|
34
34
|
# encrypted <em>public key signature</em> aboard the workstation.
|
35
|
-
class Init <
|
35
|
+
class Init < SecretsUseCase
|
36
36
|
|
37
37
|
attr_writer :safe_path, :email_addr, :store_url
|
38
38
|
@@context_name = "opensecret"
|
@@ -83,18 +83,20 @@ module OpenSecret
|
|
83
83
|
secured_keytext = asymmetric_keys.export @c[:global][:key_cipher], amalgam_key
|
84
84
|
|
85
85
|
crypt_key_segments = [ human_password, @c[:global][:separator_a], @email_addr, @c[:global][:separator_a], @c[:global][:stamp_23] ]
|
86
|
+
|
86
87
|
machine_key_crypt_key = crypt_key_segments.alphanumeric_union.concat_length
|
87
|
-
|
88
|
-
|
89
|
-
|
88
|
+
machine_key_x = Base64.urlsafe_encode64(
|
89
|
+
Blowfish.new.encryptor(machine_key, machine_key_crypt_key)
|
90
|
+
)
|
91
|
+
public_key_64 = Base64.urlsafe_encode64 asymmetric_keys.public_key.to_pem
|
90
92
|
|
91
93
|
OpenSession::Attributes.stash @c[:global][:name], @c[:global][:name], @c[:global][:machine_key_x], machine_key_x
|
92
94
|
OpenSession::Attributes.stash @c[:global][:name], @c[:global][:name], @c[:global][:stamp_key], @c[:global][:stamp_23]
|
93
|
-
OpenSession::Attributes.stash @c[:global][:name], @c[:global][:name], @c[:global][:publickey_id],
|
95
|
+
OpenSession::Attributes.stash @c[:global][:name], @c[:global][:name], @c[:global][:publickey_id], public_key_64
|
94
96
|
|
95
|
-
to_sign_segments = [ secured_keytext,
|
97
|
+
to_sign_segments = [ secured_keytext, public_key_64, @email_addr, @c[:global][:stamp_23] ]
|
96
98
|
to_sign_packet = to_sign_segments.alphanumeric_union.concat_length
|
97
|
-
signature_string = Base64.
|
99
|
+
signature_string = Base64.urlsafe_encode64( asymmetric_keys.sign( OpenSSL::Digest::SHA256.new, to_sign_packet ) )
|
98
100
|
|
99
101
|
FileUtils.mkdir_p @c[:global][:master_dirpath]
|
100
102
|
File.write @c[:global][:master_prv_key], secured_keytext
|
@@ -10,97 +10,110 @@ module OpenSecret
|
|
10
10
|
#
|
11
11
|
# The 3 core scenarios that this lock use case is equiped to handle are
|
12
12
|
#
|
13
|
-
# - a new source
|
14
|
-
# - an
|
15
|
-
# -
|
13
|
+
# - a new source that is as yet uncommitted
|
14
|
+
# - updating (overwriting) an existing source
|
15
|
+
# - requiring the destination to be deleted
|
16
16
|
#
|
17
|
-
#
|
17
|
+
# <b>Lock | Observable Value</b>
|
18
18
|
#
|
19
|
-
#
|
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
|
20
26
|
#
|
21
|
-
#
|
27
|
+
# @example
|
22
28
|
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
|
26
|
-
# - a public key that is verifid against its encrypted signature
|
27
|
-
# - deleted session material created (and encrypted) by the put use case
|
28
|
-
class Lock < OpenSession::UseCase
|
29
|
+
# $ opensecret lock
|
30
|
+
#
|
31
|
+
class Lock < SecretsUseCase
|
29
32
|
|
30
33
|
attr_writer :secret_id, :secret_value
|
31
34
|
@@context_name = "opensecret"
|
32
35
|
|
33
36
|
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
+
# The <tt>lock use case</tt> is called after {OpenSecret::Open} and {OpenSecret::Put}
|
38
|
+
# and its effect is to dispatch the doubly encrypted materrial to the configured storage
|
39
|
+
# platform, be it Git, S3, SSH or just an accessible file-system.
|
40
|
+
#
|
41
|
+
# <b>Main Flow of Events</b>
|
37
42
|
#
|
38
|
-
#
|
39
|
-
#
|
43
|
+
# To seal the envelope built up by put, file and add amongst others requires
|
44
|
+
# that we
|
40
45
|
#
|
41
|
-
#
|
46
|
+
# - get the encrypted envelope
|
47
|
+
# - create a strong asymmetric key
|
48
|
+
# - lock the envelope using opensecret's double encrypt modus operandi
|
49
|
+
# - place the doubly encrypted result into the crypt store
|
50
|
+
# - lock the asymmetric key again with opensecret's double encrypt modus operandi
|
51
|
+
# - place the doubly encrypted result into the key store
|
42
52
|
#
|
43
|
-
# The
|
53
|
+
# The second double lock of the crypted envelope is done with the public key
|
54
|
+
# aspect of an asymmetric key created here.
|
44
55
|
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
56
|
+
# The second double lock of the crypted private key (created here) is done with
|
57
|
+
# the master public key created in the {Init.execute} use case main flow.
|
58
|
+
#
|
59
|
+
# <b>Lock | Observable Value</b>
|
60
|
+
#
|
61
|
+
# The observable value after the lock use case has completed entails
|
62
|
+
#
|
63
|
+
# - a doubly encrypted data envelope placed in the backend store
|
64
|
+
# - a doubly encrypted private key placed in the frontend store
|
65
|
+
# - both stores sync'd with off-machine Git (S3, ...) mirrors
|
66
|
+
# - deletion of the (encrypted) envelope {Open}ed and stuffed with {Put}
|
67
|
+
# - deletion of {Open}ed session data to locate and decrypt envelope
|
50
68
|
def execute
|
51
69
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
put_filepath = File.join @c[:open][:open_dirpath], rel_filepath
|
57
|
-
|
58
|
-
x_dictionary = OpenSession::Dictionary.new
|
59
|
-
x_dictionary.read put_filepath, true, encrypt_key
|
70
|
+
envelope = get_envelope
|
71
|
+
asym_key = OpenSSL::PKey::RSA.new @c[:global][:bit_key_size]
|
72
|
+
lockdown = Aes256.new.encrypt_it( asym_key.public_key.to_pem, envelope.to_json )
|
60
73
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
end
|
74
|
+
#### ###########################################
|
75
|
+
#### ###########################################
|
76
|
+
#### Now Give lockdown to the Backend Store
|
77
|
+
#### ###########################################
|
78
|
+
#### ###########################################
|
67
79
|
|
68
|
-
|
69
|
-
OpenSession::Attributes.stash @@context_name, @c[:open][:open_name], @c[:open][:open_keyname], new_encryption_key
|
70
|
-
x_dictionary.write new_encryption_key
|
80
|
+
master_public_key = Base64.urlsafe_decode64( OpenSession::Attributes.instance.get_value @c[:global][:name], @c[:global][:name], "public.key" )
|
71
81
|
|
82
|
+
lockedup = Aes256.new.encrypt_it( master_public_key, asym_key.export )
|
72
83
|
|
73
|
-
|
74
|
-
|
84
|
+
puts "#### #############################"
|
85
|
+
puts "#### The Crypt Store Suitcase"
|
86
|
+
puts "#### #############################"
|
87
|
+
puts ""
|
88
|
+
puts lockdown
|
89
|
+
puts ""
|
90
|
+
puts "#### #############################"
|
91
|
+
puts "#### The Key Store Suitcase"
|
92
|
+
puts "#### #############################"
|
93
|
+
puts ""
|
94
|
+
puts lockedup
|
95
|
+
puts ""
|
96
|
+
puts "================================================================================================="
|
97
|
+
puts "Now Continue with Unencoding the public key and then locking down the above asym_key.export"
|
98
|
+
puts "================================================================================================="
|
99
|
+
puts ""
|
75
100
|
|
101
|
+
exit
|
76
102
|
|
77
103
|
|
104
|
+
locked_block = Aes256.new.encrypt_it( asym_key.public_key.to_pem, asym_key.export )
|
78
105
|
|
79
|
-
|
80
|
-
|
106
|
+
secured_keytext = asym_key.export
|
107
|
+
## public_key_text = asymmetric_keys.public_key.to_pem
|
81
108
|
|
82
109
|
|
83
|
-
|
84
|
-
File.write @c[:global][:master_pub_key], public_key_crypt
|
110
|
+
Aes256.new.encrypt_it( "rubbish", secrets_dictionary.to_s )
|
85
111
|
|
86
|
-
|
112
|
+
the_encrypted_stuff = Aes256.new.encrypt_it( "rubbish", )
|
87
113
|
|
88
|
-
big_crypted_block = Aes256.new.encrypt_it(
|
89
|
-
public_key_text,
|
90
|
-
public_key_text,
|
91
|
-
payload_signature
|
92
|
-
)
|
93
114
|
|
94
|
-
|
95
|
-
|
96
|
-
puts "Crypted Block"
|
97
|
-
puts "=============="
|
98
|
-
puts ""
|
99
|
-
puts "#{big_crypted_block}"
|
100
|
-
puts ""
|
101
|
-
puts ""
|
102
|
-
puts "Carry on development in init.rb"
|
103
|
-
puts ""
|
115
|
+
#############################################################################################
|
116
|
+
#############################################################################################
|
104
117
|
|
105
118
|
|
106
119
|
=begin
|
@@ -116,7 +129,7 @@ module OpenSecret
|
|
116
129
|
# key4_pem = File.read 'private.secure.pem'
|
117
130
|
# pass_phrase = 'superduperpasswordistoBeENTEREDRIGHT1234HereandRightNOW'
|
118
131
|
# key4 = OpenSSL::PKey::RSA.new key4_pem, pass_phrase
|
119
|
-
# decrypted_text = key4.private_decrypt(Base64.
|
132
|
+
# decrypted_text = key4.private_decrypt(Base64.urlsafe_decode64(encrypted_string))
|
120
133
|
|
121
134
|
# print "\nHey we have done the decryption.\n", "\n"
|
122
135
|
# print decrypted_text, "\n"
|
@@ -126,35 +139,6 @@ module OpenSecret
|
|
126
139
|
#############################################################################################
|
127
140
|
#############################################################################################
|
128
141
|
|
129
|
-
|
130
|
-
machine_key = Engineer.machine_key human_password.length, @c[:global][:ratio]
|
131
|
-
amalgam_key = Amalgam.passwords human_password, machine_key, @c[:global][:ratio]
|
132
|
-
asymmetric_keys = OpenSSL::PKey::RSA.new @c[:global][:bit_key_size]
|
133
|
-
secured_keytext = asymmetric_keys.export @c[:global][:key_cipher], amalgam_key
|
134
|
-
|
135
|
-
crypt_key_segments = [ human_password, @c[:global][:separator_a], @email_addr, @c[:global][:separator_a], @c[:global][:stamp_23] ]
|
136
|
-
machine_key_crypt_key = crypt_key_segments.alphanumeric_union.concat_length
|
137
|
-
blowfish_cipher = OpenSecret::Blowfish.new()
|
138
|
-
machine_key_x = blowfish_cipher.encryptor machine_key, machine_key_crypt_key
|
139
|
-
public_key_text = asymmetric_keys.public_key.to_pem
|
140
|
-
|
141
|
-
OpenSession::Attributes.stash @c[:global][:name], @c[:global][:name], @c[:global][:machine_key_x], machine_key_x
|
142
|
-
OpenSession::Attributes.stash @c[:global][:name], @c[:global][:name], @c[:global][:stamp_key], @c[:global][:stamp_23]
|
143
|
-
OpenSession::Attributes.stash @c[:global][:name], @c[:global][:name], @c[:global][:publickey_id], public_key_text.to_hex
|
144
|
-
|
145
|
-
to_sign_segments = [ secured_keytext, public_key_text, @email_addr, @c[:global][:stamp_23] ]
|
146
|
-
to_sign_packet = to_sign_segments.alphanumeric_union.concat_length
|
147
|
-
signature_string = Base64.encode64( asymmetric_keys.sign( OpenSSL::Digest::SHA256.new, to_sign_packet ) )
|
148
|
-
|
149
|
-
FileUtils.mkdir_p @c[:global][:master_dirpath]
|
150
|
-
File.write @c[:global][:master_prv_key], secured_keytext
|
151
|
-
File.write @c[:global][:master_sig_path], signature_string
|
152
|
-
|
153
|
-
|
154
|
-
#############################################################################################
|
155
|
-
#############################################################################################
|
156
|
-
|
157
|
-
|
158
142
|
end
|
159
143
|
|
160
144
|
|
data/lib/plugins/usecases/put.rb
CHANGED
@@ -5,9 +5,9 @@ module OpenSecret
|
|
5
5
|
require 'openssl'
|
6
6
|
|
7
7
|
# The <b>put use case</b> follows <b>open</b> and it adds secrets into an
|
8
|
-
# <em>(encrypted at rest)</em>
|
9
|
-
#
|
10
|
-
# into the configured storage engines.
|
8
|
+
# <em>(encrypted at rest)</em> <b>envelope</b>. Put can be called many times
|
9
|
+
# and when done, the <b>lock use case</b> can be called to commit all opened
|
10
|
+
# secrets into the configured storage engines.
|
11
11
|
#
|
12
12
|
# Calling <em>put</em> <b>before</b> calling open or <b>after</b> calling lock
|
13
13
|
# is not allowed and will result in an error.
|
@@ -50,8 +50,7 @@ module OpenSecret
|
|
50
50
|
#
|
51
51
|
# @example
|
52
52
|
#
|
53
|
-
# $ opensecret
|
54
|
-
# $ opensecret init
|
53
|
+
# $ opensecret init bill.clinton@example.com
|
55
54
|
# $ opensecret open my/friends
|
56
55
|
#
|
57
56
|
# $ opensecret put monica/surname lewinsky
|
@@ -64,7 +63,15 @@ module OpenSecret
|
|
64
63
|
#
|
65
64
|
# $ opensecret lock
|
66
65
|
#
|
67
|
-
|
66
|
+
# Soon follow up use cases will be unveiled, enabling us to
|
67
|
+
#
|
68
|
+
# - <b>get</b>
|
69
|
+
# - <b>read</b>
|
70
|
+
# - <b>list</b>
|
71
|
+
# - <b>look</b>
|
72
|
+
# - <b>peep</b> and
|
73
|
+
# - <b>peek</b>
|
74
|
+
class Put < SecretsUseCase
|
68
75
|
|
69
76
|
attr_writer :secret_id, :secret_value
|
70
77
|
@@context_name = "opensecret"
|
@@ -94,25 +101,18 @@ module OpenSecret
|
|
94
101
|
# - a new session id and encryption key is generated and used to re-encrypt
|
95
102
|
def execute
|
96
103
|
|
97
|
-
|
98
|
-
encrypt_key = OpenSession::Attributes.instance.get_value @@context_name, @c[:open][:open_name], @c[:open][:open_keyname]
|
99
|
-
rel_filepath = OpenSession::Attributes.instance.get_value @@context_name, @c[:open][:open_name], @c[:open][:open_pathname]
|
100
|
-
|
101
|
-
put_filepath = File.join @c[:open][:open_dirpath], rel_filepath
|
102
|
-
|
103
|
-
x_dictionary = OpenSession::Dictionary.new
|
104
|
-
x_dictionary.read put_filepath, true, encrypt_key
|
104
|
+
envelope = get_envelope
|
105
105
|
|
106
106
|
secret_ids = @secret_id.split("/")
|
107
|
-
if (
|
108
|
-
|
107
|
+
if ( envelope.has_key? secret_ids.first )
|
108
|
+
envelope[secret_ids.first][secret_ids.last] = @secret_value
|
109
109
|
else
|
110
|
-
|
110
|
+
envelope[secret_ids.first] = { secret_ids.last => @secret_value }
|
111
111
|
end
|
112
112
|
|
113
113
|
new_encryption_key = Engineer.strong_key @c[:open][:open_keylen]
|
114
114
|
OpenSession::Attributes.stash @@context_name, @c[:open][:open_name], @c[:open][:open_keyname], new_encryption_key
|
115
|
-
|
115
|
+
envelope.write new_encryption_key
|
116
116
|
|
117
117
|
end
|
118
118
|
|
@@ -14,7 +14,7 @@ module OpenSecret
|
|
14
14
|
# Stash the path into the host machine's configuration file and proceed
|
15
15
|
# to create the path directory chain if it does not already exist.
|
16
16
|
#
|
17
|
-
class Safe <
|
17
|
+
class Safe < SecretsUseCase
|
18
18
|
|
19
19
|
attr_writer :safe_path
|
20
20
|
@@context_name = "opensecret"
|
data/lib/session/dictionary.rb
CHANGED
@@ -15,7 +15,7 @@ module OpenSession
|
|
15
15
|
# - decrypt +after reading from+ a file
|
16
16
|
# - encrypt +before writing to+ a file
|
17
17
|
#
|
18
|
-
#
|
18
|
+
# This dictionary extends {Hash} in order to deliver on its core key value
|
19
19
|
# store, report and retrieve use cases.
|
20
20
|
#
|
21
21
|
# @example
|
@@ -80,13 +80,13 @@ module OpenSession
|
|
80
80
|
|
81
81
|
puts ""
|
82
82
|
puts "============================"
|
83
|
-
puts "Before Encryption
|
83
|
+
puts "Before Encryption"
|
84
84
|
puts "============================"
|
85
85
|
puts ini_string
|
86
86
|
puts "============================"
|
87
87
|
puts ""
|
88
88
|
|
89
|
-
ini_string = OpenSecret::Blowfish.new.encryptor(ini_string,encrypt_key) if @encrypt_at_rest
|
89
|
+
ini_string = Base64.encode64( OpenSecret::Blowfish.new.encryptor(ini_string,encrypt_key) ) if @encrypt_at_rest
|
90
90
|
|
91
91
|
File.write @filepath, ini_string
|
92
92
|
|
@@ -127,12 +127,12 @@ module OpenSession
|
|
127
127
|
|
128
128
|
file_contents = File.read( @filepath ).strip
|
129
129
|
if @encrypt_at_rest then
|
130
|
-
file_contents = OpenSecret::Blowfish.new.decryptor( file_contents, decrypt_key )
|
130
|
+
file_contents = OpenSecret::Blowfish.new.decryptor( Base64.decode64(file_contents), decrypt_key )
|
131
131
|
end
|
132
132
|
|
133
133
|
puts ""
|
134
134
|
puts "==========================="
|
135
|
-
puts "After Decryption
|
135
|
+
puts "After Decryption"
|
136
136
|
puts "==========================="
|
137
137
|
puts file_contents
|
138
138
|
puts "==========================="
|
data/lib/using.txt
CHANGED
data/lib/version.rb
CHANGED
data/opensecret.gemspec
CHANGED
@@ -28,8 +28,8 @@ Gem::Specification.new do |spec|
|
|
28
28
|
spec.add_dependency 'thor'
|
29
29
|
|
30
30
|
spec.add_development_dependency "bundler", "~> 1.16"
|
31
|
-
spec.add_development_dependency "rake", "~> 10.0"
|
32
|
-
spec.add_development_dependency "minitest", "~> 5.0"
|
31
|
+
#### in standard library ==> spec.add_development_dependency "rake", "~> 10.0"
|
32
|
+
#### in standard library ==> spec.add_development_dependency "minitest", "~> 5.0"
|
33
33
|
|
34
34
|
|
35
35
|
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.
|
4
|
+
version: 0.0.959
|
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-03-
|
11
|
+
date: 2018-03-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: inifile
|
@@ -52,34 +52,6 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '1.16'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: rake
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - "~>"
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '10.0'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - "~>"
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '10.0'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: minitest
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - "~>"
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '5.0'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - "~>"
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '5.0'
|
83
55
|
description: opensecret stashes uncrackable secrets into your Git, S3, DropBox, Google
|
84
56
|
Drive and filesystems backends. You interface with its intuitive Linux, Windows,
|
85
57
|
iOS front ends and it offers SDKs and plugins for Ruby, Python, Java, Jenkins, CodeShip,
|
@@ -127,6 +99,8 @@ files:
|
|
127
99
|
- lib/plugins/cipher.rb
|
128
100
|
- lib/plugins/ciphers/aes-256.rb
|
129
101
|
- lib/plugins/ciphers/blowfish.rb
|
102
|
+
- lib/plugins/envelope.rb
|
103
|
+
- lib/plugins/secrets.uc.rb
|
130
104
|
- lib/plugins/stores/store.rb
|
131
105
|
- lib/plugins/usecase.rb
|
132
106
|
- lib/plugins/usecases/init.rb
|