safedb 0.01.0001
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.yardopts +3 -0
- data/Gemfile +10 -0
- data/LICENSE +21 -0
- data/README.md +793 -0
- data/Rakefile +16 -0
- data/bin/safe +5 -0
- data/lib/configs/README.md +58 -0
- data/lib/extension/array.rb +162 -0
- data/lib/extension/dir.rb +35 -0
- data/lib/extension/file.rb +123 -0
- data/lib/extension/hash.rb +33 -0
- data/lib/extension/string.rb +572 -0
- data/lib/factbase/facts.safedb.net.ini +38 -0
- data/lib/interprete.rb +462 -0
- data/lib/keytools/PRODUCE_RAND_SEQ_USING_DEV_URANDOM.txt +0 -0
- data/lib/keytools/kdf.api.rb +243 -0
- data/lib/keytools/kdf.bcrypt.rb +265 -0
- data/lib/keytools/kdf.pbkdf2.rb +262 -0
- data/lib/keytools/kdf.scrypt.rb +190 -0
- data/lib/keytools/key.64.rb +326 -0
- data/lib/keytools/key.algo.rb +109 -0
- data/lib/keytools/key.api.rb +1391 -0
- data/lib/keytools/key.db.rb +330 -0
- data/lib/keytools/key.docs.rb +195 -0
- data/lib/keytools/key.error.rb +110 -0
- data/lib/keytools/key.id.rb +271 -0
- data/lib/keytools/key.ident.rb +243 -0
- data/lib/keytools/key.iv.rb +107 -0
- data/lib/keytools/key.local.rb +259 -0
- data/lib/keytools/key.now.rb +402 -0
- data/lib/keytools/key.pair.rb +259 -0
- data/lib/keytools/key.pass.rb +120 -0
- data/lib/keytools/key.rb +585 -0
- data/lib/logging/gem.logging.rb +132 -0
- data/lib/modules/README.md +43 -0
- data/lib/modules/cryptology/aes-256.rb +154 -0
- data/lib/modules/cryptology/amalgam.rb +70 -0
- data/lib/modules/cryptology/blowfish.rb +130 -0
- data/lib/modules/cryptology/cipher.rb +207 -0
- data/lib/modules/cryptology/collect.rb +138 -0
- data/lib/modules/cryptology/crypt.io.rb +225 -0
- data/lib/modules/cryptology/engineer.rb +99 -0
- data/lib/modules/mappers/dictionary.rb +288 -0
- data/lib/modules/storage/coldstore.rb +186 -0
- data/lib/modules/storage/git.store.rb +399 -0
- data/lib/session/fact.finder.rb +334 -0
- data/lib/session/require.gem.rb +112 -0
- data/lib/session/time.stamp.rb +340 -0
- data/lib/session/user.home.rb +49 -0
- data/lib/usecase/cmd.rb +487 -0
- data/lib/usecase/config/README.md +57 -0
- data/lib/usecase/docker/README.md +146 -0
- data/lib/usecase/docker/docker.rb +49 -0
- data/lib/usecase/edit/README.md +43 -0
- data/lib/usecase/edit/delete.rb +46 -0
- data/lib/usecase/export.rb +40 -0
- data/lib/usecase/files/README.md +37 -0
- data/lib/usecase/files/eject.rb +56 -0
- data/lib/usecase/files/file_me.rb +78 -0
- data/lib/usecase/files/read.rb +169 -0
- data/lib/usecase/files/write.rb +89 -0
- data/lib/usecase/goto.rb +57 -0
- data/lib/usecase/id.rb +36 -0
- data/lib/usecase/import.rb +157 -0
- data/lib/usecase/init.rb +63 -0
- data/lib/usecase/jenkins/README.md +146 -0
- data/lib/usecase/jenkins/jenkins.rb +208 -0
- data/lib/usecase/login.rb +71 -0
- data/lib/usecase/logout.rb +28 -0
- data/lib/usecase/open.rb +71 -0
- data/lib/usecase/print.rb +40 -0
- data/lib/usecase/put.rb +81 -0
- data/lib/usecase/set.rb +44 -0
- data/lib/usecase/show.rb +138 -0
- data/lib/usecase/terraform/README.md +91 -0
- data/lib/usecase/terraform/terraform.rb +121 -0
- data/lib/usecase/token.rb +35 -0
- data/lib/usecase/update/README.md +55 -0
- data/lib/usecase/update/rename.rb +180 -0
- data/lib/usecase/use.rb +41 -0
- data/lib/usecase/verse.rb +20 -0
- data/lib/usecase/view.rb +71 -0
- data/lib/usecase/vpn/README.md +150 -0
- data/lib/usecase/vpn/vpn.ini +31 -0
- data/lib/usecase/vpn/vpn.rb +54 -0
- data/lib/version.rb +3 -0
- data/safedb.gemspec +34 -0
- metadata +193 -0
@@ -0,0 +1,262 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
# coding: utf-8
|
3
|
+
|
4
|
+
module SafeDb
|
5
|
+
|
6
|
+
|
7
|
+
# PBKDF2 is a powerful leading <b>Key Derivation Function (KDF)</b> that exists to
|
8
|
+
# convert <b>low entropy</b> human created passwords into a high entropy key that
|
9
|
+
# is computationally infeasible to acquire through brute force.
|
10
|
+
#
|
11
|
+
# As human generated passwords have a relatively small key space, key derivation
|
12
|
+
# functions must be slow to compute with any implementation.
|
13
|
+
#
|
14
|
+
# PBKDF2 offers an <b>iteration count</b> that configures the number of iterations
|
15
|
+
# performed to create the key.
|
16
|
+
#
|
17
|
+
# <b>One million (1,000,000) should be the iteration count's lower bound.</b>
|
18
|
+
#
|
19
|
+
# == Upgrading the OpenSSL <em>pbkdf2_hmac</em> Behaviour
|
20
|
+
#
|
21
|
+
# As soon as the new Ruby and OpenSSL libraries become commonplace this class should
|
22
|
+
# be upgraded to use the <b>new and improved {OpenSSL::KDF.pbkdf2_hmac} behaviour</b>
|
23
|
+
# rather than {OpenSSL::PKCS5.pbkdf2_hmac}.
|
24
|
+
#
|
25
|
+
# The difficulty is in detecting the operating system's C libraries that are directly
|
26
|
+
# accessed for OpenSSL functionality. If the distinction can be made accurately, those
|
27
|
+
# with newer libraries can reap the benefits immediately.
|
28
|
+
#
|
29
|
+
# == PBKDF2 Cost Iteration Timings on an Intel i-5 Laptop
|
30
|
+
#
|
31
|
+
# An IBM ThinkPad was used to generate the timings.
|
32
|
+
#
|
33
|
+
# Memory RAM ~> 15GiB
|
34
|
+
# Processors ~> Intel(R) Core(TM) i5-7200U CPU @ 2.50GHz
|
35
|
+
#
|
36
|
+
# The timing results show that a prudent value is somewhere
|
37
|
+
# between one hundred thousand and ten million iterations.
|
38
|
+
#
|
39
|
+
# 9.6 seconds for 10,000,000 ten million iterations
|
40
|
+
# 0.96 seconds for 1,000,000 one million iterations
|
41
|
+
# 0.096 seconds for 100,000 one hundred thousand iterations
|
42
|
+
#
|
43
|
+
# Open key sets iteration counts for PBKDF2 in hexadecimal and
|
44
|
+
# a valid range starts at 1 and counts up in chunks of a hundred
|
45
|
+
# thousand (100,000).
|
46
|
+
#
|
47
|
+
# 1 ~> 100,000
|
48
|
+
# 5 ~> 500,000
|
49
|
+
# 10 ~> 1,000,000
|
50
|
+
# 16 ~> 16,000,000
|
51
|
+
# 256 ~> 256,000,000
|
52
|
+
#
|
53
|
+
# The maximum iteration multiplier allowed is 16,384.
|
54
|
+
class KeyPbkdf2
|
55
|
+
|
56
|
+
|
57
|
+
# <b>One million iterations</b> is necessary due to the
|
58
|
+
# growth of <b>GPU driven cloud based computing</b> power
|
59
|
+
# that is curently being honed by mining BitCoin and training
|
60
|
+
# neural networks.
|
61
|
+
#
|
62
|
+
# == PBKDF2 Cost Iteration Timings on an Intel i-5 Laptop
|
63
|
+
#
|
64
|
+
# An IBM ThinkPad was used to generate the timings.
|
65
|
+
#
|
66
|
+
# Memory RAM ~> 15GiB
|
67
|
+
# Processors ~> Intel(R) Core(TM) i5-7200U CPU @ 2.50GHz
|
68
|
+
#
|
69
|
+
# The timing results show that a prudent value is somewhere
|
70
|
+
# between one hundred thousand and ten million iterations.
|
71
|
+
#
|
72
|
+
# Open key sets iteration counts for PBKDF2 in hexadecimal and
|
73
|
+
# a valid range starts at 1 and counts up in chunks of a hundred
|
74
|
+
# thousand (100,000).
|
75
|
+
#
|
76
|
+
# 1 ~> 100,000
|
77
|
+
# 5 ~> 500,000
|
78
|
+
# 10 ~> 1,000,000
|
79
|
+
# 16 ~> 16,000,000
|
80
|
+
# 256 ~> 256,000,000
|
81
|
+
PBKDF2_ITERATION_MULTIPLIER = 1
|
82
|
+
|
83
|
+
# The quantity used to multiply the iteration multiplier by to
|
84
|
+
# gain the iteration count.
|
85
|
+
ONE_HUNDRED_THOUSAND = 100000
|
86
|
+
|
87
|
+
|
88
|
+
# Documentation for this algorithm says this about the key length.
|
89
|
+
#
|
90
|
+
# Make the key length <b>larger than or equal to the output length</b>
|
91
|
+
# of the <b>underlying digest function</b>, otherwise an attacker could
|
92
|
+
# simply try to brute-force the key.
|
93
|
+
#
|
94
|
+
# According to PKCS#5, security is limited by the output length of
|
95
|
+
# the underlying digest function, i.e. security is not improved if a
|
96
|
+
# key length strictly larger than the digest output length is chosen.
|
97
|
+
#
|
98
|
+
# Therefore, when using PKCS5 for password storage, it suffices to
|
99
|
+
# store values equal to the digest output length, nothing is gained
|
100
|
+
# by storing larger values.
|
101
|
+
PBKDF2_EXPORT_KEY_LENGTH = OpenSSL::Digest::SHA384.new.digest_length
|
102
|
+
|
103
|
+
|
104
|
+
# For a 384 bit digest the key length is 48 bytes and the bit length
|
105
|
+
# is 384 bits.
|
106
|
+
PBKDF2_EXPORT_BIT_LENGTH = PBKDF2_EXPORT_KEY_LENGTH * 8
|
107
|
+
|
108
|
+
|
109
|
+
# The documented recommended salt length in bytes for the PBKDF2
|
110
|
+
# algorithm is between <b>16 and 24 bytes</b>. The setting here is
|
111
|
+
# at the upper bound of that range.
|
112
|
+
PBKDF2_SALT_LENGTH_BYTES = 24
|
113
|
+
|
114
|
+
|
115
|
+
# Return a random cryptographic salt generated from twenty-four
|
116
|
+
# random bytes produced by a secure random number generator. The
|
117
|
+
# returned salt is primarily a Base64 encoded string that can be
|
118
|
+
# stored and then passed to the {KeyPbkdf2.generate_key} method.
|
119
|
+
#
|
120
|
+
# + ------------ + -------- + ------------ + ------------- +
|
121
|
+
# | | Bits | Bytes | Base64 |
|
122
|
+
# | ------------ | -------- | ------------ | ------------- |
|
123
|
+
# | PBKDF2 Salt | 192 Bits | 24 bytes | 32 characters |
|
124
|
+
# + ------------ + -------- + ------------ + ------------- +
|
125
|
+
#
|
126
|
+
# The leading part of the character sequence indicates the length
|
127
|
+
# of the salt in chunks of 100,000 and is plus sign separated.
|
128
|
+
#
|
129
|
+
# 42+12345678abcdefgh12345678ABCDEFGH ~> 4,200,000 iterations
|
130
|
+
# 9+12345678abcdefgh12345678ABCDEFGH ~> 900,000 iterations
|
131
|
+
# 100+12345678abcdefgh12345678ABCDEFGH ~> 10,000,000 iterations
|
132
|
+
#
|
133
|
+
# Note that the generate key method will convert the trailing 32
|
134
|
+
# base64 characters back into a <b>24 byte binary</b> string.
|
135
|
+
#
|
136
|
+
# @return [String]
|
137
|
+
# a relatively small iteration count multiplier separated from the
|
138
|
+
# main salt characters by a plus sign. The salt characters will
|
139
|
+
# consist of 32 base64 characters which can be stored and fed into
|
140
|
+
# the {generate_key}.
|
141
|
+
#
|
142
|
+
# These 32 characters are a representation of the twenty-four (24)
|
143
|
+
# randomly and securely generated bytes.
|
144
|
+
def self.generate_pbkdf2_salt
|
145
|
+
|
146
|
+
pbkdf2_salt = Key64.from_bits( Key.to_random_bits( PBKDF2_SALT_LENGTH_BYTES ) )
|
147
|
+
return "#{PBKDF2_ITERATION_MULTIPLIER}+#{pbkdf2_salt}"
|
148
|
+
|
149
|
+
end
|
150
|
+
|
151
|
+
|
152
|
+
# Generate a 128 bit binary key from the PBKDF2 password derivation
|
153
|
+
# function. The most important input to this function is the human
|
154
|
+
# generated key. The best responsibly sourced key with at least 95%
|
155
|
+
# entropy will contain about 40 characters spread randomly over the
|
156
|
+
# set of 95 typable characters.
|
157
|
+
#
|
158
|
+
# Aside from the human password the other inputs are
|
159
|
+
#
|
160
|
+
# - a base64 encoded randomly generated salt of 16 to 24 bytes
|
161
|
+
# - an iteration count of at least 1 million (due to GPU advances)
|
162
|
+
# - an output key length that is at least 16 bytes (128 bits)
|
163
|
+
# - a digest algorithm implementation (we use SHA512K)
|
164
|
+
#
|
165
|
+
# The {Key} returned by this method encapsulates the derived
|
166
|
+
# key of the byte (bit) length specified.
|
167
|
+
#
|
168
|
+
# <b>PBKDF2 Output Key Length Note</b>
|
169
|
+
#
|
170
|
+
# Documentation for this algorithm says this about the key length.
|
171
|
+
#
|
172
|
+
# Typically, the key length should be larger than or equal to the
|
173
|
+
# output length of the underlying digest function, otherwise an
|
174
|
+
# attacker could simply try to brute-force the key. According to
|
175
|
+
# PKCS#5, security is limited by the output length of the underlying
|
176
|
+
# digest function, i.e. security is not improved if a key length
|
177
|
+
# strictly larger than the digest output length is chosen.
|
178
|
+
#
|
179
|
+
# Therefore, when using PKCS5 for password storage, it suffices to
|
180
|
+
# store values equal to the digest output length, nothing is gained
|
181
|
+
# by storing larger values.
|
182
|
+
#
|
183
|
+
# <b>Upgrading the OpenSSL <em>pbkdf2_hmac</em> Behaviour</b>
|
184
|
+
#
|
185
|
+
# As soon as the new Ruby and OpenSSL libraries become commonplace this class should
|
186
|
+
# be upgraded to use the <b>new and improved {OpenSSL::KDF.pbkdf2_hmac} behaviour</b>
|
187
|
+
# rather than {OpenSSL::PKCS5.pbkdf2_hmac}.
|
188
|
+
#
|
189
|
+
# The difficulty is in detecting the operating system's C libraries that are directly
|
190
|
+
# accessed for OpenSSL functionality. If the distinction can be made accurately, those
|
191
|
+
# with newer libraries can reap the benefits immediately.
|
192
|
+
#
|
193
|
+
# @param human_secret [String]
|
194
|
+
# a robust human generated password with as much entropy as can
|
195
|
+
# be mustered. Remember that 40 characters spread randomly over
|
196
|
+
# the key space of about 95 characters and not relating to any
|
197
|
+
# dictionary word or name is the way to generate a powerful key
|
198
|
+
# that has embedded a near 100% entropy rating.
|
199
|
+
#
|
200
|
+
# @param pbkdf2_string [String]
|
201
|
+
# this is a relatively small iteration count multiplier separated
|
202
|
+
# from the main salt characters by a plus sign. The salt characters
|
203
|
+
# will consist of 32 base64 characters which can be stored and fed
|
204
|
+
# into the {generate_key}.
|
205
|
+
#
|
206
|
+
# The salt string presented here must have either been recently
|
207
|
+
# generated by {generate_pbkdf2salt} or read from a persistence
|
208
|
+
# store and resubmitted here in order to regenerate the same key.
|
209
|
+
#
|
210
|
+
# @return [Key]
|
211
|
+
# a key holder containing the key which can then be accessed via
|
212
|
+
# many different formats. The {Key} returned by this method
|
213
|
+
# encapsulates the derived key with the specified byte count.
|
214
|
+
def self.generate_key human_secret, pbkdf2_string
|
215
|
+
|
216
|
+
KeyError.not_new pbkdf2_string, "PBKDF2 Algorithm Salt"
|
217
|
+
multiplier = pbkdf2_string.split("+")[0].to_i
|
218
|
+
pbkdf2_salt = pbkdf2_string.split("+")[1]
|
219
|
+
|
220
|
+
mult_msg = "Iteration multiplier is an integer from 1 to 16,384 not [#{multiplier}]."
|
221
|
+
raise ArgumentError, mult_msg_msg unless( multiplier > 0 && multiplier < 16385 )
|
222
|
+
iteration_count = multiplier * ONE_HUNDRED_THOUSAND
|
223
|
+
|
224
|
+
binary_salt = Key.to_binary_from_bit_string( Key64.to_bits( pbkdf2_salt ) )
|
225
|
+
err_msg = "Expected salt of #{PBKDF2_SALT_LENGTH_BYTES} bytes not #{binary_salt.length}."
|
226
|
+
raise ArgumentError, err_msg unless binary_salt.length == PBKDF2_SALT_LENGTH_BYTES
|
227
|
+
|
228
|
+
pbkdf2_key = OpenSSL::PKCS5.pbkdf2_hmac(
|
229
|
+
human_secret,
|
230
|
+
binary_salt,
|
231
|
+
iteration_count,
|
232
|
+
PBKDF2_EXPORT_KEY_LENGTH,
|
233
|
+
OpenSSL::Digest::SHA384.new
|
234
|
+
)
|
235
|
+
|
236
|
+
return Key.from_binary( pbkdf2_key )
|
237
|
+
|
238
|
+
end
|
239
|
+
|
240
|
+
|
241
|
+
private
|
242
|
+
|
243
|
+
|
244
|
+
# ---
|
245
|
+
# --- Timings Code
|
246
|
+
# ---
|
247
|
+
# --- chopped_radix64_key = NIL
|
248
|
+
# --- require 'benchmark'
|
249
|
+
# --- timings = Benchmark.measure {
|
250
|
+
# ---
|
251
|
+
# --- -- wrapped up code block
|
252
|
+
# ---
|
253
|
+
# --- }
|
254
|
+
# ---
|
255
|
+
# --- log.info(x) { "PBKDF2 key generation timings ~> #{timings}" }
|
256
|
+
# ---
|
257
|
+
|
258
|
+
|
259
|
+
end
|
260
|
+
|
261
|
+
|
262
|
+
end
|
@@ -0,0 +1,190 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
# coding: utf-8
|
3
|
+
|
4
|
+
module SafeDb
|
5
|
+
|
6
|
+
|
7
|
+
# SCrypt is a <b>Key Derivation Function (KDF)</b> with a reliable OpenSSL
|
8
|
+
# implementation that converts <b>low entropy</b> password-like text to a
|
9
|
+
# high entropy key that is computationally infeasible to acquire through brute
|
10
|
+
# force.
|
11
|
+
#
|
12
|
+
# SCrypt is incredibly resistant to attacks using dedicated hardware with
|
13
|
+
# massive memory to boot.
|
14
|
+
#
|
15
|
+
class KdfSCrypt
|
16
|
+
|
17
|
+
# SCrypt salts are recommended to contain 16 and 32 bytes
|
18
|
+
# inclusive. Here we opt for 24 bytes which unrolls out to
|
19
|
+
# 192 bits which serializes into 32 base64 characters.
|
20
|
+
SCRYPT_SALT_BYTE_LENGTH = 24
|
21
|
+
|
22
|
+
# The iteration count is determined using the powers of
|
23
|
+
# two so if the iteration integer is 12 there will be two
|
24
|
+
# to the power of 12 ( 2^12 ) giving 4096 iterations.
|
25
|
+
# The minimum number is 4 (16 iterations) and the max is 31.
|
26
|
+
# @example
|
27
|
+
# Configuring 16 into this directive results in
|
28
|
+
# 2^16 = 65,536 iterations
|
29
|
+
#
|
30
|
+
# This is a safe default and will slow the derivation time
|
31
|
+
# to about a second on a powerful 2020 laptop.
|
32
|
+
SCRYPT_ITERATION_INTEGER = 16
|
33
|
+
|
34
|
+
# The scrypt algorithm produces a key that is 181 bits in
|
35
|
+
# length. The algorithm then converts the binary 181 bits
|
36
|
+
# into a (6-bit) Radix64 character.
|
37
|
+
#
|
38
|
+
# 181 / 6 = 30 remainder 1 (so 31 characters are needed).
|
39
|
+
SCRYPT_KEY_LENGTH = 31
|
40
|
+
|
41
|
+
|
42
|
+
# When the key is transported using a 64 character set where
|
43
|
+
# each character is represented by 6 bits - the Scrypt key
|
44
|
+
# expands to 186 bits rather than the original 181 bits.
|
45
|
+
#
|
46
|
+
# This expansion is because of the remainder.
|
47
|
+
#
|
48
|
+
# 181 bits divided by 6 is 30 characters plus 1 character
|
49
|
+
# for the extra bit.
|
50
|
+
#
|
51
|
+
# The 31 transported characters then appear as
|
52
|
+
# 31 times 6 which equals 186 bits.
|
53
|
+
SCRYPT_KEY_TRANSPORT_LENGTH = 186
|
54
|
+
|
55
|
+
# The scrypt algorithm salt string should be 22 characters
|
56
|
+
# and may include forward slashes and periods.
|
57
|
+
SCRYPT_SALT_LENGTH = 22
|
58
|
+
|
59
|
+
# Scrypt outputs a single line of text that holds the prefix
|
60
|
+
# then the Radix64 encoded salt and finally the Radix64
|
61
|
+
# encoded hash key.
|
62
|
+
#
|
63
|
+
# The prefix consists of <b>two sections</b> sandwiched within
|
64
|
+
# two dollar <b>$</b> signs at the extremeties and a third dollar
|
65
|
+
# separating them.
|
66
|
+
#
|
67
|
+
# The two sections are the
|
68
|
+
# - Scrypt algorithm <b>version number</b> (2a or 2b) and
|
69
|
+
# - a power of 2 integer defining the no. of interations
|
70
|
+
SCRYPT_OUTPUT_TEXT_PREFIX = "$2a$#{SCRYPT_ITERATION_INTEGER}$"
|
71
|
+
|
72
|
+
|
73
|
+
# Generate a secure random and unpredictable salt suitable for
|
74
|
+
# the SCrypt algorithm. SCrypt salts are recommended to contain
|
75
|
+
# 16 and 32 bytes inclusive. Here we opt for 24 bytes which
|
76
|
+
# unrolls to 192 bits which in turn is 32 base64 characters.
|
77
|
+
#
|
78
|
+
# The {SafeDb::KdfSCrypt::SCRYPT_SALT_BYTE_LENGTH} constant
|
79
|
+
# defines the <b>number of random bytes</b> required for a robust
|
80
|
+
# SCrypt salt.
|
81
|
+
#
|
82
|
+
# The salt can be persisted and then resubmitted in order to
|
83
|
+
# regenerate the same key in the future.
|
84
|
+
#
|
85
|
+
# @return [String]
|
86
|
+
# the salt in a bit string format which can be converted to
|
87
|
+
# in order to feed the derivation function or indeed converted
|
88
|
+
# to base64 in order to persist it.
|
89
|
+
def self.generate_scrypt_salt
|
90
|
+
return Key.to_random_bits( SCRYPT_SALT_BYTE_LENGTH )
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
|
95
|
+
# Key generators should first use the {generate_salt} method to create
|
96
|
+
# a Scrypt salt string and then submit it to this method together with
|
97
|
+
# a human generated password in order to derive a key.
|
98
|
+
#
|
99
|
+
# The salt can be persisted and then resubmitted again to this method
|
100
|
+
# in order to regenerate the same key at any time in the future.
|
101
|
+
#
|
102
|
+
# Generate a binary key from the scrypt password derivation function.
|
103
|
+
#
|
104
|
+
# This differs from a server side password to hash usage in that we
|
105
|
+
# are interested in the 186bit key that scrypt produces. This method
|
106
|
+
# returns this reproducible key for use during symmetric encryption and
|
107
|
+
# decryption.
|
108
|
+
#
|
109
|
+
# @param secret_text [String]
|
110
|
+
# a robust human generated password with as much entropy as can
|
111
|
+
# be mustered. Remember that 40 characters spread randomly over
|
112
|
+
# the key space of about 90 characters and not relating to any
|
113
|
+
# dictionary word or name is the way to generate a powerful key
|
114
|
+
# that has embedded a near 100% entropy rating.
|
115
|
+
#
|
116
|
+
# @param scrypt_salt [String]
|
117
|
+
# the salt string that has either been recently generated via the
|
118
|
+
# {generate_salt} method or read from a persistence store and
|
119
|
+
# resubmitted here (in the future) to regenerate the same key.
|
120
|
+
#
|
121
|
+
# @return [Key]
|
122
|
+
# a key holder containing the key which can then be accessed via
|
123
|
+
# many different formats.
|
124
|
+
def self.generate_key secret_text, scrypt_salt
|
125
|
+
|
126
|
+
binary_salt = Key.to_binary_from_bit_string( scrypt_salt )
|
127
|
+
|
128
|
+
require "openssl"
|
129
|
+
|
130
|
+
puts ""
|
131
|
+
puts $LOADED_FEATURES.grep(/openssl/)
|
132
|
+
puts ""
|
133
|
+
|
134
|
+
scrypt_key = OpenSSL::KDF.scrypt(secret_text, salt: binary_salt, N: 2**SCRYPT_ITERATION_INTEGER, r: 8, p: 1, length: 33)
|
135
|
+
|
136
|
+
|
137
|
+
|
138
|
+
=begin
|
139
|
+
hashed_secret = Scrypt::Engine.hash_secret( secret_text, to_scrypt_salt(scrypt_salt) )
|
140
|
+
encoded64_key = Scrypt::Password.new( hashed_secret ).to_s
|
141
|
+
key_begin_index = SCRYPT_OUTPUT_TEXT_PREFIX.length + SCRYPT_SALT_LENGTH
|
142
|
+
radix64_key_str = encoded64_key[ key_begin_index .. -1 ]
|
143
|
+
key_length_mesg = "The scrypt key length should have #{SCRYPT_KEY_LENGTH} characters."
|
144
|
+
raise RuntimeError, key_length_mesg unless radix64_key_str.length == SCRYPT_KEY_LENGTH
|
145
|
+
|
146
|
+
return Key.new(radix64_key_str)
|
147
|
+
=end
|
148
|
+
return scrypt_key
|
149
|
+
end
|
150
|
+
|
151
|
+
|
152
|
+
|
153
|
+
private
|
154
|
+
|
155
|
+
|
156
|
+
def self.scrypt_test_method
|
157
|
+
|
158
|
+
puts ""
|
159
|
+
puts "##############################################################################"
|
160
|
+
|
161
|
+
key_count = 20
|
162
|
+
for n in 0 .. key_count
|
163
|
+
scrypt_saltbits = SafeDb::KdfSCrypt.generate_scrypt_salt
|
164
|
+
scrypt_key = SafeDb::KdfSCrypt.generate_key( "abonekanoby", scrypt_saltbits )
|
165
|
+
scrypt_saltchar = SafeDb::Key64.from_bits( scrypt_saltbits )
|
166
|
+
puts "#{n} Salt => #{scrypt_saltchar} (#{scrypt_saltchar.length}) => Key => #{scrypt_key} (#{scrypt_key.length})"
|
167
|
+
end
|
168
|
+
|
169
|
+
puts "##############################################################################"
|
170
|
+
puts ""
|
171
|
+
|
172
|
+
end
|
173
|
+
|
174
|
+
|
175
|
+
|
176
|
+
def self.to_scrypt_salt the_salt
|
177
|
+
return SCRYPT_OUTPUT_TEXT_PREFIX + the_salt
|
178
|
+
end
|
179
|
+
|
180
|
+
def self.assert_scrypt_salt the_salt
|
181
|
+
raise RuntimeError, "scrypt salt not expected to be nil." if the_salt.nil?
|
182
|
+
salt_length_msg = "A scrypt salt is expected to contain #{SCRYPT_SALT_LENGTH} characters."
|
183
|
+
raise RuntimeError, salt_length_msg unless the_salt.length == SCRYPT_SALT_LENGTH
|
184
|
+
end
|
185
|
+
|
186
|
+
|
187
|
+
end
|
188
|
+
|
189
|
+
|
190
|
+
end
|