opensecret 0.0.988 → 0.0.9925

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +56 -159
  3. data/bin/opensecret +2 -2
  4. data/bin/ops +17 -2
  5. data/lib/extension/string.rb +14 -16
  6. data/lib/{interpreter.rb → interprete.rb} +53 -29
  7. data/lib/keytools/binary.map.rb +49 -0
  8. data/lib/keytools/kdf.api.rb +249 -0
  9. data/lib/keytools/kdf.bcrypt.rb +64 -29
  10. data/lib/keytools/kdf.pbkdf2.rb +92 -83
  11. data/lib/keytools/kdf.scrypt.rb +190 -0
  12. data/lib/keytools/key.64.rb +326 -0
  13. data/lib/keytools/key.algo.rb +109 -0
  14. data/lib/keytools/key.api.rb +1281 -0
  15. data/lib/keytools/key.db.rb +265 -0
  16. data/lib/keytools/{key.module.rb → key.docs.rb} +55 -0
  17. data/lib/keytools/key.error.rb +110 -0
  18. data/lib/keytools/key.id.rb +271 -0
  19. data/lib/keytools/key.iv.rb +107 -0
  20. data/lib/keytools/key.local.rb +265 -0
  21. data/lib/keytools/key.mach.rb +248 -0
  22. data/lib/keytools/key.now.rb +402 -0
  23. data/lib/keytools/key.pair.rb +259 -0
  24. data/lib/keytools/key.pass.rb +120 -0
  25. data/lib/keytools/key.rb +428 -298
  26. data/lib/keytools/keydebug.txt +295 -0
  27. data/lib/logging/gem.logging.rb +3 -3
  28. data/lib/modules/cryptology/collect.rb +20 -0
  29. data/lib/session/require.gem.rb +1 -1
  30. data/lib/usecase/cmd.rb +417 -0
  31. data/lib/usecase/id.rb +36 -0
  32. data/lib/usecase/import.rb +174 -0
  33. data/lib/usecase/init.rb +78 -0
  34. data/lib/usecase/login.rb +70 -0
  35. data/lib/usecase/logout.rb +30 -0
  36. data/lib/usecase/open.rb +126 -0
  37. data/lib/{interprete → usecase}/put.rb +100 -47
  38. data/lib/usecase/read.rb +89 -0
  39. data/lib/{interprete → usecase}/safe.rb +0 -0
  40. data/lib/{interprete → usecase}/set.rb +0 -0
  41. data/lib/usecase/token.rb +111 -0
  42. data/lib/{interprete → usecase}/use.rb +0 -0
  43. data/lib/version.rb +1 -1
  44. data/opensecret.gemspec +4 -3
  45. metadata +39 -33
  46. data/lib/exception/cli.error.rb +0 -53
  47. data/lib/exception/errors/cli.errors.rb +0 -31
  48. data/lib/interprete/begin.rb +0 -232
  49. data/lib/interprete/cmd.rb +0 -621
  50. data/lib/interprete/export.rb +0 -163
  51. data/lib/interprete/init.rb +0 -205
  52. data/lib/interprete/key.rb +0 -119
  53. data/lib/interprete/open.rb +0 -148
  54. data/lib/interprete/seal.rb +0 -129
  55. data/lib/keytools/digester.rb +0 -245
  56. data/lib/keytools/key.data.rb +0 -227
  57. data/lib/keytools/key.derivation.rb +0 -341
  58. data/lib/modules/mappers/collateral.rb +0 -282
  59. data/lib/modules/mappers/envelope.rb +0 -127
  60. data/lib/modules/mappers/settings.rb +0 -170
  61. data/lib/notepad/scratch.pad.rb +0 -224
  62. data/lib/store-commands.txt +0 -180
@@ -234,6 +234,55 @@ cipher.key = key
234
234
 
235
235
  end
236
236
 
237
+
238
+ def self.binbytes
239
+
240
+ for n in 0 .. 256
241
+ eight_bit_binary = "%08d" % [ n.to_s(2) ]
242
+ puts "#{eight_bit_binary} => #{n}"
243
+ end
244
+
245
+ end
246
+
247
+
248
+ def self.shovel
249
+
250
+ first_name = "joe"
251
+ last_name = "bloggs"
252
+
253
+ user_name = first_name
254
+ user_name << last_name
255
+
256
+ puts "Username => #{user_name}"
257
+ puts "First name => #{first_name}"
258
+
259
+ end
260
+
261
+
262
+ def self.print_randoms
263
+ require 'securerandom'
264
+ for n in 0 .. 99
265
+ puts "#{from_rand}"
266
+ end
267
+
268
+ end
269
+
270
+
271
+ def self.from_rand
272
+ random_bit_string = ""
273
+ the_ints = Array.new
274
+ for n in 1 .. 48
275
+ random_integer = SecureRandom.random_number( 256 )
276
+ the_ints.push random_integer
277
+ random_bit_string += "%08d" % [ random_integer.to_s(2) ]
278
+ end
279
+ puts "Integers => #{the_ints.to_s}"
280
+ return random_bit_string
281
+ end
282
+
283
+ ## BinaryMap.print_randoms
284
+ ## BinaryMap.shovel
285
+ ## BinaryMap.binbytes
237
286
  ## BinaryMap.binary
238
287
  ## BinaryMap.crypter
239
288
  ## BinaryMap.bcrypter
