xcrypt 0.1.0 → 0.1.2

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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/lib/xcrypt/version.rb +1 -1
  3. data/lib/xcrypt.rb +160 -0
  4. metadata +17 -39
  5. data/ext/libxcrypt/INSTALL +0 -380
  6. data/ext/libxcrypt/Makefile.in +0 -4110
  7. data/ext/libxcrypt/TODO +0 -1
  8. data/ext/libxcrypt/TODO.md +0 -100
  9. data/ext/libxcrypt/aclocal.m4 +0 -2617
  10. data/ext/libxcrypt/autom4te.cache/output.0 +0 -19884
  11. data/ext/libxcrypt/autom4te.cache/output.1 +0 -19884
  12. data/ext/libxcrypt/autom4te.cache/output.2 +0 -19884
  13. data/ext/libxcrypt/autom4te.cache/output.3 +0 -19885
  14. data/ext/libxcrypt/autom4te.cache/requests +0 -714
  15. data/ext/libxcrypt/autom4te.cache/traces.0 +0 -4088
  16. data/ext/libxcrypt/autom4te.cache/traces.1 +0 -1060
  17. data/ext/libxcrypt/autom4te.cache/traces.2 +0 -4088
  18. data/ext/libxcrypt/autom4te.cache/traces.3 +0 -1060
  19. data/ext/libxcrypt/build-aux/ci/ci-log-dependency-versions +0 -79
  20. data/ext/libxcrypt/build-aux/ci/ci-log-logfiles +0 -22
  21. data/ext/libxcrypt/build-aux/ci/clang-gcov-wrapper +0 -2
  22. data/ext/libxcrypt/build-aux/ci/configure-wrapper +0 -10
  23. data/ext/libxcrypt/build-aux/ci/summarize-coverage +0 -24
  24. data/ext/libxcrypt/build-aux/m4/libtool.m4 +0 -8488
  25. data/ext/libxcrypt/build-aux/m4/ltoptions.m4 +0 -467
  26. data/ext/libxcrypt/build-aux/m4/ltsugar.m4 +0 -124
  27. data/ext/libxcrypt/build-aux/m4/ltversion.m4 +0 -24
  28. data/ext/libxcrypt/build-aux/m4/lt~obsolete.m4 +0 -99
  29. data/ext/libxcrypt/build-aux/m4-autogen/compile +0 -364
  30. data/ext/libxcrypt/build-aux/m4-autogen/config.guess +0 -1815
  31. data/ext/libxcrypt/build-aux/m4-autogen/config.sub +0 -2354
  32. data/ext/libxcrypt/build-aux/m4-autogen/depcomp +0 -792
  33. data/ext/libxcrypt/build-aux/m4-autogen/install-sh +0 -541
  34. data/ext/libxcrypt/build-aux/m4-autogen/ltmain.sh +0 -11524
  35. data/ext/libxcrypt/build-aux/m4-autogen/missing +0 -236
  36. data/ext/libxcrypt/build-aux/m4-autogen/test-driver +0 -160
  37. data/ext/libxcrypt/codecov.yml +0 -4
  38. data/ext/libxcrypt/config.h.in +0 -303
  39. data/ext/libxcrypt/configure +0 -19885
  40. data/ext/libxcrypt/libxcrypt.spec.rpkg +0 -481
  41. data/ext/libxcrypt/rpkg.conf +0 -2
  42. data/ext/libxcrypt/rpkg.macros +0 -86
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0f004dd771f2475845cede2f1baf42bcbc9ec273aec345028ce8f080e1738aee
4
- data.tar.gz: 26c0ebf5fe20acc933888dfcb087e68121c511e01d117a8df7eed342f78a9b1a
3
+ metadata.gz: e50289aa4e577c8954a17b6ee720629448716ba51e93673ff49bce3d065e8260
4
+ data.tar.gz: 8df23e9c5de9299d05456f52752a6db9f6099234ed958e3f8a49dbd5ab0eff6c
5
5
  SHA512:
