opensecret 0.0.962 → 0.0.988
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/README.md +16 -10
- data/bin/opensecret +3 -4
- data/bin/ops +5 -0
- data/lib/extension/string.rb +114 -0
- data/lib/factbase/facts.opensecret.io.ini +9 -21
- data/lib/interprete/begin.rb +232 -0
- data/lib/interprete/cmd.rb +621 -0
- data/lib/{plugins/usecases/unlock.rb → interprete/export.rb} +25 -70
- data/lib/interprete/init.rb +205 -0
- data/lib/interprete/key.rb +119 -0
- data/lib/interprete/open.rb +148 -0
- data/lib/{plugins/usecases → interprete}/put.rb +19 -6
- data/lib/{plugins/usecases → interprete}/safe.rb +2 -1
- data/lib/{plugins/usecases/lock.rb → interprete/seal.rb} +24 -34
- data/lib/interprete/set.rb +46 -0
- data/lib/interprete/use.rb +43 -0
- data/lib/interpreter.rb +165 -0
- data/lib/keytools/binary.map.rb +245 -0
- data/lib/keytools/digester.rb +245 -0
- data/lib/keytools/doc.conversion.to.ones.and.zeroes.ruby +179 -0
- data/lib/keytools/doc.rsa.radix.binary-mapping.ruby +190 -0
- data/lib/keytools/doc.star.schema.strategy.txt +77 -0
- data/lib/keytools/doc.using.pbkdf2.kdf.ruby +95 -0
- data/lib/keytools/doc.using.pbkdf2.pkcs.ruby +266 -0
- data/lib/keytools/kdf.bcrypt.rb +180 -0
- data/lib/keytools/kdf.pbkdf2.rb +164 -0
- data/lib/keytools/key.data.rb +227 -0
- data/lib/keytools/key.derivation.rb +341 -0
- data/lib/keytools/key.module.rb +140 -0
- data/lib/keytools/key.rb +481 -0
- data/lib/logging/gem.logging.rb +1 -2
- data/lib/modules/cryptology.md +43 -0
- data/lib/{plugins/ciphers → modules/cryptology}/aes-256.rb +6 -0
- data/lib/{crypto → modules/cryptology}/amalgam.rb +6 -0
- data/lib/modules/cryptology/blowfish.rb +130 -0
- data/lib/modules/cryptology/cipher.rb +207 -0
- data/lib/modules/cryptology/collect.rb +118 -0
- data/lib/{plugins → modules/cryptology}/crypt.io.rb +5 -0
- data/lib/{crypto → modules/cryptology}/engineer.rb +7 -1
- data/lib/{crypto → modules/cryptology}/open.bcrypt.rb +0 -0
- data/lib/modules/mappers/collateral.rb +282 -0
- data/lib/modules/mappers/dictionary.rb +288 -0
- data/lib/modules/mappers/envelope.rb +127 -0
- data/lib/modules/mappers/settings.rb +170 -0
- data/lib/modules/storage/coldstore.rb +186 -0
- data/lib/{opensecret/plugins.io/git/git.flow.rb → modules/storage/git.store.rb} +11 -0
- data/lib/notepad/scratch.pad.rb +17 -0
- data/lib/session/fact.finder.rb +13 -0
- data/lib/session/require.gem.rb +5 -0
- data/lib/store-commands.txt +180 -0
- data/lib/version.rb +1 -1
- data/opensecret.gemspec +5 -6
- metadata +74 -29
- data/lib/crypto/blowfish.rb +0 -85
- data/lib/crypto/collect.rb +0 -140
- data/lib/crypto/verify.rb +0 -33
- data/lib/opensecret.rb +0 -236
- data/lib/plugins/cipher.rb +0 -203
- data/lib/plugins/ciphers/blowfish.rb +0 -126
- data/lib/plugins/coldstore.rb +0 -181
- data/lib/plugins/envelope.rb +0 -116
- data/lib/plugins/secrets.uc.rb +0 -94
- data/lib/plugins/usecase.rb +0 -239
- data/lib/plugins/usecases/init.rb +0 -145
- data/lib/plugins/usecases/open.rb +0 -108
- data/lib/session/attributes.rb +0 -279
- data/lib/session/dictionary.rb +0 -191
- data/lib/session/file.path.rb +0 -53
- data/lib/session/session.rb +0 -80
@@ -0,0 +1,245 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
module OpenKey
|
4
|
+
|
5
|
+
class BinaryMap
|
6
|
+
|
7
|
+
|
8
|
+
require 'openssl'
|
9
|
+
require "base64"
|
10
|
+
require "bcrypt"
|
11
|
+
|
12
|
+
|
13
|
+
CHARACTERS_64 = [
|
14
|
+
"a", "9", "W", "B", "f", "K", "O", "z",
|
15
|
+
"3", "s", "1", "5", "c", "n", "E", "J",
|
16
|
+
"L", "A", "l", "6", "I", "w", "o", "g",
|
17
|
+
"k", "N", "t", "Y", "S", "/", "T", "b",
|
18
|
+
"V", "R", "H", "0", "@", "Z", "8", "F",
|
19
|
+
"G", "j", "u", "m", "M", "h", "4", "p",
|
20
|
+
"q", "d", "7", "v", "e", "2", "U", "X",
|
21
|
+
"r", "C", "y", "Q", "D", "x", "P", "i"
|
22
|
+
]
|
23
|
+
|
24
|
+
def self.tmp_holder
|
25
|
+
|
26
|
+
|
27
|
+
bcrypt_packed_key = [ bcrypt_key.to_s ].pack("B*")
|
28
|
+
pbkdf2_packed_key = [ pbkdf2_key.to_s ].pack("B*")
|
29
|
+
|
30
|
+
bcrypt_un_pack_ed = bcrypt_packed_key.unpack("B*")[0]
|
31
|
+
pbkdf2_un_pack_ed = pbkdf2_packed_key.unpack("B*")[0]
|
32
|
+
|
33
|
+
bcrypt_they_match = bcrypt_key.to_s.eql? bcrypt_un_pack_ed
|
34
|
+
pbkdf2_they_match = pbkdf2_key.to_s.eql? pbkdf2_un_pack_ed
|
35
|
+
|
36
|
+
puts ""
|
37
|
+
puts "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
38
|
+
puts "The actual binary thing => [ #{bcrypt_key.to_s} ]"
|
39
|
+
puts "Theactual unpacked ting => [ #{bcrypt_un_pack_ed} ]"
|
40
|
+
puts "Lengthof packed version => [ #{bcrypt_packed_key.length} ]"
|
41
|
+
puts "Byte size Length of Pck => [ #{bcrypt_packed_key.bytesize} ]"
|
42
|
+
puts "The packed keys version => [ #{bcrypt_packed_key} ]"
|
43
|
+
puts ""
|
44
|
+
puts "Length unpacked version => [ #{bcrypt_un_pack_ed.length} ]"
|
45
|
+
puts "Bytesize of Unpacked Vn => [ #{bcrypt_un_pack_ed.bytesize} ]"
|
46
|
+
puts ""
|
47
|
+
puts "Is full circle correct? => [ #{bcrypt_they_match} ]"
|
48
|
+
puts ""
|
49
|
+
puts bcrypt_key.to_s
|
50
|
+
puts bcrypt_un_pack_ed
|
51
|
+
puts ""
|
52
|
+
puts "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
53
|
+
puts ""
|
54
|
+
puts "The actual binary thing => [ #{pbkdf2_key.to_s} ]"
|
55
|
+
puts "Theactual unpacked ting => [ #{pbkdf2_un_pack_ed} ]"
|
56
|
+
puts "Lengthof packed version => [ #{pbkdf2_packed_key.length} ]"
|
57
|
+
puts "Byte size Length of Pck => [ #{pbkdf2_packed_key.bytesize} ]"
|
58
|
+
puts "The packed keys version => [ #{pbkdf2_packed_key} ]"
|
59
|
+
puts ""
|
60
|
+
puts "Length unpacked version => [ #{pbkdf2_un_pack_ed.length} ]"
|
61
|
+
puts "Bytesize of Unpacked Vn => [ #{pbkdf2_un_pack_ed.bytesize} ]"
|
62
|
+
puts ""
|
63
|
+
puts "Is full circle correct? => [ #{pbkdf2_they_match} ]"
|
64
|
+
puts ""
|
65
|
+
puts pbkdf2_key.to_s
|
66
|
+
puts pbkdf2_un_pack_ed
|
67
|
+
puts ""
|
68
|
+
|
69
|
+
char_index = 1
|
70
|
+
zero_count = 0
|
71
|
+
one_count = 0
|
72
|
+
|
73
|
+
pbkdf2_key.to_s.each_char do |string_bit|
|
74
|
+
puts "Bit number [ #{char_index} ] is a [ #{string_bit} ]" if char_index % 4 == 0
|
75
|
+
char_index += 1
|
76
|
+
zero_count += 1 if string_bit.eql? "0"
|
77
|
+
one_count += 1 if string_bit.eql? "1"
|
78
|
+
end
|
79
|
+
|
80
|
+
puts "There are [ #{zero_count} ] zeroes."
|
81
|
+
puts "There are [ #{one_count} ] ones."
|
82
|
+
|
83
|
+
|
84
|
+
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
|
90
|
+
def self.bcrypter
|
91
|
+
|
92
|
+
generated_salt = BCrypt::Engine.generate_salt( 12 )
|
93
|
+
|
94
|
+
|
95
|
+
my_password = BCrypt::Password.new( BCrypt::Engine.hash_secret( "my password text", generated_salt ) )
|
96
|
+
|
97
|
+
|
98
|
+
## my_password = BCrypt::Password.create( "my password", :cost => 12 )
|
99
|
+
|
100
|
+
salt_begin_index = my_password.to_s.rindex( "$" ) + 1
|
101
|
+
salt_hash_length = my_password.to_s.length - salt_begin_index
|
102
|
+
|
103
|
+
|
104
|
+
|
105
|
+
#=> "$2a$10$vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa"
|
106
|
+
|
107
|
+
# Salt is 22 characters
|
108
|
+
# Key is 31 characters
|
109
|
+
# total is 53 characters
|
110
|
+
|
111
|
+
good_password = my_password == "my password text"
|
112
|
+
bad_password = my_password == "my password text"
|
113
|
+
|
114
|
+
puts ""
|
115
|
+
puts "Bcrypt password is #{my_password}"
|
116
|
+
puts "Bcrypt COST is => #{BCrypt::Engine.cost}"
|
117
|
+
puts "Length of salt plus hash is #{salt_hash_length}"
|
118
|
+
puts "Salt begin index is #{salt_begin_index}"
|
119
|
+
puts "Generated Salt is #{generated_salt}"
|
120
|
+
puts "The Good Password? #{good_password}"
|
121
|
+
puts "The BadBoy Password? #{bad_password}"
|
122
|
+
puts ""
|
123
|
+
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
## Bcrypt password is $2a$12$nkyYKCwljFRtcif6FCXn3ey29P8mGMeY6YGNEaoBYmkScgyYrbusC
|
129
|
+
## Bcrypt COST is => 10
|
130
|
+
## Length of salt plus hash is 53
|
131
|
+
## Salt begin index is 7
|
132
|
+
## Generated Salt is $2a$12$nkyYKCwljFRtcif6FCXn3e
|
133
|
+
## The Good Password? true
|
134
|
+
## The BadBoy Password? false
|
135
|
+
|
136
|
+
|
137
|
+
|
138
|
+
def self.salter
|
139
|
+
|
140
|
+
original_pass = "abcdefghijklmnopqrstuvwxyz@0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+"
|
141
|
+
|
142
|
+
for n in 0 .. 63
|
143
|
+
the_pass = original_pass + original_pass[0..n]
|
144
|
+
puts "==========================================="
|
145
|
+
puts "Pass #{n} => #{the_pass}"
|
146
|
+
puts "Password LENGTH => #{the_pass.length}"
|
147
|
+
puts "==========================================="
|
148
|
+
password_cruncher the_pass
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
def self.password_cruncher the_password
|
154
|
+
|
155
|
+
|
156
|
+
raise RuntimeError, "Only 72 characters change the resultant key. Strings with 73, 74, 75 (etc) characters produce the same key as the truncated 72 character input." if the_password.length > 72
|
157
|
+
|
158
|
+
preamble = "$2a$12$"
|
159
|
+
salt_chars = "nkyYKCwljFRtcif6FCXn3e"
|
160
|
+
|
161
|
+
cost_length = "12".length
|
162
|
+
expected_pre_len = 5 + cost_length
|
163
|
+
non_key_length = expected_pre_len + 22
|
164
|
+
raise RuntimeError, "Preamble length not expected" unless preamble.length == expected_pre_len
|
165
|
+
raise RuntimeError, "Salt length not expected" unless salt_chars.length == 22
|
166
|
+
|
167
|
+
generated_salt = preamble + salt_chars
|
168
|
+
|
169
|
+
my_password = BCrypt::Password.new( BCrypt::Engine.hash_secret( the_password, generated_salt ) ).to_s
|
170
|
+
|
171
|
+
salt_begin_index = my_password.rindex( "$" ) + 1
|
172
|
+
salt_hash_length = my_password.length - salt_begin_index
|
173
|
+
|
174
|
+
actual_key = my_password.gsub( generated_salt, "" )
|
175
|
+
raise RuntimeError, "Key length not expected" unless actual_key.length == 31
|
176
|
+
|
177
|
+
also_key = my_password[ non_key_length .. -1 ]
|
178
|
+
raise RuntimeError, "Key strings not matching" unless actual_key.eql? also_key
|
179
|
+
|
180
|
+
|
181
|
+
puts "Bcrypt password is #{my_password}"
|
182
|
+
puts "Bcrypt COST is => #{BCrypt::Engine.cost}"
|
183
|
+
puts "Length of salt plus hash is #{salt_hash_length}"
|
184
|
+
puts "Salt begin index is #{salt_begin_index}"
|
185
|
+
puts "Generated Salt is #{generated_salt}"
|
186
|
+
puts "Actual Key 1 => #{actual_key}"
|
187
|
+
puts "Actual Key 2 => #{also_key}"
|
188
|
+
puts "KEY Length is => [ #{also_key.length} ]"
|
189
|
+
puts ""
|
190
|
+
|
191
|
+
|
192
|
+
end
|
193
|
+
|
194
|
+
|
195
|
+
|
196
|
+
def self.crypter
|
197
|
+
|
198
|
+
cipher = OpenSSL::Cipher.new 'AES-128-CBC'
|
199
|
+
cipher.encrypt
|
200
|
+
iv = cipher.random_iv
|
201
|
+
|
202
|
+
pwd = 'some hopefully not to easily guessable password'
|
203
|
+
salt = OpenSSL::Random.random_bytes 16
|
204
|
+
iter = 20000
|
205
|
+
key_len = cipher.key_len
|
206
|
+
digest = OpenSSL::Digest::SHA512.new
|
207
|
+
|
208
|
+
key = OpenSSL::PKCS5.pbkdf2_hmac(pwd, salt, 1000000, 16, digest)
|
209
|
+
|
210
|
+
puts ""
|
211
|
+
puts "The generated salt has a length of [#{salt.length}]"
|
212
|
+
puts "The salt generated is => #{salt}"
|
213
|
+
puts "The generated key has a length of [#{key.length}]"
|
214
|
+
puts "The Key generated is => #{key}"
|
215
|
+
puts "The Key in Base64 is => #{Base64.encode64(key)}"
|
216
|
+
puts ""
|
217
|
+
|
218
|
+
cipher.key = key
|
219
|
+
|
220
|
+
##### Now encrypt the data:
|
221
|
+
|
222
|
+
### encrypted = cipher.update document
|
223
|
+
### encrypted << cipher.final
|
224
|
+
|
225
|
+
end
|
226
|
+
|
227
|
+
|
228
|
+
def self.binary
|
229
|
+
|
230
|
+
for n in 0 .. 128
|
231
|
+
six_bit_binary = "%06d" % [ n.to_s(2) ]
|
232
|
+
puts "#{n} in binary is => #{six_bit_binary}"
|
233
|
+
end
|
234
|
+
|
235
|
+
end
|
236
|
+
|
237
|
+
## BinaryMap.binary
|
238
|
+
## BinaryMap.crypter
|
239
|
+
## BinaryMap.bcrypter
|
240
|
+
## BinaryMap.salter
|
241
|
+
|
242
|
+
end
|
243
|
+
|
244
|
+
|
245
|
+
end
|
@@ -0,0 +1,245 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
module OpenKey
|
4
|
+
|
5
|
+
# If you have a possibly weak human password that you need to either store
|
6
|
+
# or derive a symmetric encryption key from - you use this digester.
|
7
|
+
#
|
8
|
+
# You can safely store the resulting key confident that no known method exists
|
9
|
+
# of deriving the original password from the key. The digester uses the
|
10
|
+
# most recent SHA512 bit hashing algorithm - twice - to mince the key into
|
11
|
+
# something worthless to everyone, but the password originator.
|
12
|
+
#
|
13
|
+
# This key digester knows how to apply one-way functions that dessimate a
|
14
|
+
# (possibly weak) human generated (password) string.
|
15
|
+
#
|
16
|
+
# It should be initialized with a nonce like the count of nanoseconds
|
17
|
+
# since the current second (for low throughput systems).
|
18
|
+
#
|
19
|
+
# ==How to Use the Digester
|
20
|
+
#
|
21
|
+
# <b><em>Generating the Hashed Key</em></b>
|
22
|
+
#
|
23
|
+
# To use the digester you instantiate it with a nonce and then call
|
24
|
+
# the generate method with a possibly weak human key that is required
|
25
|
+
# to contain a minimum of 6 characters.
|
26
|
+
#
|
27
|
+
# The 6 characters excludes any leading or trailing whitespace.
|
28
|
+
# keydigester = Digester.new "nonce"
|
29
|
+
# the_key = keydigester.generate "human_k3y"
|
30
|
+
# output_iv = keydigester.encrypted_iv
|
31
|
+
#
|
32
|
+
# You then read off the encrypted iv (initialization vector).
|
33
|
+
#
|
34
|
+
# <b><em>Re-generating the Hashed Key</em></b>
|
35
|
+
#
|
36
|
+
# To retrieve the same key (perhaps many moons later), you instantiate
|
37
|
+
# another Digester providing the same nonce you gave to the generate
|
38
|
+
# method. You then supply the encrypted iv that you pulled out during
|
39
|
+
# the generate step.
|
40
|
+
# keydigester = Digester.new "nonce"
|
41
|
+
# keydigester.encrypted_iv = "axbxcxdx1x2x3x4x"
|
42
|
+
# the_key = keydigester.regenerate "human_k3y"
|
43
|
+
#
|
44
|
+
# Now when you regenerate the key - you have the original.
|
45
|
+
#
|
46
|
+
#
|
47
|
+
# @example
|
48
|
+
# keydigester = Digester.new "nonce"
|
49
|
+
# the_key = keydigester.generate "human_k3y"
|
50
|
+
# output_iv = keydigester.encrypted_iv
|
51
|
+
#
|
52
|
+
# keydigester = Digester.new "nonce"
|
53
|
+
# keydigester.encrypted_iv = "axbxcxdx1x2x3x4x"
|
54
|
+
# the_key = keydigester.regenerate "human_k3y"
|
55
|
+
class Digester
|
56
|
+
|
57
|
+
attr_accessor :encrypted_iv
|
58
|
+
|
59
|
+
# The golden ratio is the relationship between the human password and the
|
60
|
+
# strengthening amalgam. Two is perhaps too small, three or four is perfect
|
61
|
+
# to strengthen human generated keys whose median tends to gravitate at
|
62
|
+
# around 12 characters.
|
63
|
+
AMALGAM_GOLDEN_RATIO = 3
|
64
|
+
|
65
|
+
# The inner nonce provides a salt of sorts to help with randomizing the
|
66
|
+
# keys and protecting them from pre-configured rainbow tables.
|
67
|
+
INNER_NONCE = "9]w/t$=ON@mUf(+_SoY"
|
68
|
+
|
69
|
+
# The minimum length tolerated for the assumed human provided password.
|
70
|
+
# This number excludes any leading or trailing whitespace which should
|
71
|
+
# be removed before length examination is performed.
|
72
|
+
MIN_HUMAN_KEY_LENGTH = 6
|
73
|
+
|
74
|
+
|
75
|
+
# Initialize this key digester with a nonce like the count of nanoseconds
|
76
|
+
# since the current second (for low throughput systems).
|
77
|
+
#
|
78
|
+
# Note that the same nonce must be provided in order to produce the same
|
79
|
+
# key from calling either {Digester.generate} or {Digester.regenerate}.
|
80
|
+
#
|
81
|
+
# @param the_nonce [String]
|
82
|
+
# the nonce can be the count of nanoseconds since the current second
|
83
|
+
# (for low throughput systems).
|
84
|
+
#
|
85
|
+
# @raise [ArgumentError]
|
86
|
+
# raise an error if the nonce is empty, or consists only of whitespace
|
87
|
+
# or is too short.
|
88
|
+
def initialize the_nonce
|
89
|
+
|
90
|
+
@nonce = the_nonce.strip.reverse
|
91
|
+
|
92
|
+
raise ArgumentError, "The nonce contains only whitespace." if @nonce.empty?
|
93
|
+
raise ArgumentError, "The nonce is too short." if @nonce.length < MIN_HUMAN_KEY_LENGTH
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
# Generate a viciously unretrievable nor reversable string from a possible
|
99
|
+
# weak key provided by a human being.
|
100
|
+
#
|
101
|
+
# Due to the fickle nature of human beings we use an amalgam key to frustrate
|
102
|
+
# attempts to derive the original through rainbow tables and replay attacks.
|
103
|
+
#
|
104
|
+
# <b>Getting the Initialization Vector</b>
|
105
|
+
#
|
106
|
+
# After calling this method the encrypted initialization vector generated
|
107
|
+
# must be stored and re-provided to the {Digester.regenerate} method as
|
108
|
+
# and when required.
|
109
|
+
#
|
110
|
+
# @example
|
111
|
+
# keydigester = Digester.new "nonce"
|
112
|
+
# the_key = keydigester.generate "human_k3y"
|
113
|
+
# output_iv = keydigester.encrypted_iv
|
114
|
+
#
|
115
|
+
# @param human_p4ss [String]
|
116
|
+
#
|
117
|
+
# the key provided by a human being which cannot be less than six
|
118
|
+
# characters in length. Between 24 and 32 apparently random characters
|
119
|
+
# involving upper case letters, digits and punctuators.
|
120
|
+
#
|
121
|
+
# Leading and trailing whitespace is removed from the string if found.
|
122
|
+
#
|
123
|
+
# @raise [ArgumentError] if the (possibly) human sourced password is too short
|
124
|
+
def generate human_p4ss
|
125
|
+
|
126
|
+
human_key = human_p4ss.strip.reverse
|
127
|
+
raise ArgumentError, "The password contains only whitespace." if human_key.empty?
|
128
|
+
raise ArgumentError, "The password is too short." if human_key.length < MIN_HUMAN_KEY_LENGTH
|
129
|
+
|
130
|
+
machine_key = OpenSecret::ToolBelt::Engineer.machine_key human_key.length, AMALGAM_GOLDEN_RATIO
|
131
|
+
snippet = human_key[ human_key.length - MIN_HUMAN_KEY_LENGTH .. -1 ]
|
132
|
+
|
133
|
+
iv_key = [ INNER_NONCE, snippet, @nonce ].join
|
134
|
+
@encrypted_iv = machine_key.encrypt_url_encode( iv_key )
|
135
|
+
|
136
|
+
return hashed_outcome human_key, machine_key
|
137
|
+
|
138
|
+
end
|
139
|
+
|
140
|
+
|
141
|
+
# Regenerate the viciously unretrievable nor reversable string that has been
|
142
|
+
# generated from a possible weak key provided by a human being.
|
143
|
+
#
|
144
|
+
# The difference between this and the {Digester.generate} method is that
|
145
|
+
# the encrypted initialization vector is provided here. This must first be
|
146
|
+
# decrypted before being fed back into the numerical mincer.
|
147
|
+
#
|
148
|
+
# The same nonce must also be provided in the constructor.
|
149
|
+
#
|
150
|
+
# <b>Setting the Initialization Vector</b>
|
151
|
+
#
|
152
|
+
# Before calling this method the encrypted initialization vector generated
|
153
|
+
# by the generate method needs to be faithfully returned.
|
154
|
+
#
|
155
|
+
# @example
|
156
|
+
#
|
157
|
+
# keydigester = Digester.new "nonce"
|
158
|
+
# keydigester.encrypted_iv = "axbxcxdx1x2x3x4x"
|
159
|
+
# the_key = keydigester.regenerate "human_k3y"
|
160
|
+
#
|
161
|
+
# @param human_p4ss [String]
|
162
|
+
#
|
163
|
+
# the key provided by a human being which cannot be less than six
|
164
|
+
# characters in length. Between 24 and 32 apparently random characters
|
165
|
+
# involving upper case letters, digits and punctuators.
|
166
|
+
#
|
167
|
+
# Leading and trailing whitespace is removed from the string if found.
|
168
|
+
#
|
169
|
+
# @raise [ArgumentError]
|
170
|
+
# If the human sourced password is too short.
|
171
|
+
# Or if it consists solely of whitespace.
|
172
|
+
def regenerate human_p4ss
|
173
|
+
|
174
|
+
human_key = human_p4ss.strip.reverse
|
175
|
+
raise ArgumentError, "The password contains only whitespace." if human_key.empty?
|
176
|
+
raise ArgumentError, "The password is too short." if human_key.length < MIN_HUMAN_KEY_LENGTH
|
177
|
+
|
178
|
+
snippet = human_key[ human_key.length - MIN_HUMAN_KEY_LENGTH .. -1 ]
|
179
|
+
iv_key = [ INNER_NONCE, snippet, @nonce ].join
|
180
|
+
machine_key = @encrypted_iv.url_decode_decrypt( iv_key )
|
181
|
+
|
182
|
+
return hashed_outcome human_key, machine_key
|
183
|
+
|
184
|
+
end
|
185
|
+
|
186
|
+
|
187
|
+
# This digester alphanumeric hasher employs the SHA512 digest algorithm
|
188
|
+
# to gnash the parameter key and then Base64 encode the result.
|
189
|
+
#
|
190
|
+
# This method removes any non alpha-numeric characeters after a url safe
|
191
|
+
# base 64 encoding and thus guarantees that the resultant string will
|
192
|
+
# not contain
|
193
|
+
#
|
194
|
+
# - any equals signs
|
195
|
+
# - any hyphens
|
196
|
+
# - any underscores
|
197
|
+
#
|
198
|
+
# It is safe to use this method when a result must be stored in environment
|
199
|
+
# variables or other forms (like INI) where an equals sign is frowned upon.
|
200
|
+
#
|
201
|
+
# That said, this method should not be used if one wants to return to the
|
202
|
+
# pre base64 encoded character sequence. By mashing away the non-alphanums
|
203
|
+
# it mashes away any realistic hope of a determinant return to the raw
|
204
|
+
# hashed value.
|
205
|
+
#
|
206
|
+
# @param hash_me [String]
|
207
|
+
# use a one-way function to mush me into a form that is repeatable but
|
208
|
+
# non-returnable to the original input.
|
209
|
+
#
|
210
|
+
# @return [String]
|
211
|
+
# The SHA512 mashed version of the parameter key which is Base64 encoded
|
212
|
+
# (using the url safe variant) and the result stripped of any non alpha
|
213
|
+
# numeric characters.
|
214
|
+
#
|
215
|
+
def self.alphanum_hash hash_me
|
216
|
+
return self.alphanum_encoder( OpenSSL::Digest::SHA512.digest( hash_me ) )
|
217
|
+
end
|
218
|
+
|
219
|
+
|
220
|
+
def self.mash hash_me, max_length
|
221
|
+
raise ArgumentError, "Max length #{max_length} is unacceptable." if max_length < 32
|
222
|
+
return self.alphanum_encoder( OpenSSL::Digest::SHA512.digest( hash_me ) )[0 .. (max_length-1)]
|
223
|
+
end
|
224
|
+
|
225
|
+
|
226
|
+
private
|
227
|
+
|
228
|
+
|
229
|
+
def self.alphanum_encoder encode_this
|
230
|
+
return Base64.urlsafe_encode64( encode_this ).delete("=\\-_")
|
231
|
+
end
|
232
|
+
|
233
|
+
|
234
|
+
def hashed_outcome the_human_key, the_machine_key
|
235
|
+
amalgam_key = OpenSecret::ToolBelt::Amalgam.passwords the_human_key, the_machine_key, AMALGAM_GOLDEN_RATIO
|
236
|
+
level1_hash = Digester.alphanum_encoder( OpenSSL::Digest::SHA512.digest( amalgam_key ) )
|
237
|
+
level2_hash = Digester.alphanum_encoder( OpenSSL::Digest::SHA512.digest( @nonce + level1_hash ) )
|
238
|
+
return level2_hash
|
239
|
+
end
|
240
|
+
|
241
|
+
|
242
|
+
end
|
243
|
+
|
244
|
+
|
245
|
+
end
|