go_secure 0.62 → 0.70

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.
Files changed (3) hide show
  1. checksums.yaml +5 -5
  2. data/lib/go_secure.rb +116 -12
  3. metadata +7 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 23672006525e9b8d00c32febe3e51c7f0b7f622a
4
- data.tar.gz: 9cf3d608a364304aa1f1f4d57be6d5e9d429b767
2
+ SHA256:
3
+ metadata.gz: 6c1ac3e5ca4f3cec1163eaaf94c96aeecbf9d7598a0b36b0a88b62c02ce0fdf6
4
+ data.tar.gz: 8ed2bd8c670d7903aac0c7ae127f121d1e03d39d46aeb104d6d005141b6892d7
5
5
  SHA512:
6
- metadata.gz: '019ef5cccca1afc672ce75c5370d63ee4135e1a584179a9eb7a056f54c3a4c9bd72cbdb2194e3e0dafb440aaebefbf867c9a928033a7110cc30af8abdc2aba27'
7
- data.tar.gz: c01c6899abc3711302d987daa9d23a7f5666c6c95d142bdcfc0dbade4d3cbee33ca0d20ca57eecb9c9b1d2c31344a045cecee41074012c2f27409f3870555237
6
+ metadata.gz: '06197b6cc0e35b7ba5fe6547ad58b27fff19726fe6a2508af31595c059f8f0ce23c589111c77f8a22c4de50d952a7610ea9fdc6aa187ef4b481d2df2885d15e7'
7
+ data.tar.gz: 493403cce547664bf0f29bf581ca0ee68af32ddb8d70637d37fe33fa65ea95eed5a1071cba08b8a2642b6d53120da48424d38d7f7bc74d82176ec5f4abc76898
@@ -13,17 +13,25 @@ module GoSecure
13
13
  digest = OpenSSL::Digest::SHA512.new(encryption_key || self.encryption_key)
14
14
  res = Base64.urlsafe_encode64(OpenSSL::PKCS5.pbkdf2_hmac(str.to_s, salt.to_s, 100000, digest.digest_length, digest))
15
15
  end
16
+
17
+ def self.lite_hmac(str, salt, level, encryption_key=nil)
18
+ raise "invalid level" unless level == 1
19
+ OpenSSL::HMAC.hexdigest('SHA512', OpenSSL::HMAC.hexdigest('SHA512', str.to_s, salt.to_s), encryption_key || self.encryption_key)
20
+ end
16
21
 
17
22
  def self.nonce(str)
18
23
  Digest::SHA512.hexdigest(str.to_s + Time.now.to_i.to_s + rand(999999).to_s + self.encryption_key)[0, 24]
19
24
  end
20
25
 
21
- def self.encrypt(str, ref, encryption_key=nil)
26
+ def self.encrypt(str, ref, encryption_key=nil, iv=nil)
22
27
  require 'base64'
23
- c = OpenSSL::Cipher::Cipher.new('aes-256-cbc')
28
+ c = OpenSSL::Cipher.new('aes-256-cbc')
24
29
  c.encrypt
25
- c.key = Digest::SHA2.hexdigest(ref + "_" + (encryption_key || self.encryption_key))
26
- c.iv = iv = c.random_iv
30
+ sha = Digest::SHA2.hexdigest(ref + "_" + (encryption_key || self.encryption_key))
31
+ c.key = sha[0..31]
32
+ raise "invalid iv" if iv && iv.length != 16
33
+ iv = iv || c.random_iv
34
+ c.iv = iv
27
35
  e = c.update(str)
28
36
  e << c.final
29
37
  res = [Base64.encode64(e), Base64.encode64(iv)]
@@ -32,10 +40,13 @@ module GoSecure
32
40
 
33
41
  def self.decrypt(str, salt, ref, encryption_key=nil)
34
42
  require 'base64'
35
- c = OpenSSL::Cipher::Cipher.new('aes-256-cbc')
43
+ c = OpenSSL::Cipher.new('aes-256-cbc')
36
44
  c.decrypt
37
- c.key = Digest::SHA2.hexdigest(ref + "_" + (encryption_key || self.encryption_key))
38
- c.iv = Base64.decode64(salt)
45
+ sha = Digest::SHA2.hexdigest(ref + "_" + (encryption_key || self.encryption_key))
46
+ c.key = sha[0..31]
47
+ iv = Base64.decode64(salt)
48
+
49
+ c.iv = iv[0..15]
39
50
  d = c.update(Base64.decode64(str))
40
51
  d << c.final
41
52
  d.to_s
@@ -47,7 +58,7 @@ module GoSecure
47
58
  # pw['hash_type'] = 'sha512'
48
59
  # pw['hash_type'] = 'bcrypt'
49
60
  pw['hash_type'] = 'pbkdf2-sha256-2'
50
- pw['salt'] = Digest::MD5.hexdigest(OpenSSL::Random.pseudo_bytes(4) + Time.now.to_i.to_s + self.encryption_key + "pw" + OpenSSL::Random.pseudo_bytes(16))
61
+ 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))
51
62
  # pw['hashed_password'] = Digest::SHA512.hexdigest(self.encryption_key + pw['salt'] + password.to_s)
52
63
  # salted = Digest::SHA256.hexdigest(self.encryption_key + pw['salt'] + password.to_s)
53
64
  # pw['hashed_password'] = BCrypt::Password.create(salted)
@@ -109,7 +120,8 @@ module GoSecure
109
120
 
110
121
  def self.browser_token
111
122
  # TODO: checks around whether it's actually a web browser??
112
- stamp = Time.now.strftime('%Y%j')
123
+ day = Time.now.strftime('%j')
124
+ stamp = "#{Time.now.year}#{(Time.now.yday / 366.0 * 100.0).to_i.to_s.rjust(2, '0')}"
113
125
  stamp += '-' + GoSecure.sha512(stamp, 'browser_token')