6
- metadata.gz: f5ef248f2cb841ddde2e0c427c8f7ec44818b744d30955d564fb4b4509e9006d3e58d4bfd5c9200971319f1b9ec75a913dc63b44bc72d9219c6fd05e3003156c
7
- data.tar.gz: 6f1a0e554f680f0ed399d17ac607fd2f3b2a851619012a98e440970f4922f1cd03b9ea4dfadff17d459fc5e097ee2a827070b4af3bddc77b7f4a2f8b05a8628b
6
+ metadata.gz: 1ee8df7d64fdea9f032435f67f886d622f63fbea47dd9f5156a03c45834d446177d807ee4c4ba7ddf3282c65790e695f2a641455fd3a0abd48319d3ee58181a7
7
+ data.tar.gz: 7acd5509656ba24800a87dcc2d8f6e20e53faeecc8a1bb1d253d21849266c1be9b3cae44c00f9b45d821fe282e850656b1309b0c17d645d27a7b28406ca62e19
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module XCrypt
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.2"
5
5
  end
data/lib/xcrypt.rb CHANGED
@@ -1,11 +1,36 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # Top-level module providing a high-level Ruby interface to libxcrypt, a
4
+ # modern library for one-way hashing of passwords.
5
+ #
6
+ # All public methods are available directly on the module.
7
+ # The most common entry points are the algorithm-specific convenience methods
8
+ # ({yescrypt}, {bcrypt}, {sha512}, etc.) and {verify}.
9
+ #
10
+ # @example Hash a password with yescrypt (the strongest supported algorithm)
11
+ # hash = XCrypt.yescrypt("correct horse battery staple")
12
+ # XCrypt.verify("correct horse battery staple", hash) #=> true
13
+ #
14
+ # @example Hash with an explicit cost factor
15
+ # hash = XCrypt.bcrypt("hunter2", cost: 12)
16
+ #
17
+ # @example Use the generic interface
18
+ # hash = XCrypt.crypt("hunter2", algorithm: :sha512)
3
19
  module XCrypt
4
20
  require "xcrypt/version"
5
21
  require "xcrypt/ffi"
6
22
 
23
+ # Raised when hashing or salt generation fails. Common causes include an
24
+ # unsupported algorithm, a malformed setting string, or a passphrase that
25
+ # exceeds {FFI::CRYPT_MAX_PASSPHRASE_SIZE} bytes.
7
26
  Error ||= Class.new(StandardError)
8
27
 
