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.
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
@@ -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