bcrypt 3.1.13 → 3.1.18

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8d5e2ce3f7df5807725e03678a1d8d60d24d710aefa7a3c2636c4c71d7602911
4
- data.tar.gz: 98bcb12a01f59e508d9d523dd031bab988d453abaddde47847c34e7919b67c23
3
+ metadata.gz: ba8b7b14c18d5ad7f8dcd58b2e719925695a8af445b232d50fc21695b3cd4200
4
+ data.tar.gz: a3a566bb869dcc9001dbeae8041595152444596253d152c9a374ce9c1503d817
5
5
  SHA512:
6
- metadata.gz: 2f3bc43174cdb2f8298c81c7853c973e33f745aa1ea5ddb69121ebd953b086494005dce8a9c1861e818f38a1084c301df302ee8821ae975be2186ddbc7b07c80
7
- data.tar.gz: 9380402fbc0260e1b0590e846795324144c6d8b70c16c8a8ff3edbb93297387ee452bd1cbcd0b66126f48e99d11433ad958c1ddb4b801e586752684ad52d523f
6
+ metadata.gz: 9e21ae566338f46280af6576c42b54d6dfe9e75619c35a72b87f6401bef689be8526b3385a556f332c28d9a939ca7cd4f2104ef1483f4cc24d144ba837b69af4
7
+ data.tar.gz: 1c2e714911083b8aa457d9d16c5dd084acd6610e67a4f2c489ec137b1c503f2753d4a2c98e06446bc7771caec176b7b24a207f7395541e32c31268c8d8773551
@@ -0,0 +1,59 @@
1
+ name: Test Suite
2
+
3
+ # Run against all commits and pull requests.
4
+ on: [ push, pull_request ]
5
+
6
+ jobs:
7
+ test_matrix:
8
+
9
+ strategy:
10
+ fail-fast: false
11
+ matrix:
12
+ os:
13
+ - ubuntu
14
+ - macos
15
+ - windows
16
+ ruby:
17
+ - 2.1
18
+ - 2.2
19
+ - 2.3
20
+ - 2.4
21
+ - 2.5
22
+ - 2.6
23
+ - 2.7
24
+ - '3.0'
25
+ - 3.1
26
+ - head
27
+ - jruby
28
+ - jruby-head
29
+ - truffleruby
30
+ - truffleruby-head
31
+ - mingw
32
+ exclude:
33
+ - { os: ubuntu, ruby: mingw }
34
+ - { os: macos, ruby: mingw }
35
+ - { os: windows, ruby: truffleruby }
36
+ - { os: windows, ruby: truffleruby-head }
37
+
38
+ runs-on: ${{ matrix.os }}-latest
39
+
40
+ steps:
41
+ - uses: actions/checkout@v2
42
+ - name: Set up Ruby
43
+ uses: ruby/setup-ruby@v1
44
+ with:
45
+ ruby-version: ${{ matrix.ruby }}
46
+ bundler-cache: true
47
+ env:
48
+ JAVA_OPTS: -Djdk.io.File.enableADS=true
49
+ - name: Run tests
50
+ run: bundle exec rake default
51
+ env:
52
+ JAVA_OPTS: -Djdk.io.File.enableADS=true
53
+
54
+ finish:
55
+ runs-on: ubuntu-latest
56
+ needs: [ test_matrix ]
57
+ steps:
58
+ - name: Wait for status checks
59
+ run: echo "All Green!"
data/.gitignore CHANGED
@@ -7,3 +7,4 @@ tmp
7
7
  *.jar
8
8
  .DS_Store
9
9
  .rbenv-gemsets