28
+ # Maps each supported algorithm name to its setting-string prefix.
29
+ #
30
+ # The prefix is the leading characters of any hash produced by that
31
+ # algorithm and is used to identify the algorithm from an existing hash.
32
+ #
33
+ # @return [Hash{Symbol => String}]
9
34
  ALGORITHMS = {
10
35
  yescrypt: "$y$",
11
36
  gost_yescrypt: "$gy$",
@@ -25,6 +50,77 @@ module XCrypt
25
50
 
26
51
  extend self
27
52
 
53
+ # @!method yescrypt(phrase, setting = nil, cost: nil)
54
+ # Hash +phrase+ using yescrypt, the strongest supported algorithm.
55
+ # @param phrase [String] the password to hash
56
+ # @param setting [String, nil] an existing hash or salt string to use as
57
+ # the setting; a new setting is generated automatically when +nil+
58
+ # @param cost [Integer, nil] work-factor override; uses the library
59
+ # default when +nil+
60
+ # @return [String] the hashed password
61
+ # @raise [ArgumentError] if +setting+ belongs to a different algorithm
62
+ # @raise [Error] if hashing fails
63
+
64
+ # @!method gost_yescrypt(phrase, setting = nil, cost: nil)
65
+ # Hash +phrase+ using GOST R 34.11-2012 combined with yescrypt.
66
+ # @param (see #yescrypt)
67
+ # @return (see #yescrypt)
68
+ # @raise (see #yescrypt)
69
+
70
+ # @!method scrypt(phrase, setting = nil, cost: nil)
71
+ # Hash +phrase+ using scrypt.
72
+ # @param (see #yescrypt)
73
+ # @return (see #yescrypt)
74
+ # @raise (see #yescrypt)
75
+
76
+ # @!method bcrypt(phrase, setting = nil, cost: nil)
77
+ # Hash +phrase+ using bcrypt (Blowfish-based password hashing).
78
+ # @param (see #yescrypt)
79
+ # @return (see #yescrypt)
80
+ # @raise (see #yescrypt)
81
+
82
+ # @!method sha512(phrase, setting = nil, cost: nil)
83
+ # Hash +phrase+ using SHA-512 crypt.
84
+ # @param (see #yescrypt)
85
+ # @return (see #yescrypt)
86
+ # @raise (see #yescrypt)
87
+
88
+ # @!method sha256(phrase, setting = nil, cost: nil)
89
+ # Hash +phrase+ using SHA-256 crypt.
90
+ # @param (see #yescrypt)
91
+ # @return (see #yescrypt)
92
+ # @raise (see #yescrypt)
93
+
94
+ # @!method sha1(phrase, setting = nil, cost: nil)
95
+ # Hash +phrase+ using HMAC-SHA1 NetBSD crypt.
96
+ # @param (see #yescrypt)
97
+ # @return (see #yescrypt)
98
+ # @raise (see #yescrypt)
99
+
100
+ # @!method sun_md5(phrase, setting = nil, cost: nil)
101
+ # Hash +phrase+ using SunMD5 (Solaris MD5 crypt).
102
+ # @param (see #yescrypt)
103
+ # @return (see #yescrypt)
104
+ # @raise (see #yescrypt)
105
+
106
+ # @!method md5(phrase, setting = nil, cost: nil)
107
+ # Hash +phrase+ using MD5 crypt.
108
+ # @param (see #yescrypt)
109
+ # @return (see #yescrypt)
110
+ # @raise (see #yescrypt)
111
+
112
+ # @!method bsdi_des(phrase, setting = nil, cost: nil)
113
+ # Hash +phrase+ using BSDi extended DES crypt.
114
+ # @param (see #yescrypt)
115
+ # @return (see #yescrypt)
116
+ # @raise (see #yescrypt)
117
+
118
+ # @!method des(phrase, setting = nil, cost: nil)
119
+ # Hash +phrase+ using traditional DES crypt.
120
+ # @param (see #yescrypt)
121
+ # @return (see #yescrypt)
122
+ # @raise (see #yescrypt)
123
+
28
124
  ALGORITHMS.each_key do |algorithm|
29
125
  define_method(algorithm) do |phrase, setting = nil, cost: nil|
30
126
  if setting
@@ -37,10 +133,37 @@ module XCrypt
37
133
  end
38
134
  end
39
135
 
136
+ # Returns the names of all supported algorithms.
137
+ #
138
+ # @return [Array<Symbol>] algorithm names in order from strongest to weakest
40
139
  def algorithms = ALGORITHMS.keys
41
140
 
141
+ # Detects which algorithm produced a given setting or hash string by
142
+ # matching its leading prefix against {ALGORITHMS}.
143
+ #
144
+ # @param setting [String] a setting string or an existing password hash
145
+ # @return [Symbol, nil] the algorithm name, or +nil+ if the prefix is
146
+ # unrecognized
42
147
  def detect_algorithm(setting) = PREFIXES[setting[/\A\$\w+\$?|_/].to_s]
43
148
 
149
+ # Hashes +phrase+ using libxcrypt's +crypt_rn+ function.
150
+ #
151
+ # When both +setting+ and +algorithm+ are omitted, a fresh setting is
152
+ # generated with the library's default algorithm. The result is always a
153
+ # self-describing string whose leading prefix identifies the algorithm and
154
+ # encodes the salt, making it safe to store directly.
155
+ #
156
+ # @param phrase [String] the password to hash
157
+ # @param setting [String, Symbol, nil] an existing hash or salt string, or
158
+ # an algorithm +Symbol+ as shorthand for passing only +algorithm:+;
159
+ # generates a fresh setting when +nil+
160
+ # @param algorithm [Symbol, nil] algorithm to use when generating a new
161
+ # setting; ignored when +setting+ is already a String
162
+ # @param cost [Integer, nil] work-factor override passed to
163
+ # {generate_setting}; uses the library default when +nil+
164
+ # @return [String] the hashed password
165
+ # @raise [Error] if +crypt_rn+ returns +NULL+, indicating an invalid
166
+ # setting or an unsupported algorithm
44
167
  def crypt(phrase, setting = nil, algorithm: nil, cost: nil)
45
168
  setting, algorithm = nil, setting if setting.is_a? Symbol
46
169
  setting ||= generate_setting(algorithm, cost:)
@@ -52,6 +175,17 @@ module XCrypt
52
175
  data&.clear
53
176
  end
54
177
 
178
+ # Verifies that +phrase+ matches a previously computed +hash+.
179
+ #
180
+ # Returns +false+ immediately for any hash value that would cause
181
+ # libxcrypt to return a magic failure token (strings beginning with +"*"+),
182
+ # or for empty or +nil+ input, guarding against invalid-hash oracle attacks.
183
+ # The final comparison is performed in constant time to prevent timing
184
+ # attacks.
185
+ #
186
+ # @param phrase [String] the candidate password
187
+ # @param hash [String, nil] the stored password hash to verify against
188
+ # @return [Boolean] +true+ if +phrase+ matches +hash+, +false+ otherwise
55
189
  def verify(phrase, hash)
56
190
  return false if hash.nil? || hash.empty? || hash.start_with?("*")
57
191
  result = crypt(phrase, hash)
@@ -60,6 +194,19 @@ module XCrypt
60
194
  false
61
195
  end
62
196
 
197
+ # Generates a fresh setting string suitable for passing to {crypt}.
198
+ #
199
+ # Delegates to libxcrypt's +crypt_gensalt_rn+, which draws entropy from
200
+ # the OS to produce the random salt component. When +algorithm+ is +nil+,
201
+ # the library selects its preferred (strongest) algorithm.
202
+ #
203
+ # @param algorithm [Symbol, nil] the desired algorithm; uses the library
204
+ # default when +nil+
205
+ # @param cost [Integer, nil] work-factor for the generated setting; a value
206
+ # of +0+ selects the library's own default cost
207
+ # @return [String] a setting string beginning with the algorithm prefix
208
+ # @raise [ArgumentError] if +algorithm+ is not a key in {ALGORITHMS}
209
+ # @raise [Error] if +crypt_gensalt_rn+ returns +NULL+
63
210
  def generate_setting(algorithm = nil, cost: nil)
64
211
  prefix = ALGORITHMS.fetch(algorithm) { raise ArgumentError, "unknown algorithm: #{algorithm.inspect}" } if algorithm
65
212
  cost ||= 0
@@ -73,6 +220,19 @@ module XCrypt
73
220
 
74
221
  private
75
222
 
223
+ # Compares two strings in constant time to prevent timing attacks.
224
+ #
225
+ # Pads or truncates +trusted+ to match +untrusted+'s byte length before
226
+ # comparing so that the number of loop iterations is always the same
227
+ # regardless of content. A separate length check at the end ensures that a
228
+ # length-padded match is still rejected.
229
+ #
230
+ # Uses {OpenSSL.fixed_length_secure_compare} when available (Ruby >= 2.7
231
+ # with openssl >= 2.2); otherwise falls back to a pure-Ruby XOR loop.
232
+ #
233
+ # @param trusted [String] the known-good value (e.g., the output of {crypt})
234
+ # @param untrusted [String] the value supplied by the caller
235
+ # @return [Boolean] +true+ only when both strings are identical
76
236
  def secure_compare(trusted, untrusted)
77
237
  return false unless trusted.respond_to? :to_str and trusted = trusted.to_str.b
78
238
  return false unless untrusted.respond_to? :to_str and untrusted = untrusted.to_str.b
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xcrypt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Konstantin Haase
@@ -37,10 +37,25 @@ dependencies:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
39
  version: '1.0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: rake
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '13.0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '13.0'
40
54
  description: |
41
55
  Ruby FFI bindings for libxcrypt, a modern library for one-way hashing of
42
56
  passwords. Supports yescrypt, bcrypt, SHA-512, SHA-256, and other
43
57
  algorithms provided by the bundled libxcrypt source (ext/libxcrypt).
58
+ email: ruby-xcrypt@rkh.im
44
59
  executables: []
45
60
  extensions:
46
61
  - Rakefile
@@ -50,40 +65,13 @@ files:
50
65
  - ext/libxcrypt/AUTHORS
51
66
  - ext/libxcrypt/COPYING.LIB
52
67
  - ext/libxcrypt/ChangeLog
53
- - ext/libxcrypt/INSTALL
54
68
  - ext/libxcrypt/LICENSING
55
69
  - ext/libxcrypt/Makefile.am
56
- - ext/libxcrypt/Makefile.in
57
70
  - ext/libxcrypt/NEWS
58
71
  - ext/libxcrypt/README
59
72
  - ext/libxcrypt/README.md
60
73
  - ext/libxcrypt/THANKS
61
- - ext/libxcrypt/TODO
62
- - ext/libxcrypt/TODO.md
63
- - ext/libxcrypt/aclocal.m4
64
74
  - ext/libxcrypt/autogen.sh
65
- - ext/libxcrypt/autom4te.cache/output.0
66
- - ext/libxcrypt/autom4te.cache/output.1
67
- - ext/libxcrypt/autom4te.cache/output.2
68
- - ext/libxcrypt/autom4te.cache/output.3
69
- - ext/libxcrypt/autom4te.cache/requests
70
- - ext/libxcrypt/autom4te.cache/traces.0
71
- - ext/libxcrypt/autom4te.cache/traces.1
72
- - ext/libxcrypt/autom4te.cache/traces.2
73
- - ext/libxcrypt/autom4te.cache/traces.3
74
- - ext/libxcrypt/build-aux/ci/ci-log-dependency-versions
75
- - ext/libxcrypt/build-aux/ci/ci-log-logfiles
76
- - ext/libxcrypt/build-aux/ci/clang-gcov-wrapper
77
- - ext/libxcrypt/build-aux/ci/configure-wrapper
78
- - ext/libxcrypt/build-aux/ci/summarize-coverage
79
- - ext/libxcrypt/build-aux/m4-autogen/compile
80
- - ext/libxcrypt/build-aux/m4-autogen/config.guess
81
- - ext/libxcrypt/build-aux/m4-autogen/config.sub
82
- - ext/libxcrypt/build-aux/m4-autogen/depcomp
83
- - ext/libxcrypt/build-aux/m4-autogen/install-sh
84
- - ext/libxcrypt/build-aux/m4-autogen/ltmain.sh
85
- - ext/libxcrypt/build-aux/m4-autogen/missing
86
- - ext/libxcrypt/build-aux/m4-autogen/test-driver
87
75
  - ext/libxcrypt/build-aux/m4/ax_append_compile_flags.m4
88
76
  - ext/libxcrypt/build-aux/m4/ax_append_flag.m4
89
77
  - ext/libxcrypt/build-aux/m4/ax_check_compile_flag.m4
@@ -91,11 +79,6 @@ files:
91
79
  - ext/libxcrypt/build-aux/m4/ax_gcc_func_attribute.m4
92
80
  - ext/libxcrypt/build-aux/m4/ax_require_defined.m4
93
81
  - ext/libxcrypt/build-aux/m4/ax_valgrind_check.m4
94
- - ext/libxcrypt/build-aux/m4/libtool.m4
95
- - ext/libxcrypt/build-aux/m4/ltoptions.m4
96
- - ext/libxcrypt/build-aux/m4/ltsugar.m4
97
- - ext/libxcrypt/build-aux/m4/ltversion.m4
98
- - ext/libxcrypt/build-aux/m4/lt~obsolete.m4
99
82
  - ext/libxcrypt/build-aux/m4/pkg_compat.m4
100
83
  - ext/libxcrypt/build-aux/m4/zw_alignment.m4
101
84
  - ext/libxcrypt/build-aux/m4/zw_automodern.m4
@@ -115,9 +98,6 @@ files:
115
98
  - ext/libxcrypt/build-aux/scripts/gen-libcrypt-map
116
99
  - ext/libxcrypt/build-aux/scripts/move-if-change
117
100
  - ext/libxcrypt/build-aux/scripts/skip-if-exec-format-error
118
- - ext/libxcrypt/codecov.yml
119
- - ext/libxcrypt/config.h.in
120
- - ext/libxcrypt/configure
121
101
  - ext/libxcrypt/configure.ac
122
102
  - ext/libxcrypt/doc/crypt.3
123
103
  - ext/libxcrypt/doc/crypt.5
@@ -192,9 +172,6 @@ files:
192
172
  - ext/libxcrypt/lib/util-xbzero.c
193
173
  - ext/libxcrypt/lib/util-xstrcpy.c
194
174
  - ext/libxcrypt/lib/xcrypt.h.in
195
- - ext/libxcrypt/libxcrypt.spec.rpkg
196
- - ext/libxcrypt/rpkg.conf
197
- - ext/libxcrypt/rpkg.macros
198
175
  - ext/libxcrypt/test/TestCommon.pm
199
176
  - ext/libxcrypt/test/alg-des.c
200
177
  - ext/libxcrypt/test/alg-gost3411-2012-hmac.c
@@ -243,6 +220,7 @@ files:
243
220
  - lib/xcrypt.rb
244
221
  - lib/xcrypt/ffi.rb
245
222
  - lib/xcrypt/version.rb
223
+ homepage: https://github.com/rkh/ruby-xcrypt
246
224
  licenses:
247
225
  - MIT
248
226
  metadata: