opensecret 0.0.988 → 0.0.9925
Sign up to get free protection for your applications and to get access to all the features.
- 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
|