argon2id 0.5.0-x64-mingw-ucrt → 0.7.0-x64-mingw-ucrt
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 +4 -4
- data/CHANGELOG.md +20 -0
- data/README.md +35 -8
- data/Rakefile +11 -16
- data/argon2id.gemspec +3 -3
- data/ext/argon2id/argon2id.c +13 -24
- data/ext/argon2id/extconf.rb +1 -1
- data/lib/{3.1 → argon2id/3.1}/argon2id.so +0 -0
- data/lib/{3.2 → argon2id/3.2}/argon2id.so +0 -0
- data/lib/{3.3 → argon2id/3.3}/argon2id.so +0 -0
- data/lib/argon2id/extension.rb +70 -0
- data/lib/argon2id/password.rb +9 -2
- data/lib/argon2id/version.rb +1 -1
- data/lib/argon2id.rb +2 -65
- data/test/argon2id/test_password.rb +548 -0
- data/test/test_argon2id.rb +66 -0
- metadata +8 -8
- data/test/test_hash_encoded.rb +0 -54
- data/test/test_password.rb +0 -172
- data/test/test_verify.rb +0 -35
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fe40a011ddccdbc2ebb6856704b5442180f2414b5ee3101a7953715f891ba0f3
|
4
|
+
data.tar.gz: fe8532d266ac9245174d3de13513c70e957cb1c11f5ceab196a269e8338f4031
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1554613d298bedebea3eb86a059be6bd3210cbd9c13fccdfc156d7d874ffeecaaf82f5f8c2e515001684557884c8bfa77d28feb43573de51132e0555bf52b705
|
7
|
+
data.tar.gz: e0bf4231265949e306f9486e45e46975c86107655743cc1c1965b17daa6d146a36bc2701f57af6dbb07a1e6787de6920d2123cd19f3e1457c530d93765c32488
|
data/CHANGELOG.md
CHANGED
@@ -5,6 +5,24 @@ All notable changes to this project will be documented in this file.
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
7
|
|
8
|
+
## [0.7.0] - 2024-11-08
|
9
|
+
|
10
|
+
### Fixed
|
11
|
+
|
12
|
+
- Fixed verifying Argon2id encoded hashes without a version number on JRuby
|
13
|
+
|
14
|
+
### Added
|
15
|
+
|
16
|
+
- Added a new `Argon2id::Password.valid_hash?` API for testing if a given
|
17
|
+
encoded hash is a valid Argon2id hash or not (e.g. if you want to check
|
18
|
+
which hashing function was used to store a user's password)
|
19
|
+
|
20
|
+
## [0.6.0] - 2024-11-05
|
21
|
+
|
22
|
+
### Changed
|
23
|
+
|
24
|
+
- Move the internal API to `Argon2id::Password` and make it explicitly private
|
25
|
+
|
8
26
|
## [0.5.0] - 2024-11-02
|
9
27
|
|
10
28
|
### Removed
|
@@ -93,6 +111,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
93
111
|
reference C implementation of Argon2, the password-hashing function that won
|
94
112
|
the Password Hashing Competition.
|
95
113
|
|
114
|
+
[0.7.0]: https://github.com/mudge/argon2id/releases/tag/v0.7.0
|
115
|
+
[0.6.0]: https://github.com/mudge/argon2id/releases/tag/v0.6.0
|
96
116
|
[0.5.0]: https://github.com/mudge/argon2id/releases/tag/v0.5.0
|
97
117
|
[0.4.1]: https://github.com/mudge/argon2id/releases/tag/v0.4.1
|
98
118
|
[0.4.0]: https://github.com/mudge/argon2id/releases/tag/v0.4.0
|
data/README.md
CHANGED
@@ -5,7 +5,7 @@ Ruby bindings to [Argon2][], the password-hashing function that won the 2015
|
|
5
5
|
|
6
6
|
[](https://github.com/mudge/argon2id/actions)
|
7
7
|
|
8
|
-
**Current version:** 0.
|
8
|
+
**Current version:** 0.7.0
|
9
9
|
**Bundled Argon2 version:** libargon2.1 (20190702)
|
10
10
|
|
11
11
|
```ruby
|
@@ -26,6 +26,7 @@ password.salt #=> "e-\xA7\x04U\x81\xA6{v\xF0x\xED\xCC\xD3\x96\xE3"
|
|
26
26
|
* [Usage](#usage)
|
27
27
|
* [Hashing passwords](#hashing-passwords)
|
28
28
|
* [Verifying passwords](#verifying-passwords)
|
29
|
+
* [Validating encoded hashes](#validating-encoded-hashes)
|
29
30
|
* [Errors](#errors)
|
30
31
|
* [Requirements](#requirements)
|
31
32
|
* [Native gems](#native-gems)
|
@@ -55,6 +56,8 @@ password.salt #=> "e-\xA7\x04U\x81\xA6{v\xF0x\xED\xCC\xD3\x96\xE3"
|
|
55
56
|
|
56
57
|
— [OWASP Password Storage Cheat Sheet][]
|
57
58
|
|
59
|
+
See also [argon2-cffi's "Why 'just use bcrypt' Is Not the Best Answer (Anymore)"](https://argon2-cffi.readthedocs.io/en/23.1.0/argon2.html#why-just-use-bcrypt-is-not-the-best-answer-anymore).
|
60
|
+
|
58
61
|
## Usage
|
59
62
|
|
60
63
|
Install argon2id as a dependency:
|
@@ -147,6 +150,18 @@ password.is_password?("opensesame") #=> true
|
|
147
150
|
password.is_password?("notopensesame") #=> false
|
148
151
|
```
|
149
152
|
|
153
|
+
> [!CAUTION]
|
154
|
+
> `Argon2id::Password#==` only works if the plain text password is on the right, e.g. the following behaviour may be surprising:
|
155
|
+
>
|
156
|
+
> ```ruby
|
157
|
+
> password = Argon2id::Password.create("password")
|
158
|
+
> password == "password" #=> true
|
159
|
+
> "password" == password #=> false
|
160
|
+
> password == password #=> false
|
161
|
+
> ```
|
162
|
+
>
|
163
|
+
> If you want to avoid this ambiguity, prefer the `Argon2id::Password#is_password?` alias instead.
|
164
|
+
|
150
165
|
The various parts of the encoded hash can be retrieved:
|
151
166
|
|
152
167
|
```ruby
|
@@ -160,6 +175,18 @@ password.output
|
|
160
175
|
#=> "\x9D\xFE\xB9\x10\xE8\v\xAD\x03\x11\xFE\xE2\x0F\x9C\x0E+\x12\xC1y\x87\xB4\xCA\xC9\f.\xF5M[0!\xC6\x8B\xFE"
|
161
176
|
```
|
162
177
|
|
178
|
+
### Validating encoded hashes
|
179
|
+
|
180
|
+
If you need to check ahead of time whether an encoded password hash is a valid Argon2id hash (e.g. if you're migrating between hashing functions and need to test what kind of password has been stored for a user), you can use `Argon2id::Password.valid_hash?` like so:
|
181
|
+
|
182
|
+
```ruby
|
183
|
+
Argon2id::Password.valid_hash?("$argon2id$v=19$m=65536,t=2,p=1$c29tZXNhbHQ$CTFhFdXPJO1aFaMaO6Mm5c8y7cJHAph8ArZWb2GRPPc")
|
184
|
+
#=> true
|
185
|
+
|
186
|
+
Argon2id::Password.valid_hash?("$2a$12$stsRn7Mi9r02.keRyF4OK.Aq4UWOU185lWggfUQfcupAi.b7AI/nS")
|
187
|
+
#=> false
|
188
|
+
```
|
189
|
+
|
163
190
|
### Errors
|
164
191
|
|
165
192
|
Any errors returned from Argon2 will be raised as `Argon2id::Error`, e.g.
|
@@ -201,11 +228,11 @@ notes](https://github.com/mudge/argon2id/releases) for each version and can be
|
|
201
228
|
checked with `sha256sum`, e.g.
|
202
229
|
|
203
230
|
```console
|
204
|
-
$ gem fetch argon2id -v 0.
|
205
|
-
Fetching argon2id-0.
|
206
|
-
Downloaded argon2id-0.
|
207
|
-
$ sha256sum argon2id-0.
|
208
|
-
|
231
|
+
$ gem fetch argon2id -v 0.6.0
|
232
|
+
Fetching argon2id-0.6.0-arm64-darwin.gem
|
233
|
+
Downloaded argon2id-0.6.0-arm64-darwin
|
234
|
+
$ sha256sum argon2id-0.6.0-arm64-darwin.gem
|
235
|
+
18f1f04be4b5e7badb4d491762e57874febeeb46c64ce1b0a5e3a75b39b5baeb argon2id-0.6.0-arm64-darwin.gem
|
209
236
|
```
|
210
237
|
|
211
238
|
[GPG](https://www.gnupg.org/) signatures are attached to each release (the
|
@@ -215,8 +242,8 @@ from a public keyserver, e.g. `gpg --keyserver keyserver.ubuntu.com --recv-key
|
|
215
242
|
0x39AC3530070E0F75`):
|
216
243
|
|
217
244
|
```console
|
218
|
-
$ gpg --verify argon2id-0.
|
219
|
-
gpg: Signature made
|
245
|
+
$ gpg --verify argon2id-0.6.0-arm64-darwin.gem.sig argon2id-0.6.0-arm64-darwin.gem
|
246
|
+
gpg: Signature made Tue 5 Nov 11:30:47 2024 GMT
|
220
247
|
gpg: using RSA key 702609D9C790F45B577D7BEC39AC3530070E0F75
|
221
248
|
gpg: Good signature from "Paul Mucur <mudge@mudge.name>" [unknown]
|
222
249
|
gpg: aka "Paul Mucur <paul@ghostcassette.com>" [unknown]
|
data/Rakefile
CHANGED
@@ -20,16 +20,20 @@ ENV["RUBY_CC_VERSION"] = %w[3.3.0 3.2.0 3.1.0 3.0.0 2.7.0 2.6.0].join(":")
|
|
20
20
|
|
21
21
|
gemspec = Gem::Specification.load("argon2id.gemspec")
|
22
22
|
|
23
|
-
if RUBY_PLATFORM == "java"
|
24
|
-
gemspec.files.reject! { |path| File.fnmatch?("ext/*", path) }
|
25
|
-
gemspec.extensions.clear
|
26
|
-
gemspec.platform = Gem::Platform.new("java")
|
27
|
-
gemspec.required_ruby_version = ">= 3.1.0"
|
28
|
-
end
|
29
|
-
|
30
23
|
Gem::PackageTask.new(gemspec).define
|
31
24
|
|
25
|
+
namespace :java do
|
26
|
+
java_gemspec = gemspec.dup
|
27
|
+
java_gemspec.files.reject! { |path| File.fnmatch?("ext/*", path) }
|
28
|
+
java_gemspec.extensions.clear
|
29
|
+
java_gemspec.platform = Gem::Platform.new("java")
|
30
|
+
java_gemspec.required_ruby_version = ">= 3.1.0"
|
31
|
+
|
32
|
+
Gem::PackageTask.new(java_gemspec).define
|
33
|
+
end
|
34
|
+
|
32
35
|
Rake::ExtensionTask.new("argon2id", gemspec) do |e|
|
36
|
+
e.lib_dir = "lib/argon2id"
|
33
37
|
e.cross_compile = true
|
34
38
|
e.cross_platform = cross_platforms
|
35
39
|
end
|
@@ -57,15 +61,6 @@ namespace :gem do
|
|
57
61
|
SCRIPT
|
58
62
|
end
|
59
63
|
end
|
60
|
-
|
61
|
-
desc "Compile gem for JRuby"
|
62
|
-
task :jruby do
|
63
|
-
RakeCompilerDock.sh <<~SCRIPT, rubyvm: "jruby", platform: "jruby", verbose: true
|
64
|
-
gem install bundler --no-document &&
|
65
|
-
bundle &&
|
66
|
-
bundle exec rake gem
|
67
|
-
SCRIPT
|
68
|
-
end
|
69
64
|
end
|
70
65
|
|
71
66
|
task default: [:compile, :test]
|
data/argon2id.gemspec
CHANGED
@@ -45,11 +45,11 @@ Gem::Specification.new do |s|
|
|
45
45
|
"ext/argon2id/libargon2/thread.c",
|
46
46
|
"ext/argon2id/libargon2/thread.h",
|
47
47
|
"lib/argon2id.rb",
|
48
|
+
"lib/argon2id/extension.rb",
|
48
49
|
"lib/argon2id/password.rb",
|
49
50
|
"lib/argon2id/version.rb",
|
50
|
-
"test/
|
51
|
-
"test/
|
52
|
-
"test/test_verify.rb"
|
51
|
+
"test/argon2id/test_password.rb",
|
52
|
+
"test/test_argon2id.rb"
|
53
53
|
]
|
54
54
|
s.rdoc_options = ["--main", "README.md"]
|
55
55
|
|
data/ext/argon2id/argon2id.c
CHANGED
@@ -5,21 +5,11 @@
|
|
5
5
|
|
6
6
|
#define UNUSED(x) (void)(x)
|
7
7
|
|
8
|
-
VALUE mArgon2id, cArgon2idError;
|
9
|
-
|
10
|
-
|
11
|
-
*
|
12
|
-
* Hashes a password with Argon2id, producing an encoded hash.
|
13
|
-
*
|
14
|
-
* - +t_cost+: number of iterations
|
15
|
-
* - +m_cost+: sets memory usage to +m_cost+ kibibytes
|
16
|
-
* - +parallelism+: number of threads and compute lanes
|
17
|
-
* - +pwd+: the password
|
18
|
-
* - +salt+: the salt
|
19
|
-
* - +output_len+: desired length of the hash in bytes
|
20
|
-
*/
|
8
|
+
VALUE mArgon2id, cArgon2idError, cArgon2idPassword;
|
9
|
+
ID id_encoded;
|
10
|
+
|
21
11
|
static VALUE
|
22
|
-
rb_argon2id_hash_encoded(VALUE
|
12
|
+
rb_argon2id_hash_encoded(VALUE klass, VALUE iterations, VALUE memory, VALUE threads, VALUE pwd, VALUE salt, VALUE hashlen)
|
23
13
|
{
|
24
14
|
uint32_t t_cost, m_cost, parallelism;
|
25
15
|
size_t encodedlen, outlen;
|
@@ -27,7 +17,7 @@ rb_argon2id_hash_encoded(VALUE module, VALUE iterations, VALUE memory, VALUE thr
|
|
27
17
|
int result;
|
28
18
|
VALUE hash;
|
29
19
|
|
30
|
-
UNUSED(
|
20
|
+
UNUSED(klass);
|
31
21
|
|
32
22
|
t_cost = FIX2INT(iterations);
|
33
23
|
m_cost = FIX2INT(memory);
|
@@ -53,16 +43,12 @@ rb_argon2id_hash_encoded(VALUE module, VALUE iterations, VALUE memory, VALUE thr
|
|
53
43
|
return hash;
|
54
44
|
}
|
55
45
|
|
56
|
-
/* call-seq: verify(encoded, pwd)
|
57
|
-
*
|
58
|
-
* Verifies a password against an encoded string.
|
59
|
-
*/
|
60
46
|
static VALUE
|
61
|
-
rb_argon2id_verify(VALUE
|
47
|
+
rb_argon2id_verify(VALUE self, VALUE pwd) {
|
62
48
|
int result;
|
49
|
+
VALUE encoded;
|
63
50
|
|
64
|
-
|
65
|
-
|
51
|
+
encoded = rb_ivar_get(self, id_encoded);
|
66
52
|
result = argon2id_verify(StringValueCStr(encoded), StringValuePtr(pwd), RSTRING_LEN(pwd));
|
67
53
|
if (result == ARGON2_OK) {
|
68
54
|
return Qtrue;
|
@@ -80,8 +66,11 @@ rb_argon2id_verify(VALUE module, VALUE encoded, VALUE pwd) {
|
|
80
66
|
void
|
81
67
|
Init_argon2id(void)
|
82
68
|
{
|
69
|
+
id_encoded = rb_intern("@encoded");
|
70
|
+
|
83
71
|
mArgon2id = rb_define_module("Argon2id");
|
84
72
|
cArgon2idError = rb_define_class_under(mArgon2id, "Error", rb_eStandardError);
|
85
|
-
|
86
|
-
|
73
|
+
cArgon2idPassword = rb_define_class_under(mArgon2id, "Password", rb_cObject);
|
74
|
+
rb_define_private_method(rb_singleton_class(cArgon2idPassword), "hash_encoded", rb_argon2id_hash_encoded, 6);
|
75
|
+
rb_define_private_method(cArgon2idPassword, "verify", rb_argon2id_verify, 1);
|
87
76
|
}
|
data/ext/argon2id/extconf.rb
CHANGED
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
if RUBY_PLATFORM == "java"
|
4
|
+
require "java"
|
5
|
+
require "openssl"
|
6
|
+
|
7
|
+
module Argon2id
|
8
|
+
Error = Class.new(StandardError)
|
9
|
+
|
10
|
+
class Password
|
11
|
+
def self.hash_encoded(t_cost, m_cost, parallelism, pwd, salt, hashlen)
|
12
|
+
raise Error, "Salt is too short" if salt.empty?
|
13
|
+
|
14
|
+
salt_bytes = salt.to_java_bytes
|
15
|
+
output = Java::byte[hashlen].new
|
16
|
+
params = Java::OrgBouncycastleCryptoParams::Argon2Parameters::Builder
|
17
|
+
.new(Java::OrgBouncycastleCryptoParams::Argon2Parameters::ARGON2_id)
|
18
|
+
.with_salt(salt_bytes)
|
19
|
+
.with_parallelism(parallelism)
|
20
|
+
.with_memory_as_kb(m_cost)
|
21
|
+
.with_iterations(t_cost)
|
22
|
+
.build
|
23
|
+
generator = Java::OrgBouncycastleCryptoGenerators::Argon2BytesGenerator.new
|
24
|
+
|
25
|
+
generator.init(params)
|
26
|
+
generator.generate_bytes(pwd.to_java_bytes, output)
|
27
|
+
|
28
|
+
encoder = Java::JavaUtil::Base64.get_encoder.without_padding
|
29
|
+
encoded_salt = encoder.encode_to_string(salt_bytes)
|
30
|
+
encoded_output = encoder.encode_to_string(output)
|
31
|
+
|
32
|
+
"$argon2id$v=19$m=#{m_cost},t=#{t_cost},p=#{parallelism}" \
|
33
|
+
"$#{encoded_salt}$#{encoded_output}"
|
34
|
+
rescue Java::JavaLang::IllegalStateException => e
|
35
|
+
raise Error, e.message
|
36
|
+
end
|
37
|
+
|
38
|
+
private_class_method :hash_encoded
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def verify(pwd)
|
43
|
+
other_output = Java::byte[output.bytesize].new
|
44
|
+
params = Java::OrgBouncycastleCryptoParams::Argon2Parameters::Builder
|
45
|
+
.new(Java::OrgBouncycastleCryptoParams::Argon2Parameters::ARGON2_id)
|
46
|
+
.with_salt(salt.to_java_bytes)
|
47
|
+
.with_parallelism(parallelism)
|
48
|
+
.with_memory_as_kb(m_cost)
|
49
|
+
.with_iterations(t_cost)
|
50
|
+
.with_version(version)
|
51
|
+
.build
|
52
|
+
generator = Java::OrgBouncycastleCryptoGenerators::Argon2BytesGenerator.new
|
53
|
+
generator.init(params)
|
54
|
+
generator.generate_bytes(pwd.to_java_bytes, other_output)
|
55
|
+
|
56
|
+
Java::OrgBouncycastleUtil::Arrays.constant_time_are_equal?(
|
57
|
+
output.to_java_bytes,
|
58
|
+
other_output
|
59
|
+
)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
else
|
64
|
+
begin
|
65
|
+
::RUBY_VERSION =~ /(\d+\.\d+)/
|
66
|
+
require_relative "#{Regexp.last_match(1)}/argon2id"
|
67
|
+
rescue LoadError
|
68
|
+
require "argon2id/argon2id"
|
69
|
+
end
|
70
|
+
end
|
data/lib/argon2id/password.rb
CHANGED
@@ -89,7 +89,7 @@ module Argon2id
|
|
89
89
|
# #=> "$argon2id$v=19$m=12288,t=3,p=1$JigW7fFn+N3NImt+aWpuzw$eM5F1cKeIBALNTU6LuWra75Zi2nymGvQLWzJzVFv0Nc"
|
90
90
|
def self.create(pwd, t_cost: Argon2id.t_cost, m_cost: Argon2id.m_cost, parallelism: Argon2id.parallelism, salt_len: Argon2id.salt_len, output_len: Argon2id.output_len)
|
91
91
|
new(
|
92
|
-
|
92
|
+
hash_encoded(
|
93
93
|
Integer(t_cost),
|
94
94
|
Integer(m_cost),
|
95
95
|
Integer(parallelism),
|
@@ -100,6 +100,13 @@ module Argon2id
|
|
100
100
|
)
|
101
101
|
end
|
102
102
|
|
103
|
+
# Check an encoded hash is a valid Argon2id hash.
|
104
|
+
#
|
105
|
+
# Returns true if so and false if not.
|
106
|
+
def self.valid_hash?(encoded)
|
107
|
+
PATTERN.match?(String(encoded))
|
108
|
+
end
|
109
|
+
|
103
110
|
# Create a new Password with the given encoded password hash.
|
104
111
|
#
|
105
112
|
# password = Argon2id::Password.new("$argon2id$v=19$m=19456,t=2,p=1$FI8yp1gXbthJCskBlpKPoQ$nOfCCpS2r+I8GRN71cZND4cskn7YKBNzuHUEO3YpY2s")
|
@@ -127,7 +134,7 @@ module Argon2id
|
|
127
134
|
# password == "password" #=> true
|
128
135
|
# password == "notpassword" #=> false
|
129
136
|
def ==(other)
|
130
|
-
|
137
|
+
verify(String(other))
|
131
138
|
end
|
132
139
|
|
133
140
|
alias_method :is_password?, :==
|
data/lib/argon2id/version.rb
CHANGED
data/lib/argon2id.rb
CHANGED
@@ -1,18 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
require "openssl"
|
5
|
-
else
|
6
|
-
begin
|
7
|
-
::RUBY_VERSION =~ /(\d+\.\d+)/
|
8
|
-
require_relative "#{Regexp.last_match(1)}/argon2id.so"
|
9
|
-
rescue LoadError
|
10
|
-
require "argon2id.so"
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
require "argon2id/version"
|
3
|
+
require "argon2id/extension"
|
15
4
|
require "argon2id/password"
|
5
|
+
require "argon2id/version"
|
16
6
|
|
17
7
|
module Argon2id
|
18
8
|
# The default "time cost" of 2 iterations recommended by OWASP.
|
@@ -52,57 +42,4 @@ module Argon2id
|
|
52
42
|
# The default desired length of the hash in bytes used by Argon2id::Password.create
|
53
43
|
attr_accessor :output_len
|
54
44
|
end
|
55
|
-
|
56
|
-
if RUBY_PLATFORM == "java"
|
57
|
-
Error = Class.new(StandardError)
|
58
|
-
|
59
|
-
def self.hash_encoded(t_cost, m_cost, parallelism, pwd, salt, hashlen)
|
60
|
-
output = hash_raw(t_cost, m_cost, parallelism, pwd, salt, hashlen)
|
61
|
-
|
62
|
-
encoder = Java::JavaUtil::Base64.get_encoder.without_padding
|
63
|
-
encoded_salt = encoder.encode_to_string(salt.to_java_bytes)
|
64
|
-
encoded_output = encoder.encode_to_string(output)
|
65
|
-
|
66
|
-
"$argon2id$v=19$m=#{Integer(m_cost)},t=#{Integer(t_cost)}," \
|
67
|
-
"p=#{Integer(parallelism)}$#{encoded_salt}$#{encoded_output}"
|
68
|
-
end
|
69
|
-
|
70
|
-
def self.verify(encoded, pwd)
|
71
|
-
password = Password.new(encoded)
|
72
|
-
other_raw = hash_raw(
|
73
|
-
password.t_cost,
|
74
|
-
password.m_cost,
|
75
|
-
password.parallelism,
|
76
|
-
String(pwd),
|
77
|
-
password.salt,
|
78
|
-
password.output.bytesize
|
79
|
-
)
|
80
|
-
|
81
|
-
Java::OrgBouncycastleUtil::Arrays.constant_time_are_equal(
|
82
|
-
password.output.to_java_bytes,
|
83
|
-
other_raw
|
84
|
-
)
|
85
|
-
end
|
86
|
-
|
87
|
-
def self.hash_raw(t_cost, m_cost, parallelism, pwd, salt, hashlen)
|
88
|
-
raise Error, "Salt is too short" if String(salt).empty?
|
89
|
-
|
90
|
-
hash = Java::byte[Integer(hashlen)].new
|
91
|
-
params = Java::OrgBouncycastleCryptoParams::Argon2Parameters::Builder
|
92
|
-
.new(Java::OrgBouncycastleCryptoParams::Argon2Parameters::ARGON2_id)
|
93
|
-
.with_salt(String(salt).to_java_bytes)
|
94
|
-
.with_parallelism(Integer(parallelism))
|
95
|
-
.with_memory_as_kb(Integer(m_cost))
|
96
|
-
.with_iterations(Integer(t_cost))
|
97
|
-
.build
|
98
|
-
generator = Java::OrgBouncycastleCryptoGenerators::Argon2BytesGenerator.new
|
99
|
-
|
100
|
-
generator.init(params)
|
101
|
-
generator.generate_bytes(String(pwd).to_java_bytes, hash)
|
102
|
-
|
103
|
-
hash
|
104
|
-
rescue Java::JavaLang::IllegalStateException => e
|
105
|
-
raise Error, e.message
|
106
|
-
end
|
107
|
-
end
|
108
45
|
end
|