10
+ Gemfile.lock
data/CHANGELOG CHANGED
@@ -1,94 +1,113 @@
1
- 1.0.0 Feb 27 2007
2
- - Initial release.
1
+ 3.1.18 May 16 2022
2
+ - Unlock GVL when calculating hashes and salts [GH #260]
3
+ - Fix compilation warnings in `ext/mri/bcrypt_ext.c` [GH #261]
3
4
 
4
- 2.0.0 Mar 07 2007
5
- - Removed BCrypt::Password#exactly_equals -- use BCrypt::Password#eql? instead.
6
- - Added BCrypt::Password#is_password?.
7
- - Refactored out BCrypt::Internals into more useful BCrypt::Engine.
8
- - Added validation of secrets -- nil is not healthy.
5
+ 3.1.17 Mar 14 2022
6
+ - Fix regex in validators to use \A and \z instead of ^ and $ [GH #121]
7
+ - Truncate secrets greater than 72 bytes in hash_secret [GH #255]
8
+ - Assorted test and doc improvements
9
9
 
10
- 2.0.1 Mar 09 2007
11
- - Fixed load path issues
12
- - Fixed crashes when hashing weird values (e.g., false, etc.)
10
+ 3.1.16 Sep 3 2020
11
+ - Fix compilation on FreeBSD. [GH #234]
13
12
 
14
- 2.0.2 Jun 06 2007
15
- - Fixed example code in the README [Winson]
16
- - Fixed Solaris compatibility [Jeremy LaTrasse, Twitter crew]
13
+ 3.1.15 July 21 2020
14
+ - Remove GVL optimization. Apparently it breaks things [GH #230]
17
15
 
18
- 2.0.3 May 07 2008
19
- - Made exception classes descend from StandardError, not Exception [Dan42]
20
- - Changed BCrypt::Engine.hash to BCrypt::Engine.hash_secret to avoid Merb
21
- sorting issues. [Lee Pope]
16
+ 3.1.14 July 21 2020
17
+ - Start calibration from the minimum cost supported by the algorithm [GH #206 by @sergey-alekseev]
22
18
 
23
- 2.0.4 Mar 09 2009
24
- - Added Ruby 1.9 compatibility. [Genki Takiuchi]
25
- - Fixed segfaults on some different types of empty strings. [Mike Pomraning]
19
+ 3.1.13 May 31 2019
20
+ - No longer include compiled binaries for Windows. See GH #173.
21
+ - Update C and Java implementations to latest versions [GH #182 by @fonica]
22
+ - Bump default cost to 12 [GH #181 by @bdewater]
23
+ - Remove explicit support for Rubies 1.8 and 1.9
24
+ - Define SKIP_GNU token when building extension (Fixes FreeBSD >= 12) [GH #189 by @adam12]
26
25
 
27
- 2.0.5 Mar 11 2009
28
- - Fixed Ruby 1.8.5 compatibility. [Mike Pomraning]
26
+ 3.1.12 May 16 2018
27
+ - Add support for Ruby 2.3, 2.4, and 2.5 in compiled Windows binaries
28
+ - Fix compatibility with libxcrypt - Fixes hash errors in Fedora 28 and Ubuntu 20 [GH #164 by @besser82]
29
29
 
30
- 2.1.0 Aug 12 2009
31
- - Improved code coverage, unit tests, and build chain. [Hongli Lai]
32
- - Ruby 1.9 compatibility fixes. [Hongli Lai]
33
- - JRuby support, using Damien Miller's jBCrypt. [Hongli Lai]
34
- - Ruby 1.9 GIL releasing for high-cost hashes. [Hongli Lai]
30
+ 3.1.11 Mar 06 2016
31
+ - Add support for Ruby 2.2 in compiled Windows binaries
35
32
 
36
- 2.1.1 Aug 14 2009
37
- - JVM 1.4/1.5 compatibility [Hongli Lai]
33
+ 3.1.10 Jan 28 2015
34
+ - Fix issue with dumping a BCrypt::Password instance to YAML in Ruby 2.2 [GH #107 by @mattwildig]
38
35
 
39
- 2.1.2 Sep 16 2009
40
- - Fixed support for Solaris, OpenSolaris.
36
+ 3.1.9 Oct 23 2014
37
+ - Rebuild corrupt binaries
41
38
 
42
- 3.0.0 Aug 24 2011
43
- - Bcrypt C implementation replaced with a public domain implementation.
44
- - License changed to MIT
39
+ 3.1.8 Oct 23 2014
40
+ - Add support for Ruby 2.1 in compiled Windows binaries [GH #102]
45
41
 
46
- 3.0.1 Sep 12 2011
47
- - create raises an exception if the cost is higher than 31. GH #27
42
+ 3.1.7 Feb 24 2014
43
+ - Rebuild corrupt Java binary version of gem [GH #90]
44
+ - The 2.1 support for Windows binaries alleged in 3.1.3 was a lie -- documentation removed
45
+
46
+ 3.1.6 Feb 21 2014
47
+ - Dummy version of "bcrypt-ruby" needed a couple version bumps to fix some
48
+ bugs. It felt wrong to have that at a higher version than the real gem, so
49
+ the real gem is getting bumped to 3.1.6.
50
+
51
+ 3.1.3 Feb 21 2014
52
+ - Add support for Ruby 2.1 in compiled Windows binaries
53
+ - Rename gem from "bcrypt-ruby" to just "bcrypt". [GH #86 by @sferik]
54
+
55
+ 3.1.2 Aug 26 2013
56
+ - Add support for Ruby 1.8 and 2.0 (in addition to 1.9) in compiled Windows binaries
57
+ - Add support for 64-bit Windows
58
+
59
+ 3.1.1 Jul 10 2013
60
+ - Remove support for Ruby 1.8 in compiled win32 binaries
48
61
 
49
62
  3.1.0 May 07 2013
50
63
  - Add BCrypt::Password.valid_hash?(str) to check if a string is a valid bcrypt password hash
51
64
  - BCrypt::Password cost should be set to DEFAULT_COST if nil
52
65
  - Add BCrypt::Engine.cost attribute for getting/setting a default cost externally
53
66
 
54
- 3.1.1 Jul 10 2013
55
- - Remove support for Ruby 1.8 in compiled win32 binaries
67
+ 3.0.1 Sep 12 2011
68
+ - create raises an exception if the cost is higher than 31. GH #27
56
69
 
57
- 3.1.2 Aug 26 2013
58
- - Add support for Ruby 1.8 and 2.0 (in addition to 1.9) in compiled Windows binaries
59
- - Add support for 64-bit Windows
70
+ 3.0.0 Aug 24 2011
71
+ - Bcrypt C implementation replaced with a public domain implementation.
72
+ - License changed to MIT
60
73
 
61
- 3.1.3 Feb 21 2014
62
- - Add support for Ruby 2.1 in compiled Windows binaries
63
- - Rename gem from "bcrypt-ruby" to just "bcrypt". [GH #86 by @sferik]
74
+ 2.1.2 Sep 16 2009
75
+ - Fixed support for Solaris, OpenSolaris.
64
76
 
65
- 3.1.6 Feb 21 2014
66
- - Dummy version of "bcrypt-ruby" needed a couple version bumps to fix some
67
- bugs. It felt wrong to have that at a higher version than the real gem, so
68
- the real gem is getting bumped to 3.1.6.
77
+ 2.1.1 Aug 14 2009
78
+ - JVM 1.4/1.5 compatibility [Hongli Lai]
69
79
 
70
- 3.1.7 Feb 24 2014
71
- - Rebuild corrupt Java binary version of gem [GH #90]
72
- - The 2.1 support for Windows binaries alleged in 3.1.3 was a lie -- documentation removed
80
+ 2.1.0 Aug 12 2009
81
+ - Improved code coverage, unit tests, and build chain. [Hongli Lai]
82
+ - Ruby 1.9 compatibility fixes. [Hongli Lai]
83
+ - JRuby support, using Damien Miller's jBCrypt. [Hongli Lai]
84
+ - Ruby 1.9 GIL releasing for high-cost hashes. [Hongli Lai]
73
85
 
74
- 3.1.8 Oct 23 2014
75
- - Add support for Ruby 2.1 in compiled Windows binaries [GH #102]
86
+ 2.0.5 Mar 11 2009
87
+ - Fixed Ruby 1.8.5 compatibility. [Mike Pomraning]
76
88
 
77
- 3.1.9 Oct 23 2014
78
- - Rebuild corrupt binaries
89
+ 2.0.4 Mar 09 2009
90
+ - Added Ruby 1.9 compatibility. [Genki Takiuchi]
91
+ - Fixed segfaults on some different types of empty strings. [Mike Pomraning]
79
92
 
80
- 3.1.10 Jan 28 2015
81
- - Fix issue with dumping a BCrypt::Password instance to YAML in Ruby 2.2 [GH #107 by @mattwildig]
93
+ 2.0.3 May 07 2008
94
+ - Made exception classes descend from StandardError, not Exception [Dan42]
95
+ - Changed BCrypt::Engine.hash to BCrypt::Engine.hash_secret to avoid Merb
96
+ sorting issues. [Lee Pope]
82
97
 
83
- 3.1.11 Mar 06 2016
84
- - Add support for Ruby 2.2 in compiled Windows binaries
98
+ 2.0.2 Jun 06 2007
99
+ - Fixed example code in the README [Winson]
100
+ - Fixed Solaris compatibility [Jeremy LaTrasse, Twitter crew]
85
101
 
86
- 3.1.12 May 16 2018
87
- - Add support for Ruby 2.3, 2.4, and 2.5 in compiled Windows binaries
88
- - Fix compatibility with libxcrypt [GH #164 by @besser82]
102
+ 2.0.1 Mar 09 2007
103
+ - Fixed load path issues
104
+ - Fixed crashes when hashing weird values (e.g., false, etc.)
89
105
 
90
- [DRAFT] 4.0.0 MMM DD YYYY
91
- - No longer include compiled binaries for Windows. See GH #173.
92
- - Update C and Java implementations to latest versions [GH #182 by @fonica]
93
- - Bump default cost to 12 [GH #181 by @bdewater]
94
- - Remove explicit support for Rubies 1.8 and 1.9
106
+ 2.0.0 Mar 07 2007
107
+ - Removed BCrypt::Password#exactly_equals -- use BCrypt::Password#eql? instead.
108
+ - Added BCrypt::Password#is_password?.
109
+ - Refactored out BCrypt::Internals into more useful BCrypt::Engine.
110
+ - Added validation of secrets -- nil is not healthy.
111
+
112
+ 1.0.0 Feb 27 2007
113
+ - Initial release.
data/README.md CHANGED
@@ -2,11 +2,9 @@
2
2
 
3
3
  An easy way to keep your users' passwords secure.
4
4
 
5
- * https://github.com/codahale/bcrypt-ruby/tree/master
6
-
7
- [![Travis Build Status](https://travis-ci.org/codahale/bcrypt-ruby.svg?branch=master)](https://travis-ci.org/codahale/bcrypt-ruby)
8
- [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/6fplerx9lnaf0hyo?svg=true)](https://ci.appveyor.com/project/TJSchuck35975/bcrypt-ruby)
5
+ * https://github.com/bcrypt-ruby/bcrypt-ruby/tree/master
9
6
 
7
+ [![Github Actions Build Status](https://github.com/bcrypt-ruby/bcrypt-ruby/actions/workflows/ruby.yml/badge.svg?branch=master)](https://github.com/bcrypt-ruby/bcrypt-ruby/actions/workflows/ruby.yml)
10
8
 
11
9
  ## Why you should use `bcrypt()`
12
10
 
@@ -32,8 +30,8 @@ re-hash those passwords. This vulnerability only affected the JRuby gem.
32
30
  The bcrypt gem is available on the following Ruby platforms:
33
31
 
34
32
  * JRuby
35
- * RubyInstaller 2.0 – 2.5 builds on Windows with the DevKit
36
- * Any 2.0 – 2.5 Ruby on a BSD/OS X/Linux system with a compiler
33
+ * RubyInstaller 2.0 – 3.0 builds on Windows with the DevKit
34
+ * Any 2.0 – 3.0 Ruby on a BSD/OS X/Linux system with a compiler
37
35
 
38
36
  ## How to use `bcrypt()` in your Rails application
39
37
 
data/Rakefile CHANGED
@@ -50,6 +50,8 @@ end
50
50
  if RUBY_PLATFORM =~ /java/
51
51
  Rake::JavaExtensionTask.new('bcrypt_ext', GEMSPEC) do |ext|
52
52
  ext.ext_dir = 'ext/jruby'
53
+ ext.source_version = "1.7"
54
+ ext.target_version = "1.7"
53
55
  end
54
56
  else
55
57
  Rake::ExtensionTask.new("bcrypt_ext", GEMSPEC) do |ext|
data/bcrypt.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'bcrypt'
3
- s.version = '3.1.13'
3
+ s.version = '3.1.18'
4
4
 
5
5
  s.summary = "OpenBSD's bcrypt() password hashing algorithm."
6
6
  s.description = <<-EOF
@@ -12,7 +12,7 @@ Gem::Specification.new do |s|
12
12
  s.files = `git ls-files`.split("\n")
13
13
  s.require_path = 'lib'
14
14
 
15
- s.add_development_dependency 'rake-compiler', '~> 0.9.2'
15
+ s.add_development_dependency 'rake-compiler', '~> 1.2.0'
16
16
  s.add_development_dependency 'rspec', '>= 3'
17
17
 
18
18
  s.rdoc_options += ['--title', 'bcrypt-ruby', '--line-numbers', '--inline-source', '--main', 'README.md']
@@ -22,6 +22,6 @@ Gem::Specification.new do |s|
22
22
 
23
23
  s.authors = ["Coda Hale"]
24
24
  s.email = "coda.hale@gmail.com"
25
- s.homepage = "https://github.com/codahale/bcrypt-ruby"
25
+ s.homepage = "https://github.com/bcrypt-ruby/bcrypt-ruby"
26
26
  s.license = "MIT"
27
27
  end
data/ext/mri/bcrypt_ext.c CHANGED
@@ -1,53 +1,105 @@
1
1
  #include <ruby.h>
2
2
  #include <ow-crypt.h>
3
3
 
4
+ #ifdef HAVE_RUBY_THREAD_H
5
+ #include <ruby/thread.h>
6
+ #endif
7
+
4
8
  static VALUE mBCrypt;
5
9
  static VALUE cBCryptEngine;
6
10
 
11
+ struct bc_salt_args {
12
+ const char * prefix;
13
+ unsigned long count;
14
+ const char * input;
15
+ int size;
16
+ };
17
+
18
+ static void * bc_salt_nogvl(void * ptr) {
19
+ struct bc_salt_args * args = ptr;
20
+
21
+ return crypt_gensalt_ra(args->prefix, args->count, args->input, args->size);
22
+ }
23
+
7
24
  /* Given a logarithmic cost parameter, generates a salt for use with +bc_crypt+.
8
25
  */
9
26
  static VALUE bc_salt(VALUE self, VALUE prefix, VALUE count, VALUE input) {
10
27
  char * salt;
11
28
  VALUE str_salt;
12
-
13
- salt = crypt_gensalt_ra(
14
- StringValuePtr(prefix),
15
- NUM2ULONG(count),
16
- NIL_P(input) ? NULL : StringValuePtr(input),
17
- NIL_P(input) ? 0 : RSTRING_LEN(input));
29
+ struct bc_salt_args args;
30
+
31
+ /* duplicate the parameters for thread safety. If another thread has a
32
+ * reference to the parameters and mutates them while we are working,
33
+ * that would be very bad. Duping the strings means that the reference
34
+ * isn't shared. */
35
+ prefix = rb_str_new_frozen(prefix);
36
+ input = rb_str_new_frozen(input);
37
+
38
+ args.prefix = StringValueCStr(prefix);
39
+ args.count = NUM2ULONG(count);
40
+ args.input = NIL_P(input) ? NULL : StringValuePtr(input);
41
+ args.size = NIL_P(input) ? 0 : RSTRING_LEN(input);
42
+
43
+ #ifdef HAVE_RUBY_THREAD_H
44
+ salt = rb_thread_call_without_gvl(bc_salt_nogvl, &args, NULL, NULL);
45
+ #else
46
+ salt = bc_salt_nogvl((void *)&args);
47
+ #endif
18
48
 
19
49
  if(!salt) return Qnil;
20
50
 
21
51
  str_salt = rb_str_new2(salt);
22
- xfree(salt);
52
+ free(salt);
23
53
 
24
54
  return str_salt;
25
55
  }
26
56
 
57
+ struct bc_crypt_args {
58
+ const char * key;
59
+ const char * setting;
60
+ void * data;
61
+ int size;
62
+ };
63
+
64
+ static void * bc_crypt_nogvl(void * ptr) {
65
+ struct bc_crypt_args * args = ptr;
66
+
67
+ return crypt_ra(args->key, args->setting, &args->data, &args->size);
68
+ }
69
+
27
70
  /* Given a secret and a salt, generates a salted hash (which you can then store safely).
28
71
  */
29
72
  static VALUE bc_crypt(VALUE self, VALUE key, VALUE setting) {
30
73
  char * value;
31
- void * data;
32
- int size;
33
74
  VALUE out;
34
75
 
35
- data = NULL;
36
- size = 0xDEADBEEF;
76
+ struct bc_crypt_args args;
37
77
 
38
78
  if(NIL_P(key) || NIL_P(setting)) return Qnil;
39
79
 
40
- value = crypt_ra(
41
- NIL_P(key) ? NULL : StringValuePtr(key),
42
- NIL_P(setting) ? NULL : StringValuePtr(setting),
43
- &data,
44
- &size);
80
+ /* duplicate the parameters for thread safety. If another thread has a
81
+ * reference to the parameters and mutates them while we are working,
82
+ * that would be very bad. Duping the strings means that the reference
83
+ * isn't shared. */
84
+ key = rb_str_new_frozen(key);
85
+ setting = rb_str_new_frozen(setting);
86
+
87
+ args.data = NULL;
88
+ args.size = 0xDEADBEEF;
89
+ args.key = NIL_P(key) ? NULL : StringValueCStr(key);
90
+ args.setting = NIL_P(setting) ? NULL : StringValueCStr(setting);
91
+
92
+ #ifdef HAVE_RUBY_THREAD_H
93
+ value = rb_thread_call_without_gvl(bc_crypt_nogvl, &args, NULL, NULL);
94
+ #else
95
+ value = bc_crypt_nogvl((void *)&args);
96
+ #endif
45
97
 
46
- if(!value) return Qnil;
98
+ if(!value || !args.data) return Qnil;
47
99
 
48
100
  out = rb_str_new2(value);
49
101
 
50
- xfree(data);
102
+ free(args.data);
51
103
 
52
104
  return out;
53
105
  }
@@ -361,7 +361,7 @@ static BF_ctx BF_init_state = {
361
361
  }
362
362
  };
363
363
 
364
- static unsigned char BF_itoa64[64 + 1] =
364
+ static const unsigned char BF_itoa64[64 + 1] =
365
365
  "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
366
366
 
367
367
  static unsigned char BF_atoi64[0x60] = {
@@ -387,9 +387,8 @@ static int BF_decode(BF_word *dst, const char *src, int size)
387
387
  unsigned char *dptr = (unsigned char *)dst;
388
388
  unsigned char *end = dptr + size;
389
389
  const unsigned char *sptr = (const unsigned char *)src;
390
- unsigned int tmp, c1, c2, c3, c4;
391
-
392
390
  do {
391
+ unsigned int tmp, c1, c2, c3, c4;
393
392
  BF_safe_atoi64(c1, *sptr++);
394
393
  BF_safe_atoi64(c2, *sptr++);
395
394
  *dptr++ = (c1 << 2) | ((c2 & 0x30) >> 4);
@@ -402,7 +401,6 @@ static int BF_decode(BF_word *dst, const char *src, int size)
402
401
  BF_safe_atoi64(c4, *sptr++);
403
402
  *dptr++ = ((c3 & 0x03) << 6) | c4;
404
403
  } while (dptr < end);
405
-
406
404
  return 0;
407
405
  }
408
406
 
@@ -411,9 +409,8 @@ static void BF_encode(char *dst, const BF_word *src, int size)
411
409
  const unsigned char *sptr = (const unsigned char *)src;
412
410
  const unsigned char *end = sptr + size;
413
411
  unsigned char *dptr = (unsigned char *)dst;
414
- unsigned int c1, c2;
415
-
416
412
  do {
413
+ unsigned int c1, c2;
417
414
  c1 = *sptr++;
418
415
  *dptr++ = BF_itoa64[c1 >> 2];
419
416
  c1 = (c1 & 0x03) << 4;
@@ -442,10 +439,9 @@ static void BF_swap(BF_word *x, int count)
442
439
  {
443
440
  static int endianness_check = 1;
444
441
  char *is_little_endian = (char *)&endianness_check;
445
- BF_word tmp;
446
-
447
442
  if (*is_little_endian)
448
443
  do {
444
+ BF_word tmp;
449
445
  tmp = *x;
450
446
  tmp = (tmp << 16) | (tmp >> 16);
451
447
  *x++ = ((tmp & 0x00FF00FF) << 8) | ((tmp >> 8) & 0x00FF00FF);
@@ -517,7 +513,7 @@ static void BF_swap(BF_word *x, int count)
517
513
  R = L; \
518
514
  L = tmp4 ^ data.ctx.P[BF_N + 1];
519
515
 
520
- #if BF_ASM
516
+ #if BF_ASM == 1
521
517
  #define BF_body() \
522
518
  _BF_body_r(&data.ctx);
523
519
  #else
@@ -650,7 +646,7 @@ static char *BF_crypt(const char *key, const char *setting,
650
646
  char *output, int size,
651
647
  BF_word min)
652
648
  {
653
- #if BF_ASM
649
+ #if BF_ASM == 1
654
650
  extern void _BF_body_r(BF_ctx *ctx);
655
651
  #endif
656
652
  struct {
@@ -28,7 +28,7 @@
28
28
  /* Just to make sure the prototypes match the actual definitions */
29
29
  #include "crypt_gensalt.h"
30
30
 
31
- unsigned char _crypt_itoa64[64 + 1] =
31
+ const unsigned char _crypt_itoa64[64 + 1] =
32
32
  "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
33
33
 
34
34
  char *_crypt_gensalt_traditional_rn(const char *prefix, unsigned long count,
@@ -17,7 +17,7 @@
17
17
  #ifndef _CRYPT_GENSALT_H
18
18
  #define _CRYPT_GENSALT_H
19
19
 
20
- extern unsigned char _crypt_itoa64[];
20
+ extern const unsigned char _crypt_itoa64[];
21
21
  extern char *_crypt_gensalt_traditional_rn(const char *prefix,
22
22
  unsigned long count,
23
23
  const char *input, int size, char *output, int output_size);
data/ext/mri/wrapper.c CHANGED
@@ -17,6 +17,9 @@
17
17
  #include <stdlib.h>
18
18
  #include <string.h>
19
19
 
20
+ /* Redefine strdup to ruby_strdup in case string.h doesn't export it. */
21
+ #include <ruby/util.h>
22
+
20
23
  #include <errno.h>
21
24
  #ifndef __set_errno
22
25
  #define __set_errno(val) errno = (val)
@@ -176,7 +179,7 @@ char *crypt_ra(const char *key, const char *setting,
176
179
  return _crypt_blowfish_rn(key, setting, (char *)*data, *size);
177
180
  }
178
181
 
179
- char *crypt_r(const char *key, const char *setting, void *data)
182
+ char *crypt_r(const char *key, const char *setting, struct crypt_data *data)
180
183
  {
181
184
  return _crypt_retval_magic(
182
185
  crypt_rn(key, setting, data, CRYPT_OUTPUT_SIZE),
data/ext/mri/x86.S CHANGED
@@ -199,5 +199,5 @@ BF_die:
199
199
  #endif
200
200
 
201
201
  #if defined(__ELF__) && defined(__linux__)
202
- .section .note.GNU-stack,"",@progbits
202
+ .section .note.GNU-stack,"",%progbits
203
203
  #endif
data/lib/bcrypt/engine.rb CHANGED
@@ -5,6 +5,16 @@ module BCrypt
5
5
  DEFAULT_COST = 12
6
6
  # The minimum cost supported by the algorithm.
7
7
  MIN_COST = 4
8
+ # The maximum cost supported by the algorithm.
9
+ MAX_COST = 31
10
+ # Maximum possible size of bcrypt() secrets.
11
+ # Older versions of the bcrypt library would truncate passwords longer
12
+ # than 72 bytes, but newer ones do not. We truncate like the old library for
13
+ # forward compatibility. This way users upgrading from Ubuntu 18.04 to 20.04
14
+ # will not have their user passwords invalidated, for example.
15
+ # A max secret length greater than 255 leads to bcrypt returning nil.
16
+ # https://github.com/bcrypt-ruby/bcrypt-ruby/issues/225#issuecomment-875908425
17
+ MAX_SECRET_BYTESIZE = 72
8
18
  # Maximum possible size of bcrypt() salts.
9
19
  MAX_SALT_LENGTH = 16
10
20
 
@@ -41,14 +51,16 @@ module BCrypt
41
51
  end
42
52
 
43
53
  # Given a secret and a valid salt (see BCrypt::Engine.generate_salt) calculates
44
- # a bcrypt() password hash.
54
+ # a bcrypt() password hash. Secrets longer than 72 bytes are truncated.
45
55
  def self.hash_secret(secret, salt, _ = nil)
46
56
  if valid_secret?(secret)
47
57
  if valid_salt?(salt)
48
58
  if RUBY_PLATFORM == "java"
49
59
  Java.bcrypt_jruby.BCrypt.hashpw(secret.to_s.to_java_bytes, salt.to_s)
50
60
  else
51
- __bc_crypt(secret.to_s, salt)
61
+ secret = secret.to_s
62
+ secret = secret.byteslice(0, MAX_SECRET_BYTESIZE) if secret && secret.bytesize > MAX_SECRET_BYTESIZE
63
+ __bc_crypt(secret, salt)
52
64
  end
53
65
  else
54
66
  raise Errors::InvalidSalt.new("invalid salt")
@@ -68,8 +80,7 @@ module BCrypt
68
80
  if RUBY_PLATFORM == "java"
69
81
  Java.bcrypt_jruby.BCrypt.gensalt(cost)
70
82
  else
71
- prefix = "$2a$05$CCCCCCCCCCCCCCCCCCCCC.E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW"
72
- __bc_salt(prefix, cost, OpenSSL::Random.random_bytes(MAX_SALT_LENGTH))
83
+ __bc_salt("$2a$", cost, OpenSSL::Random.random_bytes(MAX_SALT_LENGTH))
73
84
  end
74
85
  else
75
86
  raise Errors::InvalidCost.new("cost must be numeric and > 0")
@@ -78,7 +89,7 @@ module BCrypt
78
89
 
79
90
  # Returns true if +salt+ is a valid bcrypt() salt, false if not.
80
91
  def self.valid_salt?(salt)
81
- !!(salt =~ /^\$[0-9a-z]{2,}\$[0-9]{2,}\$[A-Za-z0-9\.\/]{22,}$/)
92
+ !!(salt =~ /\A\$[0-9a-z]{2,}\$[0-9]{2,}\$[A-Za-z0-9\.\/]{22,}\z/)
82
93
  end
83
94
 
84
95
  # Returns true if +secret+ is a valid bcrypt() secret, false if not.
@@ -99,7 +110,7 @@ module BCrypt
99
110
  # # should take less than 1000ms
100
111
  # BCrypt::Password.create("woo", :cost => 12)
101
112
  def self.calibrate(upper_time_limit_in_ms)
102
- 40.times do |i|
113
+ (BCrypt::Engine::MIN_COST..BCrypt::Engine::MAX_COST-1).each do |i|
103
114
  start_time = Time.now
104
115
  Password.create("testing testing", :cost => i+1)
105
116
  end_time = Time.now - start_time
@@ -42,12 +42,12 @@ module BCrypt
42
42
  # @password = BCrypt::Password.create("my secret", :cost => 13)
43
43
  def create(secret, options = {})
44
44
  cost = options[:cost] || BCrypt::Engine.cost
45
- raise ArgumentError if cost > 31
45
+ raise ArgumentError if cost > BCrypt::Engine::MAX_COST
46
46
  Password.new(BCrypt::Engine.hash_secret(secret, BCrypt::Engine.generate_salt(cost)))
47
47
  end
48
48
 
49
49
  def valid_hash?(h)
50
- h =~ /^\$[0-9a-z]{2}\$[0-9]{2}\$[A-Za-z0-9\.\/]{53}$/
50
+ /\A\$[0-9a-z]{2}\$[0-9]{2}\$[A-Za-z0-9\.\/]{53}\z/ === h
51
51
  end
52
52
  end
53
53
 
@@ -62,6 +62,17 @@ module BCrypt
62
62
  end
63
63
 
64
64
  # Compares a potential secret against the hash. Returns true if the secret is the original secret, false otherwise.
65
+ #
66
+ # Comparison edge case/gotcha:
67
+ #
68
+ # secret = "my secret"
69
+ # @password = BCrypt::Password.create(secret)
70
+ #
71
+ # @password == secret # => True
72
+ # @password == @password # => False
73
+ # @password == @password.to_s # => False
74
+ # @password.to_s == @password # => True
75
+ # @password.to_s == @password.to_s # => True
65
76
  def ==(secret)
66
77
  super(BCrypt::Engine.hash_secret(secret, @salt))
67
78
  end
@@ -83,5 +94,4 @@ module BCrypt
83
94
  return v.to_str, c.to_i, h[0, 29].to_str, mash[-31, 31].to_str
84
95
  end
85
96
  end
86
-
87
97
  end
@@ -1,9 +1,23 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper"))
2
+ require 'securerandom'
3
+
4
+ describe 'BCrypt::Engine' do
5
+ describe '.calibrate(upper_time_limit_in_ms)' do
6
+ context 'a tiny upper time limit provided' do
7
+ it 'returns a minimum cost supported by the algorithm' do
8
+ expect(BCrypt::Engine.calibrate(0.001)).to eq(4)
9
+ end
10
+ end
11
+ end
12
+ end
2
13
 
3
14
  describe "The BCrypt engine" do
4
15
  specify "should calculate the optimal cost factor to fit in a specific time" do
5
- first = BCrypt::Engine.calibrate(100)
6
- second = BCrypt::Engine.calibrate(400)
16
+ start_time = Time.now
17
+ BCrypt::Password.create("testing testing", :cost => BCrypt::Engine::MIN_COST + 1)
18
+ min_time_ms = (Time.now - start_time) * 1000
19
+ first = BCrypt::Engine.calibrate(min_time_ms)
20
+ second = BCrypt::Engine.calibrate(min_time_ms * 4)
7
21
  expect(second).to be > first
8
22
  end
9
23
  end
@@ -144,4 +158,19 @@ describe "Generating BCrypt hashes" do
144
158
  expect(BCrypt::Engine.hash_secret(secret, salt)).to eql(test_vector)
145
159
  end
146
160
  end
161
+
162
+ specify "should truncate long 1-byte character secrets to 72 bytes" do
163
+ # 'b' as a base triggers the failure at 256 characters, but 'a' does not.
164
+ too_long_secret = 'b'*(BCrypt::Engine::MAX_SECRET_BYTESIZE + 1)
165
+ just_right_secret = 'b'*BCrypt::Engine::MAX_SECRET_BYTESIZE
166
+ expect(BCrypt::Engine.hash_secret(too_long_secret, @salt)).to eq(BCrypt::Engine.hash_secret(just_right_secret, @salt))
167
+ end
168
+
169
+ specify "should truncate long multi-byte character secrets to 72 bytes" do
170
+ # 256 times causes bcrypt to return nil for libxcrypt > 4.4.18-4.
171
+ too_long_secret = '𐐷'*256
172
+ # 𐐷 takes 4 bytes in UTF-8. 18 times is 72 bytes
173
+ just_right_secret = '𐐷'*18
174
+ expect(BCrypt::Engine.hash_secret(too_long_secret, @salt)).to eq(BCrypt::Engine.hash_secret(just_right_secret, @salt))
175
+ end
147
176
  end
@@ -1,4 +1,5 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper"))
2
+ require 'securerandom'
2
3
 
3
4
  describe "Creating a hashed password" do
4
5
 
@@ -26,6 +27,10 @@ describe "Creating a hashed password" do
26
27
  expect { BCrypt::Password.create( "" ) }.not_to raise_error
27
28
  expect { BCrypt::Password.create( String.new ) }.not_to raise_error
28
29
  end
30
+
31
+ specify "should tolerate very long string secrets" do
32
+ expect { BCrypt::Password.create("abcd"*1024) }.not_to raise_error
33
+ end
29
34
  end
30
35
 
31
36
  describe "Reading a hashed password" do
@@ -108,6 +113,7 @@ end
108
113
  describe "Validating a generated salt" do
109
114
  specify "should not accept an invalid salt" do
110
115
  expect(BCrypt::Engine.valid_salt?("invalid")).to eq(false)
116
+ expect(BCrypt::Engine.valid_salt?("invalid\n#{BCrypt::Engine.generate_salt}\ninvalid")).to eq(false)
111
117
  end
112
118
  specify "should accept a valid salt" do
113
119
  expect(BCrypt::Engine.valid_salt?(BCrypt::Engine.generate_salt)).to eq(true)
@@ -116,9 +122,10 @@ end
116
122
 
117
123
  describe "Validating a password hash" do
118
124
  specify "should not accept an invalid password" do
119
- expect(BCrypt::Password.valid_hash?("i_am_so_not_valid")).to be_falsey
125
+ expect(BCrypt::Password.valid_hash?("i_am_so_not_valid")).to be(false)
126
+ expect(BCrypt::Password.valid_hash?("invalid\n#{BCrypt::Password.create "i_am_so_valid"}\ninvalid")).to be(false)
120
127
  end
121
128
  specify "should accept a valid password" do
122
- expect(BCrypt::Password.valid_hash?(BCrypt::Password.create "i_am_so_valid")).to be_truthy
129
+ expect(BCrypt::Password.valid_hash?(BCrypt::Password.create "i_am_so_valid")).to be(true)
123
130
  end
124
131
  end
metadata CHANGED
@@ -1,38 +1,38 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bcrypt
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.13
4
+ version: 3.1.18
5
5
  platform: ruby
6
6
  authors:
7
7
  - Coda Hale
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-05-31 00:00:00.000000000 Z
11
+ date: 2022-05-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
+ name: rake-compiler
14
15
  requirement: !ruby/object:Gem::Requirement
15
16
  requirements:
16
17
  - - "~>"
17
18
  - !ruby/object:Gem::Version
18
- version: 0.9.2
19
- name: rake-compiler
20
- prerelease: false
19
+ version: 1.2.0
21
20
  type: :development
21
+ prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.9.2
26
+ version: 1.2.0
27
27
  - !ruby/object:Gem::Dependency
28
+ name: rspec
28
29
  requirement: !ruby/object:Gem::Requirement
29
30
  requirements:
30
31
  - - ">="
31
32
  - !ruby/object:Gem::Version
32
33
  version: '3'
33
- name: rspec
34
- prerelease: false
35
34
  type: :development
35
+ prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
@@ -50,21 +50,19 @@ extra_rdoc_files:
50
50
  - README.md
51
51
  - COPYING
52
52
  - CHANGELOG
53
- - lib/bcrypt.rb
54
53
  - lib/bcrypt/password.rb
55
54
  - lib/bcrypt/engine.rb
56
55
  - lib/bcrypt/error.rb
56
+ - lib/bcrypt.rb
57
57
  files:
58
+ - ".github/workflows/ruby.yml"
58
59
  - ".gitignore"
59
60
  - ".rspec"
60
- - ".travis.yml"
61
61
  - CHANGELOG
62
62
  - COPYING
63
63
  - Gemfile
64
- - Gemfile.lock
65
64
  - README.md
66
65
  - Rakefile
67
- - appveyor.yml
68
66
  - bcrypt.gemspec
69
67
  - ext/jruby/bcrypt_jruby/BCrypt.java
70
68
  - ext/mri/bcrypt_ext.c
@@ -87,11 +85,11 @@ files:
87
85
  - spec/bcrypt/error_spec.rb
88
86
  - spec/bcrypt/password_spec.rb
89
87
  - spec/spec_helper.rb
90
- homepage: https://github.com/codahale/bcrypt-ruby
88
+ homepage: https://github.com/bcrypt-ruby/bcrypt-ruby
91
89
  licenses:
92
90
  - MIT
93
91
  metadata: {}
94
- post_install_message:
92
+ post_install_message:
95
93
  rdoc_options:
96
94
  - "--title"
97
95
  - bcrypt-ruby
@@ -112,9 +110,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
112
110
  - !ruby/object:Gem::Version
113
111
  version: '0'
114
112
  requirements: []
115
- rubyforge_project:
116
- rubygems_version: 2.7.6
117
- signing_key:
113
+ rubygems_version: 3.1.4
114
+ signing_key:
118
115
  specification_version: 4
119
116
  summary: OpenBSD's bcrypt() password hashing algorithm.
120
117
  test_files: []
data/.travis.yml DELETED
@@ -1,17 +0,0 @@
1
- language: ruby
2
- before_install:
3
- - "echo 'gem: --no-rdoc --no-ri' > ~/.gemrc"
4
- - gem update --system 2.7.8
5
- - gem install bundler -v 1.17.3
6
- rvm:
7
- - 2.0
8
- - 2.1
9
- - 2.2
10
- - 2.3
11
- - 2.4
12
- - 2.5
13
- - 2.6
14
- - ruby-head
15
- - jruby-head
16
- - rbx-3
17
- script: bundle exec rake
data/Gemfile.lock DELETED
@@ -1,37 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- bcrypt (3.1.13)
5
-
6
- GEM
7
- remote: https://rubygems.org/
8
- specs:
9
- diff-lcs (1.3)
10
- rake (12.3.2)
11
- rake-compiler (0.9.9)
12
- rake
13
- rspec (3.8.0)
14
- rspec-core (~> 3.8.0)
15
- rspec-expectations (~> 3.8.0)
16
- rspec-mocks (~> 3.8.0)
17
- rspec-core (3.8.0)
18
- rspec-support (~> 3.8.0)
19
- rspec-expectations (3.8.3)
20
- diff-lcs (>= 1.2.0, < 2.0)
21
- rspec-support (~> 3.8.0)
22
- rspec-mocks (3.8.0)
23
- diff-lcs (>= 1.2.0, < 2.0)
24
- rspec-support (~> 3.8.0)
25
- rspec-support (3.8.0)
26
-
27
- PLATFORMS
28
- java
29
- ruby
30
-
31
- DEPENDENCIES
32
- bcrypt!
33
- rake-compiler (~> 0.9.2)
34
- rspec (>= 3)
35
-
36
- BUNDLED WITH
37
- 1.16.1
data/appveyor.yml DELETED
@@ -1,50 +0,0 @@
1
- version: "{branch}-{build}"
2
- build: off
3
- clone_depth: 1
4
-
5
- init:
6
- # Install Ruby head
7
- - if %RUBY_VERSION%==head (
8
- appveyor DownloadFile https://github.com/oneclick/rubyinstaller2/releases/download/rubyinstaller-head/rubyinstaller-head-x86.exe -FileName C:\head_x86.exe &
9
- C:\head_x86.exe /verysilent /dir=C:\Ruby%RUBY_VERSION%
10
- )
11
- - if %RUBY_VERSION%==head-x64 (
12
- appveyor DownloadFile https://github.com/oneclick/rubyinstaller2/releases/download/rubyinstaller-head/rubyinstaller-head-x64.exe -FileName C:\head_x64.exe &
13
- C:\head_x64.exe /verysilent /dir=C:\Ruby%RUBY_VERSION%
14
- )
15
-
16
- # Add Ruby to the path
17
- - set PATH=C:\Ruby%RUBY_VERSION%\bin;%PATH%
18
-
19
- environment:
20
- matrix:
21
- - RUBY_VERSION: "head"
22
- - RUBY_VERSION: "head-x64"
23
- - RUBY_VERSION: "25"
24
- - RUBY_VERSION: "25-x64"
25
- - RUBY_VERSION: "24"
26
- - RUBY_VERSION: "24-x64"
27
- - RUBY_VERSION: "23"
28
- - RUBY_VERSION: "23-x64"
29
- - RUBY_VERSION: "22"
30
- - RUBY_VERSION: "22-x64"
31
- - RUBY_VERSION: "21"
32
- - RUBY_VERSION: "21-x64"
33
- - RUBY_VERSION: "200"
34
- - RUBY_VERSION: "200-x64"
35
-
36
- install:
37
- - ps: "Set-Content -Value 'gem: --no-ri --no-rdoc ' -Path C:\\ProgramData\\gemrc"
38
- - if %RUBY_VERSION%==head ( gem install bundler -v'< 2' )
39
- - if %RUBY_VERSION%==head-x64 ( gem install bundler -v'< 2' )
40
- - bundle install
41
-
42
- before_build:
43
- - ruby -v
44
- - gem -v
45
-
46
- build_script:
47
- - bundle exec rake compile -rdevkit
48
-
49
- test_script:
50
- - bundle exec rake spec