passwordping 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -1
- data/Gemfile +1 -1
- data/Rakefile +17 -0
- data/ext/argon2-wrapper/extconf.rb +1 -1
- data/ext/digest/whirlpool/extconf.rb +10 -0
- data/ext/digest/whirlpool/whirlpool-algorithm.c +476 -0
- data/ext/digest/whirlpool/whirlpool-algorithm.h +86 -0
- data/ext/digest/whirlpool/whirlpool-constants.h +1116 -0
- data/ext/digest/whirlpool/whirlpool-portability.h +142 -0
- data/ext/digest/whirlpool/whirlpool.c +51 -0
- data/lib/digest/whirlpool.bundle +0 -0
- data/lib/passwordping.rb +2 -2
- data/lib/passwordping/hashing.rb +66 -9
- data/lib/passwordping/version.rb +1 -1
- data/passwordping.gemspec +2 -2
- metadata +30 -22
@@ -0,0 +1,142 @@
|
|
1
|
+
/**
|
2
|
+
* The Whirlpool hashing function.
|
3
|
+
*
|
4
|
+
* The Whirlpool algorithm was developed by
|
5
|
+
* Paulo S. L. M. Barreto and Vincent Rijmen.
|
6
|
+
*
|
7
|
+
* See
|
8
|
+
* P.S.L.M. Barreto, V. Rijmen,
|
9
|
+
* ``The Whirlpool hashing function,''
|
10
|
+
* NESSIE submission, 2000 (tweaked version, 2001),
|
11
|
+
* <https://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/whirlpool.zip>
|
12
|
+
*
|
13
|
+
* @version 3.0 (2003.03.12)
|
14
|
+
*
|
15
|
+
* Modified for use in this software package.
|
16
|
+
*/
|
17
|
+
|
18
|
+
#ifndef _WHIRLPOOL_PORTABILITY_H_
|
19
|
+
#define _WHIRLPOOL_PORTABILITY_H_
|
20
|
+
|
21
|
+
/* Definition of minimum-width integer types
|
22
|
+
*
|
23
|
+
* u8 -> unsigned integer type, at least 8 bits, equivalent to unsigned char
|
24
|
+
* u16 -> unsigned integer type, at least 16 bits
|
25
|
+
* u32 -> unsigned integer type, at least 32 bits
|
26
|
+
*
|
27
|
+
* s8, s16, s32 -> signed counterparts of u8, u16, u32
|
28
|
+
*
|
29
|
+
* Always use macro's T8(), T16() or T32() to obtain exact-width results,
|
30
|
+
* i.e., to specify the size of the result of each expression.
|
31
|
+
*/
|
32
|
+
|
33
|
+
typedef signed char s8;
|
34
|
+
typedef unsigned char u8;
|
35
|
+
|
36
|
+
#if UINT_MAX >= 4294967295UL
|
37
|
+
|
38
|
+
typedef signed short s16;
|
39
|
+
typedef signed int s32;
|
40
|
+
typedef unsigned short u16;
|
41
|
+
typedef unsigned int u32;
|
42
|
+
|
43
|
+
#define ONE32 0xffffffffU
|
44
|
+
|
45
|
+
#else
|
46
|
+
|
47
|
+
typedef signed int s16;
|
48
|
+
typedef signed long s32;
|
49
|
+
typedef unsigned int u16;
|
50
|
+
typedef unsigned long u32;
|
51
|
+
|
52
|
+
#define ONE32 0xffffffffUL
|
53
|
+
|
54
|
+
#endif
|
55
|
+
|
56
|
+
#define ONE8 0xffU
|
57
|
+
#define ONE16 0xffffU
|
58
|
+
|
59
|
+
#define T8(x) ((x) & ONE8)
|
60
|
+
#define T16(x) ((x) & ONE16)
|
61
|
+
#define T32(x) ((x) & ONE32)
|
62
|
+
|
63
|
+
#ifdef _MSC_VER
|
64
|
+
typedef unsigned __int64 u64;
|
65
|
+
typedef signed __int64 s64;
|
66
|
+
#define LL(v) (v##i64)
|
67
|
+
#define ONE64 LL(0xffffffffffffffff)
|
68
|
+
#else /* !_MSC_VER */
|
69
|
+
typedef unsigned long long u64;
|
70
|
+
typedef signed long long s64;
|
71
|
+
#define LL(v) (v##ULL)
|
72
|
+
#define ONE64 LL(0xffffffffffffffff)
|
73
|
+
#endif /* ?_MSC_VER */
|
74
|
+
#define T64(x) ((x) & ONE64)
|
75
|
+
#define ROTR64(v, n) (((v) >> (n)) | T64((v) << (64 - (n))))
|
76
|
+
/*
|
77
|
+
* Note: the test is used to detect native 64-bit architectures;
|
78
|
+
* if the unsigned long is strictly greater than 32-bit, it is
|
79
|
+
* assumed to be at least 64-bit. This will not work correctly
|
80
|
+
* on (old) 36-bit architectures (PDP-11 for instance).
|
81
|
+
*
|
82
|
+
* On non-64-bit architectures, "long long" is used.
|
83
|
+
*/
|
84
|
+
|
85
|
+
/*
|
86
|
+
* U8TO32_BIG(c) returns the 32-bit value stored in big-endian convention
|
87
|
+
* in the unsigned char array pointed to by c.
|
88
|
+
*/
|
89
|
+
#define U8TO32_BIG(c) (((u32)T8(*(c)) << 24) | ((u32)T8(*((c) + 1)) << 16) | ((u32)T8(*((c) + 2)) << 8) | ((u32)T8(*((c) + 3))))
|
90
|
+
|
91
|
+
/*
|
92
|
+
* U8TO32_LITTLE(c) returns the 32-bit value stored in little-endian convention
|
93
|
+
* in the unsigned char array pointed to by c.
|
94
|
+
*/
|
95
|
+
#define U8TO32_LITTLE(c) (((u32)T8(*(c))) | ((u32)T8(*((c) + 1)) << 8) | (u32)T8(*((c) + 2)) << 16) | ((u32)T8(*((c) + 3)) << 24))
|
96
|
+
|
97
|
+
/*
|
98
|
+
* U8TO32_BIG(c, v) stores the 32-bit-value v in big-endian convention
|
99
|
+
* into the unsigned char array pointed to by c.
|
100
|
+
*/
|
101
|
+
#define U32TO8_BIG(c, v) do { u32 x = (v); u8 *d = (c); d[0] = T8(x >> 24); d[1] = T8(x >> 16); d[2] = T8(x >> 8); d[3] = T8(x); } while (0)
|
102
|
+
|
103
|
+
/*
|
104
|
+
* U8TO32_LITTLE(c, v) stores the 32-bit-value v in little-endian convention
|
105
|
+
* into the unsigned char array pointed to by c.
|
106
|
+
*/
|
107
|
+
#define U32TO8_LITTLE(c, v) do { u32 x = (v); u8 *d = (c); d[0] = T8(x); d[1] = T8(x >> 8); d[2] = T8(x >> 16); d[3] = T8(x >> 24); } while (0)
|
108
|
+
|
109
|
+
/*
|
110
|
+
* ROTL32(v, n) returns the value of the 32-bit unsigned value v after
|
111
|
+
* a rotation of n bits to the left. It might be replaced by the appropriate
|
112
|
+
* architecture-specific macro.
|
113
|
+
*
|
114
|
+
* It evaluates v and n twice.
|
115
|
+
*
|
116
|
+
* The compiler might emit a warning if n is the constant 0. The result
|
117
|
+
* is undefined if n is greater than 31.
|
118
|
+
*/
|
119
|
+
#define ROTL32(v, n) (T32((v) << (n)) | ((v) >> (32 - (n))))
|
120
|
+
|
121
|
+
/*
|
122
|
+
* Whirlpool-specific definitions.
|
123
|
+
*/
|
124
|
+
|
125
|
+
#define DIGESTBYTES WP_DIGEST_SIZE
|
126
|
+
#define DIGESTBITS (8*DIGESTBYTES) /* 512 */
|
127
|
+
|
128
|
+
#define WBLOCKBYTES 64
|
129
|
+
#define WBLOCKBITS (8*WBLOCKBYTES) /* 512 */
|
130
|
+
|
131
|
+
#define LENGTHBYTES 32
|
132
|
+
#define LENGTHBITS (8*LENGTHBYTES) /* 256 */
|
133
|
+
|
134
|
+
struct WP_Struct {
|
135
|
+
u8 bitLength[LENGTHBYTES]; /* global number of hashed bits (256-bit counter) */
|
136
|
+
u8 buffer[WBLOCKBYTES]; /* buffer of data to hash */
|
137
|
+
int bufferBits; /* current number of bits on the buffer */
|
138
|
+
int bufferPos; /* current (possibly incomplete) byte slot on the buffer */
|
139
|
+
u64 hash[DIGESTBYTES/8]; /* the hashing state */
|
140
|
+
};
|
141
|
+
|
142
|
+
#endif
|
@@ -0,0 +1,51 @@
|
|
1
|
+
/************************************************
|
2
|
+
|
3
|
+
whirlpool.c - provides Digest::Whirlpool class
|
4
|
+
|
5
|
+
Copyright (C) 2006-2013 Akinori MUSHA
|
6
|
+
|
7
|
+
************************************************/
|
8
|
+
|
9
|
+
#ifdef HAVE_RUBY_DIGEST_H
|
10
|
+
#include "ruby/digest.h"
|
11
|
+
#else
|
12
|
+
#include "digest.h"
|
13
|
+
#endif
|
14
|
+
#include "whirlpool-algorithm.h"
|
15
|
+
#include "whirlpool-portability.h"
|
16
|
+
|
17
|
+
static void WP_Update(WP_Struct * const, const unsigned char * const, size_t);
|
18
|
+
|
19
|
+
static rb_digest_metadata_t whirlpool = {
|
20
|
+
RUBY_DIGEST_API_VERSION,
|
21
|
+
WP_DIGEST_SIZE,
|
22
|
+
WBLOCKBYTES,
|
23
|
+
sizeof(WP_Struct),
|
24
|
+
(rb_digest_hash_init_func_t)WP_Init,
|
25
|
+
(rb_digest_hash_update_func_t)WP_Update,
|
26
|
+
(rb_digest_hash_finish_func_t)WP_Finalize,
|
27
|
+
};
|
28
|
+
|
29
|
+
static void
|
30
|
+
WP_Update(WP_Struct * const wp, const unsigned char * const data, size_t len)
|
31
|
+
{
|
32
|
+
WP_Add(data, len * 8, wp);
|
33
|
+
}
|
34
|
+
|
35
|
+
void
|
36
|
+
Init_whirlpool()
|
37
|
+
{
|
38
|
+
VALUE mDigest, cDigest_Base, cDigest_Whirlpool;
|
39
|
+
|
40
|
+
rb_require("digest");
|
41
|
+
|
42
|
+
mDigest = rb_path2class("Digest");
|
43
|
+
cDigest_Base = rb_path2class("Digest::Base");
|
44
|
+
|
45
|
+
cDigest_Whirlpool = rb_define_class_under(mDigest, "Whirlpool", cDigest_Base);
|
46
|
+
|
47
|
+
// rb_ivar_set(cDigest_Whirlpool, rb_intern("metadata"),
|
48
|
+
// Data_Wrap_Struct(rb_cObject, 0, 0, &whirlpool));
|
49
|
+
rb_ivar_set(cDigest_Whirlpool, rb_intern("metadata"),
|
50
|
+
Data_Wrap_Struct(0, 0, 0, (void *)&whirlpool));
|
51
|
+
}
|
Binary file
|
data/lib/passwordping.rb
CHANGED
@@ -26,7 +26,7 @@ module PasswordPing
|
|
26
26
|
def check_credentials(username, password)
|
27
27
|
raise PasswordPingFail, "API key/Secret not set" if !@authString || @authString == ''
|
28
28
|
|
29
|
-
response = make_rest_call(@baseURL + Constants::ACCOUNTS_API_PATH + "?username=" +
|
29
|
+
response = make_rest_call(@baseURL + Constants::ACCOUNTS_API_PATH + "?username=" + Hashing.sha256(username), "GET", nil)
|
30
30
|
|
31
31
|
if (response == "404")
|
32
32
|
return false
|
@@ -84,7 +84,7 @@ module PasswordPing
|
|
84
84
|
end
|
85
85
|
|
86
86
|
def get_exposures_for_user(username)
|
87
|
-
response = make_rest_call(@baseURL + Constants::EXPOSURES_API_PATH + "?username=" +
|
87
|
+
response = make_rest_call(@baseURL + Constants::EXPOSURES_API_PATH + "?username=" + Hashing.sha256(username),
|
88
88
|
"GET", nil)
|
89
89
|
|
90
90
|
if (response == "404")
|
data/lib/passwordping/hashing.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
require 'passwordping/argon2_wrapper_ffi'
|
2
2
|
require 'digest'
|
3
|
-
require 'cryptopp'
|
4
3
|
require 'bcrypt'
|
5
4
|
require 'unix_crypt'
|
5
|
+
require 'zlib'
|
6
|
+
require 'digest/whirlpool'
|
7
|
+
require 'base64'
|
6
8
|
|
7
9
|
module PasswordPing
|
8
10
|
class Hashing
|
@@ -39,21 +41,19 @@ module PasswordPing
|
|
39
41
|
end
|
40
42
|
|
41
43
|
def self.whirlpool(to_hash)
|
42
|
-
return
|
44
|
+
return Digest::Whirlpool.hexdigest(to_hash)
|
43
45
|
end
|
44
46
|
|
45
47
|
def self.whirlpool_binary(to_hash)
|
46
|
-
return
|
48
|
+
return Digest::Whirlpool.digest(to_hash)
|
47
49
|
end
|
48
50
|
|
49
51
|
def self.whirlpool_binary_array(to_hash)
|
50
|
-
return
|
52
|
+
return Digest::Whirlpool.digest(to_hash).bytes
|
51
53
|
end
|
52
54
|
|
53
55
|
def self.crc32(to_hash)
|
54
|
-
|
55
|
-
# correct for endian-ness
|
56
|
-
return hash[6] + hash[7] + hash[4] + hash[5] + hash[2] + hash[3] + hash[0] + hash[1]
|
56
|
+
return Zlib.crc32(to_hash, 0).to_s(16)
|
57
57
|
end
|
58
58
|
|
59
59
|
def self.mybb(to_hash, salt)
|
@@ -65,7 +65,23 @@ module PasswordPing
|
|
65
65
|
end
|
66
66
|
|
67
67
|
def self.bcrypt(to_hash, salt)
|
68
|
-
|
68
|
+
# if salt starts with $2y$, first replace with $2a$
|
69
|
+
if salt[0..3] == "$2y$"
|
70
|
+
y_variant = true
|
71
|
+
checked_salt = "$2a$" + salt[4..-1]
|
72
|
+
else
|
73
|
+
y_variant = false
|
74
|
+
checked_salt = salt
|
75
|
+
end
|
76
|
+
|
77
|
+
result = BCrypt::Engine.hash_secret(to_hash, checked_salt)
|
78
|
+
|
79
|
+
if y_variant
|
80
|
+
# replace with $2y$
|
81
|
+
result = "$2y$" + result[4..-1]
|
82
|
+
end
|
83
|
+
|
84
|
+
return result
|
69
85
|
end
|
70
86
|
|
71
87
|
def self.phpbb3(to_hash, salt)
|
@@ -135,8 +151,49 @@ module PasswordPing
|
|
135
151
|
return UnixCrypt::MD5.build(to_hash, salt.start_with?("$1$") ? salt[3..salt.length] : salt);
|
136
152
|
end
|
137
153
|
|
154
|
+
def self.custom_algorithm4(to_hash, salt)
|
155
|
+
return self.bcrypt(self.md5(to_hash), salt)
|
156
|
+
end
|
157
|
+
|
138
158
|
def self.argon2(to_hash, salt)
|
139
|
-
|
159
|
+
time_cost = 3
|
160
|
+
mem_cost = 10
|
161
|
+
threads = 2
|
162
|
+
hash_length = 20
|
163
|
+
just_salt = salt
|
164
|
+
|
165
|
+
#$argon2i$v=19$m=65536,t=2,p=4$c29tZXNhbHQ$RdescudvJCsgt3ub+b+dWRWJTmaaJObG
|
166
|
+
if (salt[0..6] == "$argon2")
|
167
|
+
# looks like we specified algo info for argon2 in the salt
|
168
|
+
salt_values = salt.split("$")
|
169
|
+
just_salt = Base64.decode64(salt_values[4])
|
170
|
+
cost_params = salt_values[3].split(",")
|
171
|
+
|
172
|
+
for param in cost_params
|
173
|
+
begin
|
174
|
+
param_parts = param.split("=")
|
175
|
+
if (param_parts[0] == "t")
|
176
|
+
time_cost = Integer(param_parts[1])
|
177
|
+
elsif (param_parts[0] == "m")
|
178
|
+
mem_cost = Math.log2(Integer(param_parts[1])).round
|
179
|
+
elsif (param_parts[0] == "p")
|
180
|
+
threads = Integer(param_parts[1])
|
181
|
+
elsif (param_parts[0] == "l")
|
182
|
+
hash_length = Integer(param_parts[1])
|
183
|
+
end
|
184
|
+
rescue ArgumentError
|
185
|
+
# ignore invalid params and just use default
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
if (salt_values[1] == "argon2i")
|
190
|
+
return Argon2Wrapper.hash_argon2i_encode(to_hash, just_salt, time_cost, mem_cost, threads, hash_length)
|
191
|
+
else
|
192
|
+
return Argon2Wrapper.hash_argon2d_encode(to_hash, just_salt, time_cost, mem_cost, threads, hash_length)
|
193
|
+
end
|
194
|
+
else
|
195
|
+
return Argon2Wrapper.hash_argon2d_encode(to_hash, just_salt, time_cost, mem_cost, threads, hash_length)
|
196
|
+
end
|
140
197
|
end
|
141
198
|
|
142
199
|
def self.xor(byte_array1, byte_array2)
|
data/lib/passwordping/version.rb
CHANGED
data/passwordping.gemspec
CHANGED
@@ -23,12 +23,12 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.add_dependency 'ffi', '~> 1.9'
|
24
24
|
spec.add_dependency 'ffi-compiler', '~> 0.1'
|
25
25
|
spec.add_dependency 'rest-client', '~> 2.0', '>= 2.0.2'
|
26
|
-
spec.add_dependency 'cryptopp', '~> 0.0', '>= 0.0.5'
|
27
26
|
spec.add_dependency 'bcrypt', '~> 3.1', '>= 3.1.11'
|
28
27
|
spec.add_dependency 'unix-crypt', '~> 1.3'
|
29
28
|
|
30
29
|
spec.add_development_dependency "bundler", '~> 1.10', '>= 1.10.5'
|
31
30
|
spec.add_development_dependency "rake", '~> 10.4', '>= 10.4.2'
|
32
31
|
spec.add_development_dependency "test-unit", '~> 3.2', '>= 3.2.4'
|
33
|
-
spec.
|
32
|
+
spec.add_development_dependency "rake-compiler", '~> 1.0', '>= 1.0.4'
|
33
|
+
spec.extensions = ['ext/argon2-wrapper/extconf.rb', "ext/digest/whirlpool/extconf.rb" ]
|
34
34
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: passwordping
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- PasswordPing
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-06-
|
11
|
+
date: 2017-06-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ffi
|
@@ -58,26 +58,6 @@ dependencies:
|
|
58
58
|
- - ">="
|
59
59
|
- !ruby/object:Gem::Version
|
60
60
|
version: 2.0.2
|
61
|
-
- !ruby/object:Gem::Dependency
|
62
|
-
name: cryptopp
|
63
|
-
requirement: !ruby/object:Gem::Requirement
|
64
|
-
requirements:
|
65
|
-
- - "~>"
|
66
|
-
- !ruby/object:Gem::Version
|
67
|
-
version: '0.0'
|
68
|
-
- - ">="
|
69
|
-
- !ruby/object:Gem::Version
|
70
|
-
version: 0.0.5
|
71
|
-
type: :runtime
|
72
|
-
prerelease: false
|
73
|
-
version_requirements: !ruby/object:Gem::Requirement
|
74
|
-
requirements:
|
75
|
-
- - "~>"
|
76
|
-
- !ruby/object:Gem::Version
|
77
|
-
version: '0.0'
|
78
|
-
- - ">="
|
79
|
-
- !ruby/object:Gem::Version
|
80
|
-
version: 0.0.5
|
81
61
|
- !ruby/object:Gem::Dependency
|
82
62
|
name: bcrypt
|
83
63
|
requirement: !ruby/object:Gem::Requirement
|
@@ -172,12 +152,33 @@ dependencies:
|
|
172
152
|
- - ">="
|
173
153
|
- !ruby/object:Gem::Version
|
174
154
|
version: 3.2.4
|
155
|
+
- !ruby/object:Gem::Dependency
|
156
|
+
name: rake-compiler
|
157
|
+
requirement: !ruby/object:Gem::Requirement
|
158
|
+
requirements:
|
159
|
+
- - "~>"
|
160
|
+
- !ruby/object:Gem::Version
|
161
|
+
version: '1.0'
|
162
|
+
- - ">="
|
163
|
+
- !ruby/object:Gem::Version
|
164
|
+
version: 1.0.4
|
165
|
+
type: :development
|
166
|
+
prerelease: false
|
167
|
+
version_requirements: !ruby/object:Gem::Requirement
|
168
|
+
requirements:
|
169
|
+
- - "~>"
|
170
|
+
- !ruby/object:Gem::Version
|
171
|
+
version: '1.0'
|
172
|
+
- - ">="
|
173
|
+
- !ruby/object:Gem::Version
|
174
|
+
version: 1.0.4
|
175
175
|
description: Ruby library for PasswordPing API
|
176
176
|
email:
|
177
177
|
- support@passwordping.com
|
178
178
|
executables: []
|
179
179
|
extensions:
|
180
180
|
- ext/argon2-wrapper/extconf.rb
|
181
|
+
- ext/digest/whirlpool/extconf.rb
|
181
182
|
extra_rdoc_files: []
|
182
183
|
files:
|
183
184
|
- ".gitignore"
|
@@ -191,6 +192,12 @@ files:
|
|
191
192
|
- ext/argon2-wrapper/libargon2-wrapper.bundle
|
192
193
|
- ext/argon2-wrapper/libargon2-wrapper.bundle.dSYM/Contents/Info.plist
|
193
194
|
- ext/argon2-wrapper/libargon2-wrapper.bundle.dSYM/Contents/Resources/DWARF/libargon2-wrapper.bundle
|
195
|
+
- ext/digest/whirlpool/extconf.rb
|
196
|
+
- ext/digest/whirlpool/whirlpool-algorithm.c
|
197
|
+
- ext/digest/whirlpool/whirlpool-algorithm.h
|
198
|
+
- ext/digest/whirlpool/whirlpool-constants.h
|
199
|
+
- ext/digest/whirlpool/whirlpool-portability.h
|
200
|
+
- ext/digest/whirlpool/whirlpool.c
|
194
201
|
- ext/phc-winner-argon2/.git
|
195
202
|
- ext/phc-winner-argon2/.gitattributes
|
196
203
|
- ext/phc-winner-argon2/.gitignore
|
@@ -269,6 +276,7 @@ files:
|
|
269
276
|
- ext/phc-winner-argon2/vs2015/Argon2RefGenKAT/Argon2RefGenKAT.vcxproj.filters
|
270
277
|
- ext/phc-winner-argon2/vs2015/Argon2RefTestCI/Argon2RefTestCI.vcxproj
|
271
278
|
- ext/phc-winner-argon2/vs2015/Argon2RefTestCI/Argon2RefTestCI.vcxproj.filters
|
279
|
+
- lib/digest/whirlpool.bundle
|
272
280
|
- lib/passwordping.rb
|
273
281
|
- lib/passwordping/argon2_wrapper_ffi.rb
|
274
282
|
- lib/passwordping/constants.rb
|