114
126
  end
115
127
 
@@ -121,7 +133,8 @@ module GoSecure
121
133
  def self.valid_browser_token?(token)
122
134
  return false if !token || token.length == 0 || !token.match(/-/)
123
135
  stamp, hash = token.split(/-/, 2)
124
- if Time.now.strftime('%Y%j').to_i - stamp.to_i < 14 # 14 days?!
136
+ current_stamp = "#{Time.now.year}#{(Time.now.yday / 366.0 * 100.0).to_i.to_s.rjust(2, '0')}"
137
+ if current_stamp.to_i - stamp.to_i < (14/365.0*100.0) # 14 days?!
125
138
  return valid_browser_token_signature?(token)
126
139
  end
127
140
  false
@@ -135,10 +148,10 @@ module GoSecure
135
148
  def self.load(str)
136
149
  return nil unless str
137
150
  if str.match(/^\*\*/)
138
- Oj.load(str[2..-1])
151
+ Oj.load(str[2..-1], mode: :compat)
139
152
  else
140
153
  salt, secret = str.split(/--/, 2)
141
- Oj.load(GoSecure.decrypt(secret, salt, "secure_json"))
154
+ Oj.load(GoSecure.decrypt(secret, salt, "secure_json"), mode: :compat)
142
155
  end
143
156
  end
144
157
 
@@ -157,4 +170,95 @@ module GoSecure
157
170
  end
158
171
  end
159
172
  end
173
+
174
+ module SerializeInstanceMethods
175
+ def load_secure_object
176
+ @secure_object_json = nil.to_json
177
+ if self.id
178
+ attr = read_attribute(self.class.secure_column) || (!self.respond_to?(:secure_column_value) && self.send(self.class.secure_column)) || (@secure_object.is_a?(String) && @secure_object) || nil
179
+ if attr && attr.match(/\s*^{/)
180
+ @secure_object = JSON.parse(attr)
181
+ else
182
+ @secure_object = GoSecure::SecureJson.load(attr)
183
+ end
184
+ @secure_object_json = @secure_object.to_json
185
+ @loaded_secure_object = true
186
+ end
187
+ true
188
+ end
189
+
190
+ # If the serialized data has changed since initialize and paper_trail
191
+ # is configured, then we need to manually mark the column as dirty
192
+ # to make sure a proper paper_trail is maintained
193
+ def mark_changed_secure_object_hash
194
+ if !send("#{self.class.secure_column}_changed?")
195
+ json = @secure_object.to_json
196
+ if json != @secure_object_json
197
+ send("#{self.class.secure_column}_will_change!")
198
+ end
199
+ end
200
+ true
201
+ end
202
+
203
+ def persist_secure_object
204
+ self.class.more_before_saves ||= []
205
+ self.class.more_before_saves.each do |method|
206
+ res = send(method)
207
+ return false if res == false
208
+ end
209
+ mark_changed_secure_object_hash
210
+ if send("#{self.class.secure_column}_changed?")
211
+ secure = GoSecure::SecureJson.dump(@secure_object)
212
+ @secure_object = GoSecure::SecureJson.load(secure)
213
+ write_attribute(self.class.secure_column, secure)
214
+ end
215
+ true
216
+ end
217
+ end
218
+
219
+ module SerializeClassMethods
220
+ def secure_serialize(column)
221
+ raise "only one secure column per record! (yes I'm lazy)" if self.respond_to?(:secure_column) && self.secure_column
222
+ cattr_accessor :secure_column
223
+ cattr_accessor :more_before_saves
224
+ self.secure_column = column
225
+ prepend SecureSerializeHelpers
226
+
227
+ before_save :persist_secure_object
228
+ define_singleton_method(:before_save) do |*args|
229
+ raise "only simple before_save calls after secure_serialize: #{args.to_json}" unless args.length == 1 && args[0].is_a?(Symbol)
230
+ self.more_before_saves ||= []
231
+ self.more_before_saves << args[0]
232
+ end
233
+ define_method("secure_column_value") do
234
+ nil
235
+ end
236
+ define_method("#{column}") do
237
+ load_secure_object unless @loaded_secure_object
238
+ @secure_object
239
+ end
240
+ define_method("#{column}=") do |val|
241
+ @loaded_secure_object = true
242
+ @secure_object = val
243
+ end
244
+ # Commented out because eager-loading an encrypted data column is not efficient
245
+ # after_initialize :load_secure_object
246
+ end
247
+ end
248
+
249
+ module SecureSerializeHelpers
250
+ def reload(*args)
251
+ res = super
252
+ load_secure_object
253
+ res
254
+ end
255
+
256
+ def []=(*args)
257
+ if args[0].to_s == self.class.secure_column
258
+ send("#{self.class.secure_column}=", args[1])
259
+ else
260
+ super
261
+ end
262
+ end
263
+ end
160
264
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: go_secure
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.62'
4
+ version: '0.70'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Whitmer
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-14 00:00:00.000000000 Z
11
+ date: 2020-09-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: oj
@@ -66,7 +66,7 @@ homepage: https://github.com/CoughDrop/obf
66
66
  licenses:
67
67
  - MIT
68
68
  metadata: {}
69
- post_install_message:
69
+ post_install_message:
70
70
  rdoc_options: []
71
71
  require_paths:
72
72
  - lib
@@ -81,9 +81,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  requirements: []
84
- rubyforge_project:
85
- rubygems_version: 2.5.2
86
- signing_key:
84
+ rubyforge_project:
85
+ rubygems_version: 2.7.6
86
+ signing_key:
87
87
  specification_version: 4
88
88
  summary: Go Secure
89
89
  test_files: []