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