safedb 0.3.1011 → 0.4.1002

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +56 -19
  3. data/README.md +15 -15
  4. data/Rakefile +7 -0
  5. data/bin/safe +2 -2
  6. data/lib/{interprete.rb → cli.rb} +168 -121
  7. data/lib/controller/admin/README.md +47 -0
  8. data/lib/controller/admin/access.rb +47 -0
  9. data/lib/controller/admin/checkin.rb +83 -0
  10. data/lib/controller/admin/checkout.rb +57 -0
  11. data/lib/controller/admin/diff.rb +75 -0
  12. data/lib/{usecase → controller/admin}/export.rb +15 -14
  13. data/lib/controller/admin/goto.rb +52 -0
  14. data/lib/controller/admin/import.rb +54 -0
  15. data/lib/controller/admin/init.rb +113 -0
  16. data/lib/controller/admin/login.rb +88 -0
  17. data/lib/{usecase → controller/admin}/logout.rb +0 -0
  18. data/lib/controller/admin/open.rb +39 -0
  19. data/lib/{usecase → controller/admin}/token.rb +2 -2
  20. data/lib/controller/admin/tree.md +54 -0
  21. data/lib/{usecase → controller/admin}/use.rb +0 -0
  22. data/lib/controller/admin/view.rb +61 -0
  23. data/lib/{usecase → controller/api}/docker/README.md +0 -0
  24. data/lib/{usecase → controller/api}/docker/docker.rb +1 -1
  25. data/lib/{usecase → controller/api}/jenkins/README.md +0 -0
  26. data/lib/{usecase → controller/api}/jenkins/jenkins.rb +1 -1
  27. data/lib/{usecase → controller/api}/terraform/README.md +1 -1
  28. data/lib/{usecase → controller/api}/terraform/terraform.rb +1 -1
  29. data/lib/{usecase → controller/api}/vpn/README.md +1 -1
  30. data/lib/{usecase → controller/api}/vpn/vpn.ini +0 -0
  31. data/lib/{usecase → controller/api}/vpn/vpn.rb +0 -0
  32. data/lib/{usecase → controller}/config/README.md +0 -0
  33. data/lib/{usecase → controller}/edit/README.md +0 -0
  34. data/lib/controller/edit/editverse.rb +48 -0
  35. data/lib/controller/edit/put.rb +35 -0
  36. data/lib/controller/edit/remove.rb +29 -0
  37. data/lib/{usecase/update/README.md → controller/edit/rename.md} +0 -0
  38. data/lib/{usecase → controller}/files/README.md +1 -1
  39. data/lib/controller/files/read.rb +36 -0
  40. data/lib/{usecase/files/eject.rb → controller/files/write.rb} +15 -20
  41. data/lib/{usecase → controller}/id.rb +0 -0
  42. data/lib/controller/query/print.rb +26 -0
  43. data/lib/controller/query/queryverse.rb +39 -0
  44. data/lib/controller/query/show.rb +50 -0
  45. data/lib/{session/require.gem.rb → controller/requirer.rb} +13 -9
  46. data/lib/{usecase → controller}/set.rb +4 -4
  47. data/lib/controller/usecase.rb +244 -0
  48. data/lib/{usecase → controller}/verse.rb +0 -0
  49. data/lib/{usecase → controller}/visit/README.md +0 -0
  50. data/lib/{usecase → controller}/visit/visit.rb +0 -0
  51. data/lib/factbase/facts.safedb.net.ini +7 -7
  52. data/lib/{keytools/key.docs.rb → model/README.md} +102 -66
  53. data/lib/model/book.rb +484 -0
  54. data/lib/model/branch.rb +48 -0
  55. data/lib/model/checkin.feature +33 -0
  56. data/lib/{configs/README.md → model/configs.md} +4 -4
  57. data/lib/model/content.rb +214 -0
  58. data/lib/model/indices.rb +132 -0
  59. data/lib/model/safe_tree.rb +51 -0
  60. data/lib/model/state.inspect.rb +221 -0
  61. data/lib/model/state.migrate.rb +334 -0
  62. data/lib/model/text_chunk.rb +68 -0
  63. data/lib/{extension → utils/extend}/array.rb +0 -0
  64. data/lib/{extension → utils/extend}/dir.rb +0 -0
  65. data/lib/{extension → utils/extend}/file.rb +0 -0
  66. data/lib/utils/extend/hash.rb +76 -0
  67. data/lib/{extension → utils/extend}/string.rb +6 -6
  68. data/lib/{session/fact.finder.rb → utils/facts/fact.rb} +0 -0
  69. data/lib/utils/identity/identifier.rb +356 -0
  70. data/lib/{keytools/key.ident.rb → utils/identity/machine.id.rb} +67 -4
  71. data/lib/utils/inspect/inspector.rb +81 -0
  72. data/lib/{keytools/kdf.bcrypt.rb → utils/kdfs/bcrypt.rb} +0 -0
  73. data/lib/{keytools → utils/kdfs}/kdf.api.rb +16 -16
  74. data/lib/{keytools/key.local.rb → utils/kdfs/kdfs.rb} +40 -40
  75. data/lib/{keytools/kdf.pbkdf2.rb → utils/kdfs/pbkdf2.rb} +0 -0
  76. data/lib/{keytools/kdf.scrypt.rb → utils/kdfs/scrypt.rb} +0 -0
  77. data/lib/{keytools → utils}/key.error.rb +2 -2
  78. data/lib/{keytools → utils}/key.pass.rb +2 -2
  79. data/lib/{keytools → utils/keys}/key.64.rb +0 -0
  80. data/lib/{keytools → utils/keys}/key.rb +6 -2
  81. data/lib/{keytools/key.iv.rb → utils/keys/random.iv.rb} +0 -0
  82. data/lib/{logging/gem.logging.rb → utils/logs/logger.rb} +6 -5
  83. data/lib/{keytools/key.pair.rb → utils/store/datamap.rb} +48 -30
  84. data/lib/{keytools/key.db.rb → utils/store/datastore.rb} +38 -104
  85. data/lib/utils/store/merge-boys-school.json +40 -0
  86. data/lib/utils/store/merge-girls-school.json +48 -0
  87. data/lib/utils/store/merge-merged-data.json +56 -0
  88. data/lib/utils/store/struct.rb +75 -0
  89. data/lib/utils/store/test-commands.sh +24 -0
  90. data/lib/{keytools/key.now.rb → utils/time/timestamp.rb} +32 -21
  91. data/lib/version.rb +1 -1
  92. metadata +86 -73
  93. data/lib/extension/hash.rb +0 -33
  94. data/lib/keytools/key.algo.rb +0 -109
  95. data/lib/keytools/key.api.rb +0 -1326
  96. data/lib/keytools/key.id.rb +0 -322
  97. data/lib/modules/cryptology/amalgam.rb +0 -70
  98. data/lib/modules/cryptology/engineer.rb +0 -99
  99. data/lib/modules/mappers/dictionary.rb +0 -288
  100. data/lib/session/time.stamp.rb +0 -340
  101. data/lib/session/user.home.rb +0 -49
  102. data/lib/usecase/cmd.rb +0 -471
  103. data/lib/usecase/edit/delete.rb +0 -46
  104. data/lib/usecase/files/file_me.rb +0 -78
  105. data/lib/usecase/files/read.rb +0 -169
  106. data/lib/usecase/files/write.rb +0 -89
  107. data/lib/usecase/goto.rb +0 -57
  108. data/lib/usecase/import.rb +0 -157
  109. data/lib/usecase/init.rb +0 -61
  110. data/lib/usecase/login.rb +0 -72
  111. data/lib/usecase/open.rb +0 -71
  112. data/lib/usecase/print.rb +0 -40
  113. data/lib/usecase/put.rb +0 -81
  114. data/lib/usecase/show.rb +0 -138
  115. data/lib/usecase/update/rename.rb +0 -180
  116. data/lib/usecase/view.rb +0 -71
