opensecret 0.0.988 → 0.0.9925
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.
- checksums.yaml +5 -5
- data/README.md +56 -159
- data/bin/opensecret +2 -2
- data/bin/ops +17 -2
- data/lib/extension/string.rb +14 -16
- data/lib/{interpreter.rb → interprete.rb} +53 -29
- data/lib/keytools/binary.map.rb +49 -0
- data/lib/keytools/kdf.api.rb +249 -0
- data/lib/keytools/kdf.bcrypt.rb +64 -29
- data/lib/keytools/kdf.pbkdf2.rb +92 -83
- 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 +1281 -0
- data/lib/keytools/key.db.rb +265 -0
- data/lib/keytools/{key.module.rb → key.docs.rb} +55 -0
- data/lib/keytools/key.error.rb +110 -0
- data/lib/keytools/key.id.rb +271 -0
- data/lib/keytools/key.iv.rb +107 -0
- data/lib/keytools/key.local.rb +265 -0
- data/lib/keytools/key.mach.rb +248 -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 +428 -298
- data/lib/keytools/keydebug.txt +295 -0
- data/lib/logging/gem.logging.rb +3 -3
- data/lib/modules/cryptology/collect.rb +20 -0
- data/lib/session/require.gem.rb +1 -1
- data/lib/usecase/cmd.rb +417 -0
- data/lib/usecase/id.rb +36 -0
- data/lib/usecase/import.rb +174 -0
- data/lib/usecase/init.rb +78 -0
- data/lib/usecase/login.rb +70 -0
- data/lib/usecase/logout.rb +30 -0
- data/lib/usecase/open.rb +126 -0
- data/lib/{interprete → usecase}/put.rb +100 -47
- data/lib/usecase/read.rb +89 -0
- data/lib/{interprete → usecase}/safe.rb +0 -0
- data/lib/{interprete → usecase}/set.rb +0 -0
- data/lib/usecase/token.rb +111 -0
- data/lib/{interprete → usecase}/use.rb +0 -0
- data/lib/version.rb +1 -1
- data/opensecret.gemspec +4 -3
- metadata +39 -33
- data/lib/exception/cli.error.rb +0 -53
- data/lib/exception/errors/cli.errors.rb +0 -31
- data/lib/interprete/begin.rb +0 -232
- data/lib/interprete/cmd.rb +0 -621
- data/lib/interprete/export.rb +0 -163
- data/lib/interprete/init.rb +0 -205
- data/lib/interprete/key.rb +0 -119
- data/lib/interprete/open.rb +0 -148
- data/lib/interprete/seal.rb +0 -129
- data/lib/keytools/digester.rb +0 -245
- data/lib/keytools/key.data.rb +0 -227
- data/lib/keytools/key.derivation.rb +0 -341
- data/lib/modules/mappers/collateral.rb +0 -282
- data/lib/modules/mappers/envelope.rb +0 -127
- data/lib/modules/mappers/settings.rb +0 -170
- data/lib/notepad/scratch.pad.rb +0 -224
- data/lib/store-commands.txt +0 -180
data/lib/interprete/open.rb
DELETED
@@ -1,148 +0,0 @@
|
|
1
|
-
#!/usr/bin/ruby
|
2
|
-
|
3
|
-
module OpenSecret
|
4
|
-
|
5
|
-
require 'openssl'
|
6
|
-
|
7
|
-
# The <tt>open use case</tt> allows us to add (put), subtract (del)ete, change
|
8
|
-
# (update) and list the secrets within an envelope (outer path) at a given
|
9
|
-
# position (inner path), whether that envelope exists or not.
|
10
|
-
#
|
11
|
-
# Also see the <b>reopen</b> command which only differs from open in that it
|
12
|
-
# fails if the path specified does not exist in either the sealed or session
|
13
|
-
# envelopes.
|
14
|
-
#
|
15
|
-
# == The Open Path Parameter
|
16
|
-
#
|
17
|
-
# Open must be called with a single <b>path</b> parameter with an optional
|
18
|
-
# single colon separating the outer (path to envelope) from the inner (path
|
19
|
-
# within envelope).
|
20
|
-
#
|
21
|
-
# ops open aws.credentials:s3reader
|
22
|
-
#
|
23
|
-
# The outer and inner paths can contain forward slashes that segment the path.
|
24
|
-
#
|
25
|
-
# ops open production/aws.credentials:s3/s3reader
|
26
|
-
# ops put access_key ABCD1234
|
27
|
-
# ops put secret_key FGHIJ56789
|
28
|
-
# ops put region_key eu-central-1
|
29
|
-
# ops seal
|
30
|
-
#
|
31
|
-
#
|
32
|
-
# == Before Opening a Path
|
33
|
-
#
|
34
|
-
# To open a path these conditions must be true.
|
35
|
-
#
|
36
|
-
# - the OPS_KEY environment variable must have been set for the session
|
37
|
-
# - either <tt>ops begin</tt> or <tt>ops init</tt> must have been issued
|
38
|
-
# - the external drive (eg usb key) must be configured and accessible
|
39
|
-
#
|
40
|
-
#
|
41
|
-
# == After Opening a Path
|
42
|
-
#
|
43
|
-
# After a path is opened we can
|
44
|
-
#
|
45
|
-
# - <tt>open</tt> to relative or absolutely change the path
|
46
|
-
# - <tt>put</tt> key/value data
|
47
|
-
# - <tt>add</tt> a single value
|
48
|
-
# - <tt>drop</tt> the value at the opened path
|
49
|
-
# - <tt>mod</tt> change (modify) value at path
|
50
|
-
# - <tt>seal</tt> to permanently write opened envelopes
|
51
|
-
#
|
52
|
-
# == Observable Value
|
53
|
-
#
|
54
|
-
# $ opensecret open home/wifi
|
55
|
-
#
|
56
|
-
# The observable value delivered by +[open]+ boils down to
|
57
|
-
#
|
58
|
-
# - an openkey (eg asdfx1234) and corresponding open encryption key
|
59
|
-
# - open encryption key written to <tt>~/.opensecret/open.keys/asdfx1234.x.txt</tt>
|
60
|
-
# - the opened path (ending in filename) written to session.cache base in [safe]
|
61
|
-
# - the INI string (were the file to be decrypted) would look like the below
|
62
|
-
#
|
63
|
-
# [session]
|
64
|
-
# base.path = home/wifi
|
65
|
-
#
|
66
|
-
class Open < Command
|
67
|
-
|
68
|
-
attr_writer :open_path
|
69
|
-
|
70
|
-
# The activities performed by the executing open use case is to
|
71
|
-
#
|
72
|
-
def execute
|
73
|
-
|
74
|
-
instantiate_collateral
|
75
|
-
@domain_name = @collateral.domain_name
|
76
|
-
|
77
|
-
param_outer_path = @open_path.split(":").first
|
78
|
-
param_inner_path = @open_path.split(":").last
|
79
|
-
|
80
|
-
index = get_session_dictionary
|
81
|
-
index.put OUTER_PATH, param_outer_path
|
82
|
-
index.put INNER_PATH, param_inner_path
|
83
|
-
|
84
|
-
index.write( create_session_dict_lock )
|
85
|
-
|
86
|
-
puts ""
|
87
|
-
puts index.to_s
|
88
|
-
puts ""
|
89
|
-
|
90
|
-
exit
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
last_fwdslash_index = param_outer_path.rindex "/"
|
95
|
-
folder_path = param_outer_path[0 .. last_fwdslash_index]
|
96
|
-
file_word = param_outer_path[last_fwdslash_index .. -1]
|
97
|
-
|
98
|
-
session_tree_dir = @collateral.session_envelopes_path
|
99
|
-
session_folder_path = File.join session_tree_dir, folder_path
|
100
|
-
|
101
|
-
FileUtils.mkdir_p session_folder_path
|
102
|
-
open_id = ToolBelt::Engineer.strong_key @p[:open_idlen]
|
103
|
-
open_key = ToolBelt::Engineer.strong_key @p[:open_keylen]
|
104
|
-
|
105
|
-
file_name = file_word + ".#{open_id}.os.txt"
|
106
|
-
file_key = File.join folder_path, file_name
|
107
|
-
|
108
|
-
Mapper::Settings.write @p[:open_name], @p[:open_idname], open_id
|
109
|
-
Mapper::Settings.write @p[:open_name], @p[:open_keyname], open_key
|
110
|
-
Mapper::Settings.write @p[:open_name], @p[:open_pathname], file_key
|
111
|
-
|
112
|
-
puts ""
|
113
|
-
puts "---------------------------"
|
114
|
-
puts "success | envelope opened"
|
115
|
-
puts "---------------------------"
|
116
|
-
puts ""
|
117
|
-
puts "envelope path => #{param_outer_path}"
|
118
|
-
puts "envelope file => #{nickname file_key}"
|
119
|
-
puts "time [opened] => #{@c[:global][:stamp_23]}"
|
120
|
-
puts ""
|
121
|
-
puts "------------------"
|
122
|
-
puts "now put secrets"
|
123
|
-
puts "------------------"
|
124
|
-
puts ""
|
125
|
-
puts "ops put virgin/ssid VM68256973"
|
126
|
-
puts "ops put virgin/password Wn5lsfixjfy"
|
127
|
-
puts ""
|
128
|
-
|
129
|
-
|
130
|
-
end
|
131
|
-
|
132
|
-
|
133
|
-
# Perform pre-conditional validations in preparation to executing the main flow
|
134
|
-
# of events for this use case. This method may throw the below exceptions.
|
135
|
-
#
|
136
|
-
# @raise [SafeDirNotConfigured] if the safe's url has not been configured
|
137
|
-
# @raise [EmailAddrNotConfigured] if the email address has not been configured
|
138
|
-
# @raise [StoreUrlNotConfigured] if the crypt store url is not configured
|
139
|
-
def pre_validation
|
140
|
-
|
141
|
-
|
142
|
-
end
|
143
|
-
|
144
|
-
|
145
|
-
end
|
146
|
-
|
147
|
-
|
148
|
-
end
|
data/lib/interprete/seal.rb
DELETED
@@ -1,129 +0,0 @@
|
|
1
|
-
#!/usr/bin/ruby
|
2
|
-
|
3
|
-
module OpenSecret
|
4
|
-
|
5
|
-
require 'openssl'
|
6
|
-
|
7
|
-
# The <tt>lock use case</tt> is called after {OpenSecret::Open} and {OpenSecret::Put}
|
8
|
-
# and its effect is to dispatch the doubly encrypted materrial to the configured storage
|
9
|
-
# platform, be it Git, S3, SSH or just an accessible file-system.
|
10
|
-
#
|
11
|
-
# The 3 core scenarios that this lock use case is equiped to handle are
|
12
|
-
#
|
13
|
-
# - a new source that is as yet uncommitted
|
14
|
-
# - updating (overwriting) an existing source
|
15
|
-
# - requiring the destination to be deleted
|
16
|
-
#
|
17
|
-
# <b>Lock | Observable Value</b>
|
18
|
-
#
|
19
|
-
# The observable value after the lock use case has completed entails
|
20
|
-
#
|
21
|
-
# - a doubly encrypted data envelope placed in the backend store
|
22
|
-
# - a doubly encrypted private key placed in the frontend store
|
23
|
-
# - both stores sync'd with off-machine Git (S3, ...) mirrors
|
24
|
-
# - deletion of the (encrypted) envelope {Open}ed and stuffed with {Put}
|
25
|
-
# - deletion of {Open}ed session data to locate and decrypt envelope
|
26
|
-
#
|
27
|
-
# @example
|
28
|
-
#
|
29
|
-
# $ ops seal
|
30
|
-
#
|
31
|
-
class Seal < Command
|
32
|
-
|
33
|
-
attr_writer :envelope_path
|
34
|
-
|
35
|
-
# The <tt>lock use case</tt> is called after {OpenSecret::Open} and {OpenSecret::Put}
|
36
|
-
# and its effect is to dispatch the doubly encrypted materrial to the configured storage
|
37
|
-
# platform, be it Git, S3, SSH or just an accessible file-system.
|
38
|
-
#
|
39
|
-
# <b>Main Flow of Events</b>
|
40
|
-
#
|
41
|
-
# To seal the envelope built up by put, file and add amongst others requires
|
42
|
-
# that we
|
43
|
-
#
|
44
|
-
# - get the encrypted envelope
|
45
|
-
# - create a strong asymmetric key
|
46
|
-
# - lock the envelope using opensecret's double encrypt modus operandi
|
47
|
-
# - place the doubly encrypted result into the crypt store
|
48
|
-
# - lock the asymmetric key again with opensecret's double encrypt modus operandi
|
49
|
-
# - place the doubly encrypted result into the key store
|
50
|
-
#
|
51
|
-
# The second double lock of the crypted envelope is done with the public key
|
52
|
-
# aspect of an asymmetric key created here.
|
53
|
-
#
|
54
|
-
# The second double lock of the crypted private key (created here) is done with
|
55
|
-
# the master public key created in the {Init.execute} use case main flow.
|
56
|
-
#
|
57
|
-
# <b>Lock | Observable Value</b>
|
58
|
-
#
|
59
|
-
# The observable value after the lock use case has completed entails
|
60
|
-
#
|
61
|
-
# - a doubly encrypted data envelope placed in the backend store
|
62
|
-
# - a doubly encrypted private key placed in the frontend store
|
63
|
-
# - both stores sync'd with off-machine Git (S3, ...) mirrors
|
64
|
-
# - deletion of the (encrypted) envelope {Open}ed and stuffed with {Put}
|
65
|
-
# - deletion of {Open}ed session data to locate and decrypt envelope
|
66
|
-
def execute
|
67
|
-
|
68
|
-
instantiate_collateral
|
69
|
-
|
70
|
-
rel_filepath = Mapper::Settings.read @c[:open][:open_name], @c[:open][:open_pathname]
|
71
|
-
master_public_key = OpenSSL::PKey::RSA.new ( @collateral.read_public_key )
|
72
|
-
|
73
|
-
keys_store = Store::ColdStore.new( @collateral.frontend_keystore_path )
|
74
|
-
main_store = Store::ColdStore.new( @collateral.backend_cryptstore_path )
|
75
|
-
|
76
|
-
envelope = get_envelope
|
77
|
-
asym_key = OpenSSL::PKey::RSA.new @c[:global][:bit_key_size]
|
78
|
-
lockdown = ToolBelt::Cipher.encrypt_it( asym_key.public_key, envelope.to_json )
|
79
|
-
lockedup = ToolBelt::Cipher.encrypt_it( master_public_key, asym_key.export )
|
80
|
-
|
81
|
-
##### ###################################### #####
|
82
|
-
##### ###################################### #####
|
83
|
-
### Now put the CRYPTS into [Cold] Storage ###
|
84
|
-
##### ###################################### #####
|
85
|
-
##### ###################################### #####
|
86
|
-
|
87
|
-
keys_store.write lockedup, rel_filepath
|
88
|
-
main_store.write lockdown, rel_filepath
|
89
|
-
|
90
|
-
puts ""
|
91
|
-
puts "================================================================="
|
92
|
-
puts "[Lock] => Now DELETE the session files and configured variables."
|
93
|
-
puts "================================================================="
|
94
|
-
puts ""
|
95
|
-
|
96
|
-
|
97
|
-
end
|
98
|
-
|
99
|
-
|
100
|
-
# Perform pre-conditional validations in preparation to executing the main flow
|
101
|
-
# of events for this use case. This method may throw the below exceptions.
|
102
|
-
#
|
103
|
-
# @raise [SafeDirNotConfigured] if the safe's url has not been configured
|
104
|
-
# @raise [EmailAddrNotConfigured] if the email address has not been configured
|
105
|
-
# @raise [StoreUrlNotConfigured] if the crypt store url is not configured
|
106
|
-
def pre_validation
|
107
|
-
|
108
|
-
|
109
|
-
end
|
110
|
-
|
111
|
-
|
112
|
-
end
|
113
|
-
|
114
|
-
|
115
|
-
end
|
116
|
-
|
117
|
-
|
118
|
-
#############################################################################################
|
119
|
-
#############################################################################################
|
120
|
-
|
121
|
-
=begin
|
122
|
-
GitFlow.do_clone_repo @p[:public_gitrepo], @p[:local_gitrepo]
|
123
|
-
FileUtils.mkdir_p @p[:public_keydir]
|
124
|
-
File.write @p[:public_keypath], public_key_text
|
125
|
-
GitFlow.push @p[:local_gitrepo], @p[:public_keyname], @c[:time][:stamp]
|
126
|
-
=end
|
127
|
-
|
128
|
-
#############################################################################################
|
129
|
-
#############################################################################################
|
data/lib/keytools/digester.rb
DELETED
@@ -1,245 +0,0 @@
|
|
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
|