argon2id 0.3.0-x86-linux → 0.4.1-x86-linux

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
2
  SHA256:
3
- metadata.gz: d04472310d5c3f2ce514946ee659af41265deabf3d407138b24da6331bba54bb
4
- data.tar.gz: b9cb95db085d04431e6720bb691f29339d0d854fe1d1f2698278c31a09a18e94
3
+ metadata.gz: bd4d3ab5b623d55b5a531dd45d9bc035d4ad43bf7c3baac190eac648274370ba
4
+ data.tar.gz: 42cc78c19bdb2a37062ab0cd4aba4100b97fac6186b2b81652633982f96997b4
5
5
  SHA512:
6
- metadata.gz: 704669c139df342c654883ec52b11a6084aa2b1cbc1be2417c7dcacd33f9e63224834a89c2d604d980c106e3163fd892d70b1baaa6991f9fc778e059cf897faf
7
- data.tar.gz: 3c6df59db1d9a489638380857f11206a14953a568c0707539835b0d9cc2d955e7a077ced70c82346825b096de0400ee794a148e7fa454ce5fd601dc5a9cc245a
6
+ metadata.gz: 414aa8a79b7cfe8023071982ba2355b9de5ca8b63d8293293812a82555d441d7497e855608e5603bdca922e0f132273a585cdd021a761b68830c2c7c584bfb41
7
+ data.tar.gz: 06bb633361f10d2e863e5423699e0e6f44714c30a8aff7a389a98fd6a0a085b8fc04ec2065731a6c1dfca5ccb64847bc40f204d733f815880c2914f24e575119
data/CHANGELOG.md CHANGED
@@ -5,6 +5,29 @@ 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.4.1] - 2024-11-02
9
+
10
+ ### Changed
11
+
12
+ - Refactor verification on JRuby to avoid parsing encoded hashes unnecessarily
13
+ - No longer describe the gem in terms of bindings to the reference C
14
+ implementation given the Bouncy Castle-based JRuby implementation
15
+ - Only wrap `IllegalStateException` with `Argon2id::Error` on JRuby
16
+
17
+ ## [0.4.0] - 2024-11-02
18
+
19
+ ### Added
20
+
21
+ - Added support for JRuby 9.4 by adding an implementation of Argon2id hashing
22
+ and verification using JRuby-OpenSSL's Bouncy Castle internals
23
+ - Added `output` to `Argon2id::Password` instances so the actual "output" part
24
+ of a password hash can be retrieved (and compared)
25
+
26
+ ### Changed
27
+
28
+ - Verifying a password will now consistently raise an `ArgumentError` when
29
+ given an invalid encoded hash rather than an `Argon2id::Error`
30
+
8
31
  ## [0.3.0] - 2024-11-01
9
32
 
10
33
  ### Added
@@ -63,6 +86,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
63
86
  reference C implementation of Argon2, the password-hashing function that won
64
87
  the Password Hashing Competition.
65
88
 
89
+ [0.4.1]: https://github.com/mudge/argon2id/releases/tag/v0.4.1
90
+ [0.4.0]: https://github.com/mudge/argon2id/releases/tag/v0.4.0
66
91
  [0.3.0]: https://github.com/mudge/argon2id/releases/tag/v0.3.0
67
92
  [0.2.1]: https://github.com/mudge/argon2id/releases/tag/v0.2.1
68
93
  [0.2.0]: https://github.com/mudge/argon2id/releases/tag/v0.2.0
data/README.md CHANGED
@@ -1,11 +1,11 @@
1
1
  # Argon2id - Ruby bindings to the OWASP recommended password-hashing function
2
2
 
3
- Ruby bindings to the reference C implementation of [Argon2][], the password-hashing
4
- function that won the 2015 [Password Hashing Competition][].
3
+ Ruby bindings to [Argon2][], the password-hashing function that won the 2015
4
+ [Password Hashing Competition][].
5
5
 