@@ -0,0 +1,249 @@
1
+ #!/usr/bin/ruby
2
+ # coding: utf-8
3
+
4
+ module OpenKey
5
+
6
+ # The OpenKey underlying security strategy is to lock a master index file
7
+ # with a <b>symmetric encryption key</b> that is based on two randomly generated
8
+ # and amalgamated <b>55 and 45 character keys</b> and then to lock that key
9
+ # <b>(and only that key)</b> with a 256 bit symmetric encryption key derived from
10
+ # a human password and generated by at least two cryptographic workhorses known
11
+ # as <b>key derivation functions</b>.
12
+ #
13
+ # Random powerful keys are derived are seeded with 55 random bytes and
14
+ # then fed through the master key generator and its two key derivation
15
+ # functions (BCrypt and PBKDF2).
16
+ #
17
+ # == What Does the Master Encryption Key Generator Do?
18
+ #
19
+ # This class sits at the core of implementing that strategy and works to produce
20
+ # 256 bit encryption key derived from a human password which is then minced by
21
+ # two best of breed key derivation functions (BCrypt and PBKDF2).
22
+ #
23
+ # BCrypt (Blowfish) and PBKDF2 are the leading <b>key derivation functions</b>
24
+ # whose modus operandi is to convert <b>low entropy</b> human generated passwords
25
+ # into a high entropy key that is computationally infeasible to acquire via brute
26
+ # force.
27
+ #
28
+ # == How to Create the Encryption Key
29
+ #
30
+ # To create a high entropy encryption key this method takes the first
31
+ # 168 bits from the 186 bit BCrypt key produced by {KdfBCrypt} and
32
+ # the first 96 bits from the 132 bit PBKDF2 key produced inside the
33
+ # {KeyPbkdf2} class and amalgamates them to produce a 264 bit key.
34
+ #
35
+ # The 264 bit key is then digested to produce a 256bit encryption key.
36
+ class KdfApi
37
+
38
+
39
+ # BCrypt (Blowfish) and PBKDF2 are the leading <b>key derivation functions</b>
40
+ # whose modus operandi is to convert <b>low entropy</b> human generated passwords
41
+ # into a high entropy key that is computationally infeasible to acquire via brute
42
+ # force.
43
+ BCRYPT_SALT_KEY_NAME = "bcrypt.salt"
44
+
45
+
46
+ # BCrypt (Blowfish) and PBKDF2 are the leading <b>key derivation functions</b>
47
+ # whose modus operandi is to convert <b>low entropy</b> human generated passwords
48
+ # into a high entropy key that is computationally infeasible to acquire via brute
49
+ # force.
50
+ PBKDF2_SALT_KEY_NAME = "pbkdf2.salt"
51
+
52
+
53
+ # To create a high entropy encryption key we use the full 180 bits
54
+ # from the returned 180 bit BCrypt key produced by {KdfBCrypt}.
55
+ #
56
+ # When amalgamated with the <b>332 bits from the PBKDF2 Key</b> we
57
+ # achieve a powerful <b>union key length</b> of 512 bits.
58
+ BCRYPT_KEY_CONTRIBUTION_SIZE = 180
59
+
60
+
61
+ # The first 332 bits are used from the 384 bit key returned by the
62
+ # PBKDF2 algorithm.
63
+ #
64
+ # When amalgamated with the <b>180 bits from the BCrypt Key</b> we
65
+ # achieve a powerful <b>union key length</b> of 512 bits.
66
+ PBKDF2_KEY_CONTRIBUTION_SIZE = 332
67
+
68
+
69
+ # To create a high entropy encryption key we use the full 180 bits
70
+ # from the returned 180 bit BCrypt key produced by {KdfBCrypt} and
71
+ # the first 332 bits from the 384 bit key returned by PBKDF2.
72
+ #
73
+ # On amalgamation, the outcome is a quality <b>union key length</b>
74
+ # of <b>512 bits</b>.
75
+ AMALGAM_KEY_RAW_BIT_SIZE = BCRYPT_KEY_CONTRIBUTION_SIZE + PBKDF2_KEY_CONTRIBUTION_SIZE
76
+
77
+
78
+ # This method generates a 256 bit symmetric encryption key by passing a
79
+ # textual human sourced secret into two <b>key derivation functions</b>,
80
+ # namely <b>BCrypt and PBKDF2</b>. BCrypt, PBKDF2 and SCrypt are today's
81
+ # <b>in form best of breed</b> cryptographic workhorses for producing a
82
+ # high entropy key from possibly weak human sourced secret text.
83
+ #
84
+ # <b>Example | Derive Key from Password</b>
85
+ #
86
+ # key_store = KeyPair.new( "/path/to/kdf-salt-data.ini" )
87
+ # key_store.use( "peter-pan" )
88
+ # human_key = KdfApi.generate_from_password( "my_s3cr3t", key_store )
89
+ #
90
+ # strong_key = Key.from_random()
91
+ # human_key.encrypt_key( strong_key, key_store )
92
+ #
93
+ # strong_key.encrypt_file "/path/to/file-to-encrypt.pdf"
94
+ # strong_key.encrypt_text "I am the text to encrypt."
95
+ #
96
+ # ---
97
+ #
98
+ # <b>Do not use the key derived from a human secret</b> to encrypt anything
99
+ # other than a <b>high entropy key</b> randomly sourced from 48 bytes.
100
+ #
101
+ # Every time the user logs in, generate (recycle), another human key and
102
+ # another strong key and discard the previously outputted cipher texts.
103
+ #
104
+ # == BCrypt and the PBKDF2 Cryptographic Algorithms
105
+ #
106
+ # BCrypt (Blowfish) and PBKDF2 are the leading <b>key derivation functions</b>
107
+ # that exists to convert <b>low entropy</b> human generated passwords into a high
108
+ # entropy key that is computationally infeasible to acquire through brute force.
109
+ #
110
+ # To create a high entropy encryption key we use the full 180 bits
111
+ # from the returned 180 bit BCrypt key produced by {KdfBCrypt} and
112
+ # the first 332 bits from the 384 bit key returned by PBKDF2.
113
+ #
114
+ # On amalgamation, the outcome is a quality <b>union key length</b>
115
+ # of <b>512 bits</b>.
116
+ #
117
+ # == Creating a High Entropy Encryption Key
118
+ #
119
+ # To create a high entropy encryption key this method takes the first
120
+ # 168 bits from the 186 bit BCrypt key produced by {KdfBCrypt} and
121
+ # the first 96 bits from the 132 bit PBKDF2 key produced inside the
122
+ # {KeyPbkdf2} class and amalgamates them to produce a 264 bit key.
123
+ #
124
+ # Note that all four of the above numbers are divisable by six (6), for
125
+ # representation with a 64 character set, and eight (8), for transport
126
+ # via the byte (8 bit) protocols.
127
+ #
128
+ # <b>Size of BCrypt and PBKDF2 Derived Keys</b>
129
+ #
130
+ # + --------- - --------- +
131
+ # + --------- | --------- +
132
+ # | Algorithm | Bit Count |
133
+ # ----------- | --------- |
134
+ # | BCrypt | 180 Bits |
135
+ # | Pbkdf2 | 332 Bits |
136
+ # ----------- | --------- |
137
+ # | Total | 512 Bits |
138
+ # + --------- | --------- +
139
+ # + --------- - --------- +
140
+ #
141
+ # <b>256 Bit Encryption Key | Remove 8 Bits</b>
142
+ #
143
+ # The manufactured encryption key, an amalgam of the above now has
144
+ # 264 bits carried by 44 Base64 characters.
145
+ #
146
+ # Just before it is used to encrypt vital keys, eight (8) bits are
147
+ # removed from the end of the key. The key is then converted into a
148
+ # powerful 32 byte (256 bit) encryption agent and is hashed by the
149
+ # SHA256 digest and delivered.
150
+ #
151
+ # @param human_secret [String]
152
+ # a robust human generated password with as much entropy as can
153
+ # be mustered. Remember that 40 characters spread randomly over
154
+ # the key space of about 90 characters and not relating to any
155
+ # dictionary word or name is the way to generate a powerful key
156
+ # that has embedded a near 100% entropy rating.
157
+ #
158
+ # @param key_map [KeyPair]
159
+ # The KeyPair storage service must have been initialized and a
160
+ # section specified using {KeyPair.use} thus allowing this method
161
+ # to <b>write key-value pairs</b> representing the BCrypt and
162
+ # PBKDF2 salts through the {KeyPair.set} behaviour.
163
+ #
164
+ # @return [Key]
165
+ # the 256 bit symmetric encryption key derived from a human password
166
+ # and passed through two cryptographic workhorses.
167
+ def self.generate_from_password human_secret, key_map
168
+
169
+ bcrypt_salt = KdfBCrypt.generate_bcrypt_salt
170
+ pbkdf2_salt = KeyPbkdf2.generate_pbkdf2_salt
171
+
172
+ key_map.set( BCRYPT_SALT_KEY_NAME, bcrypt_salt )
173
+ key_map.set( PBKDF2_SALT_KEY_NAME, pbkdf2_salt )
174
+
175
+ return derive_and_amalgamate( human_secret, bcrypt_salt, pbkdf2_salt )
176
+
177
+ end
178
+
179
+
180
+ # Regenerate the viciously unretrievable nor reversable key that was
181
+ # generated in the past and with the same salts that were used during
182
+ # the original key derivation process.
183
+ #
184
+ # @param key_map [Hash]
185
+ # an instantiated and populated hash object containing the salts
186
+ # which were created in the past during the generation. These are
187
+ # now vital for a successful regeneration.
188
+ #
189
+ # @return [Key]
190
+ # the 256 bit symmetric encryption key that was previously generated
191
+ # from the secret and the cryptographic salts within the key_map.
192
+ def self.regenerate_from_salts human_secret, key_map
193
+
194
+ bcrypt_salt = key_map.get( BCRYPT_SALT_KEY_NAME )
195
+ pbkdf2_salt = key_map.get( PBKDF2_SALT_KEY_NAME )
196
+
197
+ return derive_and_amalgamate( human_secret, bcrypt_salt, pbkdf2_salt )
198
+
199
+ end
200
+
201
+
202
+
203
+ private
204
+
205
+
206
+
207
+ def self.derive_and_amalgamate( human_secret, bcrypt_salt, pbkdf2_salt )
208
+
209
+ bcrypt_key = OpenKey::KdfBCrypt.generate_key( human_secret, bcrypt_salt )
210
+ pbkdf2_key = OpenKey::KeyPbkdf2.generate_key( human_secret.reverse, pbkdf2_salt )
211
+
212
+ assert_bcrypt_key_bit_length bcrypt_key
213
+ assert_pbkdf2_key_bit_length pbkdf2_key
214
+
215
+ amalgam_key = Key.new ( bcrypt_key.to_s[ 0 .. (BCRYPT_KEY_CONTRIBUTION_SIZE-1) ] + pbkdf2_key.to_s[ 0 .. (PBKDF2_KEY_CONTRIBUTION_SIZE-1) ] )
216
+
217
+ assert_amalgam_key_bit_length amalgam_key
218
+
219
+ return amalgam_key
220
+
221
+ end
222
+
223
+
224
+ def self.assert_bcrypt_key_bit_length bcrypt_key
225
+ bcrypt_key_bit_length = bcrypt_key.to_s.bytesize
226
+ bcrypt_keysize_msg = "Expecting #{KdfBCrypt::BCRYPT_KEY_EXPORT_BIT_LENGTH} not #{bcrypt_key_bit_length} bits in bcrypt key."
227
+ raise RuntimeError, bcrypt_keysize_msg unless bcrypt_key_bit_length == KdfBCrypt::BCRYPT_KEY_EXPORT_BIT_LENGTH
228
+ end
229
+
230
+
231
+ def self.assert_pbkdf2_key_bit_length pbkdf2_key
232
+ pbkdf2_key_bit_length = pbkdf2_key.to_s.bytesize
233
+ pbkdf2_keysize_msg = "Expecting #{KeyPbkdf2::PBKDF2_EXPORT_BIT_LENGTH} not #{pbkdf2_key_bit_length} bits in pbkdf2 key."
234
+ raise RuntimeError, pbkdf2_keysize_msg unless pbkdf2_key_bit_length == KeyPbkdf2::PBKDF2_EXPORT_BIT_LENGTH
235
+ end
236
+
237
+
238
+ def self.assert_amalgam_key_bit_length amalgam_key
239
+
240
+ amalgam_key_bit_length = amalgam_key.to_s.bytesize
241
+ amalgam_keysize_msg = "Expecting #{AMALGAM_KEY_RAW_BIT_SIZE} not #{amalgam_key_bit_length} bits in amalgam key."
242
+ raise RuntimeError, amalgam_keysize_msg unless amalgam_key_bit_length == AMALGAM_KEY_RAW_BIT_SIZE
243
+ end
244
+
245
+
246
+ end
247
+
248
+
249
+ end
@@ -21,12 +21,10 @@ module OpenKey
21
21
  #
22
22
  # The <b>minimum cost</b> is 4 (16 iterations) and the maximum is 31.
23
23
  #
24
- # <b>A cost of 16 will result in 2^16 = 65,536 iterations</b>.
24
+ # <b>A cost of 16 will result in 2^16 = 65,536 iterations</b> and will slow the
25
+ # derivation time to about a second on a powerful 2020 laptop.
25
26
  #
26
- # This is a safe default and will slow the derivation time
27
- # to about a second on a powerful 2020 laptop.
28
- #
29
- class BCryptKeyGen
27
+ class KdfBCrypt
30
28
 
31
29
  require "bcrypt"
32
30
 
@@ -50,20 +48,21 @@ module OpenKey
50
48
  BCRYPT_KEY_LENGTH = 31
51
49
 
52
50
 
53
- # When the key is transported using a 64 character set where
54
- # each character is represented by 6 bits - the BCrypt key
55
- # expands to 186 bits rather than the original 181 bits.
56
- #
57
- # This expansion is because of the remainder.
58
- #
59
- # 181 bits divided by 6 is 30 characters plus 1 character
60
- # for the extra bit.
51
+ # BCrypt key derivation (from text) implementations truncate
52
+ # the first 55 characters of the incoming text.
53
+ BCRYPT_MAX_IN_TEXT_LENGTH = 55
54
+
55
+
56
+ # The BCrypt algorithm produces 181 raw binary bits which is just
57
+ # one bit more than a 30 character base64 string. Hence the algorithm
58
+ # puts out 31 characters.
61
59
  #
62
- # The 31 transported characters then appear as
63
- # 31 times 6 which equals 186 bits.
64
- BCRYPT_KEY_TRANSPORT_LENGTH = 186
60
+ # We discard the 31st character because 5 of its 6 bits are 100%
61
+ # predictable. Thus the returned key will contribute 180 bits.
62
+ BCRYPT_KEY_EXPORT_BIT_LENGTH = 180
63
+
65
64
 
66
- # The bcrypt algorithm salt string should be 22 characters
65
+ # The BCrypt algorithm salt string should be 22 characters
67
66
  # and may include forward slashes and periods.
68
67
  BCRYPT_SALT_LENGTH = 22
69
68
 
@@ -78,7 +77,7 @@ module OpenKey
78
77
  # The two sections are the
79
78
  # - BCrypt algorithm <b>version number</b> (2a or 2b) and
80
79
  # - a power of 2 integer defining the no. of interations
81
- BCRYPT_OUTPUT_TEXT_PREFIX = "$2a$#{BCRYPT_ITERATION_INTEGER}$"
80
+ BCRYPT_OUTPUT_TEXT_PREFIX = "$2x$#{BCRYPT_ITERATION_INTEGER}$"
82
81
 
83
82
 
84
83
  # Key generators should use this method to create a BCrypt salt
@@ -101,15 +100,45 @@ module OpenKey
101
100
  # This method removes the $2a$16$ preamble string and stores only
102
101
  # the actual salt string whose length should be 22 characters.
103
102
  #
