sorcery-argon2 1.0.0
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 +7 -0
- data/.document +1 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +37 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +22 -0
- data/.github/ISSUE_TEMPLATE/need_help.md +24 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +5 -0
- data/.github/workflows/ruby.yml +66 -0
- data/.gitignore +68 -0
- data/.gitmodules +4 -0
- data/.rubocop.yml +208 -0
- data/CHANGELOG.md +20 -0
- data/CODE_OF_CONDUCT.md +14 -0
- data/Gemfile +6 -0
- data/LICENSE.md +23 -0
- data/MAINTAINING.md +65 -0
- data/README.md +164 -0
- data/Rakefile +16 -0
- data/SECURITY.md +17 -0
- data/bin/console +15 -0
- data/bin/setup +11 -0
- data/bin/test +10 -0
- data/ext/argon2_wrap/Makefile +74 -0
- data/ext/argon2_wrap/argon_wrap.c +167 -0
- data/ext/argon2_wrap/extconf.rb +2 -0
- data/ext/argon2_wrap/test.c +117 -0
- data/lib/argon2.rb +17 -0
- data/lib/argon2/constants.rb +12 -0
- data/lib/argon2/engine.rb +18 -0
- data/lib/argon2/errors.rb +121 -0
- data/lib/argon2/ffi_engine.rb +114 -0
- data/lib/argon2/password.rb +220 -0
- data/lib/argon2/version.rb +8 -0
- data/sorcery-argon2.gemspec +51 -0
- metadata +191 -0
@@ -0,0 +1,114 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'ffi'
|
4
|
+
require 'ffi-compiler/loader'
|
5
|
+
|
6
|
+
module Argon2
|
7
|
+
##
|
8
|
+
# Direct external bindings. Call these methods via the Engine class to ensure
|
9
|
+
# points are dealt with.
|
10
|
+
#
|
11
|
+
module Ext
|
12
|
+
extend FFI::Library
|
13
|
+
ffi_lib FFI::Compiler::Loader.find(FFI::Platform.windows? ? 'libargon2_wrap' : 'argon2_wrap')
|
14
|
+
|
15
|
+
# int argon2i_hash_raw(const uint32_t t_cost, const uint32_t m_cost,
|
16
|
+
# const uint32_t parallelism, const void *pwd,
|
17
|
+
# const size_t pwdlen, const void *salt,
|
18
|
+
# const size_t saltlen, void *hash, const size_t hashlen);
|
19
|
+
|
20
|
+
attach_function :argon2i_hash_raw, %i[
|
21
|
+
uint uint uint pointer
|
22
|
+
size_t pointer size_t pointer size_t
|
23
|
+
], :int, :blocking => true
|
24
|
+
|
25
|
+
# int argon2id_hash_raw(const uint32_t t_cost, const uint32_t m_cost,
|
26
|
+
# const uint32_t parallelism, const void *pwd,
|
27
|
+
# const size_t pwdlen, const void *salt,
|
28
|
+
# const size_t saltlen, void *hash, const size_t hashlen)
|
29
|
+
attach_function :argon2id_hash_raw, %i[
|
30
|
+
uint uint uint pointer
|
31
|
+
size_t pointer size_t pointer size_t
|
32
|
+
], :int, :blocking => true
|
33
|
+
|
34
|
+
# void argon2_wrap(uint8_t *out, char *pwd, size_t pwdlen,
|
35
|
+
# uint8_t *salt, uint32_t saltlen, uint32_t t_cost,
|
36
|
+
# uint32_t m_cost, uint32_t lanes,
|
37
|
+
# uint8_t *secret, uint32_t secretlen)
|
38
|
+
attach_function :argon2_wrap, %i[
|
39
|
+
pointer pointer size_t pointer uint uint
|
40
|
+
uint uint pointer size_t
|
41
|
+
], :int, :blocking => true
|
42
|
+
|
43
|
+
# int argon2i_verify(const char *encoded, const void *pwd,
|
44
|
+
# const size_t pwdlen);
|
45
|
+
attach_function :wrap_argon2_verify, %i[pointer pointer size_t
|
46
|
+
pointer size_t], :int, :blocking => true
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# The engine class shields users from the FFI interface.
|
51
|
+
# It is generally not advised to directly use this class.
|
52
|
+
#
|
53
|
+
class Engine
|
54
|
+
def self.hash_argon2i(password, salt, t_cost, m_cost, out_len = nil)
|
55
|
+
out_len = (out_len || Constants::OUT_LEN).to_i
|
56
|
+
raise ::Argon2::Errors::InvalidOutputLength if out_len < 1
|
57
|
+
|
58
|
+
result = ''
|
59
|
+
FFI::MemoryPointer.new(:char, out_len) do |buffer|
|
60
|
+
ret = Ext.argon2i_hash_raw(t_cost, 1 << m_cost, 1, password,
|
61
|
+
password.length, salt, salt.length,
|
62
|
+
buffer, out_len)
|
63
|
+
raise ::Argon2::Errors::ExtError, ERRORS[ret.abs] unless ret.zero?
|
64
|
+
|
65
|
+
result = buffer.read_string(out_len)
|
66
|
+
end
|
67
|
+
result.unpack('H*').join
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.hash_argon2id(password, salt, t_cost, m_cost, out_len = nil)
|
71
|
+
out_len = (out_len || Constants::OUT_LEN).to_i
|
72
|
+
raise ::Argon2::Errors::InvalidOutputLength if out_len < 1
|
73
|
+
|
74
|
+
result = ''
|
75
|
+
FFI::MemoryPointer.new(:char, out_len) do |buffer|
|
76
|
+
ret = Ext.argon2id_hash_raw(t_cost, 1 << m_cost, 1, password,
|
77
|
+
password.length, salt, salt.length,
|
78
|
+
buffer, out_len)
|
79
|
+
raise ::Argon2::Errors::ExtError, ERRORS[ret.abs] unless ret.zero?
|
80
|
+
|
81
|
+
result = buffer.read_string(out_len)
|
82
|
+
end
|
83
|
+
result.unpack('H*').join
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.hash_argon2id_encode(password, salt, t_cost, m_cost, secret)
|
87
|
+
result = ''
|
88
|
+
secretlen = secret.nil? ? 0 : secret.bytesize
|
89
|
+
passwordlen = password.nil? ? 0 : password.bytesize
|
90
|
+
raise ::Argon2::Errors::InvalidSaltSize if salt.length != Constants::SALT_LEN
|
91
|
+
|
92
|
+
FFI::MemoryPointer.new(:char, Constants::ENCODE_LEN) do |buffer|
|
93
|
+
ret = Ext.argon2_wrap(buffer, password, passwordlen,
|
94
|
+
salt, salt.length, t_cost, (1 << m_cost),
|
95
|
+
1, secret, secretlen)
|
96
|
+
raise ::Argon2::Errors::ExtError, ERRORS[ret.abs] unless ret.zero?
|
97
|
+
|
98
|
+
result = buffer.read_string(Constants::ENCODE_LEN)
|
99
|
+
end
|
100
|
+
result.delete "\0"
|
101
|
+
end
|
102
|
+
|
103
|
+
def self.argon2_verify(pwd, hash, secret)
|
104
|
+
secretlen = secret.nil? ? 0 : secret.bytesize
|
105
|
+
passwordlen = pwd.nil? ? 0 : pwd.bytesize
|
106
|
+
|
107
|
+
ret = Ext.wrap_argon2_verify(hash, pwd, passwordlen, secret, secretlen)
|
108
|
+
return false if ERRORS[ret.abs] == 'ARGON2_DECODING_FAIL'
|
109
|
+
raise ::Argon2::Errors::ExtError, ERRORS[ret.abs] unless ret.zero?
|
110
|
+
|
111
|
+
true
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,220 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Argon2
|
4
|
+
##
|
5
|
+
# Front-end API for the Argon2 module.
|
6
|
+
#
|
7
|
+
class Password
|
8
|
+
# Used as the default time cost if one isn't provided when calling
|
9
|
+
# Argon2::Password.create
|
10
|
+
DEFAULT_T_COST = 2
|
11
|
+
# Used to validate the minimum acceptable time cost
|
12
|
+
MIN_T_COST = 1
|
13
|
+
# Used to validate the maximum acceptable time cost
|
14
|
+
MAX_T_COST = 750
|
15
|
+
# Used as the default memory cost if one isn't provided when calling
|
16
|
+
# Argon2::Password.create
|
17
|
+
DEFAULT_M_COST = 16
|
18
|
+
# Used to validate the minimum acceptable memory cost
|
19
|
+
MIN_M_COST = 3
|
20
|
+
# Used to validate the maximum acceptable memory cost
|
21
|
+
MAX_M_COST = 31
|
22
|
+
# The complete Argon2 digest string (not to be confused with the checksum).
|
23
|
+
attr_reader :digest
|
24
|
+
# The hash portion of the stored password hash.
|
25
|
+
attr_reader :checksum
|
26
|
+
# The salt of the stored password hash.
|
27
|
+
attr_reader :salt
|
28
|
+
# Variant used (argon2i / argon2d / argon2id)
|
29
|
+
attr_reader :variant
|
30
|
+
# The version of the argon2 algorithm used to create the hash.
|
31
|
+
attr_reader :version
|
32
|
+
# The time cost factor used to create the hash.
|
33
|
+
attr_reader :t_cost
|
34
|
+
# The memory cost factor used to create the hash.
|
35
|
+
attr_reader :m_cost
|
36
|
+
# The parallelism cost factor used to create the hash.
|
37
|
+
attr_reader :p_cost
|
38
|
+
|
39
|
+
##
|
40
|
+
# Class methods
|
41
|
+
#
|
42
|
+
class << self
|
43
|
+
##
|
44
|
+
# Takes a user provided password and returns an Argon2::Password instance
|
45
|
+
# with the resulting Argon2 hash.
|
46
|
+
#
|
47
|
+
# Usage:
|
48
|
+
#
|
49
|
+
# Argon2::Password.create(password)
|
50
|
+
# Argon2::Password.create(password, t_cost: 4, m_cost: 20)
|
51
|
+
# Argon2::Password.create(password, secret: pepper)
|
52
|
+
# Argon2::Password.create(password, m_cost: 17, secret: pepper)
|
53
|
+
#
|
54
|
+
# Currently available options:
|
55
|
+
#
|
56
|
+
# * :t_cost
|
57
|
+
# * :m_cost
|
58
|
+
# * :secret
|
59
|
+
#
|
60
|
+
def create(password, options = {})
|
61
|
+
raise Argon2::Errors::InvalidPassword unless password.is_a?(String)
|
62
|
+
|
63
|
+
t_cost = options[:t_cost] || DEFAULT_T_COST
|
64
|
+
m_cost = options[:m_cost] || DEFAULT_M_COST
|
65
|
+
|
66
|
+
raise Argon2::Errors::InvalidTCost if t_cost < MIN_T_COST || t_cost > MAX_T_COST
|
67
|
+
raise Argon2::Errors::InvalidMCost if m_cost < MIN_M_COST || m_cost > MAX_M_COST
|
68
|
+
|
69
|
+
# TODO: Add support for changing the p_cost
|
70
|
+
|
71
|
+
salt = Engine.saltgen
|
72
|
+
secret = options[:secret]
|
73
|
+
|
74
|
+
Argon2::Password.new(
|
75
|
+
Argon2::Engine.hash_argon2id_encode(
|
76
|
+
password, salt, t_cost, m_cost, secret
|
77
|
+
)
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
81
|
+
##
|
82
|
+
# Regex to validate if the provided String is a valid Argon2 hash output.
|
83
|
+
#
|
84
|
+
# Supports 1 and argon2id formats.
|
85
|
+
#
|
86
|
+
def valid_hash?(digest)
|
87
|
+
/^\$argon2(id?|d).{,113}/ =~ digest
|
88
|
+
end
|
89
|
+
|
90
|
+
##
|
91
|
+
# Takes a password, Argon2 hash, and optionally a secret, then uses the
|
92
|
+
# Argon2 C Library to verify if they match.
|
93
|
+
#
|
94
|
+
# Also accepts passing another Argon2::Password instance as the password,
|
95
|
+
# in which case it will compare the final Argon2 hash for each against
|
96
|
+
# each other.
|
97
|
+
#
|
98
|
+
# Usage:
|
99
|
+
#
|
100
|
+
# Argon2::Password.verify_password(password, argon2_hash)
|
101
|
+
# Argon2::Password.verify_password(password, argon2_hash, secret)
|
102
|
+
#
|
103
|
+
def verify_password(password, digest, secret = nil)
|
104
|
+
digest = digest.to_s
|
105
|
+
if password.is_a?(Argon2::Password)
|
106
|
+
password == Argon2::Password.new(digest)
|
107
|
+
else
|
108
|
+
Argon2::Engine.argon2_verify(password, digest, secret)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
######################
|
114
|
+
## Instance Methods ##
|
115
|
+
######################
|
116
|
+
|
117
|
+
##
|
118
|
+
# Initialize an Argon2::Password instance using any valid Argon2 digest.
|
119
|
+
#
|
120
|
+
def initialize(digest)
|
121
|
+
digest = digest.to_s
|
122
|
+
|
123
|
+
raise Argon2::Errors::InvalidHash unless valid_hash?(digest)
|
124
|
+
|
125
|
+
# Split the digest into its component pieces
|
126
|
+
split_digest = split_hash(digest)
|
127
|
+
# Assign each piece to the Argon2::Password instance
|
128
|
+
@digest = digest
|
129
|
+
@variant = split_digest[:variant]
|
130
|
+
@version = split_digest[:version]
|
131
|
+
@t_cost = split_digest[:t_cost]
|
132
|
+
@m_cost = split_digest[:m_cost]
|
133
|
+
@p_cost = split_digest[:p_cost]
|
134
|
+
@salt = split_digest[:salt]
|
135
|
+
@checksum = split_digest[:checksum]
|
136
|
+
end
|
137
|
+
|
138
|
+
##
|
139
|
+
# Helper function to allow easily comparing an Argon2::Password against the
|
140
|
+
# provided password and secret.
|
141
|
+
#
|
142
|
+
def matches?(password, secret = nil)
|
143
|
+
self.class.verify_password(password, digest, secret)
|
144
|
+
end
|
145
|
+
|
146
|
+
##
|
147
|
+
# Compares two Argon2::Password instances to see if they come from the same
|
148
|
+
# digest/hash.
|
149
|
+
#
|
150
|
+
def ==(other)
|
151
|
+
# TODO: Should this return false instead of raising an error?
|
152
|
+
unless other.is_a?(Argon2::Password)
|
153
|
+
raise ArgumentError,
|
154
|
+
'Can only compare an Argon2::Password against another Argon2::Password'
|
155
|
+
end
|
156
|
+
|
157
|
+
digest == other.digest
|
158
|
+
end
|
159
|
+
|
160
|
+
##
|
161
|
+
# Converts an Argon2::Password instance into a String.
|
162
|
+
#
|
163
|
+
def to_s
|
164
|
+
digest.to_s
|
165
|
+
end
|
166
|
+
|
167
|
+
##
|
168
|
+
# Converts an Argon2::Password instance into a String.
|
169
|
+
#
|
170
|
+
def to_str
|
171
|
+
digest.to_str
|
172
|
+
end
|
173
|
+
|
174
|
+
private
|
175
|
+
|
176
|
+
##
|
177
|
+
# Helper method to allow checking if a hash is valid in the initializer.
|
178
|
+
#
|
179
|
+
def valid_hash?(digest)
|
180
|
+
self.class.valid_hash?(digest)
|
181
|
+
end
|
182
|
+
|
183
|
+
# FIXME: Reduce complexity/AbcSize
|
184
|
+
# rubocop:disable Metrics/AbcSize
|
185
|
+
|
186
|
+
##
|
187
|
+
# Helper method to extract the various values from a digest into attributes.
|
188
|
+
#
|
189
|
+
def split_hash(digest)
|
190
|
+
# TODO: Is there a better way to explode the digest into attributes?
|
191
|
+
_, variant, version, config, salt, checksum = digest.split('$')
|
192
|
+
# Regex magic to extract the values for each setting
|
193
|
+
version = /v=(\d+)/.match(version)
|
194
|
+
t_cost = /t=(\d+),/.match(config)
|
195
|
+
m_cost = /m=(\d+),/.match(config)
|
196
|
+
p_cost = /p=(\d+)/.match(config)
|
197
|
+
|
198
|
+
# Make sure none of the values are missing
|
199
|
+
raise Argon2::Errors::InvalidVersion if version.nil?
|
200
|
+
raise Argon2::Errors::InvalidTCost if t_cost.nil?
|
201
|
+
raise Argon2::Errors::InvalidMCost if m_cost.nil?
|
202
|
+
raise Argon2::Errors::InvalidPCost if p_cost.nil?
|
203
|
+
|
204
|
+
# Undo the 2^m_cost operation when encoding the hash to get the original
|
205
|
+
# m_cost input back.
|
206
|
+
m_cost = Math.log2(m_cost[1].to_i).to_i
|
207
|
+
|
208
|
+
{
|
209
|
+
variant: variant.to_str,
|
210
|
+
version: version[1].to_i,
|
211
|
+
t_cost: t_cost[1].to_i,
|
212
|
+
m_cost: m_cost,
|
213
|
+
p_cost: p_cost[1].to_i,
|
214
|
+
salt: salt.to_str,
|
215
|
+
checksum: checksum.to_str
|
216
|
+
}
|
217
|
+
end
|
218
|
+
# rubocop:enable Metrics/AbcSize
|
219
|
+
end
|
220
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'argon2/version'
|
6
|
+
|
7
|
+
version = Argon2::VERSION
|
8
|
+
repo_url = 'https://github.com/sorcery/argon2'
|
9
|
+
|
10
|
+
Gem::Specification.new do |s|
|
11
|
+
s.version = version
|
12
|
+
s.platform = Gem::Platform::RUBY
|
13
|
+
s.name = 'sorcery-argon2'
|
14
|
+
s.summary = 'A Ruby wrapper for the Argon2 Password hashing algorithm'
|
15
|
+
s.description =
|
16
|
+
'Provides a minimal ruby wrapper for the Argon2 password hashing algorithm.'
|
17
|
+
|
18
|
+
s.required_ruby_version = '>= 2.5.0'
|
19
|
+
|
20
|
+
s.license = 'MIT'
|
21
|
+
s.author = 'Josh Buker'
|
22
|
+
s.email = 'crypto@joshbuker.com'
|
23
|
+
s.homepage = repo_url
|
24
|
+
s.metadata = {
|
25
|
+
'bug_tracker_uri' => "#{repo_url}/issues",
|
26
|
+
'changelog_uri' => "#{repo_url}/releases/tag/v#{version}",
|
27
|
+
'documentation_uri' => 'https://rubydoc.info/gems/sorcery-argon2',
|
28
|
+
'source_code_uri' => "#{repo_url}/tree/v#{version}"
|
29
|
+
}
|
30
|
+
|
31
|
+
s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
32
|
+
s.files << `find ext`.split
|
33
|
+
|
34
|
+
s.bindir = 'exe'
|
35
|
+
s.executables = s.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
36
|
+
s.require_paths = ['lib']
|
37
|
+
|
38
|
+
s.add_dependency 'ffi', '~> 1.14'
|
39
|
+
s.add_dependency 'ffi-compiler', '~> 1.0'
|
40
|
+
|
41
|
+
# Gems required for testing the wrapper locally.
|
42
|
+
s.add_development_dependency 'bundler', '~> 2.0'
|
43
|
+
s.add_development_dependency 'minitest', '~> 5.8'
|
44
|
+
s.add_development_dependency 'rake', '~> 13.0.1'
|
45
|
+
s.add_development_dependency 'rubocop', '~> 1.7'
|
46
|
+
s.add_development_dependency 'simplecov', '~> 0.20'
|
47
|
+
s.add_development_dependency 'simplecov-lcov', '~> 0.8'
|
48
|
+
|
49
|
+
# Argon2 C Extension
|
50
|
+
s.extensions << 'ext/argon2_wrap/extconf.rb'
|
51
|
+
end
|
metadata
ADDED
@@ -0,0 +1,191 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sorcery-argon2
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Josh Buker
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-04-09 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ffi
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.14'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.14'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: ffi-compiler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '2.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '2.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: minitest
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '5.8'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '5.8'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 13.0.1
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 13.0.1
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubocop
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.7'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1.7'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: simplecov
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0.20'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0.20'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: simplecov-lcov
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0.8'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0.8'
|
125
|
+
description: Provides a minimal ruby wrapper for the Argon2 password hashing algorithm.
|
126
|
+
email: crypto@joshbuker.com
|
127
|
+
executables: []
|
128
|
+
extensions:
|
129
|
+
- ext/argon2_wrap/extconf.rb
|
130
|
+
extra_rdoc_files: []
|
131
|
+
files:
|
132
|
+
- ".document"
|
133
|
+
- ".github/ISSUE_TEMPLATE/bug_report.md"
|
134
|
+
- ".github/ISSUE_TEMPLATE/feature_request.md"
|
135
|
+
- ".github/ISSUE_TEMPLATE/need_help.md"
|
136
|
+
- ".github/PULL_REQUEST_TEMPLATE.md"
|
137
|
+
- ".github/workflows/ruby.yml"
|
138
|
+
- ".gitignore"
|
139
|
+
- ".gitmodules"
|
140
|
+
- ".rubocop.yml"
|
141
|
+
- CHANGELOG.md
|
142
|
+
- CODE_OF_CONDUCT.md
|
143
|
+
- Gemfile
|
144
|
+
- LICENSE.md
|
145
|
+
- MAINTAINING.md
|
146
|
+
- README.md
|
147
|
+
- Rakefile
|
148
|
+
- SECURITY.md
|
149
|
+
- bin/console
|
150
|
+
- bin/setup
|
151
|
+
- bin/test
|
152
|
+
- ext/argon2_wrap/Makefile
|
153
|
+
- ext/argon2_wrap/argon_wrap.c
|
154
|
+
- ext/argon2_wrap/extconf.rb
|
155
|
+
- ext/argon2_wrap/test.c
|
156
|
+
- lib/argon2.rb
|
157
|
+
- lib/argon2/constants.rb
|
158
|
+
- lib/argon2/engine.rb
|
159
|
+
- lib/argon2/errors.rb
|
160
|
+
- lib/argon2/ffi_engine.rb
|
161
|
+
- lib/argon2/password.rb
|
162
|
+
- lib/argon2/version.rb
|
163
|
+
- sorcery-argon2.gemspec
|
164
|
+
homepage: https://github.com/sorcery/argon2
|
165
|
+
licenses:
|
166
|
+
- MIT
|
167
|
+
metadata:
|
168
|
+
bug_tracker_uri: https://github.com/sorcery/argon2/issues
|
169
|
+
changelog_uri: https://github.com/sorcery/argon2/releases/tag/v1.0.0
|
170
|
+
documentation_uri: https://rubydoc.info/gems/sorcery-argon2
|
171
|
+
source_code_uri: https://github.com/sorcery/argon2/tree/v1.0.0
|
172
|
+
post_install_message:
|
173
|
+
rdoc_options: []
|
174
|
+
require_paths:
|
175
|
+
- lib
|
176
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: 2.5.0
|
181
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
182
|
+
requirements:
|
183
|
+
- - ">="
|
184
|
+
- !ruby/object:Gem::Version
|
185
|
+
version: '0'
|
186
|
+
requirements: []
|
187
|
+
rubygems_version: 3.1.2
|
188
|
+
signing_key:
|
189
|
+
specification_version: 4
|
190
|
+
summary: A Ruby wrapper for the Argon2 Password hashing algorithm
|
191
|
+
test_files: []
|