enzoic 1.1.3 → 1.3.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 193cc6ee5e5585ea3a76add970ce69feb44c2383
4
- data.tar.gz: a77cdcf48592e05a9f06ef1ad486467002f2df30
2
+ SHA256:
3
+ metadata.gz: a9299615755ffc582bb35414b6851ba06c11f236565542ef1d7b5d8b681ec776
4
+ data.tar.gz: 12e91e3208c526598672ecbf066af5734237345954e76320ae7163691d4f25e7
5
5
  SHA512:
6
- metadata.gz: 641ca919dd26147fe4e06550923f380f2b54eb0959372171f57a4f17ff2bcd5f98adcd446d3d39e9f0205910671307c7e78b6954ffa77e0ad58513f25ca31084
7
- data.tar.gz: 9acf2c9d120dc0292f136b7583ba0d36f2aacd4c7e9fe52de19ec2c6468f7f42738e939250893345fe1fdc6e5d77b44e203db2558b34b0a541303365515b393d
6
+ metadata.gz: 888318919c30799a05c6cb91ddf0d986a5b86ac9d0a4ca0db76ed725fac7f4e91dd2d8a9a9353af0bd375b9c3e4284a979a3391d1649292521a145b04f9e577f
7
+ data.tar.gz: dad8311f61c0bdadd39436e53db8ec02e0f61313233aba3f0337c7cf403ec3cbe0b04d2b97a16194c3c4d1c2e578cdf0233bfea560046208f0c692e08a73497b
data/README.md CHANGED
@@ -35,6 +35,7 @@ require 'enzoic'
35
35
  enzoic = Enzoic::Enzoic.new(apiKey: YOUR_API_KEY, secret: YOUR_API_SECRET)
36
36
 
37
37
  # Check whether a password has been compromised
38
+ # see https://www.enzoic.com/docs-passwords-api/ for more information
38
39
  if enzoic.check_password("password-to-test")
39
40
  puts("Password is compromised")
40
41
  else
@@ -42,6 +43,7 @@ else
42
43
  end
43
44
 
44
45
  # Check whether a specific set of credentials are compromised
46
+ # see https://www.enzoic.com/docs-credentials-api/ for more information
45
47
  if enzoic.check_credentials("test@enzoic.com", "password-to-test")
46
48
  puts("Credentials are compromised")
47
49
  else
@@ -53,7 +55,7 @@ end
53
55
  # lastCheckDate is the timestamp for the last check you performed for this user.
54
56
  # If the DateTime you provide for the last check is greater than the timestamp Enzoic has
55
57
  # for the last breach affecting this user, the check will not be performed.
56
- # This can be used to substantially increase performance.
58
+ # This can be used to substantially increase performance.
57
59
  if enzoic.check_credentials("test@enzoic.com", "password-to-test", DateTime.parse("2019-07-15T19:57:43.000Z"))
58
60
  puts("Credentials are compromised")
59
61
  else
@@ -61,12 +63,20 @@ else
61
63
  end
62
64
 
63
65
  # get all exposures for a given user
66
+ # see https://www.enzoic.com/docs-exposures-api/#get-exposures for more information
64
67
  exposures = enzoic.get_exposures_for_user("test@enzoic.com")
65
68
  puts(exposures.count.to_s + " exposures found for test@enzoic.com")
66
69
 
67
70
  # now get the full details for the first exposure found
71
+ # see https://www.enzoic.com/docs-exposures-api/#get-exposure-details for more information
68
72
  details = enzoic.get_exposure_details(exposures.exposures[0])
69
73
  puts("First exposure for test@enzoic.com was " + details.title)
