Module: GoSecure
- Defined in:
- lib/go_secure.rb
Defined Under Namespace
Modules: SecureJson, SecureSerializeHelpers, SerializeClassMethods, SerializeInstanceMethods
Class Method Summary
collapse
-
.browser_token ⇒ Object
-
.decrypt(str, salt, ref, encryption_key = nil) ⇒ Object
-
.encrypt(str, ref, encryption_key = nil, iv = nil) ⇒ Object
-
.encryption_key ⇒ Object
-
.generate_password(password) ⇒ Object
-
.hmac(str, salt, level, encryption_key = nil) ⇒ Object
-
.lite_hmac(str, salt, level, encryption_key = nil) ⇒ Object
-
.matches_password?(attempt, password_hash) ⇒ Boolean
-
.nonce(str) ⇒ Object
-
.outdated_password?(password_hash) ⇒ Boolean
-
.sha512(str, salt, encryption_key = nil) ⇒ Object
-
.valid_browser_token?(token) ⇒ Boolean
-
.valid_browser_token_signature?(token) ⇒ Boolean
-
.validate_encryption_key ⇒ Object
Class Method Details
.browser_token ⇒ Object
121
122
123
124
125
126
|
# File 'lib/go_secure.rb', line 121
def self.browser_token
day = Time.now.strftime('%j')
stamp = "#{Time.now.year}#{(Time.now.yday / 366.0 * 100.0).to_i.to_s.rjust(2, '0')}"
stamp += '-' + GoSecure.sha512(stamp, 'browser_token')
end
|
.decrypt(str, salt, ref, encryption_key = nil) ⇒ Object
41
42
43
44
45
46
47
48
49
50
51
52
53
|
# File 'lib/go_secure.rb', line 41
def self.decrypt(str, salt, ref, encryption_key=nil)
require 'base64'
c = OpenSSL::Cipher.new('aes-256-cbc')
c.decrypt
sha = Digest::SHA2.hexdigest(ref + "_" + (encryption_key || self.encryption_key))
c.key = sha[0..31]
iv = Base64.decode64(salt)
c.iv = iv[0..15]
d = c.update(Base64.decode64(str))
d << c.final
d.to_s
end
|
.encrypt(str, ref, encryption_key = nil, iv = nil) ⇒ Object
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
# File 'lib/go_secure.rb', line 26
def self.encrypt(str, ref, encryption_key=nil, iv=nil)
require 'base64'
c = OpenSSL::Cipher.new('aes-256-cbc')
c.encrypt
sha = Digest::SHA2.hexdigest(ref + "_" + (encryption_key || self.encryption_key))
c.key = sha[0..31]
raise "invalid iv" if iv && iv.length != 16
iv = iv || c.random_iv
c.iv = iv
e = c.update(str)
e << c.final
res = [Base64.encode64(e), Base64.encode64(iv)]
res
end
|
.encryption_key ⇒ Object
117
118
119
|
# File 'lib/go_secure.rb', line 117
def self.encryption_key
ENV['SECURE_ENCRYPTION_KEY']
end
|
.generate_password(password) ⇒ Object
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
# File 'lib/go_secure.rb', line 55
def self.generate_password(password)
raise "password required" if password == nil || password.length == 0
pw = {}
pw['hash_type'] = 'pbkdf2-sha256-2'
pw['salt'] = Digest::MD5.hexdigest(OpenSSL::Random.random_bytes(4) + Time.now.to_i.to_s + self.encryption_key + "pw" + OpenSSL::Random.random_bytes(16))
digest = OpenSSL::Digest::SHA512.new(self.encryption_key)
pw['hashed_password'] = Base64.urlsafe_encode64(OpenSSL::PKCS5.pbkdf2_hmac(password.to_s, pw['salt'], 100000, digest.digest_length, digest))
pw
end
|
.hmac(str, salt, level, encryption_key = nil) ⇒ Object
10
11
12
13
14
15
|
# File 'lib/go_secure.rb', line 10
def self.hmac(str, salt, level, encryption_key=nil)
raise "invalid level" unless level == 1
digest = OpenSSL::Digest::SHA512.new(encryption_key || self.encryption_key)
res = Base64.urlsafe_encode64(OpenSSL::PKCS5.pbkdf2_hmac(str.to_s, salt.to_s, 100000, digest.digest_length, digest))
end
|
.lite_hmac(str, salt, level, encryption_key = nil) ⇒ Object
17
18
19
20
|
# File 'lib/go_secure.rb', line 17
def self.lite_hmac(str, salt, level, encryption_key=nil)
raise "invalid level" unless level == 1
OpenSSL::HMAC.hexdigest('SHA512', OpenSSL::HMAC.hexdigest('SHA512', str.to_s, salt.to_s), encryption_key || self.encryption_key)
end
|
.matches_password?(attempt, password_hash) ⇒ Boolean
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
# File 'lib/go_secure.rb', line 74
def self.matches_password?(attempt, password_hash)
if password_hash && password_hash['hash_type'] == 'sha512' && password_hash['salt']
str = Digest::SHA512.hexdigest(self.encryption_key + password_hash['salt'] + attempt.to_s)
res = str == password_hash['hashed_password']
if !res && password_hash['old_passwords']
else
res
end
elsif password_hash && password_hash['hash_type'] == 'bcrypt' && password_hash['salt']
pw = BCrypt::Password.new(password_hash['hashed_password'])
salted = Digest::SHA256.hexdigest(self.encryption_key + password_hash['salt'] + attempt.to_s)
res = pw == salted
elsif password_hash && password_hash['hash_type'] == 'pbkdf2-sha256' && password_hash['salt']
digest = OpenSSL::Digest::SHA256.new
str = Base64.encode64(OpenSSL::PKCS5.pbkdf2_hmac(attempt.to_s, password_hash['salt'], 100000, digest.digest_length, digest))
res = str == password_hash['hashed_password']
elsif password_hash && password_hash['hash_type'] == 'pbkdf2-sha256-2' && password_hash['salt']
digest = OpenSSL::Digest::SHA512.new(self.encryption_key)
str = Base64.urlsafe_encode64(OpenSSL::PKCS5.pbkdf2_hmac(attempt.to_s, password_hash['salt'], 100000, digest.digest_length, digest))
res = str == password_hash['hashed_password']
else
false
end
end
|
.nonce(str) ⇒ Object
22
23
24
|
# File 'lib/go_secure.rb', line 22
def self.nonce(str)
Digest::SHA512.hexdigest(str.to_s + Time.now.to_i.to_s + rand(999999).to_s + self.encryption_key)[0, 24]
end
|
.outdated_password?(password_hash) ⇒ Boolean
70
71
72
|
# File 'lib/go_secure.rb', line 70
def self.outdated_password?(password_hash)
return password_hash && password_hash['hash_type'] != 'pbkdf2-sha256-2'
end
|
.sha512(str, salt, encryption_key = nil) ⇒ Object
6
7
8
|
# File 'lib/go_secure.rb', line 6
def self.sha512(str, salt, encryption_key=nil)
Digest::SHA512.hexdigest(str.to_s + salt.to_s + (encryption_key || self.encryption_key))
end
|
.valid_browser_token?(token) ⇒ Boolean
133
134
135
136
137
138
139
140
141
|
# File 'lib/go_secure.rb', line 133
def self.valid_browser_token?(token)
return false if !token || token.length == 0 || !token.match(/-/)
stamp, hash = token.split(/-/, 2)
current_stamp = "#{Time.now.year}#{(Time.now.yday / 366.0 * 100.0).to_i.to_s.rjust(2, '0')}"
if current_stamp.to_i - stamp.to_i < (14/365.0*100.0) return valid_browser_token_signature?(token)
end
false
end
|
.valid_browser_token_signature?(token) ⇒ Boolean
128
129
130
131
|
# File 'lib/go_secure.rb', line 128
def self.valid_browser_token_signature?(token)
stamp, hash = token.split(/-/, 2)
return hash == GoSecure.sha512(stamp, 'browser_token')
end
|
.validate_encryption_key ⇒ Object
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
# File 'lib/go_secure.rb', line 100
def self.validate_encryption_key
if !self.encryption_key || self.encryption_key.length < 24
raise "SECURE_ENCRYPTION_KEY env variable should be at least 24 characters"
end
return if !ActiveRecord::Base.connection.data_source_exists?('settings')
config_hash = Digest::SHA1.hexdigest(self.encryption_key)
stored_hash = Setting.get('encryption_hash')
return if stored_hash == config_hash
if stored_hash.nil?
Setting.set('encryption_hash', config_hash);
else
raise "SECURE_ENCRYPTION_KEY env variable doesn't match the value stored in the database." +
" If this is intentional you can try DELETE FROM settings WHERE key='encryption_hash' to reset."
end
end
|