6
6
  [![Build Status](https://github.com/mudge/argon2id/actions/workflows/tests.yml/badge.svg?branch=main)](https://github.com/mudge/argon2id/actions)
7
7
 
8
- **Current version:** 0.3.0
8
+ **Current version:** 0.4.1
9
9
  **Bundled Argon2 version:** libargon2.1 (20190702)
10
10
 
11
11
  ```ruby
@@ -13,7 +13,7 @@ Argon2id::Password.create("password").to_s
13
13
  #=> "$argon2id$v=19$m=19456,t=2,p=1$agNV6OfDL1OwE44WdrFCJw$ITrBwvCsW4b5GjgZuL67RCcvVMEWBWXtASc9TVyI3rY"
14
14
 
15
15
  password = Argon2id::Password.new("$argon2id$v=19$m=19456,t=2,p=1$ZS2nBFWBpnt28HjtzNOW4w$SQ+p+dIcWbpzWpZQ/ZZFj8IQkyhYZf127U4QdkRmKFU")
16
- password == "password" #=> true
16
+ password == "password" #=> true
17
17
  password == "not password" #=> false
18
18
 
19
19
  password.m_cost #=> 19456
@@ -127,7 +127,7 @@ password == "opensesame" #=> true
127
127
  password == "notopensesame" #=> false
128
128
  ```
129
129
 
130
- Or, if you only have the hash (e.g. retrieved from storage):
130
+ Or, if you only have the encoded hash (e.g. retrieved from storage):
131
131
 
132
132
  ```ruby
133
133
  password = Argon2id::Password.new("$argon2id$v=19$m=19456,t=2,p=1$ZS2nBFWBpnt28HjtzNOW4w$SQ+p+dIcWbpzWpZQ/ZZFj8IQkyhYZf127U4QdkRmKFU")
@@ -143,7 +143,7 @@ password.is_password?("opensesame") #=> true
143
143
  password.is_password?("notopensesame") #=> false
144
144
  ```
145
145
 
146
- The various parameters for the password can be retrieved:
146
+ The various parts of the encoded hash can be retrieved:
147
147
 
148
148
  ```ruby
149
149
  password = Argon2id::Password.new("$argon2id$v=19$m=256,t=2,p=1$c29tZXNhbHQ$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/4")
@@ -153,6 +153,8 @@ password.m_cost #=> 256
153
153
  password.t_cost #=> 2
154
154
  password.parallelism #=> 1
155
155
  password.salt #=> "somesalt"
156
+ password.output
157
+ #=> "\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"
156
158
  ```
157
159
 
158
160
  ### Errors
@@ -166,9 +168,16 @@ Argon2id::Password.create("password", salt_len: 0)
166
168
 
167
169
  ## Requirements
168
170
 
169
- This gem requires the following to run:
171
+ This gem requires any of the following to run:
170
172
 
171
173
  * [Ruby](https://www.ruby-lang.org/en/) 2.6 to 3.3
174
+ * [JRuby](https://www.jruby.org) 9.4
175
+ * [TruffleRuby](https://www.graalvm.org/ruby/) 24.1
176
+
177
+ > [!NOTE]
178
+ > The JRuby version of the gem uses
179
+ > [JRuby-OpenSSL](https://github.com/jruby/jruby-openssl)'s implementation of
180
+ > Argon2 while the others use the reference C implementation.
172
181
 
173
182
  ### Native gems
174
183
 
@@ -180,6 +189,7 @@ Where possible, a pre-compiled native gem will be provided for the following pla
180
189
  * [musl](https://musl.libc.org/)-based systems such as [Alpine](https://alpinelinux.org) are supported as long as a [glibc-compatible library is installed](https://wiki.alpinelinux.org/wiki/Running_glibc_programs)
181
190
  * macOS `x86_64-darwin` and `arm64-darwin`
182
191
  * Windows `x64-mingw32` and `x64-mingw-ucrt`
192
+ * Java: any platform running JRuby 9.4 or higher
183
193
 
184
194
  ### Verifying the gems
185
195
 
@@ -188,11 +198,11 @@ notes](https://github.com/mudge/argon2id/releases) for each version and can be
188
198
  checked with `sha256sum`, e.g.
189
199
 
190
200
  ```console
191
- $ gem fetch argon2id -v 0.2.1
192
- Fetching argon2id-0.2.1-arm64-darwin.gem
193
- Downloaded argon2id-0.2.1-arm64-darwin
194
- $ sha256sum argon2id-0.2.1-arm64-darwin.gem
195
- aea93700e989e421dd4e66b99038b9fec1acc9a265fe9d35e2100ceb5c18e5a9 argon2id-0.2.1-arm64-darwin.gem
201
+ $ gem fetch argon2id -v 0.4.0
202
+ Fetching argon2id-0.4.0-arm64-darwin.gem
203
+ Downloaded argon2id-0.4.0-arm64-darwin
204
+ $ sha256sum argon2id-0.4.0-arm64-darwin.gem
205
+ 2cecd6d5a1ecaf0a025e95714c0dee22dfc3d4585b649c57c06f432031b55a77 argon2id-0.4.0-arm64-darwin.gem
196
206
  ```
197
207
 
198
208
  [GPG](https://www.gnupg.org/) signatures are attached to each release (the
@@ -202,8 +212,8 @@ from a public keyserver, e.g. `gpg --keyserver keyserver.ubuntu.com --recv-key
202
212
  0x39AC3530070E0F75`):
203
213
 
204
214
  ```console
205
- $ gpg --verify argon2id-0.2.1-arm64-darwin.gem.sig argon2id-0.2.1-arm64-darwin.gem
206
- gpg: Signature made Fri 1 Nov 15:06:30 2024 GMT
215
+ $ gpg --verify argon2id-0.4.0-arm64-darwin.gem.sig argon2id-0.4.0-arm64-darwin.gem
216
+ gpg: Signature made Sat 2 Nov 15:25:15 2024 GMT
207
217
  gpg: using RSA key 702609D9C790F45B577D7BEC39AC3530070E0F75
208
218
  gpg: Good signature from "Paul Mucur <mudge@mudge.name>" [unknown]
209
219
  gpg: aka "Paul Mucur <paul@ghostcassette.com>" [unknown]
data/Rakefile CHANGED
@@ -20,6 +20,13 @@ 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
+
23
30
  Gem::PackageTask.new(gemspec).define
24
31
 
25
32
  Rake::ExtensionTask.new("argon2id", gemspec) do |e|
@@ -50,6 +57,15 @@ namespace :gem do
50
57
  SCRIPT
51
58
  end
52
59
  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
53
69
  end
54
70
 
55
71
  task default: [:compile, :test]
data/argon2id.gemspec CHANGED
@@ -6,7 +6,7 @@ Gem::Specification.new do |s|
6
6
  s.name = "argon2id"
7
7
  s.version = Argon2id::VERSION
8
8
  s.summary = "Ruby bindings to Argon2"
9
- s.description = "Ruby bindings to the reference C implementation of Argon2, the password-hashing function that won the 2015 Password Hashing Competition."
9
+ s.description = "Ruby bindings to Argon2, the password-hashing function that won the 2015 Password Hashing Competition."
10
10
  s.license = "BSD-3-Clause"
11
11
  s.authors = ["Paul Mucur"]
12
12
  s.homepage = "https://github.com/mudge/argon2id"
@@ -70,6 +70,9 @@ rb_argon2id_verify(VALUE module, VALUE encoded, VALUE pwd) {
70
70
  if (result == ARGON2_VERIFY_MISMATCH) {
71
71
  return Qfalse;
72
72
  }
73
+ if (result == ARGON2_DECODING_FAIL || result == ARGON2_DECODING_LENGTH_FAIL) {
74
+ rb_raise(rb_eArgError, "%s", argon2_error_message(result));
75
+ }
73
76
 
74
77
  rb_raise(cArgon2idError, "%s", argon2_error_message(result));
75
78
  }
data/lib/2.6/argon2id.so CHANGED
Binary file
data/lib/2.7/argon2id.so CHANGED
Binary file
data/lib/3.0/argon2id.so CHANGED
Binary file
data/lib/3.1/argon2id.so CHANGED
Binary file
data/lib/3.2/argon2id.so CHANGED
Binary file
data/lib/3.3/argon2id.so CHANGED
Binary file
@@ -44,7 +44,7 @@ module Argon2id
44
44
  \$
45
45
  ([a-zA-Z0-9+/]+)
46
46
  \$
47
- [a-zA-Z0-9+/]+
47
+ ([a-zA-Z0-9+/]+)
48
48
  \z
49
49
  }x.freeze
50
50
 
@@ -69,6 +69,9 @@ module Argon2id
69
69
  # The salt.
70
70
  attr_reader :salt
71
71
 
72
+ # The hash output.
73
+ attr_reader :output
74
+
72
75
  # Create a new Password object that hashes a given plain text password +pwd+.
73
76
  #
74
77
  # - +:t_cost+: integer (default 2) the "time cost" given as a number of iterations
@@ -101,8 +104,6 @@ module Argon2id
101
104
  )
102
105
  end
103
106
 
104
- # call-seq: Argon2id::Password.new(encoded)
105
- #
106
107
  # Create a new Password with the given encoded password hash.
107
108
  #
108
109
  # password = Argon2id::Password.new("$argon2id$v=19$m=19456,t=2,p=1$FI8yp1gXbthJCskBlpKPoQ$nOfCCpS2r+I8GRN71cZND4cskn7YKBNzuHUEO3YpY2s")
@@ -113,11 +114,12 @@ module Argon2id
113
114
 
114
115
  @encoded = $&
115
116
  @type = $1
116
- @version = ($2 || 0x10).to_i
117
- @m_cost = $3.to_i
118
- @t_cost = $4.to_i
119
- @parallelism = $5.to_i
117
+ @version = Integer($2 || 0x10)
118
+ @m_cost = Integer($3)
119
+ @t_cost = Integer($4)
120
+ @parallelism = Integer($5)
120
121
  @salt = $6.unpack1("m")
122
+ @output = $7.unpack1("m")
121
123
  end
122
124
 
123
125
  # Return the encoded password hash.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Argon2id
4
- VERSION = "0.3.0"
4
+ VERSION = "0.4.1"
5
5
  end
data/lib/argon2id.rb CHANGED
@@ -1,10 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- begin
4
- ::RUBY_VERSION =~ /(\d+\.\d+)/
5
- require_relative "#{Regexp.last_match(1)}/argon2id.so"
6
- rescue LoadError
7
- require "argon2id.so"
3
+ if RUBY_PLATFORM == "java"
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
8
12
  end
9
13
 
10
14
  require "argon2id/version"
@@ -48,4 +52,57 @@ module Argon2id
48
52
  # The default desired length of the hash in bytes used by Argon2id::Password.create
49
53
  attr_accessor :output_len
50
54
  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
51
108
  end
@@ -10,6 +10,12 @@ class TestHashEncoded < Minitest::Test
10
10
  assert_equal "$argon2id$v=19$m=256,t=2,p=1$c29tZXNhbHQ$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/4", encoded
11
11
  end
12
12
 
13
+ def test_password_with_parallelism_of_two
14
+ encoded = Argon2id.hash_encoded(2, 256, 2, "password", "somesalt", 32)
15
+
16
+ assert_equal "$argon2id$v=19$m=256,t=2,p=2$c29tZXNhbHQ$bQk8UB/VmZZF4Oo79iDXuL5/0ttZwg2f/5U52iv1cDc", encoded
17
+ end
18
+
13
19
  def test_valid_password_does_not_include_trailing_null_byte
14
20
  encoded = Argon2id.hash_encoded(2, 256, 1, "password", "somesalt", 32)
15
21
 
@@ -17,42 +23,32 @@ class TestHashEncoded < Minitest::Test
17
23
  end
18
24
 
19
25
  def test_raises_with_too_short_output
20
- error = assert_raises(Argon2id::Error) do
26
+ assert_raises(Argon2id::Error) do
21
27
  Argon2id.hash_encoded(2, 256, 1, "password", "somesalt", 1)
22
28
  end
23
-
24
- assert_equal "Output is too short", error.message
25
29
  end
26
30
 
27
31
  def test_raises_with_too_few_lanes
28
- error = assert_raises(Argon2id::Error) do
32
+ assert_raises(Argon2id::Error) do
29
33
  Argon2id.hash_encoded(2, 256, 0, "password", "somesalt", 32)
30
34
  end
31
-
32
- assert_equal "Too few lanes", error.message
33
35
  end
34
36
 
35
37
  def test_raises_with_too_small_memory_cost
36
- error = assert_raises(Argon2id::Error) do
38
+ assert_raises(Argon2id::Error) do
37
39
  Argon2id.hash_encoded(2, 0, 1, "password", "somesalt", 32)
38
40
  end
39
-
40
- assert_equal "Memory cost is too small", error.message
41
41
  end
42
42
 
43
43
  def test_raises_with_too_small_time_cost
44
- error = assert_raises(Argon2id::Error) do
44
+ assert_raises(Argon2id::Error) do
45
45
  Argon2id.hash_encoded(0, 256, 1, "password", "somesalt", 32)
46
46
  end
47
-
48
- assert_equal "Time cost is too small", error.message
49
47
  end
50
48
 
51
49
  def test_raises_with_too_short_salt
52
- error = assert_raises(Argon2id::Error) do
53
- Argon2id.hash_encoded(0, 256, 1, "password", "", 32)
50
+ assert_raises(Argon2id::Error) do
51
+ Argon2id.hash_encoded(2, 256, 1, "password", "", 32)
54
52
  end
55
-
56
- assert_equal "Salt is too short", error.message
57
53
  end
58
54
  end
@@ -169,4 +169,10 @@ class TestPassword < Minitest::Test
169
169
 
170
170
  assert_equal 1, password.parallelism
171
171
  end
172
+
173
+ def test_extracting_output_from_hash
174
+ password = Argon2id::Password.new("$argon2id$v=19$m=256,t=2,p=1$c29tZXNhbHQ$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/4")
175
+
176
+ assert_equal "\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".b, password.output
177
+ end
172
178
  end
data/test/test_verify.rb CHANGED
@@ -19,7 +19,7 @@ class TestVerify < Minitest::Test
19
19
  end
20
20
 
21
21
  def test_raises_if_given_invalid_encoded
22
- assert_raises(Argon2id::Error) do
22
+ assert_raises(ArgumentError) do
23
23
  Argon2id.verify("", "opensesame")
24
24
  end
25
25
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: argon2id
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.1
5
5
  platform: x86-linux
6
6
  authors:
7
7
  - Paul Mucur
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-11-01 00:00:00.000000000 Z
11
+ date: 2024-11-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler
@@ -52,8 +52,8 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '5.25'
55
- description: Ruby bindings to the reference C implementation of Argon2, the password-hashing
56
- function that won the 2015 Password Hashing Competition.
55
+ description: Ruby bindings to Argon2, the password-hashing function that won the 2015
56
+ Password Hashing Competition.
57
57
  email:
58
58
  executables: []
59
59
  extensions: []