argon2id 0.4.0-java

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ecd94924e9be36c2d5cc914996688424ed5ac72b6a42e9f3c11062d4a95f5a57
4
+ data.tar.gz: fba3c84cb52265555796ab00e50578fb2711e080fca794e865743f4290c1d43c
5
+ SHA512:
6
+ metadata.gz: a83e14f427cf90a788535a08c992e699501d15678825a1efbef93966859a309d73dfabde9d33aa4e0bde37ac2f97abb0fd911d2faee028eaab55f972583dc2a4
7
+ data.tar.gz: 9d2d6186851a7ce7ca5ab3a05889ee540820169632d7c98dcf921a61de2731592f6038457f1ad506b858db216710ad6ca1597a4cd56408c1647c297f66a63697
data/CHANGELOG.md ADDED
@@ -0,0 +1,86 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.4.0] - 2024-11-02
9
+
10
+ ### Added
11
+
12
+ - Added support for JRuby 9.4 by adding an implementation of Argon2id hashing
13
+ and verification using JRuby-OpenSSL's Bouncy Castle internals.
14
+ - Added `output` to `Argon2id::Password` instances so the actual "output" part
15
+ of a password hash can be retrieved (and compared)
16
+
17
+ ### Changed
18
+
19
+ - Verifying a password will now consistently raise an `ArgumentError` when
20
+ given an invalid encoded hash rather than an `Argon2id::Error`
21
+
22
+ ## [0.3.0] - 2024-11-01
23
+
24
+ ### Added
25
+
26
+ - Expose all parameters of a hash through new readers on `Argon2id::Password`:
27
+ namely, `type`, `version`, `m_cost`, `t_cost`, and `parallelism`
28
+
29
+ ### Changed
30
+
31
+ - Remove the dependency on the `base64` gem by inlining the definition of
32
+ `Base64.decode64` (thanks to @etiennebarrie for the tip)
33
+
34
+ ## [0.2.1] - 2024-11-01
35
+
36
+ ### Added
37
+
38
+ - Anything that can be coerced to a String can now be passed to
39
+ `Argon2id::Password.new`
40
+
41
+ ## [0.2.0] - 2024-11-01
42
+
43
+ ### Added
44
+
45
+ - The original salt for an `Argon2id::Password` can now be retrieved with
46
+ `Argon2id::Password#salt`
47
+
48
+ ### Changed
49
+
50
+ - Encoded hashes are now validated when initialising an `Argon2id::Password`,
51
+ raising an `ArgumentError` if they are invalid
52
+
53
+ ## [0.1.2] - 2024-11-01
54
+
55
+ ### Fixed
56
+
57
+ - Validate that the encoded hash passed to `Argon2id::Password.new` is a
58
+ null-terminated C string, raising an `ArgumentError` if it contains extra null
59
+ bytes
60
+
61
+ ## [0.1.1] - 2024-11-01
62
+
63
+ ### Added
64
+
65
+ - RDoc documentation for the API
66
+
67
+ ### Fixed
68
+
69
+ - Saved a superfluous extra byte when allocating the buffer for the encoded
70
+ hash
71
+
72
+ ## [0.1.0] - 2024-10-31
73
+
74
+ ### Added
75
+
76
+ - The initial version of the Argon2id gem, providing Ruby bindings to the
77
+ reference C implementation of Argon2, the password-hashing function that won
78
+ the Password Hashing Competition.
79
+
80
+ [0.4.0]: https://github.com/mudge/argon2id/releases/tag/v0.4.0
81
+ [0.3.0]: https://github.com/mudge/argon2id/releases/tag/v0.3.0
82
+ [0.2.1]: https://github.com/mudge/argon2id/releases/tag/v0.2.1
83
+ [0.2.0]: https://github.com/mudge/argon2id/releases/tag/v0.2.0
84
+ [0.1.2]: https://github.com/mudge/argon2id/releases/tag/v0.1.2
85
+ [0.1.1]: https://github.com/mudge/argon2id/releases/tag/v0.1.1
86
+ [0.1.0]: https://github.com/mudge/argon2id/releases/tag/v0.1.0
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gemspec
6
+
7
+ group :memcheck, optional: true do
8
+ gem "ruby_memcheck"
9
+ end
data/LICENSE ADDED
@@ -0,0 +1,11 @@
1
+ Copyright (c) 2024 Paul Mucur.
2
+
3
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
4
+
5
+ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
6
+
7
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8
+
9
+ 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
10
+
11
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,285 @@
1
+ # Argon2id - Ruby bindings to the OWASP recommended password-hashing function
2
+
3
+ Ruby bindings to the reference C implementation of [Argon2][], the password-hashing
4
+ function that won the 2015 [Password Hashing Competition][].
5
+
6
+ [![Build Status](https://github.com/mudge/argon2id/actions/workflows/tests.yml/badge.svg?branch=main)](https://github.com/mudge/argon2id/actions)
7
+
8
+ **Current version:** 0.4.0
9
+ **Bundled Argon2 version:** libargon2.1 (20190702)
10
+
11
+ ```ruby
12
+ Argon2id::Password.create("password").to_s
13
+ #=> "$argon2id$v=19$m=19456,t=2,p=1$agNV6OfDL1OwE44WdrFCJw$ITrBwvCsW4b5GjgZuL67RCcvVMEWBWXtASc9TVyI3rY"
14
+
15
+ password = Argon2id::Password.new("$argon2id$v=19$m=19456,t=2,p=1$ZS2nBFWBpnt28HjtzNOW4w$SQ+p+dIcWbpzWpZQ/ZZFj8IQkyhYZf127U4QdkRmKFU")
16
+ password == "password" #=> true
17
+ password == "not password" #=> false
18
+
19
+ password.m_cost #=> 19456
20
+ password.salt #=> "e-\xA7\x04U\x81\xA6{v\xF0x\xED\xCC\xD3\x96\xE3"
21
+ ```
22
+
23
+ ## Table of contents
24
+
25
+ * [Why Argon2id?](#why-argon2id)
26
+ * [Usage](#usage)
27
+ * [Hashing passwords](#hashing-passwords)
28
+ * [Verifying passwords](#verifying-passwords)
29
+ * [Errors](#errors)
30
+ * [Requirements](#requirements)
31
+ * [Native gems](#native-gems)
32
+ * [Verifying the gems](#verifying-the-gems)
33
+ * [Installing the `ruby` platform gem](#installing-the-ruby-platform-gem)
34
+ * [Thanks](#thanks)
35
+ * [Contact](#contact)
36
+ * [License](#license)
37
+ * [Dependencies](#dependencies)
38
+
39
+ ## Why Argon2id?
40
+
41
+ > Argon2 is a password-hashing function that summarizes the state of the art in
42
+ > the design of memory-hard functions and can be used to hash passwords for
43
+ > credential storage, key derivation, or other applications.
44
+ >
45
+ > It has a simple design aimed at the highest memory filling rate and effective
46
+ > use of multiple computing units, while still providing defense against
47
+ > tradeoff attacks (by exploiting the cache and memory organization of the
48
+ > recent processors).
49
+
50
+ — [Argon2][]
51
+
52
+ > Argon2 was the winner of the 2015 Password Hashing Competition. Out of the
53
+ > three Argon2 versions, use the Argon2id variant since it provides a balanced
54
+ > approach to resisting both side-channel and GPU-based attacks.
55
+
56
+ — [OWASP Password Storage Cheat Sheet][]
57
+
58
+ ## Usage
59
+
60
+ Install argon2id as a dependency:
61
+
62
+ ```ruby
63
+ # In your Gemfile
64
+ gem "argon2id"
65
+
66
+ # Or without Bundler
67
+ gem install argon2id
68
+ ```
69
+
70
+ Include in your code:
71
+
72
+ ```ruby
73
+ require "argon2id"
74
+ ```
75
+
76
+ ### Hashing passwords
77
+
78
+ Hash a plain text password (e.g. from user input) with
79
+ `Argon2id::Password.create`:
80
+
81
+ ```ruby
82
+ password = Argon2id::Password.create("opensesame")
83
+ ```
84
+
85
+ The encoded value of the resulting hash is available via
86
+ `Argon2id::Password#to_s` (ideal for persisting somewhere):
87
+
88
+ ```ruby
89
+ password.to_s
90
+ #=> "$argon2id$v=19$m=19456,t=2,p=1$ZS2nBFWBpnt28HjtzNOW4w$SQ+p+dIcWbpzWpZQ/ZZFj8IQkyhYZf127U4QdkRmKFU"
91
+ ```
92
+
93
+ By default, `Argon2id::Password.create` will use the second set of parameters
94
+ recommended by [OWASP][OWASP Password Storage Cheat Sheet] but these can be
95
+ overridden by passing keyword arguments to `Argon2id::Password.create`:
96
+
97
+ * `t_cost`: the "time cost" given as a number of iterations (defaults to 2)
98
+ * `m_cost`: the "memory cost" given in kibibytes (defaults to 19 mebibytes)
99
+ * `parallelism`: the number of threads and compute lanes to use (defaults to 1)
100
+ * `salt_len`: the salt size in bytes (defaults to 16)
101
+ * `output_len`: the desired length of the hash in bytes (defaults to 32)
102
+
103
+ ```ruby
104
+ password = Argon2id::Password.create("opensesame", t_cost: 3, m_cost: 12288)
105
+ password.to_s
106
+ #=> "$argon2id$v=19$m=12288,t=3,p=1$uukIsLS6y6etvsgoN20kVg$exMvDX/P9exvEPmnZL2gZClRyMdrnqjqyysLMP/VUWA"
107
+ ```
108
+
109
+ If you want to override the parameters for all calls to
110
+ `Argon2id::Password.create`, you can set them on `Argon2id` directly:
111
+
112
+ ```ruby
113
+ Argon2id.t_cost = 3
114
+ Argon2id.m_cost = 12288
115
+ Argon2id.parallelism = 1
116
+ Argon2id.salt_len = 16
117
+ Argon2id.output_len = 32
118
+ ```
119
+
120
+ ### Verifying passwords
121
+
122
+ To verify a password against a hash, use `Argon2id::Password#==`:
123
+
124
+ ```ruby
125
+ password = Argon2id::Password.create("opensesame")
126
+ password == "opensesame" #=> true
127
+ password == "notopensesame" #=> false
128
+ ```
129
+
130
+ Or, if you only have the hash (e.g. retrieved from storage):
131
+
132
+ ```ruby
133
+ password = Argon2id::Password.new("$argon2id$v=19$m=19456,t=2,p=1$ZS2nBFWBpnt28HjtzNOW4w$SQ+p+dIcWbpzWpZQ/ZZFj8IQkyhYZf127U4QdkRmKFU")
134
+ password == "opensesame" #=> true
135
+ password == "notopensesame" #=> false
136
+ ```
137
+
138
+ For compatibility with [bcrypt-ruby][], `Argon2id::Password#==` is aliased to `Argon2id::Password.is_password?`:
139
+
140
+ ```ruby
141
+ password = Argon2id::Password.new("$argon2id$v=19$m=19456,t=2,p=1$ZS2nBFWBpnt28HjtzNOW4w$SQ+p+dIcWbpzWpZQ/ZZFj8IQkyhYZf127U4QdkRmKFU")
142
+ password.is_password?("opensesame") #=> true
143
+ password.is_password?("notopensesame") #=> false
144
+ ```
145
+
146
+ The various parts of the encoded password can be retrieved:
147
+
148
+ ```ruby
149
+ password = Argon2id::Password.new("$argon2id$v=19$m=256,t=2,p=1$c29tZXNhbHQ$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/4")
150
+ password.type #=> "argon2id"
151
+ password.version #=> 19
152
+ password.m_cost #=> 256
153
+ password.t_cost #=> 2
154
+ password.parallelism #=> 1
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"
158
+ ```
159
+
160
+ ### Errors
161
+
162
+ Any errors returned from Argon2 will be raised as `Argon2id::Error`, e.g.
163
+
164
+ ```ruby
165
+ Argon2id::Password.create("password", salt_len: 0)
166
+ # Salt is too short (Argon2id::Error)
167
+ ```
168
+
169
+ ## Requirements
170
+
171
+ This gem requires any of the following to run:
172
+
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 instead of the reference C implementation.
181
+
182
+ ### Native gems
183
+
184
+ Where possible, a pre-compiled native gem will be provided for the following platforms:
185
+
186
+ * Linux
187
+ * `aarch64-linux` and `arm-linux` (requires [glibc](https://www.gnu.org/software/libc/) 2.29+)
188
+ * `x86-linux` and `x86_64-linux` (requires [glibc](https://www.gnu.org/software/libc/) 2.17+)
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)
190
+ * macOS `x86_64-darwin` and `arm64-darwin`
191
+ * Windows `x64-mingw32` and `x64-mingw-ucrt`
192
+ * Java: any platform running JRuby 9.4 or higher
193
+
194
+ ### Verifying the gems
195
+
196
+ SHA256 checksums are included in the [release
197
+ notes](https://github.com/mudge/argon2id/releases) for each version and can be
198
+ checked with `sha256sum`, e.g.
199
+
200
+ ```console
201
+ $ gem fetch argon2id -v 0.3.0
202
+ Fetching argon2id-0.3.0-arm64-darwin.gem
203
+ Downloaded argon2id-0.3.0-arm64-darwin
204
+ $ sha256sum argon2id-0.3.0-arm64-darwin.gem
205
+ 9d49de6840942b48d020dddd422a1577fde7289ccb08a637bdb29f4a09b4e181 argon2id-0.3.0-arm64-darwin.gem
206
+ ```
207
+
208
+ [GPG](https://www.gnupg.org/) signatures are attached to each release (the
209
+ assets ending in `.sig`) and can be verified if you import [our signing key
210
+ `0x39AC3530070E0F75`](https://mudge.name/39AC3530070E0F75.asc) (or fetch it
211
+ from a public keyserver, e.g. `gpg --keyserver keyserver.ubuntu.com --recv-key
212
+ 0x39AC3530070E0F75`):
213
+
214
+ ```console
215
+ $ gpg --verify argon2id-0.3.0-arm64-darwin.gem.sig argon2id-0.3.0-arm64-darwin.gem
216
+ gpg: Signature made Fri 1 Nov 18:15:47 2024 GMT
217
+ gpg: using RSA key 702609D9C790F45B577D7BEC39AC3530070E0F75
218
+ gpg: Good signature from "Paul Mucur <mudge@mudge.name>" [unknown]
219
+ gpg: aka "Paul Mucur <paul@ghostcassette.com>" [unknown]
220
+ gpg: WARNING: This key is not certified with a trusted signature!
221
+ gpg: There is no indication that the signature belongs to the owner.
222
+ Primary key fingerprint: 7026 09D9 C790 F45B 577D 7BEC 39AC 3530 070E 0F75
223
+ ```
224
+
225
+ The fingerprint should be as shown above or you can independently verify it
226
+ with the ones shown in the footer of https://mudge.name.
227
+
228
+ ### Installing the `ruby` platform gem
229
+
230
+ > [!WARNING]
231
+ > We strongly recommend using the native gems where possible to avoid the need
232
+ > for compiling the C extension and its dependencies which will take longer and
233
+ > be less reliable.
234
+
235
+ If you wish to compile the gem, you will need to explicitly install the `ruby` platform gem:
236
+
237
+ ```ruby
238
+ # In your Gemfile with Bundler 2.3.18+
239
+ gem "argon2id", force_ruby_platform: true
240
+
241
+ # With Bundler 2.1+
242
+ bundle config set force_ruby_platform true
243
+
244
+ # With older versions of Bundler
245
+ bundle config force_ruby_platform true
246
+
247
+ # Without Bundler
248
+ gem install argon2id --platform=ruby
249
+ ```
250
+
251
+ You will need a full compiler toolchain for compiling Ruby C extensions (see
252
+ [Nokogiri's "The Compiler
253
+ Toolchain"](https://nokogiri.org/tutorials/installing_nokogiri.html#appendix-a-the-compiler-toolchain))
254
+ plus the toolchain required for compiling the vendored version of Argon2.
255
+
256
+ ## Thanks
257
+
258
+ * Thanks to [Mike Dalessio](https://github.com/flavorjones) for his advice and
259
+ [Ruby C Extensions Explained](https://github.com/flavorjones/ruby-c-extensions-explained)
260
+ project
261
+
262
+ ## Contact
263
+
264
+ All issues and suggestions should go to [GitHub
265
+ Issues](https://github.com/mudge/argon2id/issues).
266
+
267
+ ## License
268
+
269
+ This library is licensed under the BSD 3-Clause License, see `LICENSE`.
270
+
271
+ Copyright © 2024, Paul Mucur.
272
+
273
+ ### Dependencies
274
+
275
+ The source code of [Argon2][] is distributed in the gem. This code is copyright
276
+ © 2015 Daniel Dinu, Dmitry Khovratovich (main authors), Jean-Philippe Aumasson
277
+ and Samuel Neves, and dual licensed under the [CC0 License][] and the [Apache
278
+ 2.0 License][].
279
+
280
+ [Argon2]: https://github.com/P-H-C/phc-winner-argon2/
281
+ [OWASP Password Storage Cheat Sheet]: https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#argon2id
282
+ [bcrypt-ruby]: https://github.com/bcrypt-ruby/bcrypt-ruby
283
+ [CC0 License]: https://creativecommons.org/about/cc0
284
+ [Apache 2.0 License]: https://www.apache.org/licenses/LICENSE-2.0
285
+ [Password Hashing Competition]: https://www.password-hashing.net
data/Rakefile ADDED
@@ -0,0 +1,71 @@
1
+ require "rake/extensiontask"
2
+ require "rake_compiler_dock"
3
+ require "minitest/test_task"
4
+
5
+ CLEAN.add("lib/**/*.{o,so,bundle}", "pkg")
6
+
7
+ cross_platforms = %w[
8
+ aarch64-linux
9
+ arm-linux
10
+ arm64-darwin
11
+ x64-mingw-ucrt
12
+ x64-mingw32
13
+ x86-linux
14
+ x86-mingw32
15
+ x86_64-darwin
16
+ x86_64-linux
17
+ ].freeze
18
+
19
+ 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
+
21
+ gemspec = Gem::Specification.load("argon2id.gemspec")
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
+ Gem::PackageTask.new(gemspec).define
31
+
32
+ Rake::ExtensionTask.new("argon2id", gemspec) do |e|
33
+ e.cross_compile = true
34
+ e.cross_platform = cross_platforms
35
+ end
36
+
37
+ Minitest::TestTask.create
38
+
39
+ begin
40
+ require "ruby_memcheck"
41
+
42
+ namespace :test do
43
+ RubyMemcheck::TestTask.new(valgrind: :compile)
44
+ end
45
+ rescue LoadError
46
+ # Only define the test:valgrind task if ruby_memcheck is installed
47
+ end
48
+
49
+ namespace :gem do
50
+ cross_platforms.each do |platform|
51
+ desc "Compile and build native gem for #{platform}"
52
+ task platform do
53
+ RakeCompilerDock.sh <<~SCRIPT, platform: platform, verbose: true
54
+ gem install bundler --no-document &&
55
+ bundle &&
56
+ bundle exec rake native:#{platform} pkg/#{gemspec.full_name}-#{Gem::Platform.new(platform)}.gem PATH="/usr/local/bin:$PATH"
57
+ SCRIPT
58
+ end
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
69
+ end
70
+
71
+ task default: [:compile, :test]
data/argon2id.gemspec ADDED
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/argon2id/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "argon2id"
7
+ s.version = Argon2id::VERSION
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."
10
+ s.license = "BSD-3-Clause"
11
+ s.authors = ["Paul Mucur"]
12
+ s.homepage = "https://github.com/mudge/argon2id"
13
+ s.metadata = {
14
+ "bug_tracker_uri" => "https://github.com/mudge/argon2id/issues",
15
+ "changelog_uri" => "https://github.com/mudge/argon2id/blob/main/CHANGELOG.md",
16
+ "funding_uri" => "https://github.com/sponsors/mudge",
17
+ "homepage_uri" => "https://github.com/mudge/argon2id",
18
+ "source_code_uri" => "https://github.com/mudge/argon2id",
19
+ "rubygems_mfa_required" => "true"
20
+ }
21
+ s.required_ruby_version = ">= 2.6.0"
22
+ s.extensions = ["ext/argon2id/extconf.rb"]
23
+ s.files = [
24
+ "CHANGELOG.md",
25
+ "Gemfile",
26
+ "LICENSE",
27
+ "README.md",
28
+ "Rakefile",
29
+ "argon2id.gemspec",
30
+ "ext/argon2id/argon2id.c",
31
+ "ext/argon2id/extconf.rb",
32
+ "ext/argon2id/libargon2/LICENSE",
33
+ "ext/argon2id/libargon2/argon2.c",
34
+ "ext/argon2id/libargon2/argon2.h",
35
+ "ext/argon2id/libargon2/blake2/blake2-impl.h",
36
+ "ext/argon2id/libargon2/blake2/blake2.h",
37
+ "ext/argon2id/libargon2/blake2/blake2b.c",
38
+ "ext/argon2id/libargon2/blake2/blamka-round-opt.h",
39
+ "ext/argon2id/libargon2/blake2/blamka-round-ref.h",
40
+ "ext/argon2id/libargon2/core.c",
41
+ "ext/argon2id/libargon2/core.h",
42
+ "ext/argon2id/libargon2/encoding.c",
43
+ "ext/argon2id/libargon2/encoding.h",
44
+ "ext/argon2id/libargon2/ref.c",
45
+ "ext/argon2id/libargon2/thread.c",
46
+ "ext/argon2id/libargon2/thread.h",
47
+ "lib/argon2id.rb",
48
+ "lib/argon2id/password.rb",
49
+ "lib/argon2id/version.rb",
50
+ "test/test_hash_encoded.rb",
51
+ "test/test_password.rb",
52
+ "test/test_verify.rb"
53
+ ]
54
+ s.rdoc_options = ["--main", "README.md"]
55
+
56
+ s.add_development_dependency("rake-compiler", "~> 1.2")
57
+ s.add_development_dependency("rake-compiler-dock", "~> 1.5")
58
+ s.add_development_dependency("minitest", "~> 5.25")
59
+ end
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openssl"
4
+
5
+ module Argon2id
6
+ # The Password class encapsulates an encoded Argon2id password hash.
7
+ #
8
+ # To hash a plain text password, use Argon2id::Password.create:
9
+ #
10
+ # password = Argon2id::Password.create("password")
11
+ # password.to_s
12
+ # #=> "$argon2id$v=19$m=19456,t=2,p=1$+Lrjry9Ifq0poLr15OGU1Q$utkDvejJB0ugwm4s9+a+vF6+1a/W+Y3CYa5Wte/85ig"
13
+ #
14
+ # To wrap an encoded Argon2id password hash, use Argon2id::Password.new:
15
+ #
16
+ # password = Argon2id::Password.new("$argon2id$v=19$m=256,t=2,p=1$c29tZXNhbHQ$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/4")
17
+ #
18
+ # You can then verify it matches a given plain text:
19
+ #
20
+ # password == "password" #=> true
21
+ # password == "not password" #=> false
22
+ #
23
+ # password.is_password?("password") #=> true
24
+ # password.is_password?("not password") #=> false
25
+ #
26
+ # You can read various parameters out of a password hash:
27
+ #
28
+ # password.type #=> "argon2id"
29
+ # password.version #=> 19
30
+ # password.m_cost #=> 19456
31
+ # password.t_cost #=> 2
32
+ # password.parallelism #=> 1
33
+ # password.salt #=> "somesalt"
34
+ class Password
35
+ # A regular expression to match valid hashes.
36
+ PATTERN = %r{
37
+ \A
38
+ \$
39
+ (argon2(?:id|i|d))
40
+ (?:\$v=(\d+))?
41
+ \$m=(\d+)
42
+ ,t=(\d+)
43
+ ,p=(\d+)
44
+ \$
45
+ ([a-zA-Z0-9+/]+)
46
+ \$
47
+ ([a-zA-Z0-9+/]+)
48
+ \z
49
+ }x.freeze
50
+
51
+ # The encoded password hash.
52
+ attr_reader :encoded
53
+
54
+ # The type of the hashing function.
55
+ attr_reader :type
56
+
57
+ # The version number of the hashing function.
58
+ attr_reader :version
59
+
60
+ # The "time cost" of the hashing function.
61
+ attr_reader :t_cost
62
+
63
+ # The "memory cost" of the hashing function.
64
+ attr_reader :m_cost
65
+
66
+ # The number of threads and compute lanes of the hashing function.
67
+ attr_reader :parallelism
68
+
69
+ # The salt.
70
+ attr_reader :salt
71
+
72
+ # The hash output.
73
+ attr_reader :output
74
+
75
+ # Create a new Password object that hashes a given plain text password +pwd+.
76
+ #
77
+ # - +:t_cost+: integer (default 2) the "time cost" given as a number of iterations
78
+ # - +:m_cost+: integer (default 19456) the "memory cost" given in kibibytes
79
+ # - +:parallelism+: integer (default 1) the number of threads and compute lanes to use
80
+ # - +:salt_len+: integer (default 16) the salt size in bytes
81
+ # - +:output_len+: integer (default 32) the desired length of the hash in bytes
82
+ #
83
+ # For example, with the default configuration:
84
+ #
85
+ # password = Argon2id::Password.create("password")
86
+ # password.to_s
87
+ # #=> "$argon2id$v=19$m=19456,t=2,p=1$FI8yp1gXbthJCskBlpKPoQ$nOfCCpS2r+I8GRN71cZND4cskn7YKBNzuHUEO3YpY2s"
88
+ #
89
+ # When overriding the configuration:
90
+ #
91
+ # password = Argon2id::Password.create("password", t_cost: 3, m_cost: 12288)
92
+ # password.to_s
93
+ # #=> "$argon2id$v=19$m=12288,t=3,p=1$JigW7fFn+N3NImt+aWpuzw$eM5F1cKeIBALNTU6LuWra75Zi2nymGvQLWzJzVFv0Nc"
94
+ 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)
95
+ new(
96
+ Argon2id.hash_encoded(
97
+ Integer(t_cost),
98
+ Integer(m_cost),
99
+ Integer(parallelism),
100
+ String(pwd),
101
+ OpenSSL::Random.random_bytes(Integer(salt_len)),
102
+ Integer(output_len)
103
+ )
104
+ )
105
+ end
106
+
107
+ # Create a new Password with the given encoded password hash.
108
+ #
109
+ # password = Argon2id::Password.new("$argon2id$v=19$m=19456,t=2,p=1$FI8yp1gXbthJCskBlpKPoQ$nOfCCpS2r+I8GRN71cZND4cskn7YKBNzuHUEO3YpY2s")
110
+ #
111
+ # Raises an ArgumentError if given an invalid hash.
112
+ def initialize(encoded)
113
+ raise ArgumentError, "invalid hash" unless PATTERN =~ String(encoded)
114
+
115
+ @encoded = $&
116
+ @type = $1
117
+ @version = Integer($2 || 0x10)
118
+ @m_cost = Integer($3)
119
+ @t_cost = Integer($4)
120
+ @parallelism = Integer($5)
121
+ @salt = $6.unpack1("m")
122
+ @output = $7.unpack1("m")
123
+ end
124
+
125
+ # Return the encoded password hash.
126
+ alias_method :to_s, :encoded
127
+
128
+ # Compare the password with the given plain text, returning true if it
129
+ # verifies successfully.
130
+ #
131
+ # password = Argon2id::Password.new("$argon2id$v=19$m=19456,t=2,p=1$FI8yp1gXbthJCskBlpKPoQ$nOfCCpS2r+I8GRN71cZND4cskn7YKBNzuHUEO3YpY2s")
132
+ # password == "password" #=> true
133
+ # password == "notpassword" #=> false
134
+ def ==(other)
135
+ Argon2id.verify(encoded, String(other))
136
+ end
137
+
138
+ alias_method :is_password?, :==
139
+ end
140
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Argon2id
4
+ VERSION = "0.4.0"
5
+ end
data/lib/argon2id.rb ADDED
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
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
12
+ end
13
+
14
+ require "argon2id/version"
15
+ require "argon2id/password"
16
+
17
+ module Argon2id
18
+ # The default "time cost" of 2 iterations recommended by OWASP.
19
+ DEFAULT_T_COST = 2
20
+
21
+ # The default "memory cost" of 19 mebibytes recommended by OWASP.
22
+ DEFAULT_M_COST = 19_456
23
+
24
+ # The default 1 thread and compute lane recommended by OWASP.
25
+ DEFAULT_PARALLELISM = 1
26
+
27
+ # The default salt length of 16 bytes.
28
+ DEFAULT_SALT_LEN = 16
29
+
30
+ # The default desired hash length of 32 bytes.
31
+ DEFAULT_OUTPUT_LEN = 32
32
+
33
+ @t_cost = DEFAULT_T_COST
34
+ @m_cost = DEFAULT_M_COST
35
+ @parallelism = DEFAULT_PARALLELISM
36
+ @salt_len = DEFAULT_SALT_LEN
37
+ @output_len = DEFAULT_OUTPUT_LEN
38
+
39
+ class << self
40
+ # The default number of iterations used by Argon2id::Password.create
41
+ attr_accessor :t_cost
42
+
43
+ # The default memory cost in kibibytes used by Argon2id::Password.create
44
+ attr_accessor :m_cost
45
+
46
+ # The default number of threads and compute lanes used by Argon2id::Password.create
47
+ attr_accessor :parallelism
48
+
49
+ # The default salt size in bytes used by Argon2id::Password.create
50
+ attr_accessor :salt_len
51
+
52
+ # The default desired length of the hash in bytes used by Argon2id::Password.create
53
+ attr_accessor :output_len
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
+ raise Error, "Salt is too short" unless String(salt).bytesize.positive?
61
+
62
+ hash = Java::byte[Integer(hashlen)].new
63
+ params = Java::OrgBouncycastleCryptoParams::Argon2Parameters::Builder
64
+ .new(Java::OrgBouncycastleCryptoParams::Argon2Parameters::ARGON2_id)
65
+ .with_salt(String(salt).to_java_bytes)
66
+ .with_parallelism(Integer(parallelism))
67
+ .with_memory_as_kb(Integer(m_cost))
68
+ .with_iterations(Integer(t_cost))
69
+ .build
70
+ generator = Java::OrgBouncycastleCryptoGenerators::Argon2BytesGenerator.new
71
+ encoder = Java::JavaUtil::Base64.get_encoder.without_padding
72
+
73
+ generator.init(params)
74
+ generator.generate_bytes(String(pwd).to_java_bytes, hash)
75
+
76
+ encoded_salt = encoder.encode_to_string(params.get_salt)
77
+ encoded_output = encoder.encode_to_string(hash)
78
+
79
+ "$argon2id$v=#{params.get_version}$m=#{params.get_memory}," \
80
+ "t=#{params.get_iterations},p=#{params.get_lanes}" \
81
+ "$#{encoded_salt}$#{encoded_output}"
82
+ rescue => e
83
+ raise Error, e.message
84
+ end
85
+
86
+ def self.verify(encoded, pwd)
87
+ password = Password.new(encoded)
88
+ other_password = Password.new(
89
+ hash_encoded(
90
+ password.t_cost,
91
+ password.m_cost,
92
+ password.parallelism,
93
+ String(pwd),
94
+ password.salt,
95
+ password.output.bytesize
96
+ )
97
+ )
98
+
99
+ Java::OrgBouncycastleUtil::Arrays.constant_time_are_equal(
100
+ password.output.to_java_bytes,
101
+ other_password.output.to_java_bytes
102
+ )
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "minitest/autorun"
4
+ require "argon2id"
5
+
6
+ class TestHashEncoded < Minitest::Test
7
+ def test_valid_password_and_salt_encodes_successfully
8
+ encoded = Argon2id.hash_encoded(2, 256, 1, "password", "somesalt", 32)
9
+
10
+ assert_equal "$argon2id$v=19$m=256,t=2,p=1$c29tZXNhbHQ$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/4", encoded
11
+ end
12
+
13
+ def test_valid_password_does_not_include_trailing_null_byte
14
+ encoded = Argon2id.hash_encoded(2, 256, 1, "password", "somesalt", 32)
15
+
16
+ refute encoded.end_with?("\x00")
17
+ end
18
+
19
+ def test_raises_with_too_short_output
20
+ assert_raises(Argon2id::Error) do
21
+ Argon2id.hash_encoded(2, 256, 1, "password", "somesalt", 1)
22
+ end
23
+ end
24
+
25
+ def test_raises_with_too_few_lanes
26
+ assert_raises(Argon2id::Error) do
27
+ Argon2id.hash_encoded(2, 256, 0, "password", "somesalt", 32)
28
+ end
29
+ end
30
+
31
+ def test_raises_with_too_small_memory_cost
32
+ assert_raises(Argon2id::Error) do
33
+ Argon2id.hash_encoded(2, 0, 1, "password", "somesalt", 32)
34
+ end
35
+ end
36
+
37
+ def test_raises_with_too_small_time_cost
38
+ assert_raises(Argon2id::Error) do
39
+ Argon2id.hash_encoded(0, 256, 1, "password", "somesalt", 32)
40
+ end
41
+ end
42
+
43
+ def test_raises_with_too_short_salt
44
+ assert_raises(Argon2id::Error) do
45
+ Argon2id.hash_encoded(2, 256, 1, "password", "", 32)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,172 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "minitest/autorun"
4
+ require "argon2id"
5
+
6
+ class TestPassword < Minitest::Test
7
+ def test_create_returns_encoded_password_with_defaults
8
+ password = Argon2id::Password.create("opensesame")
9
+
10
+ assert password.to_s.start_with?("$argon2id$")
11
+ assert password.to_s.include?("t=2")
12
+ assert password.to_s.include?("m=19456")
13
+ end
14
+
15
+ def test_create_options_can_override_parameters
16
+ password = Argon2id::Password.create("opensesame", t_cost: 2, m_cost: 256)
17
+
18
+ assert password.to_s.include?("t=2")
19
+ assert password.to_s.include?("m=256")
20
+ end
21
+
22
+ def test_create_uses_argon2id_configuration
23
+ Argon2id.t_cost = 2
24
+ Argon2id.m_cost = 256
25
+
26
+ password = Argon2id::Password.create("opensesame")
27
+
28
+ assert password.to_s.include?("t=2")
29
+ assert password.to_s.include?("m=256")
30
+ ensure
31
+ Argon2id.t_cost = Argon2id::DEFAULT_T_COST
32
+ Argon2id.m_cost = Argon2id::DEFAULT_M_COST
33
+ end
34
+
35
+ def test_create_coerces_pwd_to_string
36
+ password = Argon2id::Password.create(123, t_cost: 2, m_cost: 256)
37
+
38
+ assert password.to_s.start_with?("$argon2id$")
39
+ end
40
+
41
+ def test_create_coerces_costs_to_integer
42
+ password = Argon2id::Password.create("opensesame", t_cost: "2", m_cost: "256", parallelism: "1", salt_len: "8", output_len: "32")
43
+
44
+ assert password.to_s.start_with?("$argon2id$")
45
+ end
46
+
47
+ def test_create_raises_if_given_non_integer_costs
48
+ assert_raises(ArgumentError) do
49
+ Argon2id::Password.create("opensesame", t_cost: "not an integer")
50
+ end
51
+ end
52
+
53
+ def test_equals_correct_password
54
+ password = Argon2id::Password.create("opensesame", t_cost: 2, m_cost: 256)
55
+
56
+ assert password == "opensesame"
57
+ end
58
+
59
+ def test_does_not_equal_invalid_password
60
+ password = Argon2id::Password.create("opensesame", t_cost: 2, m_cost: 256)
61
+
62
+ refute password == "notopensesame"
63
+ end
64
+
65
+ def test_is_password_returns_true_with_correct_password
66
+ password = Argon2id::Password.create("opensesame", t_cost: 2, m_cost: 256)
67
+
68
+ assert password.is_password?("opensesame")
69
+ end
70
+
71
+ def test_is_password_returns_false_with_incorrect_password
72
+ password = Argon2id::Password.create("opensesame", t_cost: 2, m_cost: 256)
73
+
74
+ refute password.is_password?("notopensesame")
75
+ end
76
+
77
+ def test_salt_returns_the_original_salt
78
+ password = Argon2id::Password.new("$argon2id$v=19$m=256,t=2,p=1$c29tZXNhbHQ$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/4")
79
+
80
+ assert_equal "somesalt", password.salt
81
+ end
82
+
83
+ def test_salt_returns_raw_bytes
84
+ password = Argon2id::Password.new("$argon2id$v=19$m=256,t=2,p=1$KmIxrXv4lrnSJPO0LN7Gdw$lB3724qLPL9MNi10lkvIb4VxIk3q841CLvq0WTCZ0VQ")
85
+
86
+ assert_equal "*b1\xAD{\xF8\x96\xB9\xD2$\xF3\xB4,\xDE\xC6w".b, password.salt
87
+ end
88
+
89
+ def test_raises_for_invalid_hashes
90
+ assert_raises(ArgumentError) do
91
+ Argon2id::Password.new("not a valid hash")
92
+ end
93
+ end
94
+
95
+ def test_raises_for_partial_hashes
96
+ assert_raises(ArgumentError) do
97
+ Argon2id::Password.new("$argon2id$v=19$m=256,t=2,p=1$KmIxrXv4lrnSJPO0LN7Gdw")
98
+ end
99
+ end
100
+
101
+ def test_salt_supports_versionless_hashes
102
+ password = Argon2id::Password.new("$argon2id$m=256,t=2,p=1$c29tZXNhbHQ$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/4")
103
+
104
+ assert_equal "somesalt", password.salt
105
+ end
106
+
107
+ def test_coerces_given_hash_to_string
108
+ password = Argon2id::Password.create("password")
109
+
110
+ assert Argon2id::Password.new(password) == "password"
111
+ end
112
+
113
+ def test_extracting_type_from_hash
114
+ password = Argon2id::Password.new("$argon2id$v=19$m=256,t=2,p=1$c29tZXNhbHQ$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/4")
115
+
116
+ assert_equal "argon2id", password.type
117
+ end
118
+
119
+ def test_extracting_type_from_argoni_hash
120
+ password = Argon2id::Password.new("$argon2i$v=19$m=256,t=2,p=1$c29tZXNhbHQ$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/4")
121
+
122
+ assert_equal "argon2i", password.type
123
+ end
124
+
125
+ def test_extracting_version_from_hash
126
+ password = Argon2id::Password.new("$argon2id$v=19$m=256,t=2,p=1$c29tZXNhbHQ$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/4")
127
+
128
+ assert_equal 19, password.version
129
+ end
130
+
131
+ def test_extracting_version_from_versionless_hash
132
+ password = Argon2id::Password.new("$argon2id$m=256,t=2,p=1$c29tZXNhbHQ$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/4")
133
+
134
+ assert_equal 16, password.version
135
+ end
136
+
137
+ def test_extracting_time_cost_from_hash
138
+ password = Argon2id::Password.new("$argon2id$v=19$m=256,t=2,p=1$c29tZXNhbHQ$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/4")
139
+
140
+ assert_equal 2, password.t_cost
141
+ end
142
+
143
+ def test_extracting_time_cost_from_versionless_hash
144
+ password = Argon2id::Password.new("$argon2id$m=256,t=2,p=1$c29tZXNhbHQ$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/4")
145
+
146
+ assert_equal 2, password.t_cost
147
+ end
148
+
149
+ def test_extracting_memory_cost_from_hash
150
+ password = Argon2id::Password.new("$argon2id$v=19$m=256,t=2,p=1$c29tZXNhbHQ$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/4")
151
+
152
+ assert_equal 256, password.m_cost
153
+ end
154
+
155
+ def test_extracting_memory_cost_from_versionless_hash
156
+ password = Argon2id::Password.new("$argon2id$m=256,t=2,p=1$c29tZXNhbHQ$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/4")
157
+
158
+ assert_equal 256, password.m_cost
159
+ end
160
+
161
+ def test_extracting_parallelism_from_hash
162
+ password = Argon2id::Password.new("$argon2id$v=19$m=256,t=2,p=1$c29tZXNhbHQ$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/4")
163
+
164
+ assert_equal 1, password.parallelism
165
+ end
166
+
167
+ def test_extracting_parallelism_from_versionless_hash
168
+ password = Argon2id::Password.new("$argon2id$m=256,t=2,p=1$c29tZXNhbHQ$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/4")
169
+
170
+ assert_equal 1, password.parallelism
171
+ end
172
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "minitest/autorun"
4
+ require "argon2id"
5
+
6
+ class TestVerify < Minitest::Test
7
+ def test_returns_true_with_correct_password
8
+ assert Argon2id.verify(
9
+ "$argon2id$v=19$m=256,t=2,p=1$c29tZXNhbHQ$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/4",
10
+ "password"
11
+ )
12
+ end
13
+
14
+ def test_returns_false_with_incorrect_password
15
+ refute Argon2id.verify(
16
+ "$argon2id$v=19$m=256,t=2,p=1$c29tZXNhbHQ$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/4",
17
+ "not password"
18
+ )
19
+ end
20
+
21
+ def test_raises_if_given_invalid_encoded
22
+ assert_raises(ArgumentError) do
23
+ Argon2id.verify("", "opensesame")
24
+ end
25
+ end
26
+
27
+ def test_raises_if_given_encoded_with_null_byte
28
+ assert_raises(ArgumentError) do
29
+ Argon2id.verify(
30
+ "$argon2id$v=19$m=256,t=2,p=1$c29tZXNhbHQ$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/4\x00foo",
31
+ "password"
32
+ )
33
+ end
34
+ end
35
+ end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: argon2id
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.0
5
+ platform: java
6
+ authors:
7
+ - Paul Mucur
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-11-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '1.2'
19
+ name: rake-compiler
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.2'
27
+ - !ruby/object:Gem::Dependency
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '1.5'
33
+ name: rake-compiler-dock
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.5'
41
+ - !ruby/object:Gem::Dependency
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '5.25'
47
+ name: minitest
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
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.
57
+ email:
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - CHANGELOG.md
63
+ - Gemfile
64
+ - LICENSE
65
+ - README.md
66
+ - Rakefile
67
+ - argon2id.gemspec
68
+ - lib/argon2id.rb
69
+ - lib/argon2id/password.rb
70
+ - lib/argon2id/version.rb
71
+ - test/test_hash_encoded.rb
72
+ - test/test_password.rb
73
+ - test/test_verify.rb
74
+ homepage: https://github.com/mudge/argon2id
75
+ licenses:
76
+ - BSD-3-Clause
77
+ metadata:
78
+ bug_tracker_uri: https://github.com/mudge/argon2id/issues
79
+ changelog_uri: https://github.com/mudge/argon2id/blob/main/CHANGELOG.md
80
+ funding_uri: https://github.com/sponsors/mudge
81
+ homepage_uri: https://github.com/mudge/argon2id
82
+ source_code_uri: https://github.com/mudge/argon2id
83
+ rubygems_mfa_required: 'true'
84
+ post_install_message:
85
+ rdoc_options:
86
+ - "--main"
87
+ - README.md
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: 3.1.0
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ requirements: []
101
+ rubygems_version: 3.3.25
102
+ signing_key:
103
+ specification_version: 4
104
+ summary: Ruby bindings to Argon2
105
+ test_files: []