@@ -1,322 +0,0 @@
1
- #!/usr/bin/ruby
2
- # coding: utf-8
3
-
4
-
5
- module SafeDb
6
-
7
-
8
- # This class derives <b>non secret but unique identifiers</b> based on different
9
- # combinations of the <b>application, shell and machine (compute element)</b>
10
- # references.
11
- #
12
- # == Identifier Are Not Secrets
13
- #
14
- # <b>And their starting values are retrievable</b>
15
- #
16
- # Note that the principle and practise of <b>identifiers is not about keeping secrets</b>.
17
- # An identifier can easily give up its starting value/s if and when brute force is
18
- # applied. The properties of a good iidentifier (ID) are
19
- #
20
- # - non repeatability (also known as uniqueness)
21
- # - non predictability (of the next identifier)
22
- # - containing alphanumerics (for file/folder/url names)
23
- # - human readable (hence hyphens and separators)
24
- # - non offensive (no swear words popping out)
25
- #
26
- # == Story | Identifiers Speak Volumes
27
- #
28
- # I told a friend what the turnover of his company was and how many clients he had.
29
- # He was shocked and wanted to know how I had gleened this information.
30
- #
31
- # The invoices he sent me (a year apart). Both his invoice IDs (identifiers) and his
32
- # user IDs where integers that counted up. So I could determine how many new clients
33
- # he had in the past year, how many clients he had when I got the invoice, and I
34
- # determined the turnover by guesstimating the average invoice amount.
35
- #
36
- # Many successful website attacks are owed to a predictable customer ID or a counter
37
- # type session ID within the cookies.
38
- #
39
- # == Good Identifiers Need Volumes
40
- #
41
- # IDs are not secrets - but even so, a large number of properties are required
42
- # to produce a high quality ID.
43
- #
44
- class KeyId
45
-
46
-
47
- # The identity chunk length is set at four (4) which means each of the
48
- # fabricated identifiers comprises of four character segments divided by
49
- # hyphens. Only the <b>62 alpha-numerics ( a-z, A-Z and 0-9 )</b> will
50
- # appear within identifiers - which maintains simplicity and provides an
51
- # opportunity to re-iterate that <b>identifiers</b> are designed to be
52
- # <b>unpredictable</b>, but <b>not secret</b>.
53
- IDENTITY_CHUNK_LENGTH = 4
54
-
55
-
56
- # A hyphen is the chosen character for dividing the identifier strings
57
- # into chunks of four (4) as per the {IDENTITY_CHUNK_LENGTH} constant.
58
- SEGMENT_CHAR = "-"
59
-
60
-
61
- # Get an identifier that is <b>always the same</b> for the parameter
62
- # application reference <b>regardless of the machine or shell</b> or
63
- # even the machine user, coming together to make the request.
64
- #
65
- # The returned identifier will consist only of alphanumeric characters
66
- # and one hyphen, plus it always starts and ends with an alphanumeric.
67
- #
68
- # @param app_instance_ref [String]
69
- # the string reference of the application instance (or shard) that
70
- # is in play and needs to be digested into a unique but not-a-secret
71
- # identifier.
72
- #
73
- # @return [String]
74
- # An identifier that is guaranteed to be the same whenever the
75
- # same application reference is provided on any machine, using any
76
- # user through any shell interface or command prompt.
77
- #
78
- # It must be different for any other application reference.
79
- def self.derive_app_instance_identifier( app_instance_ref )
80
- return derive_identifier( app_instance_ref )
81
- end
82
-
83
-
84
- # Get an identifier that is <b>always the same</b> for the application
85
- # instance (with reference given in parameter) on <b>this machine</b>
86
- # and is always different when either/or or both the application ref
87
- # and machine are different.
88
- #
89
- # The returned identifier will consist of only alphanumeric characters
90
- # and hyphens - it will always start and end with an alphanumeric.
91
- #
92
- # This behaviour draws a fine line around the concept of machine, virtual
93
- # machine, <b>workstation</b> and/or <b>compute element</b>.
94
- #
95
- # <b>(aka) The AIM ID</b>
96
- #
97
- # Returned ID is aka the <b>Application Instance Machine (AIM)</b> Id.
98
- #
99
- # @param app_ref [String]
100
- # the string reference of the application instance (or shard) that
101
- # is being used.
102
- #
103
- # @return [String]
104
- # an identifier that is guaranteed to be the same whenever the
105
- # same application reference is provided on this machine.
106
- #
107
- # it must be different on another machine even when the same
108
- # application reference is provided.
109
- #
110
- # It will also be different on this workstation if the application
111
- # instance identifier provided is different.
112
- def self.derive_app_instance_machine_id( app_ref )
113
- return derive_identifier( app_ref + derive_machine_identifier() )
114
- end
115
-
116
-
117
- # This method uses a one-way function to return a combinatorial digested
118
- # machine identification string using a number of distinct input parameters
119
- # to deliver the characteristic of producing the same identifier for the
120
- # same machine, virtual machine, workstation and/or compute element, and
121
- # reciprocally, a different one on a different machine.
122
- #
123
- # The userspace is also a key machine identifier so a different machine user
124
- # generates a different identifier when all other things remain equal.
125
- #
126
- # @return [String]
127
- # a one line textual machine workstation or compute element identifier
128
- # that is (surprisingly) different when the machine user changes.
129
- def self.derive_machine_identifier
130
-
131
- require 'socket'
132
-
133
- identity_text = [
134
- Etc.getlogin,
135
- get_machine_id(),
136
- Socket.gethostname()
137
- ].join.reverse
138
-
139
- return identity_text
140
-
141
- end
142
-
143
-
144
- # The machine identifier is a UUID based hash value that is tied to the
145
- # CPU and motherboard of the machine. This read-only identifier can be
146
- # accessed without sudoer permissions so is perfect for license generators
147
- # and environment sensitive software.
148
- #
149
- # In the modern era of virtualization you should always check the behaviour
150
- # of the above identifiers when used inside
151
- #
152
- # - docker containers
153
- # - Amazon EC2 servers (or Azure or GCE)
154
- # - vagrant (VirtualBox/VMWare)
155
- # - Windows MSGYWIN (Ubuntu) environments
156
- # - Kubernetes pods
157
- #
158
- # @return [String] the machine ID hash value
159
- def self.get_machine_id
160
-
161
- machine_id_cmd = "cat /etc/machine-id"
162
- machine_id_str = %x[ #{machine_id_cmd} ]
163
- return machine_id_str.chomp
164
-
165
- end
166
-
167
-
168
- # The <b>32 character</b> <b>universal identifier</b> bonds a digested
169
- # <b>application state identifier</b> with the <b>shell identifier</b>.
170
- # This method gives <b>dual double guarantees</b> to the effect that
171
- #
172
- # - a change in one, or in the other, or in both returns a different universal id
173
- # - the same app state identifier in the same shell produces the same universal id
174
- #
175
- # <b>The 32 Character Universal Identifier</b>
176
- #
177
- # The universal identifier is an amalgam of two digests which can be individually
178
- # retrieved from other methods in this class. An example is
179
- #
180
- # universal id => hg2x0-g3uslf-pa2bl5-09xvbd-n4wcq
181
- # the shell id => g3uslf-pa2bl5-09xvbd
182
- # app state id => hg2x0-n4wcq
183
- #
184
- # The 32 character universal identifier comprises of 18 session identifier
185
- # characters (see {derive_session_id}) <b>sandwiched between</b>
186
- # ten (10) digested application identifier characters, five (5) in front and
187
- # five (5) at the back - all segmented by four (4) hyphens.
188
- #
189
- # @param app_reference [String]
190
- # the chosen plaintext application reference identifier that
191
- # is the input to the digesting (hashing) algorithm.
192
- #
193
- # @param session_token [String]
194
- # a triply segmented (and one liner) text token instantiated by
195
- # {KeyLocal.generate_shell_key_and_token} and provided
196
- # here ad verbatim.
197
- #
198
- # @return [String]
199
- # a 32 character string that cannot feasibly be repeated due to the use
200
- # of one way functions within its derivation. The returned identifier bonds
201
- # the application state reference with the present session.
202
- def self.derive_universal_id( app_reference, session_token )
203
-
204
- shellid = derive_session_id( session_token )
205
- app_ref = derive_identifier( app_reference + shellid )
206
- chunk_1 = app_ref[ 0 .. IDENTITY_CHUNK_LENGTH ]
207
- chunk_3 = app_ref[ ( IDENTITY_CHUNK_LENGTH + 1 ) .. -1 ]
208
-
209
- return "#{chunk_1}#{shellid}#{SEGMENT_CHAR}#{chunk_3}".downcase
210
-
211
- end
212
-
213
-
214
- # The session ID generated here is a derivative of the 150 character
215
- # session token instantiated by {KeyLocal.generate_shell_key_and_token}
216
- # and provided here <b>ad verbatim</b>.
217
- #
218
- # The algorithm for deriving the session ID is as follows.
219
- #
220
- # - convert the 150 characters to an alphanumeric string
221
- # - convert the result to a bit string and then to a key
222
- # - put the key's binary form through a 384 bit digest
223
- # - convert the digest's output to 64 YACHT64 characters
224
- # - remove the (on average 2) non-alphanumeric characters
225
- # - cherry pick a spread out 12 characters from the pool
226
- # - hiphenate the character positions five (5) and ten (10)
227
- # - ensure the length of the resultant ID is fourteen (14)
228
- #
229
- # The resulting session id will look something like this
230
- #
231
- # g3sf-pab5-9xvd
232
- #
233
- # @param session_token [String]
234
- # a triply segmented (and one liner) text token instantiated by
235
- # {KeyLocal.generate_shell_key_and_token} and provided here ad
236
- # verbatim.
237
- #
238
- # @return [String]
239
- # a 14 character string that cannot feasibly be repeated
240
- # within the keyspace of even a gigantic organisation.
241
- #
242
- # This method guarantees that the session id will always be the same when
243
- # called by commands within the same shell in the same machine.
244
- def self.derive_session_id( session_token )
245
-
246
- assert_session_token_size( session_token )
247
- random_length_id_key = Key.from_char64( session_token.to_alphanumeric )
248
- a_384_bit_key = random_length_id_key.to_384_bit_key()
249
- a_64_char_str = a_384_bit_key.to_char64()
250
- base_64_chars = a_64_char_str.to_alphanumeric
251
-
252
- id_chars_pool = KeyAlgo.cherry_picker( ID_TRI_CHUNK_LEN, base_64_chars )
253
- id_hyphen_one = id_chars_pool.insert( IDENTITY_CHUNK_LENGTH, SEGMENT_CHAR )
254
- id_characters = id_hyphen_one.insert( ( IDENTITY_CHUNK_LENGTH * 2 + 1 ), SEGMENT_CHAR )
255
-
256
- err_msg = "Shell ID needs #{ID_TRI_TOTAL_LEN} not #{id_characters.length} characters."
257
- raise RuntimeError, err_msg unless id_characters.length == ID_TRI_TOTAL_LEN
258
-
259
- return id_characters.downcase
260
-
261
- end
262
-
263
-
264
- # This method returns a <b>10 character</b> digest of the parameter
265
- # <b>reference</b> string.
266
- #
267
- # <b>How to Derive the 10 Character Identifier</b>
268
- #
269
- # So how are the 10 characters derived from the reference provided in
270
- # the first parameter. The algorithm is this.
271
- #
272
- # - reverse the reference and feed it to a 256 bit digest
273
- # - chop away the rightmost digits so that 252 bits are left
274
- # - convert the one-zero bit str to 42 (YACHT64) characters
275
- # - remove the (on average 1.5) non-alphanumeric characters
276
- # - cherry pick and return <b>spread out 8 characters</b>
277
- #
278
- # @param reference [String]
279
- # the plaintext reference input to the digest algorithm
280
- #
281
- # @return [String]
282
- # a 10 character string that is a digest of the reference string
283
- # provided in the parameter.
284
- def self.derive_identifier( reference )
285
-
286
- bitstr_256 = Key.from_binary( Digest::SHA256.digest( reference.reverse ) ).to_s
287
- bitstr_252 = bitstr_256[ 0 .. ( BIT_LENGTH_252 - 1 ) ]
288
- id_err_msg = "The ID digest needs #{BIT_LENGTH_252} not #{bitstr_252.length} chars."
289
- raise RuntimeError, id_err_msg unless bitstr_252.length == BIT_LENGTH_252
290
-
291
- id_chars_pool = Key64.from_bits( bitstr_252 ).to_alphanumeric
292
- undivided_str = KeyAlgo.cherry_picker( ID_TWO_CHUNK_LEN, id_chars_pool )
293
- id_characters = undivided_str.insert( IDENTITY_CHUNK_LENGTH, SEGMENT_CHAR )
294
-
295
- min_size_msg = "Id length #{id_characters.length} is not #{(ID_TWO_CHUNK_LEN + 1)} chars."
296
- raise RuntimeError, min_size_msg unless id_characters.length == ( ID_TWO_CHUNK_LEN + 1 )
297
-
298
- return id_characters.downcase
299
-
300
- end
301
-
302
-
303
- private
304
-
305
-
306
- ID_TWO_CHUNK_LEN = IDENTITY_CHUNK_LENGTH * 2
307
- ID_TRI_CHUNK_LEN = IDENTITY_CHUNK_LENGTH * 3
308
- ID_TRI_TOTAL_LEN = ID_TRI_CHUNK_LEN + 2
309
-
310
- BIT_LENGTH_252 = 252
311
-
312
-
313
- def self.assert_session_token_size session_token
314
- err_msg = "Session token has #{session_token.length} and not #{KeyLocal::SESSION_TOKEN_SIZE} chars."
315
- raise RuntimeError, err_msg unless session_token.length == KeyLocal::SESSION_TOKEN_SIZE
316
- end
317
-
318
-
319
- end
320
-
321
-
322
- end
@@ -1,70 +0,0 @@
1
- #!/usr/bin/ruby
2
-
3
- module SafeDb
4
-
5
- module ToolBelt
6
-
7
-
8
- # This class knows how to amalgamate passwords, keys and string data in
9
- # a manner that is the cryptographical equivalent of synergy.
10
- #
11
- # The amalgamated keys are synergially (cryptographically) greater than
12
- # the sum of their parts.
13
- class Amalgam
14
-
15
- # Amalgamate the two parameter passwords in a manner that is the
16
- # cryptographical equivalent of synergy. The amalgamated keys are
17
- # synergially greater than the sum of their parts.
18
- #
19
- # -- Get a viable machine password taking into account the human
20
- # -- password length and the specified mix_ratio.
21
- #
22
- #
23
- # @param human_password [String] the password originating from a human
24
- # @param machine_key [String] a machine engineered ascii password (key)
25
- # @mixparam machine_key [String] a machine engineered ascii password (key)
26
- #
27
- # @return [String] the union of the two parameter passwords
28
- #
29
- # @raise [ArgumentError] when the size of the two passwords and the
30
- # mix ratio do not conform to the constraint imposed by the below
31
- # equation which must hold true.
32
- # <tt>machine password length = human password length * mix_ratio - 1</tt>
33
- #
34
- def self.passwords human_password, machine_password, mix_ratio
35
-
36
- size_error_msg = "Human pass length times mix_ratio must equal machine pass length."
37
- lengths_are_perfect = human_password.length * mix_ratio == machine_password.length
38
- raise ArgumentError.new size_error_msg unless lengths_are_perfect
39
-
40
- machine_passwd_chunk = 0
41
- amalgam_passwd_index = 0
42
- amalgamated_password = ""
43
-
44
- human_password.each_char do |passwd_char|
45
-
46
- amalgamated_password[amalgam_passwd_index] = passwd_char
47
- amalgam_passwd_index += 1
48
-
49
- for i in 0..(mix_ratio-1) do
50
- machine_pass_index = machine_passwd_chunk * mix_ratio + i
51
- amalgamated_password[amalgam_passwd_index] = machine_password[machine_pass_index]
52
- amalgam_passwd_index += 1
53
- end
54
-
55
- machine_passwd_chunk += 1
56
-
57
- end
58
-
59
- return amalgamated_password
60
-
61
- end
62
-
63
-
64
- end
65
-
66
-
67
- end
68
-
69
-
70
- end
@@ -1,99 +0,0 @@
1
- #!/usr/bin/ruby
2
-
3
- module SafeDb
4
-
5
- module ToolBelt
6
-
7
-
8
- require 'securerandom'
9
-
10
- # This class will be refactored into an interface implemented by a set
11
- # of plugins that will capture sensitive information from users from an
12
- # Ubuntu, Windows, RHEL, CoreOS, iOS or CentOS command line interface.
13
- #
14
- # An equivalent REST API will also be available for bringing in sensitive
15
- # information in the most secure (but simple) manner.
16
- class Engineer
17
-
18
-
19
- # --
20
- # -- Get a viable machine password taking into account the human
21
- # -- password length and the specified mix_ratio.
22
- # --
23
- # -- machine password length = human password length * mix_ratio - 1
24
- # --
25
- def self.machine_key human_password_length, mix_ratio
26
-
27
- machine_raw_secret = strong_key( human_password_length * ( mix_ratio + 1) )
28
- return machine_raw_secret[ 0..( human_password_length * mix_ratio - 1 ) ]
29
-
30
- end
31
-
32
-
33
- # --
34
- # -- Engineer a raw password that is similar (approximate) in
35
- # -- length to the integer parameter.
36
- # --
37
- def self.strong_key approx_length
38
-
39
- non_alphanum = SecureRandom.urlsafe_base64(approx_length);
40
- return non_alphanum.delete("-_")
41
-
42
- end
43
-
44
-
45
- # Amalgamate the parameter passwords using a specific mix ratio. This method
46
- # produces cryptographically stronger secrets than algorithms that simply
47
- # concatenate two string keys together. If knowledge of one key were gained, this
48
- # amalgamation algorithm still provides extremely strong protection even when
49
- # one of the keys has a single digit length.
50
- #
51
- # This +length constraint formula+ binds the two input strings together with
52
- # the integer mix ratio.
53
- #
54
- # <tt>machine password length = human password length * mix_ratio - 1</tt>
55
- #
56
- # @param human_password [String] the first password (shorter one) to amalgamate
57
- # @param machine_password [String] the second password (longer one) to amalgamate
58
- # @param mix_ratio [Fixnum] the mix ratio that must be respected by the
59
- # previous two parameters.
60
- # @return [String] an amalgamated (reproducible) union of the 2 parameter passwords
61
- #
62
- # @raise [ArgumentError] if the length constraint assertion does not hold true
63
- def self.get_amalgam_password human_password, machine_password, mix_ratio
64
-
65
- size_error_msg = "Human pass length times mix_ratio must equal machine pass length."
66
- lengths_are_perfect = human_password.length * mix_ratio == machine_password.length
67
- raise ArgumentError.new size_error_msg unless lengths_are_perfect
68
-
69
- machine_passwd_chunk = 0
70
- amalgam_passwd_index = 0
71
- amalgamated_password = ""
72
-
73
- human_password.each_char do |passwd_char|
74
-
75
- amalgamated_password[amalgam_passwd_index] = passwd_char
76
- amalgam_passwd_index += 1
77
-
78
- for i in 0..(mix_ratio-1) do
79
- machine_pass_index = machine_passwd_chunk * mix_ratio + i
80
- amalgamated_password[amalgam_passwd_index] = machine_password[machine_pass_index]
81
- amalgam_passwd_index += 1
82
- end
83
-
84
- machine_passwd_chunk += 1
85
-
86
- end
87
-
88
- return amalgamated_password
89
-
90
- end
91
-
92
-
93
- end
94
-
95
-
96
- end
97
-
98
-
99
- end