74
+
75
+ # get all passwords for a given user - requires special approval, contact Enzoic sales
76
+ # see https://www.enzoic.com/docs-raw-passwords-api/ for more information
77
+ user_passwords = enzoic.get_passwords_for_user("eicar_0@enzoic.com")
78
+ puts("First password for eicar_0@enzoic.com was " + user_passwords.passwords[0].password)
79
+
70
80
  ```
71
81
 
72
82
  More information in reference format can be found below.
data/Rakefile CHANGED
@@ -20,9 +20,9 @@ Rake::ExtensionTask.new('whirlpool', gemspec) do |ext|
20
20
  ext.lib_dir = 'lib/digest'
21
21
  end
22
22
 
23
- # Rake::ExtensionTask.new('argon2-wrapper', gemspec) do |ext|
24
- # ext.ext_dir = 'ext/argon2-wrapper'
25
- # ext.lib_dir = 'lib/enzoic'
26
- # end
23
+ Rake::ExtensionTask.new('argon2-wrapper', gemspec) do |ext|
24
+ ext.ext_dir = 'ext/argon2-wrapper'
25
+ ext.lib_dir = 'lib/enzoic'
26
+ end
27
27
 
28
28
  task :default => :test
data/enzoic.gemspec CHANGED
@@ -20,14 +20,14 @@ Gem::Specification.new do |spec|
20
20
  spec.bindir = "exe"
21
21
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
22
  spec.require_paths = ["lib"]
23
- spec.add_dependency 'ffi', '~> 1.11.1'
23
+ spec.add_dependency 'ffi', '~> 1.15.5'
24
24
  spec.add_dependency 'ffi-compiler', '~> 1.0.1'
25
25
  spec.add_dependency 'rest-client', '~> 2.0', '>= 2.0.2'
26
26
  spec.add_dependency 'bcrypt', '~> 3.1', '>= 3.1.11'
27
27
  spec.add_dependency 'unix-crypt', '~> 1.3'
28
28
  spec.add_dependency 'base64url', '~> 1.0', '>= 1.0.1'
29
29
 
30
- spec.add_development_dependency "bundler", '~> 2.0.2', '>= 2.0.2'
30
+ spec.add_development_dependency "bundler", '~> 2.2.11', '>= 2.2.11'
31
31
  spec.add_development_dependency "rake", '~> 10.4', '>= 10.4.2'
32
32
  spec.add_development_dependency "test-unit", '~> 3.2', '>= 3.2.4'
33
33
  spec.add_development_dependency "rake-compiler", '~> 1.0', '>= 1.0.4'
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -3,7 +3,8 @@ require 'digest'
3
3
  require 'bcrypt'
4
4
  require 'unix_crypt'
5
5
  require 'zlib'
6
- require 'digest/whirlpool'
6
+ require 'digest/whirlpool.bundle'
7
+ #require 'open_ssl'
7
8
  require 'base64url'
8
9
 
9
10
  module Enzoic
@@ -24,6 +25,14 @@ module Enzoic
24
25
  return Digest::SHA1.hexdigest to_hash
25
26
  end
26
27
 
28
+ def self.sha1_binary(to_hash)
29
+ return Digest::SHA1.digest(to_hash).bytes
30
+ end
31
+
32
+ def self.sha1_binary_array(to_hash_bytes)
33
+ return Digest::SHA1.digest(to_hash_bytes.pack('c*')).bytes
34
+ end
35
+
27
36
  def self.sha256(to_hash)
28
37
  return Digest::SHA256.hexdigest to_hash
29
38
  end
@@ -91,7 +100,7 @@ module Enzoic
91
100
 
92
101
  itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
93
102
  to_hash_bytes = to_hash.bytes
94
- count = 2**itoa64.index(salt[3])
103
+ count = 2 ** itoa64.index(salt[3])
95
104
  justsalt = salt[4..12]
96
105
 
97
106
  hash = self.md5_binary(justsalt + to_hash)
@@ -148,13 +157,169 @@ module Enzoic
148
157
  end
149
158
 
150
159
  def self.md5crypt(to_hash, salt)
151
- return UnixCrypt::MD5.build(to_hash, salt.start_with?("$1$") ? salt[3..salt.length] : salt);
160
+ return UnixCrypt::MD5.build(to_hash, salt.start_with?("$1$") ? salt[3..salt.length] : salt)
152
161
  end
153
162
 
154
163
  def self.custom_algorithm4(to_hash, salt)
155
164
  return self.bcrypt(self.md5(to_hash), salt)
156
165
  end
157
166
 
167
+ def self.custom_algorithm5(to_hash, salt)
168
+ return self.sha256(self.md5(to_hash + salt))
169
+ end
170
+
171
+ def self.osCommerce_AEF(to_hash, salt)
172
+ return self.md5(salt + to_hash)
173
+ end
174
+
175
+ def self.desCrypt(to_hash, salt)
176
+ return UnixCrypt::DES.build(to_hash, salt)
177
+ end
178
+
179
+ def self.convertToUnsigned(val)
180
+ return [val].pack('L').unpack('L').first
181
+ end
182
+
183
+ def self.mySQLPre4_1(to_hash)
184
+ nr = 1345345333
185
+ add = 7
186
+ nr2 = 0x12345671
187
+
188
+ for i in 0..to_hash.length - 1 do
189
+ c = to_hash[i]
190
+
191
+ if c == " " || c == "\t"
192
+ next
193
+ end
194
+
195
+ tmp = c.ord
196
+ nr = nr ^ ((((nr & 63) + add) * tmp) + (self.convertToUnsigned(nr << 8)))
197
+ nr2 += (self.convertToUnsigned(nr2 << 8)) ^ nr
198
+ add += tmp
199
+ end
200
+
201
+ result1 = nr & ((self.convertToUnsigned(1 << 31)) - 1)
202
+ result2 = nr2 & ((self.convertToUnsigned(1 << 31)) - 1)
203
+
204
+ return result1.to_s(16) + result2.to_s(16)
205
+ end
206
+
207
+ def self.mySQLPost4_1(to_hash)
208
+ return "*" + self.bytes_to_hex(self.sha1_binary_array(self.sha1_binary(to_hash)));
209
+ end
210
+
211
+ def self.punBB(to_hash, salt)
212
+ return self.sha1(salt + self.sha1(to_hash))
213
+ end
214
+
215
+ def self.custom_algorithm6(to_hash, salt)
216
+ return self.sha1(to_hash + salt)
217
+ end
218
+
219
+ def self.partial_md5_20(to_hash)
220
+ return self.md5(to_hash)[0..19]
221
+ end
222
+
223
+ def self.partial_md5_29(to_hash)
224
+ return self.md5(to_hash)[0..28]
225
+ end
226
+
227
+ def self.ave_datalife_diferior(to_hash)
228
+ return self.md5(self.md5(to_hash))
229
+ end
230
+
231
+ def self.django_md5(to_hash, salt)
232
+ return "md5$" + salt + "$" + self.md5(salt + to_hash)
233
+ end
234
+
235
+ def self.django_sha1(to_hash, salt)
236
+ return "sha1$" + salt + "$" + self.sha1(salt + to_hash)
237
+ end
238
+
239
+ def self.pligg_cms(to_hash, salt)
240
+ return salt + self.sha1(salt + to_hash)
241
+ end
242
+
243
+ def self.runcms_smf1_1(to_hash, salt)
244
+ return self.sha1(salt + to_hash)
245
+ end
246
+
247
+ def self.ntlm(to_hash)
248
+ pwd = to_hash.dup
249
+ pwd = pwd.dup.force_encoding('UTF-8').encode(Encoding::UTF_16LE, Encoding::UTF_8).force_encoding('UTF-8')
250
+ OpenSSL::Digest::MD4.hexdigest pwd
251
+ end
252
+
253
+ def self.sha1dash(to_hash, salt)
254
+ return self.sha1("--" + salt + "--" + to_hash + "--")
255
+ end
256
+
257
+ def self.sha384(to_hash)
258
+ return Digest::SHA384.hexdigest to_hash
259
+ end
260
+
261
+ def self.custom_algorithm7(to_hash, salt)
262
+ derived_salt = self.sha1(salt)
263
+ return OpenSSL::HMAC.hexdigest("SHA256",
264
+ "d2e1a4c569e7018cc142e9cce755a964bd9b193d2d31f02d80bb589c959afd7e",
265
+ derived_salt + to_hash)
266
+ end
267
+
268
+ def self.custom_algorithm9(to_hash, salt)
269
+ result = self.sha512(to_hash + salt)
270
+ for i in 0..10 do
271
+ result = self.sha512(result)
272
+ end
273
+ return result
274
+ end
275
+
276
+ def self.sha256crypt(to_hash, salt)
277
+ return self.sha_crypt("5", UnixCrypt::SHA256, to_hash, salt)
278
+ end
279
+
280
+ def self.sha512crypt(to_hash, salt)
281
+ return self.sha_crypt("6", UnixCrypt::SHA512, to_hash, salt)
282
+ end
283
+
284
+ def self.sha_crypt(crypt_version, crypter, to_hash, salt)
285
+ # special handling if the salt contains an embedded rounds specifier
286
+ if salt.start_with?("$" + crypt_version + "$") && salt.include?("$rounds=")
287
+ # extract rounds
288
+ rounds_starting_idx = salt.index("$rounds=") + 8
289
+ rounds = salt[rounds_starting_idx..salt.length]
290
+ salt_portion = rounds[rounds.index("$") + 1..rounds.length]
291
+
292
+ begin
293
+ rounds = Integer(rounds[0..rounds.index("$") - 1])
294
+ rescue ArgumentError
295
+ rounds = 5000
296
+ end
297
+
298
+ result = crypter.build(to_hash, salt_portion, rounds)
299
+
300
+ # if the default rounds of 5000 was used, add this back in to the resultant hash as this library, unlike most,
301
+ # will strip it out.
302
+ if rounds == 5000
303
+ result = result[0..2] + "rounds=5000$" + result[3..result.length]
304
+ end
305
+
306
+ return result
307
+ end
308
+ return crypter.build(to_hash, salt.start_with?("$" + crypt_version + "$") ? salt[3..salt.length] : salt)
309
+ end
310
+
311
+ def self.custom_algorithm10(to_hash, salt)
312
+ return self.sha512(to_hash + ":" + salt)
313
+ end
314
+
315
+ def self.hmac_sha1_salt_as_hash(to_hash, salt)
316
+ return OpenSSL::HMAC.hexdigest("sha1", salt, to_hash)
317
+ end
318
+
319
+ def self.authMeSHA256(to_hash, salt)
320
+ return "$SHA$" + salt + "$" + self.sha256(self.sha256(to_hash) + salt);
321
+ end
322
+
158
323
  def self.argon2_raw(to_hash, salt)
159
324
  time_cost = 3
160
325
  mem_cost = 10
@@ -238,13 +403,13 @@ module Enzoic
238
403
  end
239
404
 
240
405
  def self.xor(byte_array1, byte_array2)
241
- result = Array.new(byte_array1.length);
406
+ result = Array.new(byte_array1.length);
242
407
 
243
- for i in 0..byte_array1.length - 1 do
244
- result[i] = byte_array1[i] ^ byte_array2[i];
245
- end
408
+ for i in 0..byte_array1.length - 1 do
409
+ result[i] = byte_array1[i] ^ byte_array2[i];
410
+ end
246
411
 
247
- return result;
412
+ return result;
248
413
  end
249
414
 
250
415
  def self.bytes_to_hex(bytes)
@@ -18,6 +18,33 @@ module Enzoic
18
18
  SHA512 = 14
19
19
  MD5Crypt = 16
20
20
  CustomAlgorithm4 = 17
21
+ CustomAlgorithm5 = 18
22
+ OsCommerce_AEF = 19
23
+ DESCrypt = 20
24
+ MySQLPre4_1 = 21
25
+ MySQLPost4_1 = 22
26
+ PeopleSoft = 23
27
+ PunBB = 24
28
+ CustomAlgorithm6 = 25
29
+ PartialMD5_20 = 26
30
+ AVE_DataLife_Diferior = 27
31
+ DjangoMD5 = 28
32
+ DjangoSHA1 = 29
33
+ PartialMD5_29 = 30
34
+ PliggCMS = 31
35
+ RunCMS_SMF1_1 = 32
36
+ NTLM = 33
37
+ SHA1Dash = 34
38
+ SHA384 = 35
39
+ CustomAlgorithm7 = 36
40
+ CustomAlgorithm8 = 37
41
+ CustomAlgorithm9 = 38
42
+ SHA512Crypt = 39
43
+ CustomAlgorithm10 = 40
44
+ HMACSHA1_SaltAsHash = 41
45
+ AuthMeSHA256 = 42
46
+ SHA256Crypt = 43
47
+
21
48
  Unknown = 97
22
49
  UnusablePassword = 98
23
50
  None = 99
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  # Standard Gem version constant.
3
3
  module Enzoic
4
- VERSION = "1.1.3".freeze
4
+ VERSION = "1.3.0".freeze
5
5
  end
data/lib/enzoic.rb CHANGED
@@ -15,61 +15,72 @@ module Enzoic
15
15
  # to access the Enzoic API.
16
16
  class Enzoic
17
17
  def initialize(options = {})
18
- @apiKey = options[:apiKey] || '';
18
+ @apiKey = options[:apiKey] || ''
19
19
  raise EnzoicFail, "No API key provided" if @apiKey == ''
20
- @secret = options[:secret] || '';
20
+ @secret = options[:secret] || ''
21
21
  raise EnzoicFail, "No Secret provided" if @secret == ''
22
22
  @baseURL = options[:baseURL] || "https://api.enzoic.com/v1"
23
23
  @authString = calc_auth_string(@apiKey, @secret)
24
24
  end
25
25
 
26
- def check_credentials(username, password, lastCheckTimestamp = Date.new(1980, 1, 1))
26
+ def check_credentials(username, password, last_check_timestamp = Date.new(1980, 1, 1))
27
27
  raise EnzoicFail, "API key/Secret not set" if !@authString || @authString == ''
28
28
 
29
- response = make_rest_call(@baseURL + Constants::ACCOUNTS_API_PATH + "?username=" + Hashing.sha256(username), "GET", nil)
29
+ response = make_rest_call(@baseURL + Constants::ACCOUNTS_API_PATH +
30
+ "?username=" + Hashing.sha256(username.downcase),
31
+ "GET", nil)
30
32
 
31
- if (response == "404")
33
+ if response == "404"
32
34
  return false
33
35
  end
34
36
 
35
37
  account_response = JSON.parse(response)
36
38
 
37
39
  # if lastCheckTimestamp was provided, see if we need to go any further
38
- if (Date.parse(account_response["lastBreachDate"]) > lastCheckTimestamp)
40
+ if Date.parse(account_response["lastBreachDate"]) > last_check_timestamp
39
41
  hashes_required = account_response["passwordHashesRequired"]
40
42
 
41
43
  bcrypt_count = 0
42
44
  query_string = ""
45
+ credential_hashes = []
43
46
 
44
- for i in 0..hashes_required.length - 1 do
45
- hash_spec = hashes_required[i]
46
-
47
+ hashes_required.each do |hash_spec|
47
48
  # bcrypt gets far too expensive for good response time if there are many of them to calculate.
48
49
  # some mostly garbage accounts have accumulated a number of them in our DB and if we happen to hit one it
49
50
  # kills performance, so short circuit out after at most 2 BCrypt hashes
50
- if (hash_spec["hashType"] != PasswordType::BCrypt || bcrypt_count <= 2)
51
- if (hash_spec["hashType"] == PasswordType::BCrypt)
51
+ if hash_spec["hashType"] != PasswordType::BCrypt || bcrypt_count <= 2
52
+ if hash_spec["hashType"] == PasswordType::BCrypt
52
53
  bcrypt_count = bcrypt_count + 1
53
54
  end
54
55
 
55
- if (hash_spec["hashType"] != nil)
56
- credential_hash = calc_credential_hash(username, password, account_response["salt"], hash_spec);
56
+ if hash_spec["hashType"] != nil
57
+ credential_hash = calc_credential_hash(username.downcase, password, account_response["salt"], hash_spec)
58
+
59
+ if credential_hash != nil
60
+ credential_hashes << credential_hash
57
61
 
58
- if (credential_hash != nil)
59
- if (query_string.length == 0)
60
- query_string = query_string + "?hashes=" + CGI.escape(credential_hash);
62
+ if query_string.length == 0
63
+ query_string = query_string + "?partialHashes=" + CGI.escape(credential_hash[0..6])
61
64
  else
62
- query_string = query_string + "&hashes=" + CGI.escape(credential_hash);
65
+ query_string = query_string + "&partialHashes=" + CGI.escape(credential_hash[0..6])
63
66
  end
64
67
  end
65
68
  end
66
69
  end
67
70
  end
68
71
 
69
- if (query_string.length > 0)
72
+ if query_string.length > 0
70
73
  creds_response = make_rest_call(
71
- @baseURL + Constants::CREDENTIALS_API_PATH + query_string, "GET", nil)
72
- return creds_response != "404"
74
+ @baseURL + Constants::CREDENTIALS_API_PATH + query_string, "GET", nil)
75
+
76
+ if creds_response != "404"
77
+ creds_result = JSON.parse(creds_response, object_class: OpenStruct)
78
+ creds_result.candidateHashes.each do |candidateHash|
79
+ if credential_hashes.include? candidateHash
80
+ return true
81
+ end
82
+ end
83
+ end
73
84
  end
74
85
  end
75
86
 
@@ -77,21 +88,36 @@ module Enzoic
77
88
  end
78
89
 
79
90
  def check_password(password)
91
+ md5 = Hashing.md5(password)
92
+ sha1 = Hashing.sha1(password)
93
+ sha256 = Hashing.sha256(password)
94
+
80
95
  response = make_rest_call(
81
- @baseURL + Constants::PASSWORDS_API_PATH +
82
- "?md5=" + Hashing.md5(password) +
83
- "&sha1=" + Hashing.sha1(password) +
84
- "&sha256=" + Hashing.sha256(password),
85
- "GET", nil)
96
+ @baseURL + Constants::PASSWORDS_API_PATH, "POST",
97
+ '{' +
98
+ '"partialMD5":"' + md5[0..6] + '",' +
99
+ '"partialSHA1":"' + sha1[0..6] + '",' +
100
+ '"partialSHA256":"' + sha256[0..6] + '"' +
101
+ '}')
86
102
 
87
- return response != "404"
103
+ if response != "404"
104
+ result = JSON.parse(response, object_class: OpenStruct)
105
+
106
+ result.candidates.each do |candidate|
107
+ if candidate.md5 == md5 || candidate.sha1 == sha1 || candidate.sha256 == sha256
108
+ return true
109
+ end
110
+ end
111
+ end
112
+
113
+ return false
88
114
  end
89
115
 
90
116
  def get_exposures_for_user(username)
91
- response = make_rest_call(@baseURL + Constants::EXPOSURES_API_PATH + "?username=" + Hashing.sha256(username),
92
- "GET", nil)
117
+ response = make_rest_call(@baseURL + Constants::EXPOSURES_API_PATH + "?username=" + Hashing.sha256(username.downcase),
118
+ "GET", nil)
93
119
 
94
- if (response == "404")
120
+ if response == "404"
95
121
  # don't have this email in the DB - return empty response
96
122
  return JSON.parse('{ "count": 0, "exposures": [] }', object_class: OpenStruct)
97
123
  else
@@ -102,9 +128,9 @@ module Enzoic
102
128
 
103
129
  def get_exposure_details(exposure_id)
104
130
  response = make_rest_call(@baseURL + Constants::EXPOSURES_API_PATH + "?id=" + CGI.escape(exposure_id),
105
- "GET", nil)
131
+ "GET", nil)
106
132
 
107
- if (response != "404")
133
+ if response != "404"
108
134
  # deserialize response
109
135
  return JSON.parse(response, object_class: OpenStruct)
110
136
  else
@@ -112,82 +138,180 @@ module Enzoic
112
138
  end
113
139
  end
114
140
 
115
- private
116
- def make_rest_call(rest_url, method, body)
117
- begin
118
- response = RestClient::Request.execute(method: method, url: rest_url,
119
- headers: { content_type: :json, accept: :json, authorization: @authString })
120
- return response.body
121
- rescue RestClient::NotFound
122
- return "404"
123
- end
141
+ def get_passwords_for_user(username)
142
+ response = make_rest_call(@baseURL + Constants::ACCOUNTS_API_PATH + "?username=" +
143
+ Hashing.sha256(username.downcase) + "&includePasswords=1",
144
+ "GET", nil)
145
+
146
+ if response == "404"
147
+ # don't have this email in the DB - return empty response
148
+ return JSON.parse('{ "lastBreachDate": null, "passwords": [] }', object_class: OpenStruct)
149
+ else
150
+ # deserialize response
151
+ return JSON.parse(response, object_class: OpenStruct)
124
152
  end
153
+ end
125
154
 
126
- def calc_credential_hash(username, password, salt, hash_spec)
127
- password_hash = calc_password_hash(hash_spec["hashType"], password, hash_spec["salt"])
155
+ private
128
156
 
129
- if (password_hash != nil)
130
- return Hashing.argon2_raw(username + "$" + password_hash, salt)
131
- else
132
- return nil
133
- end
157
+ def make_rest_call(rest_url, method, body)
158
+ begin
159
+ response = RestClient::Request.execute(method: method, url: rest_url,
160
+ payload: body,
161
+ headers: { content_type: :json, accept: :json, authorization: @authString })
162
+ return response.body
163
+ rescue RestClient::NotFound
164
+ return "404"
134
165
  end
166
+ end
135
167
 
136
- def calc_password_hash(password_type, password, salt)
137
- case password_type
138
- when PasswordType::MD5
139
- return Hashing.md5(password)
140
- when PasswordType::SHA1
141
- return Hashing.sha1(password)
142
- when PasswordType::SHA256
143
- return Hashing.sha256(password)
144
- when PasswordType::SHA512
145
- return Hashing.sha512(password)
146
- when PasswordType::IPBoard_MyBB
147
- if (salt != nil && salt.length > 0)
148
- return Hashing.mybb(password, salt)
149
- end
150
- when PasswordType::VBulletinPre3_8_5
151
- if (salt != nil && salt.length > 0)
152
- return Hashing.vbulletin(password, salt)
153
- end
154
- when PasswordType::VBulletinPost3_8_5
155
- if (salt != nil && salt.length > 0)
156
- return Hashing.vbulletin(password, salt)
157
- end
158
- when PasswordType::BCrypt
159
- if (salt != nil && salt.length > 0)
160
- return Hashing.bcrypt(password, salt)
161
- end
162
- when PasswordType::CRC32
163
- return Hashing.crc32(password)
164
- when PasswordType::PHPBB3
165
- if (salt != nil && salt.length > 0)
166
- return Hashing.phpbb3(password, salt)
167
- end
168
- when PasswordType::CustomAlgorithm1
169
- if (salt != nil && salt.length > 0)
170
- return Hashing.custom_algorithm1(password, salt)
171
- end
172
- when PasswordType::CustomAlgorithm2
173
- if (salt != nil && salt.length > 0)
174
- return Hashing.custom_algorithm2(password, salt)
175
- end
176
- when PasswordType::MD5Crypt
177
- if (salt != nil && salt.length > 0)
178
- return Hashing.md5crypt(password, salt)
179
- end
180
- when PasswordType::CustomAlgorithm4
181
- if (salt != nil && salt.length > 0)
182
- return Hashing.custom_algorithm4(password, salt)
183
- end
184
- end
168
+ def calc_credential_hash(username, password, salt, hash_spec)
169
+ password_hash = calc_password_hash(hash_spec["hashType"], password, hash_spec["salt"])
185
170
 
171
+ if password_hash != nil
172
+ return Hashing.argon2_raw(username.downcase + "$" + password_hash, salt)
173
+ else
186
174
  return nil
187
175
  end
176
+ end
188
177
 
189
- def calc_auth_string(apiKey, secret)
190
- return "basic " + Base64.strict_encode64(apiKey + ":" + secret);
178
+ def calc_password_hash(password_type, password, salt)
179
+ case password_type
180
+ when PasswordType::MD5
181
+ return Hashing.md5(password)
182
+ when PasswordType::SHA1
183
+ return Hashing.sha1(password)
184
+ when PasswordType::SHA256
185
+ return Hashing.sha256(password)
186
+ when PasswordType::SHA512
187
+ return Hashing.sha512(password)
188
+ when PasswordType::IPBoard_MyBB
189
+ if salt != nil && salt.length > 0
190
+ return Hashing.mybb(password, salt)
191
+ end
192
+ when PasswordType::VBulletinPre3_8_5
193
+ if salt != nil && salt.length > 0
194
+ return Hashing.vbulletin(password, salt)
195
+ end
196
+ when PasswordType::VBulletinPost3_8_5
197
+ if salt != nil && salt.length > 0
198
+ return Hashing.vbulletin(password, salt)
199
+ end
200
+ when PasswordType::BCrypt
201
+ if salt != nil && salt.length > 0
202
+ return Hashing.bcrypt(password, salt)
203
+ end
204
+ when PasswordType::CRC32
205
+ return Hashing.crc32(password)
206
+ when PasswordType::PHPBB3
207
+ if salt != nil && salt.length > 0
208
+ return Hashing.phpbb3(password, salt)
209
+ end
210
+ when PasswordType::CustomAlgorithm1
211
+ if salt != nil && salt.length > 0
212
+ return Hashing.custom_algorithm1(password, salt)
213
+ end
214
+ when PasswordType::CustomAlgorithm2
215
+ if salt != nil && salt.length > 0
216
+ return Hashing.custom_algorithm2(password, salt)
217
+ end
218
+ when PasswordType::MD5Crypt
219
+ if salt != nil && salt.length > 0
220
+ return Hashing.md5crypt(password, salt)
221
+ end
222
+ when PasswordType::CustomAlgorithm4
223
+ if salt != nil && salt.length > 0
224
+ return Hashing.custom_algorithm4(password, salt)
225
+ end
226
+ when PasswordType::CustomAlgorithm5
227
+ if salt != nil && salt.length > 0
228
+ return Hashing.custom_algorithm5(password, salt)
229
+ end
230
+ when PasswordType::OsCommerce_AEF
231
+ if salt != nil && salt.length > 0
232
+ return Hashing.osCommerce_AEF(password, salt)
233
+ end
234
+ when PasswordType::DESCrypt
235
+ if salt != nil && salt.length > 0
236
+ return Hashing.desCrypt(password, salt)
237
+ end
238
+ when PasswordType::MySQLPre4_1
239
+ return Hashing.mySQLPre4_1(password)
240
+ when PasswordType::MySQLPost4_1
241
+ return Hashing.mySQLPost4_1(password)
242
+ when PasswordType::PunBB
243
+ if salt != nil && salt.length > 0
244
+ return Hashing.punBB(password, salt)
245
+ end
246
+ when PasswordType::CustomAlgorithm6
247
+ if salt != nil && salt.length > 0
248
+ return Hashing.custom_algorithm6(password, salt)
249
+ end
250
+ when PasswordType::PartialMD5_20
251
+ return Hashing.partial_md5_20(password)
252
+ when PasswordType::AVE_DataLife_Diferior
253
+ return Hashing.ave_datalife_diferior(password)
254
+ when PasswordType::DjangoMD5
255
+ if salt != nil && salt.length > 0
256
+ return Hashing.django_md5(password, salt)
257
+ end
258
+ when PasswordType::DjangoSHA1
259
+ if salt != nil && salt.length > 0
260
+ return Hashing.django_sha1(password, salt)
261
+ end
262
+ when PasswordType::PartialMD5_29
263
+ return Hashing.partial_md5_29(password)
264
+ when PasswordType::PliggCMS
265
+ if salt != nil && salt.length > 0
266
+ return Hashing.pligg_cms(password, salt)
267
+ end
268
+ when PasswordType::RunCMS_SMF1_1
269
+ if salt != nil && salt.length > 0
270
+ return Hashing.runcms_smf1_1(password, salt)
271
+ end
272
+ when PasswordType::NTLM
273
+ return Hashing.ntlm(password)
274
+ when PasswordType::SHA1Dash
275
+ if salt != nil && salt.length > 0
276
+ return Hashing.sha1dash(password, salt)
277
+ end
278
+ when PasswordType::SHA384
279
+ return Hashing.sha384(password)
280
+ when PasswordType::CustomAlgorithm7
281
+ if salt != nil && salt.length > 0
282
+ return Hashing.custom_algorithm7(password, salt)
283
+ end
284
+ when PasswordType::CustomAlgorithm9
285
+ if salt != nil && salt.length > 0
286
+ return Hashing.custom_algorithm9(password, salt)
287
+ end
288
+ when PasswordType::SHA512Crypt
289
+ if salt != nil && salt.length > 0
290
+ return Hashing.sha512crypt(password, salt)
291
+ end
292
+ when PasswordType::CustomAlgorithm10
293
+ if salt != nil && salt.length > 0
294
+ return Hashing.custom_algorithm10(password, salt)
295
+ end
296
+ when PasswordType::SHA256Crypt
297
+ if salt != nil && salt.length > 0
298
+ return Hashing.sha256crypt(password, salt)
299
+ end
300
+ when PasswordType::AuthMeSHA256
301
+ if salt != nil && salt.length > 0
302
+ return Hashing.authMeSHA256(password, salt)
303
+ end
304
+ when PasswordType::HMACSHA1_SaltAsHash
305
+ if salt != nil && salt.length > 0
306
+ return Hashing.hmac_sha1_salt_as_hash(password, salt)
307
+ end
308
+ else
309
+ return nil
191
310
  end
311
+ end
312
+
313
+ def calc_auth_string(api_key, secret)
314
+ return "basic " + Base64.strict_encode64(api_key + ":" + secret)
315
+ end
192
316
  end
193
317
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: enzoic
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.3
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Enzoic
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-08-27 00:00:00.000000000 Z
11
+ date: 2023-05-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 1.11.1
19
+ version: 1.15.5
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 1.11.1
26
+ version: 1.15.5
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: ffi-compiler
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -118,20 +118,20 @@ dependencies:
118
118
  requirements:
119
119
  - - "~>"
120
120
  - !ruby/object:Gem::Version
121
- version: 2.0.2
121
+ version: 2.2.11
122
122
  - - ">="
123
123
  - !ruby/object:Gem::Version
124
- version: 2.0.2
124
+ version: 2.2.11
125
125
  type: :development
126
126
  prerelease: false
127
127
  version_requirements: !ruby/object:Gem::Requirement
128
128
  requirements:
129
129
  - - "~>"
130
130
  - !ruby/object:Gem::Version
131
- version: 2.0.2
131
+ version: 2.2.11
132
132
  - - ">="
133
133
  - !ruby/object:Gem::Version
134
- version: 2.0.2
134
+ version: 2.2.11
135
135
  - !ruby/object:Gem::Dependency
136
136
  name: rake
137
137
  requirement: !ruby/object:Gem::Requirement
@@ -307,8 +307,8 @@ files:
307
307
  - ext/phc-winner-argon2/src/genkat.c
308
308
  - ext/phc-winner-argon2/src/genkat.h
309
309
  - ext/phc-winner-argon2/src/opt.c
310
- - ext/phc-winner-argon2/src/opt.o
311
310
  - ext/phc-winner-argon2/src/ref.c
311
+ - ext/phc-winner-argon2/src/ref.o
312
312
  - ext/phc-winner-argon2/src/run.c
313
313
  - ext/phc-winner-argon2/src/test.c
314
314
  - ext/phc-winner-argon2/src/thread.c
@@ -361,8 +361,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
361
361
  - !ruby/object:Gem::Version
362
362
  version: '0'
363
363
  requirements: []
364
- rubyforge_project:
365
- rubygems_version: 2.5.2.3
364
+ rubygems_version: 3.1.6
366
365
  signing_key:
367
366
  specification_version: 4
368
367
  summary: Ruby library for Enzoic API
Binary file