argon2id 0.1.0

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: 1d82db47aaab5dae5c5123f1a7e333256d736be27a93ba3817b9b569501d5ef1
4
+ data.tar.gz: 0dad93f3f34a8c3bc592b5b839aeecdf4975cf42c93f6690cfdb5bbb033be2b4
5
+ SHA512:
6
+ metadata.gz: 3fb64986c811e4fa6f510d73475184305f23a233e6f9486cbd10e1bdd8d8f24e59b755fb71cd67eb4edadb22122d0313c815f789e6d86cd14b5e99ab57e0ef6d
7
+ data.tar.gz: b0b406c29495e2c8f5b79bc6ffe30cfbae4fc4bb889005159b07f7e148d09f20d0ad88044e699f0b0553b40849d5abf702f576d2e496e856126ad461f306e0f9
data/CHANGELOG.md ADDED
@@ -0,0 +1,16 @@
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.1.0] - 2024-10-31
9
+
10
+ ### Added
11
+
12
+ - The initial version of the Argon2id gem, providing Ruby bindings to the
13
+ reference C implementation of Argon2, the password-hashing function that won
14
+ the Password Hashing Competition.
15
+
16
+ [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,248 @@
1
+ # Argon2id - Ruby bindings to the award-winning 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.1.0
9
+ **Bundled Argon2 version:** libargon2.1 (20190702)
10
+
11
+ ```ruby
12
+ Argon2::Password.create("opensesame").to_s
13
+ #=> "$argon2id$v=19$m=19456,t=2,p=1$ZS2nBFWBpnt28HjtzNOW4w$SQ+p+dIcWbpzWpZQ/ZZFj8IQkyhYZf127U4QdkRmKFU"
14
+ Argon2::Password.create("opensesame") == "opensesame" #=> true
15
+ Argon2::Password.create("opensesame") == "notopensesame" #=> false
16
+ ```
17
+
18
+ ## Table of contents
19
+
20
+ * [Why Argon2id?](#why-argon2id)
21
+ * [Usage](#usage)
22
+ * [Hashing passwords](#hashing-passwords)
23
+ * [Verifying passwords](#verifying-passwords)
24
+ * [Errors](#errors)
25
+ * [Requirements](#requirements)
26
+ * [Native gems](#native-gems)
27
+ * [Verifying the gems](#verifying-the-gems)
28
+ * [Installing the `ruby` platform gem](#installing-the-ruby-platform-gem)
29
+ * [Thanks](#thanks)
30
+ * [Contact](#contact)
31
+ * [License](#license)
32
+ * [Dependencies](#dependencies)
33
+
34
+ ## Why Argon2id?
35
+
36
+ > Argon2 is a password-hashing function that summarizes the state of the art in
37
+ > the design of memory-hard functions and can be used to hash passwords for
38
+ > credential storage, key derivation, or other applications.
39
+ >
40
+ > It has a simple design aimed at the highest memory filling rate and effective
41
+ > use of multiple computing units, while still providing defense against
42
+ > tradeoff attacks (by exploiting the cache and memory organization of the
43
+ > recent processors).
44
+
45
+ — [Argon2][]
46
+
47
+ > Argon2 was the winner of the 2015 Password Hashing Competition. Out of the
48
+ > three Argon2 versions, use the Argon2id variant since it provides a balanced
49
+ > approach to resisting both side-channel and GPU-based attacks.
50
+
51
+ — [OWASP Password Storage Cheat Sheet][]
52
+
53
+ ## Usage
54
+
55
+ Install argon2id as a dependency:
56
+
57
+ ```ruby
58
+ # In your Gemfile
59
+ gem "argon2id"
60
+
61
+ # Or without Bundler
62
+ gem install argon2id
63
+ ```
64
+
65
+ Include in your code:
66
+
67
+ ```ruby
68
+ require "argon2id"
69
+ ```
70
+
71
+ ### Hashing passwords
72
+
73
+ Hash a plain text password (e.g. from user input) with
74
+ `Argon2id::Password.create`:
75
+
76
+ ```ruby
77
+ password = Argon2id::Password.create("opensesame")
78
+ ```
79
+
80
+ The encoded value of the resulting hash is available via
81
+ `Argon2id::Password#to_s` (ideal for persisting somewhere):
82
+
83
+ ```ruby
84
+ password.to_s
85
+ #=> "$argon2id$v=19$m=19456,t=2,p=1$ZS2nBFWBpnt28HjtzNOW4w$SQ+p+dIcWbpzWpZQ/ZZFj8IQkyhYZf127U4QdkRmKFU"
86
+ ```
87
+
88
+ By default, `Argon2id::Password.create` will use the second set of parameters
89
+ recommended by [OWASP][OWASP Password Storage Cheat Sheet] but these can be
90
+ overridden by passing keyword arguments to `Argon2id::Password.create`:
91
+
92
+ * `t_cost`: the "time cost" given as a number of iterations (defaults to 2)
93
+ * `m_cost`: the "memory cost" given in kibibytes (defaults to 19 mebibytes)
94
+ * `parallelism`: the number of threads and compute lanes to use (defaults to 1)
95
+ * `salt_len`: the salt size in bytes (defaults to 16)
96
+ * `output_len`: the desired length of the hash in bytes (defaults to 32)
97
+
98
+ ```ruby
99
+ password = Argon2id::Password.create("opensesame", t_cost: 3, m_cost: 12288)
100
+ password.to_s
101
+ #=> "$argon2id$v=19$m=12288,t=3,p=1$uukIsLS6y6etvsgoN20kVg$exMvDX/P9exvEPmnZL2gZClRyMdrnqjqyysLMP/VUWA"
102
+ ```
103
+
104
+ If you want to override the parameters for all calls to
105
+ `Argon2id::Password.create`, you can set them on `Argon2id` directly:
106
+
107
+ ```ruby
108
+ Argon2id.t_cost = 3
109
+ Argon2id.m_cost = 12288
110
+ Argon2id.parallelism = 1
111
+ Argon2id.salt_len = 16
112
+ Argon2id.output_len = 32
113
+ ```
114
+
115
+ ### Verifying passwords
116
+
117
+ To verify a password against a hash, use `Argon2id::Password#==`:
118
+
119
+ ```ruby
120
+ password = Argon2id::Password.create("opensesame")
121
+ password == "opensesame" #=> true
122
+ password == "notopensesame" #=> false
123
+ ```
124
+
125
+ Or, if you only have the hash (e.g. retrieved from storage):
126
+
127
+ ```ruby
128
+ password = Argon2id::Password.new("$argon2id$v=19$m=19456,t=2,p=1$ZS2nBFWBpnt28HjtzNOW4w$SQ+p+dIcWbpzWpZQ/ZZFj8IQkyhYZf127U4QdkRmKFU")
129
+ password == "opensesame" #=> true
130
+ password == "notopensesame" #=> false
131
+ ```
132
+
133
+ For compatibility with [bcrypt-ruby][], `Argon2id::Password#==` is aliased to `Argon2id::Password.is_password?`:
134
+
135
+ ```ruby
136
+ password = Argon2id::Password.new("$argon2id$v=19$m=19456,t=2,p=1$ZS2nBFWBpnt28HjtzNOW4w$SQ+p+dIcWbpzWpZQ/ZZFj8IQkyhYZf127U4QdkRmKFU")
137
+ password.is_password?("opensesame") #=> true
138
+ password.is_password?("notopensesame") #=> false
139
+ ```
140
+
141
+ ### Errors
142
+
143
+ Any errors returned from Argon2 will be raised as `Argon2id::Error`, e.g.
144
+
145
+ ```ruby
146
+ password = Argon2id::Password.new("not a valid hash encoding")
147
+ password == "opensesame"
148
+ # Decoding failed (Argon2id::Error)
149
+ ```
150
+
151
+ ## Requirements
152
+
153
+ This gem requires the following to run:
154
+
155
+ * [Ruby](https://www.ruby-lang.org/en/) 2.6 to 3.3
156
+
157
+ ### Native gems
158
+
159
+ SHA256 checksums are included in the [release
160
+ notes](https://github.com/mudge/argon2id/releases) for each version and can be
161
+ checked with `sha256sum`, e.g.
162
+
163
+ ```console
164
+ $ gem fetch argon2id -v 0.1.0
165
+ Fetching argon2id-0.1.0-arm64-darwin.gem
166
+ Downloaded argon2id-0.1.0-arm64-darwin
167
+ $ sha256sum argon2id-0.1.0-arm64-darwin.gem
168
+ e71e4acaa5cae6ca763bc078bde121fb76ea07bad72bc471c9efd2ba444be604 argon2id-0.1.0-arm64-darwin.gem
169
+ ```
170
+
171
+ [GPG](https://www.gnupg.org/) signatures are attached to each release (the
172
+ assets ending in `.sig`) and can be verified if you import [our signing key
173
+ `0x39AC3530070E0F75`](https://mudge.name/39AC3530070E0F75.asc) (or fetch it
174
+ from a public keyserver, e.g. `gpg --keyserver keyserver.ubuntu.com --recv-key
175
+ 0x39AC3530070E0F75`):
176
+
177
+ ```console
178
+ $ gpg --verify argon2id-0.1.0-arm64-darwin.gem.sig argon2id-0.1.0-arm64-darwin.gem
179
+ gpg: Signature made Thu 31 Oct 11:16:18 2024 BST
180
+ gpg: using RSA key 702609D9C790F45B577D7BEC39AC3530070E0F75
181
+ gpg: Good signature from "Paul Mucur <mudge@mudge.name>" [unknown]
182
+ gpg: aka "Paul Mucur <paul@ghostcassette.com>" [unknown]
183
+ gpg: WARNING: This key is not certified with a trusted signature!
184
+ gpg: There is no indication that the signature belongs to the owner.
185
+ Primary key fingerprint: 7026 09D9 C790 F45B 577D 7BEC 39AC 3530 070E 0F75
186
+ ```
187
+
188
+ The fingerprint should be as shown above or you can independently verify it
189
+ with the ones shown in the footer of https://mudge.name.
190
+
191
+ ### Installing the `ruby` platform gem
192
+
193
+ > [!WARNING]
194
+ > We strongly recommend using the native gems where possible to avoid the need
195
+ > for compiling the C extension and its dependencies which will take longer and
196
+ > be less reliable.
197
+
198
+ If you wish to compile the gem, you will need to explicitly install the `ruby` platform gem:
199
+
200
+ ```ruby
201
+ # In your Gemfile with Bundler 2.3.18+
202
+ gem "argon2id", force_ruby_platform: true
203
+
204
+ # With Bundler 2.1+
205
+ bundle config set force_ruby_platform true
206
+
207
+ # With older versions of Bundler
208
+ bundle config force_ruby_platform true
209
+
210
+ # Without Bundler
211
+ gem install argon2id --platform=ruby
212
+ ```
213
+
214
+ You will need a full compiler toolchain for compiling Ruby C extensions (see
215
+ [Nokogiri's "The Compiler
216
+ Toolchain"](https://nokogiri.org/tutorials/installing_nokogiri.html#appendix-a-the-compiler-toolchain))
217
+ plus the toolchain required for compiling the vendored version of Argon2.
218
+
219
+ ## Thanks
220
+
221
+ * Thanks to [Mike Dalessio](https://github.com/flavorjones) for his advice and
222
+ [Ruby C Extensions Explained](https://github.com/flavorjones/ruby-c-extensions-explained)
223
+ project
224
+
225
+ ## Contact
226
+
227
+ All issues and suggestions should go to [GitHub
228
+ Issues](https://github.com/mudge/argon2id/issues).
229
+
230
+ ## License
231
+
232
+ This library is licensed under the BSD 3-Clause License, see `LICENSE.txt`.
233
+
234
+ Copyright © 2024, Paul Mucur.
235
+
236
+ ### Dependencies
237
+
238
+ The source code of [Argon2][] is distributed in the gem. This code is copyright
239
+ © 2015 Daniel Dinu, Dmitry Khovratovich (main authors), Jean-Philippe Aumasson
240
+ and Samuel Neves, and dual licensed under the [CC0 License][] and the [Apache
241
+ 2.0 License][].
242
+
243
+ [Argon2]: https://github.com/P-H-C/phc-winner-argon2/
244
+ [OWASP Password Storage Cheat Sheet]: https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#argon2id
245
+ [bcrypt-ruby]: https://github.com/bcrypt-ruby/bcrypt-ruby
246
+ [CC0 License]: https://creativecommons.org/about/cc0
247
+ [Apache 2.0 License]: https://www.apache.org/licenses/LICENSE-2.0
248
+ [Password Hashing Competition]: https://www.password-hashing.net
data/Rakefile ADDED
@@ -0,0 +1,57 @@
1
+ require "rake/extensiontask"
2
+ require "rake_compiler_dock"
3
+ require "rake/testtask"
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
+ Gem::PackageTask.new(gemspec).define
24
+
25
+ Rake::ExtensionTask.new("argon2id", gemspec) do |e|
26
+ e.cross_compile = true
27
+ e.cross_platform = cross_platforms
28
+ end
29
+
30
+ Rake::TestTask.new do |t|
31
+ t.warning = true
32
+ end
33
+
34
+ begin
35
+ require "ruby_memcheck"
36
+
37
+ namespace :test do
38
+ RubyMemcheck::TestTask.new(valgrind: :compile)
39
+ end
40
+ rescue LoadError
41
+ # Only define the test:valgrind task if ruby_memcheck is installed
42
+ end
43
+
44
+ namespace :gem do
45
+ cross_platforms.each do |platform|
46
+ desc "Compile and build native gem for #{platform}"
47
+ task platform do
48
+ RakeCompilerDock.sh <<~SCRIPT, platform: platform, verbose: true
49
+ gem install bundler --no-document &&
50
+ bundle &&
51
+ bundle exec rake native:#{platform} pkg/#{gemspec.full_name}-#{Gem::Platform.new(platform)}.gem PATH="/usr/local/bin:$PATH"
52
+ SCRIPT
53
+ end
54
+ end
55
+ end
56
+
57
+ task default: [:compile, :test]
data/argon2id.gemspec ADDED
@@ -0,0 +1,58 @@
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
+
55
+ s.add_development_dependency("rake-compiler", "~> 1.2")
56
+ s.add_development_dependency("rake-compiler-dock", "~> 1.5")
57
+ s.add_development_dependency("minitest", "~> 5.25")
58
+ end
@@ -0,0 +1,69 @@
1
+ #include <ruby.h>
2
+ #include <stdint.h>
3
+
4
+ #include "argon2.h"
5
+
6
+ #define UNUSED(x) (void)(x)
7
+
8
+ VALUE mArgon2id, cArgon2idError;
9
+
10
+ static VALUE
11
+ rb_argon2id_hash_encoded(VALUE module, VALUE iterations, VALUE memory, VALUE threads, VALUE pwd, VALUE salt, VALUE hashlen)
12
+ {
13
+ uint32_t t_cost, m_cost, parallelism;
14
+ size_t encodedlen, outlen;
15
+ char * encoded;
16
+ int result;
17
+ VALUE hash;
18
+
19
+ UNUSED(module);
20
+
21
+ t_cost = FIX2INT(iterations);
22
+ m_cost = FIX2INT(memory);
23
+ parallelism = FIX2INT(threads);
24
+ outlen = FIX2INT(hashlen);
25
+
26
+ encodedlen = argon2_encodedlen(t_cost, m_cost, parallelism, (uint32_t)RSTRING_LEN(salt), (uint32_t)outlen, Argon2_id);
27
+ encoded = malloc(encodedlen + 1);
28
+ if (!encoded) {
29
+ rb_raise(rb_eNoMemError, "not enough memory to allocate for encoded password");
30
+ }
31
+
32
+ result = argon2id_hash_encoded(t_cost, m_cost, parallelism, StringValuePtr(pwd), RSTRING_LEN(pwd), StringValuePtr(salt), RSTRING_LEN(salt), outlen, encoded, encodedlen);
33
+
34
+ if (result != ARGON2_OK) {
35
+ free(encoded);
36
+ rb_raise(cArgon2idError, "%s", argon2_error_message(result));
37
+ }
38
+
39
+ hash = rb_str_new(encoded, strlen(encoded));
40
+ free(encoded);
41
+
42
+ return hash;
43
+ }
44
+
45
+ static VALUE
46
+ rb_argon2id_verify(VALUE module, VALUE encoded, VALUE pwd) {
47
+ int result;
48
+
49
+ UNUSED(module);
50
+
51
+ result = argon2id_verify(StringValuePtr(encoded), StringValuePtr(pwd), RSTRING_LEN(pwd));
52
+ if (result == ARGON2_OK) {
53
+ return Qtrue;
54
+ }
55
+ if (result == ARGON2_VERIFY_MISMATCH) {
56
+ return Qfalse;
57
+ }
58
+
59
+ rb_raise(cArgon2idError, "%s", argon2_error_message(result));
60
+ }
61
+
62
+ void
63
+ Init_argon2id(void)
64
+ {
65
+ mArgon2id = rb_define_module("Argon2id");
66
+ cArgon2idError = rb_define_class_under(mArgon2id, "Error", rb_eStandardError);
67
+ rb_define_singleton_method(mArgon2id, "hash_encoded", rb_argon2id_hash_encoded, 6);
68
+ rb_define_singleton_method(mArgon2id, "verify", rb_argon2id_verify, 2);
69
+ }
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mkmf"
4
+
5
+ $CFLAGS << " -Wextra"
6
+
7
+ $VPATH << "$(srcdir)/libargon2"
8
+ $VPATH << "$(srcdir)/libargon2/blake2"
9
+
10
+ $srcs = Dir.glob("#{$srcdir}/{,libargon2/,libargon2/blake2/}*.c").map { |n| File.basename(n) }.sort
11
+
12
+ $CPPFLAGS << " " << "-I$(srcdir)/libargon2"
13
+
14
+ have_header("stdint.h")
15
+ have_header("argon2.h")
16
+
17
+ create_makefile "argon2id"