103
+ # <b>Why do BCrypt salts always end with zero, e, u or period</b>?
104
+ #
105
+ # Two <b>(2) leftover bits</b> is the short answer.
106
+ #
107
+ # This is because the salts are a random 16 bytes and must be
108
+ # stored in base64. The 16 bytes equals 128bits which when converted
109
+ # to base64 (6bits per character) results in 21 characters and only
110
+ # two leftover bits.
111
+ #
112
+ # BCrypt Salt => t4bDqoJlHbb/k7bkt4/1Ku (22 characters)
113
+ # BCrypt Salt => 9BjuJU67IG9Lz5tYUhOqeO (22 characters)
114
+ # BCrypt Salt => grz.QREI35585Y3AaCoCTe (22 characters)
115
+ # BCrypt Salt => zsxrVW2RGIltSu.AoS4E7e (22 characters)
116
+ # BCrypt Salt => dTlRJZ6ijDDVk2cFoCQHPO (22 characters)
117
+ # BCrypt Salt => S9B1azH7oD8L3.CQfxxzJO (22 characters)
118
+ # BCrypt Salt => LoZh.q3NdnTIuOmR6gHJF. (22 characters)
119
+ # BCrypt Salt => y6DKk23SmgNR863pTZ8nYe (22 characters)
120
+ # BCrypt Salt => rokdUF6tg6wHV6F0ymKFme (22 characters)
121
+ # BCrypt Salt => jrDpNgh.0OEIYaxsR7E7d. (22 characters)
122
+ #
123
+ # Don't forget BCrypt uses Radix64 (from OpenBSD). So the two (2)
124
+ # leftover bits result in 4 possible values which effectively is
125
+ #
126
+ # a period (.)
127
+ # a zero (0)
128
+ # an e (e)
129
+ # or a u (u)
130
+ #
104
131
  # @return [String]
105
132
  # the salt in a printable format like base64, hex or a string
106
133
  # of ones and zeroes. This salt should be submitted in the exact
107
134
  # same form to the {generate_key} method.
108
- def self.generate_salt
135
+ def self.generate_bcrypt_salt
136
+
109
137
  the_salt_str = BCrypt::Engine.generate_salt( BCRYPT_ITERATION_INTEGER )
110
138
  bcrypt_salt = the_salt_str[ BCRYPT_OUTPUT_TEXT_PREFIX.length .. -1 ]
111
139
  assert_bcrypt_salt bcrypt_salt
112
140
  return bcrypt_salt
141
+
113
142
  end
114
143
 
115
144
 
@@ -141,19 +170,30 @@ module OpenKey
141
170
  # resubmitted here (in the future) to regenerate the same key.
142
171
  #
143
172
  # @return [Key]
144
- # a key holder containing the key which can then be accessed via
145
- # many different formats.
173
+ # an {OpenKey::Key} that has been initialized from the 30 RADIX64
174
+ # character output from the BCrypt algorithm.
175
+ #
176
+ # The BCrypt algorithm produces 181 raw binary bits which is just
177
+ # one bit more than a 30 character base64 string. Hence the algorithm
178
+ # puts out 31 characters.
179
+ #
180
+ # We discard the 31st character because 5 of its 6 bits are 100%
181
+ # predictable. Thus the returned key will contribute 180 bits.
146
182
  def self.generate_key human_secret, bcrypt_salt
147
183
 
148
- hashed_secret = BCrypt::Engine.hash_secret( human_secret, to_bcrypt_salt(bcrypt_salt) )
184
+ assert_bcrypt_salt( bcrypt_salt )
185
+ full_bcrypt_salt = BCRYPT_OUTPUT_TEXT_PREFIX + bcrypt_salt
186
+ hashed_secret = BCrypt::Engine.hash_secret( human_secret, full_bcrypt_salt )
149
187
  encoded64_key = BCrypt::Password.new( hashed_secret ).to_s
150
188
 
151
189
  key_begin_index = BCRYPT_OUTPUT_TEXT_PREFIX.length + BCRYPT_SALT_LENGTH
152
190
  radix64_key_str = encoded64_key[ key_begin_index .. -1 ]
153
- key_length_mesg = "The bcrypt key length should have #{BCRYPT_KEY_LENGTH} characters."
191
+ key_length_mesg = "The BCrypt key length should have #{BCRYPT_KEY_LENGTH} characters."
154
192
  raise RuntimeError, key_length_mesg unless radix64_key_str.length == BCRYPT_KEY_LENGTH
155
193
 
156
- return Key.new(radix64_key_str)
194
+ chopped_radix64_key = radix64_key_str.chop()
195
+
196
+ return Key.from_radix64( chopped_radix64_key )
157
197
 
158
198
  end
159
199
 
@@ -162,11 +202,6 @@ module OpenKey
162
202
  private
163
203
 
164
204
 
165
-
166
- def self.to_bcrypt_salt the_salt
167
- return BCRYPT_OUTPUT_TEXT_PREFIX + the_salt
168
- end
169
-
170
205
  def self.assert_bcrypt_salt the_salt
171
206
  raise RuntimeError, "bcrypt salt not expected to be nil." if the_salt.nil?
172
207
  salt_length_msg = "A bcrypt salt is expected to contain #{BCRYPT_SALT_LENGTH} characters."