From 27e168927a10d0028366fe364c1aafe1b62a25b4 Mon Sep 17 00:00:00 2001 From: Sergey Alekseev Date: Fri, 5 Jul 2019 21:00:31 +0300 Subject: [PATCH 01/92] start calibration from the minimum cost supported by the algorithm --- CHANGELOG | 1 + lib/bcrypt/engine.rb | 4 +++- lib/bcrypt/password.rb | 2 +- spec/bcrypt/engine_spec.rb | 10 ++++++++++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 8bead60..2f14add 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -92,3 +92,4 @@ - Update C and Java implementations to latest versions [GH #182 by @fonica] - Bump default cost to 12 [GH #181 by @bdewater] - Remove explicit support for Rubies 1.8 and 1.9 + - Start calibration from the minimum cost supported by the algorithm [GH #206 by @sergey-alekseev] diff --git a/lib/bcrypt/engine.rb b/lib/bcrypt/engine.rb index 226d142..2204843 100644 --- a/lib/bcrypt/engine.rb +++ b/lib/bcrypt/engine.rb @@ -5,6 +5,8 @@ class Engine DEFAULT_COST = 12 # The minimum cost supported by the algorithm. MIN_COST = 4 + # The maximum cost supported by the algorithm. + MAX_COST = 31 # Maximum possible size of bcrypt() salts. MAX_SALT_LENGTH = 16 @@ -99,7 +101,7 @@ def self.valid_secret?(secret) # # should take less than 1000ms # BCrypt::Password.create("woo", :cost => 12) def self.calibrate(upper_time_limit_in_ms) - 40.times do |i| + (BCrypt::Engine::MIN_COST..BCrypt::Engine::MAX_COST-1).each do |i| start_time = Time.now Password.create("testing testing", :cost => i+1) end_time = Time.now - start_time diff --git a/lib/bcrypt/password.rb b/lib/bcrypt/password.rb index 509a8d9..f984e32 100644 --- a/lib/bcrypt/password.rb +++ b/lib/bcrypt/password.rb @@ -42,7 +42,7 @@ class << self # @password = BCrypt::Password.create("my secret", :cost => 13) def create(secret, options = {}) cost = options[:cost] || BCrypt::Engine.cost - raise ArgumentError if cost > 31 + raise ArgumentError if cost > BCrypt::Engine::MAX_COST Password.new(BCrypt::Engine.hash_secret(secret, BCrypt::Engine.generate_salt(cost))) end diff --git a/spec/bcrypt/engine_spec.rb b/spec/bcrypt/engine_spec.rb index cde842c..90a681e 100644 --- a/spec/bcrypt/engine_spec.rb +++ b/spec/bcrypt/engine_spec.rb @@ -1,5 +1,15 @@ require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper")) +describe 'BCrypt::Engine' do + describe '.calibrate(upper_time_limit_in_ms)' do + context 'a tiny upper time limit provided' do + it 'returns a minimum cost supported by the algorithm' do + expect(BCrypt::Engine.calibrate(0.001)).to eq(4) + end + end + end +end + describe "The BCrypt engine" do specify "should calculate the optimal cost factor to fit in a specific time" do first = BCrypt::Engine.calibrate(100) From 653b6fc67b82f425a885282ff663ccc643938f79 Mon Sep 17 00:00:00 2001 From: bfarago Date: Mon, 14 Oct 2019 04:02:19 +0800 Subject: [PATCH 02/92] fix original repos issue #201 compilation on non-i386 platforms and #204 objs when... --- ext/mri/crypt_blowfish.c | 4 ++-- ext/mri/x86.S | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ext/mri/crypt_blowfish.c b/ext/mri/crypt_blowfish.c index 9d3f3be..1bec87c 100644 --- a/ext/mri/crypt_blowfish.c +++ b/ext/mri/crypt_blowfish.c @@ -517,7 +517,7 @@ static void BF_swap(BF_word *x, int count) R = L; \ L = tmp4 ^ data.ctx.P[BF_N + 1]; -#if BF_ASM +#if BF_ASM == 1 #define BF_body() \ _BF_body_r(&data.ctx); #else @@ -650,7 +650,7 @@ static char *BF_crypt(const char *key, const char *setting, char *output, int size, BF_word min) { -#if BF_ASM +#if BF_ASM == 1 extern void _BF_body_r(BF_ctx *ctx); #endif struct { diff --git a/ext/mri/x86.S b/ext/mri/x86.S index b0f1cd2..12eded2 100644 --- a/ext/mri/x86.S +++ b/ext/mri/x86.S @@ -198,6 +198,8 @@ BF_die: #endif +#ifdef __i386__ #if defined(__ELF__) && defined(__linux__) .section .note.GNU-stack,"",@progbits #endif +#endif From 2b40bb6c52bb99b7e0f0e20f8b0cadfb30a9fde4 Mon Sep 17 00:00:00 2001 From: bfarago Date: Mon, 14 Oct 2019 11:19:19 +0800 Subject: [PATCH 03/92] Fix cppcheck style findings #213 --- ext/mri/crypt_blowfish.c | 12 ++++-------- ext/mri/crypt_gensalt.c | 2 +- ext/mri/crypt_gensalt.h | 2 +- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/ext/mri/crypt_blowfish.c b/ext/mri/crypt_blowfish.c index 1bec87c..5760064 100644 --- a/ext/mri/crypt_blowfish.c +++ b/ext/mri/crypt_blowfish.c @@ -361,7 +361,7 @@ static BF_ctx BF_init_state = { } }; -static unsigned char BF_itoa64[64 + 1] = +static const unsigned char BF_itoa64[64 + 1] = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; static unsigned char BF_atoi64[0x60] = { @@ -387,9 +387,8 @@ static int BF_decode(BF_word *dst, const char *src, int size) unsigned char *dptr = (unsigned char *)dst; unsigned char *end = dptr + size; const unsigned char *sptr = (const unsigned char *)src; - unsigned int tmp, c1, c2, c3, c4; - do { + unsigned int tmp, c1, c2, c3, c4; BF_safe_atoi64(c1, *sptr++); BF_safe_atoi64(c2, *sptr++); *dptr++ = (c1 << 2) | ((c2 & 0x30) >> 4); @@ -402,7 +401,6 @@ static int BF_decode(BF_word *dst, const char *src, int size) BF_safe_atoi64(c4, *sptr++); *dptr++ = ((c3 & 0x03) << 6) | c4; } while (dptr < end); - return 0; } @@ -411,9 +409,8 @@ static void BF_encode(char *dst, const BF_word *src, int size) const unsigned char *sptr = (const unsigned char *)src; const unsigned char *end = sptr + size; unsigned char *dptr = (unsigned char *)dst; - unsigned int c1, c2; - do { + unsigned int c1, c2; c1 = *sptr++; *dptr++ = BF_itoa64[c1 >> 2]; c1 = (c1 & 0x03) << 4; @@ -442,10 +439,9 @@ static void BF_swap(BF_word *x, int count) { static int endianness_check = 1; char *is_little_endian = (char *)&endianness_check; - BF_word tmp; - if (*is_little_endian) do { + BF_word tmp; tmp = *x; tmp = (tmp << 16) | (tmp >> 16); *x++ = ((tmp & 0x00FF00FF) << 8) | ((tmp >> 8) & 0x00FF00FF); diff --git a/ext/mri/crypt_gensalt.c b/ext/mri/crypt_gensalt.c index 73c15a1..744912a 100644 --- a/ext/mri/crypt_gensalt.c +++ b/ext/mri/crypt_gensalt.c @@ -28,7 +28,7 @@ /* Just to make sure the prototypes match the actual definitions */ #include "crypt_gensalt.h" -unsigned char _crypt_itoa64[64 + 1] = +const unsigned char _crypt_itoa64[64 + 1] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; char *_crypt_gensalt_traditional_rn(const char *prefix, unsigned long count, diff --git a/ext/mri/crypt_gensalt.h b/ext/mri/crypt_gensalt.h index 457bbfe..3a5ca08 100644 --- a/ext/mri/crypt_gensalt.h +++ b/ext/mri/crypt_gensalt.h @@ -17,7 +17,7 @@ #ifndef _CRYPT_GENSALT_H #define _CRYPT_GENSALT_H -extern unsigned char _crypt_itoa64[]; +extern const unsigned char _crypt_itoa64[]; extern char *_crypt_gensalt_traditional_rn(const char *prefix, unsigned long count, const char *input, int size, char *output, int output_size); From 591776c57d38494f1184e4a02dca8f98f1bf2934 Mon Sep 17 00:00:00 2001 From: Felix Date: Thu, 14 Nov 2019 20:49:06 +0100 Subject: [PATCH 04/92] Update Changeloge for v3.1.13 --- CHANGELOG | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 2f14add..bf9fd46 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -87,9 +87,13 @@ - Add support for Ruby 2.3, 2.4, and 2.5 in compiled Windows binaries - Fix compatibility with libxcrypt [GH #164 by @besser82] -[DRAFT] 4.0.0 MMM DD YYYY +3.1.13 May 31 2019 - No longer include compiled binaries for Windows. See GH #173. - Update C and Java implementations to latest versions [GH #182 by @fonica] - Bump default cost to 12 [GH #181 by @bdewater] - Remove explicit support for Rubies 1.8 and 1.9 - Start calibration from the minimum cost supported by the algorithm [GH #206 by @sergey-alekseev] + - Remove explicit support for Rubies 1.8 and 1.9 [GH #185 by @tjschuck] + - Define SKIP_GNU token when building extension (Fixes FreeBSD >= 12) [GH #189 by @adam12] + +[DRAFT] 4.0.0 MMM DD YYYY \ No newline at end of file From 50060d84608dde66066a7e7d680131a7eba2f7ed Mon Sep 17 00:00:00 2001 From: Felix Date: Thu, 14 Nov 2019 20:54:12 +0100 Subject: [PATCH 05/92] Reverse CHANGELOG order to fix #203 --- CHANGELOG | 142 +++++++++++++++++++++++++++--------------------------- 1 file changed, 71 insertions(+), 71 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index bf9fd46..8c83b8b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,99 +1,99 @@ -1.0.0 Feb 27 2007 - - Initial release. +[DRAFT] 4.0.0 MMM DD YYYY -2.0.0 Mar 07 2007 - - Removed BCrypt::Password#exactly_equals -- use BCrypt::Password#eql? instead. - - Added BCrypt::Password#is_password?. - - Refactored out BCrypt::Internals into more useful BCrypt::Engine. - - Added validation of secrets -- nil is not healthy. +3.1.13 May 31 2019 + - No longer include compiled binaries for Windows. See GH #173. + - Update C and Java implementations to latest versions [GH #182 by @fonica] + - Bump default cost to 12 [GH #181 by @bdewater] + - Remove explicit support for Rubies 1.8 and 1.9 + - Start calibration from the minimum cost supported by the algorithm [GH #206 by @sergey-alekseev] + - Remove explicit support for Rubies 1.8 and 1.9 [GH #185 by @tjschuck] + - Define SKIP_GNU token when building extension (Fixes FreeBSD >= 12) [GH #189 by @adam12] -2.0.1 Mar 09 2007 - - Fixed load path issues - - Fixed crashes when hashing weird values (e.g., false, etc.) +3.1.12 May 16 2018 + - Add support for Ruby 2.3, 2.4, and 2.5 in compiled Windows binaries + - Fix compatibility with libxcrypt [GH #164 by @besser82] -2.0.2 Jun 06 2007 - - Fixed example code in the README [Winson] - - Fixed Solaris compatibility [Jeremy LaTrasse, Twitter crew] +3.1.11 Mar 06 2016 + - Add support for Ruby 2.2 in compiled Windows binaries -2.0.3 May 07 2008 - - Made exception classes descend from StandardError, not Exception [Dan42] - - Changed BCrypt::Engine.hash to BCrypt::Engine.hash_secret to avoid Merb - sorting issues. [Lee Pope] +3.1.10 Jan 28 2015 + - Fix issue with dumping a BCrypt::Password instance to YAML in Ruby 2.2 [GH #107 by @mattwildig] -2.0.4 Mar 09 2009 - - Added Ruby 1.9 compatibility. [Genki Takiuchi] - - Fixed segfaults on some different types of empty strings. [Mike Pomraning] +3.1.9 Oct 23 2014 + - Rebuild corrupt binaries -2.0.5 Mar 11 2009 - - Fixed Ruby 1.8.5 compatibility. [Mike Pomraning] +3.1.8 Oct 23 2014 + - Add support for Ruby 2.1 in compiled Windows binaries [GH #102] -2.1.0 Aug 12 2009 - - Improved code coverage, unit tests, and build chain. [Hongli Lai] - - Ruby 1.9 compatibility fixes. [Hongli Lai] - - JRuby support, using Damien Miller's jBCrypt. [Hongli Lai] - - Ruby 1.9 GIL releasing for high-cost hashes. [Hongli Lai] +3.1.7 Feb 24 2014 + - Rebuild corrupt Java binary version of gem [GH #90] + - The 2.1 support for Windows binaries alleged in 3.1.3 was a lie -- documentation removed -2.1.1 Aug 14 2009 - - JVM 1.4/1.5 compatibility [Hongli Lai] +3.1.6 Feb 21 2014 + - Dummy version of "bcrypt-ruby" needed a couple version bumps to fix some + bugs. It felt wrong to have that at a higher version than the real gem, so + the real gem is getting bumped to 3.1.6. -2.1.2 Sep 16 2009 - - Fixed support for Solaris, OpenSolaris. +3.1.3 Feb 21 2014 + - Add support for Ruby 2.1 in compiled Windows binaries + - Rename gem from "bcrypt-ruby" to just "bcrypt". [GH #86 by @sferik] -3.0.0 Aug 24 2011 - - Bcrypt C implementation replaced with a public domain implementation. - - License changed to MIT +3.1.2 Aug 26 2013 + - Add support for Ruby 1.8 and 2.0 (in addition to 1.9) in compiled Windows binaries + - Add support for 64-bit Windows -3.0.1 Sep 12 2011 - - create raises an exception if the cost is higher than 31. GH #27 +3.1.1 Jul 10 2013 + - Remove support for Ruby 1.8 in compiled win32 binaries 3.1.0 May 07 2013 - Add BCrypt::Password.valid_hash?(str) to check if a string is a valid bcrypt password hash - BCrypt::Password cost should be set to DEFAULT_COST if nil - Add BCrypt::Engine.cost attribute for getting/setting a default cost externally -3.1.1 Jul 10 2013 - - Remove support for Ruby 1.8 in compiled win32 binaries +3.0.1 Sep 12 2011 + - create raises an exception if the cost is higher than 31. GH #27 -3.1.2 Aug 26 2013 - - Add support for Ruby 1.8 and 2.0 (in addition to 1.9) in compiled Windows binaries - - Add support for 64-bit Windows +3.0.0 Aug 24 2011 + - Bcrypt C implementation replaced with a public domain implementation. + - License changed to MIT -3.1.3 Feb 21 2014 - - Add support for Ruby 2.1 in compiled Windows binaries - - Rename gem from "bcrypt-ruby" to just "bcrypt". [GH #86 by @sferik] +2.1.2 Sep 16 2009 + - Fixed support for Solaris, OpenSolaris. -3.1.6 Feb 21 2014 - - Dummy version of "bcrypt-ruby" needed a couple version bumps to fix some - bugs. It felt wrong to have that at a higher version than the real gem, so - the real gem is getting bumped to 3.1.6. +2.1.1 Aug 14 2009 + - JVM 1.4/1.5 compatibility [Hongli Lai] -3.1.7 Feb 24 2014 - - Rebuild corrupt Java binary version of gem [GH #90] - - The 2.1 support for Windows binaries alleged in 3.1.3 was a lie -- documentation removed +2.1.0 Aug 12 2009 + - Improved code coverage, unit tests, and build chain. [Hongli Lai] + - Ruby 1.9 compatibility fixes. [Hongli Lai] + - JRuby support, using Damien Miller's jBCrypt. [Hongli Lai] + - Ruby 1.9 GIL releasing for high-cost hashes. [Hongli Lai] -3.1.8 Oct 23 2014 - - Add support for Ruby 2.1 in compiled Windows binaries [GH #102] +2.0.5 Mar 11 2009 + - Fixed Ruby 1.8.5 compatibility. [Mike Pomraning] -3.1.9 Oct 23 2014 - - Rebuild corrupt binaries +2.0.4 Mar 09 2009 + - Added Ruby 1.9 compatibility. [Genki Takiuchi] + - Fixed segfaults on some different types of empty strings. [Mike Pomraning] -3.1.10 Jan 28 2015 - - Fix issue with dumping a BCrypt::Password instance to YAML in Ruby 2.2 [GH #107 by @mattwildig] +2.0.3 May 07 2008 + - Made exception classes descend from StandardError, not Exception [Dan42] + - Changed BCrypt::Engine.hash to BCrypt::Engine.hash_secret to avoid Merb + sorting issues. [Lee Pope] -3.1.11 Mar 06 2016 - - Add support for Ruby 2.2 in compiled Windows binaries +2.0.2 Jun 06 2007 + - Fixed example code in the README [Winson] + - Fixed Solaris compatibility [Jeremy LaTrasse, Twitter crew] -3.1.12 May 16 2018 - - Add support for Ruby 2.3, 2.4, and 2.5 in compiled Windows binaries - - Fix compatibility with libxcrypt [GH #164 by @besser82] +2.0.1 Mar 09 2007 + - Fixed load path issues + - Fixed crashes when hashing weird values (e.g., false, etc.) -3.1.13 May 31 2019 - - No longer include compiled binaries for Windows. See GH #173. - - Update C and Java implementations to latest versions [GH #182 by @fonica] - - Bump default cost to 12 [GH #181 by @bdewater] - - Remove explicit support for Rubies 1.8 and 1.9 - - Start calibration from the minimum cost supported by the algorithm [GH #206 by @sergey-alekseev] - - Remove explicit support for Rubies 1.8 and 1.9 [GH #185 by @tjschuck] - - Define SKIP_GNU token when building extension (Fixes FreeBSD >= 12) [GH #189 by @adam12] +2.0.0 Mar 07 2007 + - Removed BCrypt::Password#exactly_equals -- use BCrypt::Password#eql? instead. + - Added BCrypt::Password#is_password?. + - Refactored out BCrypt::Internals into more useful BCrypt::Engine. + - Added validation of secrets -- nil is not healthy. -[DRAFT] 4.0.0 MMM DD YYYY \ No newline at end of file +1.0.0 Feb 27 2007 + - Initial release. \ No newline at end of file From 3382230eaf16226dc9f7f1a050c37c0841b5d730 Mon Sep 17 00:00:00 2001 From: Jeremy Daer Date: Tue, 26 Nov 2019 15:45:56 -0800 Subject: [PATCH 06/92] CI: allow failures on bleeding edge Rubies So we can get a clear picture of PR status. --- .travis.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.travis.yml b/.travis.yml index 621ca7f..94e234e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,4 +14,10 @@ rvm: - ruby-head - jruby-head - rbx-3 +matrix: + allow_failures: + - rvm: ruby-head + - rvm: jruby-head + - rvm: rbx-3 + fast_finish: true script: bundle exec rake From f48c58fc5e8419dd7322f6873e0faff468865c65 Mon Sep 17 00:00:00 2001 From: Jeremy Daer Date: Mon, 25 Nov 2019 16:30:45 -0800 Subject: [PATCH 07/92] Fix rare strdup segfault Caused by compiler confusion about what to export from string.h, depending on ANSI/ISO C standards used. When strdup isn't exported, GCC provides a builtin. When cross-compiled for another platform, this can lead to returning a 32-bit pointer instead of 64-bit -> segfault. Fix by including ruby/util.h which unsets and redefines strdup as ruby_strdup, a portable implementation. Further reading * https://stackoverflow.com/questions/8359966/strdup-returning-address-out-of-bounds * https://bitbucket.org/einsteintoolkit/tickets/issues/1816 Similar issue affected Nokogiri, with a similar fix: * https://github.com/sparklemotion/nokogiri/pull/1517 --- ext/mri/wrapper.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ext/mri/wrapper.c b/ext/mri/wrapper.c index 1e49c90..c88c0bd 100644 --- a/ext/mri/wrapper.c +++ b/ext/mri/wrapper.c @@ -17,6 +17,9 @@ #include #include +/* Redefine strdup to ruby_strdup in case string.h doesn't export it. */ +#include + #include #ifndef __set_errno #define __set_errno(val) errno = (val) From e1320b0328b54a890be5f8ba7199fb4f59660fd7 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 27 Oct 2015 17:42:05 -0700 Subject: [PATCH 08/92] unlock the gvl when calculating hashes / salts Holding on to the GVL means we can't do anything in parallel. Since these are CPU-only operations that do not involve the ruby interpreter, we can safely unlock the GVL when calculating hashes. This program demonstrates the difference: ```ruby require 'bcrypt' require 'thread' GUESSES = (ENV['GUESSES'] || 100).to_i THREADS = (ENV['THREADS'] || 1).to_i p GUESSES: GUESSES, THREADS: THREADS password = BCrypt::Password.create 'hello world!' queue = Queue.new GUESSES.times { queue << "x" * 90 } THREADS.times { queue << nil } THREADS.times.map { Thread.new { while guess = queue.pop password == guess end } }.each(&:join) ``` Without this patch: ``` [aaron@TC bcrypt-ruby (master)]$ time THREADS=4 ruby test.rb {:GUESSES=>100, :THREADS=>4} real 0m30.014s user 0m29.739s sys 0m0.153s ``` With the patch: ``` [aaron@TC bcrypt-ruby (master)]$ time THREADS=4 ruby -Ilib test.rb {:GUESSES=>100, :THREADS=>4} real 0m12.293s user 0m42.382s sys 0m0.169s ``` If you run this program with the patch, you can see Ruby use nearly 400% CPU, as long as you have a 4 core machine. --- ext/mri/bcrypt_ext.c | 93 ++++++++++++++++++++++++++++++++++++-------- ext/mri/extconf.rb | 1 + 2 files changed, 77 insertions(+), 17 deletions(-) diff --git a/ext/mri/bcrypt_ext.c b/ext/mri/bcrypt_ext.c index b2edd1d..eb38758 100644 --- a/ext/mri/bcrypt_ext.c +++ b/ext/mri/bcrypt_ext.c @@ -1,20 +1,57 @@ #include #include +#ifdef HAVE_RUBY_THREAD_H +#include +#endif + +/* Delete this when 1.8 support is dropped. */ +#ifdef HAVE_RB_STR_NEW_FROZEN + #define RB_STR_NEW_FROZEN rb_str_new_frozen +#else + #define RB_STR_NEW_FROZEN rb_str_new4 +#endif + static VALUE mBCrypt; static VALUE cBCryptEngine; +struct bc_salt_args { + const char * prefix; + unsigned long count; + const char * input; + int size; +}; + +static void * bc_salt_nogvl(void * ptr) { + struct bc_salt_args * args = ptr; + + return crypt_gensalt_ra(args->prefix, args->count, args->input, args->size); +} + /* Given a logarithmic cost parameter, generates a salt for use with +bc_crypt+. */ static VALUE bc_salt(VALUE self, VALUE prefix, VALUE count, VALUE input) { char * salt; VALUE str_salt; - - salt = crypt_gensalt_ra( - StringValuePtr(prefix), - NUM2ULONG(count), - NIL_P(input) ? NULL : StringValuePtr(input), - NIL_P(input) ? 0 : RSTRING_LEN(input)); + struct bc_salt_args args; + + /* duplicate the parameters for thread safety. If another thread has a + * reference to the parameters and mutates them while we are working, + * that would be very bad. Duping the strings means that the reference + * isn't shared. */ + prefix = RB_STR_NEW_FROZEN(prefix); + input = RB_STR_NEW_FROZEN(input); + + args.prefix = StringValuePtr(prefix); + args.count = NUM2ULONG(count); + args.input = NIL_P(input) ? NULL : StringValuePtr(input); + args.size = NIL_P(input) ? 0 : RSTRING_LEN(input); + +#ifdef HAVE_RUBY_THREAD_H + salt = rb_thread_call_without_gvl(bc_salt_nogvl, &args, NULL, NULL); +#else + salt = bc_salt_nogvl((void *)&args); +#endif if(!salt) return Qnil; @@ -24,30 +61,52 @@ static VALUE bc_salt(VALUE self, VALUE prefix, VALUE count, VALUE input) { return str_salt; } +struct bc_crypt_args { + const char * key; + const char * setting; + void * data; + int size; +}; + +static void * bc_crypt_nogvl(void * ptr) { + struct bc_crypt_args * args = ptr; + + return crypt_ra(args->key, args->setting, &args->data, &args->size); +} + /* Given a secret and a salt, generates a salted hash (which you can then store safely). */ static VALUE bc_crypt(VALUE self, VALUE key, VALUE setting) { char * value; - void * data; - int size; VALUE out; - data = NULL; - size = 0xDEADBEEF; + struct bc_crypt_args args; if(NIL_P(key) || NIL_P(setting)) return Qnil; - value = crypt_ra( - NIL_P(key) ? NULL : StringValuePtr(key), - NIL_P(setting) ? NULL : StringValuePtr(setting), - &data, - &size); + /* duplicate the parameters for thread safety. If another thread has a + * reference to the parameters and mutates them while we are working, + * that would be very bad. Duping the strings means that the reference + * isn't shared. */ + key = RB_STR_NEW_FROZEN(key); + setting = RB_STR_NEW_FROZEN(setting); + + args.data = NULL; + args.size = 0xDEADBEEF; + args.key = NIL_P(key) ? NULL : StringValuePtr(key); + args.setting = NIL_P(setting) ? NULL : StringValuePtr(setting); + +#ifdef HAVE_RUBY_THREAD_H + value = rb_thread_call_without_gvl(bc_crypt_nogvl, &args, NULL, NULL); +#else + value = bc_crypt_nogvl((void *)&args); +#endif if(!value) return Qnil; - out = rb_str_new2(value); + out = rb_str_new(args.data, args.size - 1); - xfree(data); + xfree(args.data); return out; } diff --git a/ext/mri/extconf.rb b/ext/mri/extconf.rb index c2222de..aacf806 100644 --- a/ext/mri/extconf.rb +++ b/ext/mri/extconf.rb @@ -18,5 +18,6 @@ $defs << "-D__SKIP_GNU" dir_config("bcrypt_ext") + have_func 'rb_str_new_frozen' # Ruby 1.8 support. create_makefile("bcrypt_ext") end From 25fbc55f05646c03406762c8b279cd8a0e614ffb Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 27 Nov 2019 14:40:55 -0800 Subject: [PATCH 09/92] make sure we use null padded buffers --- ext/mri/bcrypt_ext.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ext/mri/bcrypt_ext.c b/ext/mri/bcrypt_ext.c index eb38758..4f2a159 100644 --- a/ext/mri/bcrypt_ext.c +++ b/ext/mri/bcrypt_ext.c @@ -42,7 +42,7 @@ static VALUE bc_salt(VALUE self, VALUE prefix, VALUE count, VALUE input) { prefix = RB_STR_NEW_FROZEN(prefix); input = RB_STR_NEW_FROZEN(input); - args.prefix = StringValuePtr(prefix); + args.prefix = StringValueCStr(prefix); args.count = NUM2ULONG(count); args.input = NIL_P(input) ? NULL : StringValuePtr(input); args.size = NIL_P(input) ? 0 : RSTRING_LEN(input); @@ -93,8 +93,8 @@ static VALUE bc_crypt(VALUE self, VALUE key, VALUE setting) { args.data = NULL; args.size = 0xDEADBEEF; - args.key = NIL_P(key) ? NULL : StringValuePtr(key); - args.setting = NIL_P(setting) ? NULL : StringValuePtr(setting); + args.key = NIL_P(key) ? NULL : StringValueCStr(key); + args.setting = NIL_P(setting) ? NULL : StringValueCStr(setting); #ifdef HAVE_RUBY_THREAD_H value = rb_thread_call_without_gvl(bc_crypt_nogvl, &args, NULL, NULL); @@ -102,7 +102,7 @@ static VALUE bc_crypt(VALUE self, VALUE key, VALUE setting) { value = bc_crypt_nogvl((void *)&args); #endif - if(!value) return Qnil; + if(!value || !args.data) return Qnil; out = rb_str_new(args.data, args.size - 1); From c396e397c3927cb706a4a74afa2c0c83130881eb Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 27 Nov 2019 14:50:18 -0800 Subject: [PATCH 10/92] We don't support 1.8 anymore --- ext/mri/bcrypt_ext.c | 15 ++++----------- ext/mri/extconf.rb | 1 - 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/ext/mri/bcrypt_ext.c b/ext/mri/bcrypt_ext.c index 4f2a159..f23a10d 100644 --- a/ext/mri/bcrypt_ext.c +++ b/ext/mri/bcrypt_ext.c @@ -5,13 +5,6 @@ #include #endif -/* Delete this when 1.8 support is dropped. */ -#ifdef HAVE_RB_STR_NEW_FROZEN - #define RB_STR_NEW_FROZEN rb_str_new_frozen -#else - #define RB_STR_NEW_FROZEN rb_str_new4 -#endif - static VALUE mBCrypt; static VALUE cBCryptEngine; @@ -39,8 +32,8 @@ static VALUE bc_salt(VALUE self, VALUE prefix, VALUE count, VALUE input) { * reference to the parameters and mutates them while we are working, * that would be very bad. Duping the strings means that the reference * isn't shared. */ - prefix = RB_STR_NEW_FROZEN(prefix); - input = RB_STR_NEW_FROZEN(input); + prefix = rb_str_new_frozen(prefix); + input = rb_str_new_frozen(input); args.prefix = StringValueCStr(prefix); args.count = NUM2ULONG(count); @@ -88,8 +81,8 @@ static VALUE bc_crypt(VALUE self, VALUE key, VALUE setting) { * reference to the parameters and mutates them while we are working, * that would be very bad. Duping the strings means that the reference * isn't shared. */ - key = RB_STR_NEW_FROZEN(key); - setting = RB_STR_NEW_FROZEN(setting); + key = rb_str_new_frozen(key); + setting = rb_str_new_frozen(setting); args.data = NULL; args.size = 0xDEADBEEF; diff --git a/ext/mri/extconf.rb b/ext/mri/extconf.rb index aacf806..c2222de 100644 --- a/ext/mri/extconf.rb +++ b/ext/mri/extconf.rb @@ -18,6 +18,5 @@ $defs << "-D__SKIP_GNU" dir_config("bcrypt_ext") - have_func 'rb_str_new_frozen' # Ruby 1.8 support. create_makefile("bcrypt_ext") end From 75d8aa0fcfd3923357c3a0e7bd8f9a6fa807eb52 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 27 Nov 2019 15:19:42 -0800 Subject: [PATCH 11/92] Fix free function The crypt library is almost certainly using `malloc` and not `xmalloc`. We should use `free` instead of `xfree` to ensure the malloc / free calls are correctly balanced. --- ext/mri/bcrypt_ext.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/mri/bcrypt_ext.c b/ext/mri/bcrypt_ext.c index f23a10d..3acfb46 100644 --- a/ext/mri/bcrypt_ext.c +++ b/ext/mri/bcrypt_ext.c @@ -49,7 +49,7 @@ static VALUE bc_salt(VALUE self, VALUE prefix, VALUE count, VALUE input) { if(!salt) return Qnil; str_salt = rb_str_new2(salt); - xfree(salt); + free(salt); return str_salt; } @@ -99,7 +99,7 @@ static VALUE bc_crypt(VALUE self, VALUE key, VALUE setting) { out = rb_str_new(args.data, args.size - 1); - xfree(args.data); + free(args.data); return out; } From eed596f003636487a673acff23802a1ca68c1088 Mon Sep 17 00:00:00 2001 From: Jeffrey Martin Date: Wed, 19 Jun 2019 17:33:55 -0500 Subject: [PATCH 12/92] Update to more compatible syntax & protect stack By attempting to include `x86.S` from Openwall crypt other hardware architectures are attempting to use a source file that does not apply. Update the stack protection to use a more compatible syntax and allow for inclusion of the assembly file to all compilers. --- ext/mri/x86.S | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ext/mri/x86.S b/ext/mri/x86.S index 12eded2..4c5c069 100644 --- a/ext/mri/x86.S +++ b/ext/mri/x86.S @@ -198,8 +198,6 @@ BF_die: #endif -#ifdef __i386__ #if defined(__ELF__) && defined(__linux__) -.section .note.GNU-stack,"",@progbits -#endif +.section .note.GNU-stack,"",%progbits #endif From 13ad68b7c56f9f3356fe788b271bcb384c0b7dd6 Mon Sep 17 00:00:00 2001 From: Sergey Alekseev Date: Sat, 28 Dec 2019 01:52:19 +0700 Subject: [PATCH 13/92] fix v3.1.13 changelog entry - move a not released changelog entry out of 3.1.13 - remove a duplicated line - add a newline to the end of file Fixes #214. Closes #211. [ci skip] --- CHANGELOG | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 8c83b8b..794f11d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,12 +1,11 @@ [DRAFT] 4.0.0 MMM DD YYYY + - Start calibration from the minimum cost supported by the algorithm [GH #206 by @sergey-alekseev] 3.1.13 May 31 2019 - No longer include compiled binaries for Windows. See GH #173. - Update C and Java implementations to latest versions [GH #182 by @fonica] - Bump default cost to 12 [GH #181 by @bdewater] - Remove explicit support for Rubies 1.8 and 1.9 - - Start calibration from the minimum cost supported by the algorithm [GH #206 by @sergey-alekseev] - - Remove explicit support for Rubies 1.8 and 1.9 [GH #185 by @tjschuck] - Define SKIP_GNU token when building extension (Fixes FreeBSD >= 12) [GH #189 by @adam12] 3.1.12 May 16 2018 @@ -96,4 +95,4 @@ - Added validation of secrets -- nil is not healthy. 1.0.0 Feb 27 2007 - - Initial release. \ No newline at end of file + - Initial release. From bb0c1da8c977734642585c73ade132f5a30d09e1 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Tue, 31 Mar 2020 10:42:50 -0500 Subject: [PATCH 14/92] Add TruffleRuby to CI --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 94e234e..1cecdb2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,10 +14,14 @@ rvm: - ruby-head - jruby-head - rbx-3 + - truffleruby + - truffleruby-head matrix: allow_failures: - rvm: ruby-head - rvm: jruby-head - rvm: rbx-3 + - rvm: truffleruby + - rvm: truffleruby-head fast_finish: true script: bundle exec rake From 919d58472b63f276eb2c63797d784cb27f0191e2 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Tue, 14 Apr 2020 11:48:55 -0500 Subject: [PATCH 15/92] Calculate minimum calibration time variably --- spec/bcrypt/engine_spec.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/spec/bcrypt/engine_spec.rb b/spec/bcrypt/engine_spec.rb index 90a681e..7c6d6f3 100644 --- a/spec/bcrypt/engine_spec.rb +++ b/spec/bcrypt/engine_spec.rb @@ -12,8 +12,11 @@ describe "The BCrypt engine" do specify "should calculate the optimal cost factor to fit in a specific time" do - first = BCrypt::Engine.calibrate(100) - second = BCrypt::Engine.calibrate(400) + start_time = Time.now + BCrypt::Password.create("testing testing", :cost => BCrypt::Engine::MIN_COST + 1) + min_time_ms = (Time.now - start_time) * 1000 + first = BCrypt::Engine.calibrate(min_time_ms) + second = BCrypt::Engine.calibrate(min_time_ms * 2) expect(second).to be > first end end From eb567cb788635759323691ec07178e1f06290855 Mon Sep 17 00:00:00 2001 From: Nathan Kramer Date: Tue, 26 May 2020 09:40:49 +1000 Subject: [PATCH 16/92] Ensure valid_hash? returns a Boolean I noticed that valid_hash? returns either nil or 0, in the usual cases. Since the docs list valid_hash? as returning a Boolean, I thought this might be a bug. at the very least I suspect think this would be less confusing. --- lib/bcrypt/password.rb | 2 +- spec/bcrypt/password_spec.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/bcrypt/password.rb b/lib/bcrypt/password.rb index f984e32..554967c 100644 --- a/lib/bcrypt/password.rb +++ b/lib/bcrypt/password.rb @@ -47,7 +47,7 @@ def create(secret, options = {}) end def valid_hash?(h) - h =~ /^\$[0-9a-z]{2}\$[0-9]{2}\$[A-Za-z0-9\.\/]{53}$/ + /^\$[0-9a-z]{2}\$[0-9]{2}\$[A-Za-z0-9\.\/]{53}$/ === h end end diff --git a/spec/bcrypt/password_spec.rb b/spec/bcrypt/password_spec.rb index 648e614..f880f1c 100644 --- a/spec/bcrypt/password_spec.rb +++ b/spec/bcrypt/password_spec.rb @@ -116,9 +116,9 @@ describe "Validating a password hash" do specify "should not accept an invalid password" do - expect(BCrypt::Password.valid_hash?("i_am_so_not_valid")).to be_falsey + expect(BCrypt::Password.valid_hash?("i_am_so_not_valid")).to be(false) end specify "should accept a valid password" do - expect(BCrypt::Password.valid_hash?(BCrypt::Password.create "i_am_so_valid")).to be_truthy + expect(BCrypt::Password.valid_hash?(BCrypt::Password.create "i_am_so_valid")).to be(true) end end From 1b9d33c38f0c3380a697ebab65ca7b5443dafadb Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 21 Jul 2020 09:50:24 -0700 Subject: [PATCH 17/92] bumping version --- CHANGELOG | 2 +- bcrypt.gemspec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 794f11d..90c40df 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,4 @@ -[DRAFT] 4.0.0 MMM DD YYYY +3.1.14 July 21 2020 - Start calibration from the minimum cost supported by the algorithm [GH #206 by @sergey-alekseev] 3.1.13 May 31 2019 diff --git a/bcrypt.gemspec b/bcrypt.gemspec index e67bad2..4323c0b 100644 --- a/bcrypt.gemspec +++ b/bcrypt.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = 'bcrypt' - s.version = '3.1.13' + s.version = '3.1.14' s.summary = "OpenBSD's bcrypt() password hashing algorithm." s.description = <<-EOF From 2c17728c1d89cb0fe964d04aa50a0cb9395084f1 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 21 Jul 2020 09:51:18 -0700 Subject: [PATCH 18/92] updating lockfile --- Gemfile.lock | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 9981158..f12d616 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,31 +1,30 @@ PATH remote: . specs: - bcrypt (3.1.13) + bcrypt (3.1.14) GEM remote: https://rubygems.org/ specs: - diff-lcs (1.3) - rake (12.3.2) + diff-lcs (1.4.4) + rake (13.0.1) rake-compiler (0.9.9) rake - rspec (3.8.0) - rspec-core (~> 3.8.0) - rspec-expectations (~> 3.8.0) - rspec-mocks (~> 3.8.0) - rspec-core (3.8.0) - rspec-support (~> 3.8.0) - rspec-expectations (3.8.3) + rspec (3.9.0) + rspec-core (~> 3.9.0) + rspec-expectations (~> 3.9.0) + rspec-mocks (~> 3.9.0) + rspec-core (3.9.2) + rspec-support (~> 3.9.3) + rspec-expectations (3.9.2) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.8.0) - rspec-mocks (3.8.0) + rspec-support (~> 3.9.0) + rspec-mocks (3.9.1) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.8.0) - rspec-support (3.8.0) + rspec-support (~> 3.9.0) + rspec-support (3.9.3) PLATFORMS - java ruby DEPENDENCIES @@ -34,4 +33,4 @@ DEPENDENCIES rspec (>= 3) BUNDLED WITH - 1.16.1 + 2.2.0.dev From bdaa2fa8dde46123fd03e4527f679bd079d205bb Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 21 Jul 2020 11:36:50 -0700 Subject: [PATCH 19/92] Fixing Java build https://github.com/rake-compiler/rake-compiler/pull/172 --- Rakefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Rakefile b/Rakefile index 98ed63b..a47ce55 100644 --- a/Rakefile +++ b/Rakefile @@ -50,6 +50,8 @@ end if RUBY_PLATFORM =~ /java/ Rake::JavaExtensionTask.new('bcrypt_ext', GEMSPEC) do |ext| ext.ext_dir = 'ext/jruby' + ext.source_version = "1.7" + ext.target_version = "1.7" end else Rake::ExtensionTask.new("bcrypt_ext", GEMSPEC) do |ext| From 8f99fc1cc31b51269fa951708ba3a62ceb0cc8e4 Mon Sep 17 00:00:00 2001 From: Adam Grare Date: Tue, 21 Jul 2020 17:13:13 -0400 Subject: [PATCH 20/92] Add ruby 2.7 to the test matrix --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 94e234e..c838727 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,7 @@ rvm: - 2.4 - 2.5 - 2.6 + - 2.7 - ruby-head - jruby-head - rbx-3 From fbb89d7de4c45a4fe1fb4a072bc991bb26cb8f59 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 21 Jul 2020 14:18:44 -0700 Subject: [PATCH 21/92] Revert "unlock the gvl when calculating hashes / salts" This reverts commit e1320b0328b54a890be5f8ba7199fb4f59660fd7. --- ext/mri/bcrypt_ext.c | 88 +++++++++----------------------------------- 1 file changed, 18 insertions(+), 70 deletions(-) diff --git a/ext/mri/bcrypt_ext.c b/ext/mri/bcrypt_ext.c index 3acfb46..c8db933 100644 --- a/ext/mri/bcrypt_ext.c +++ b/ext/mri/bcrypt_ext.c @@ -1,50 +1,20 @@ #include #include -#ifdef HAVE_RUBY_THREAD_H -#include -#endif - static VALUE mBCrypt; static VALUE cBCryptEngine; -struct bc_salt_args { - const char * prefix; - unsigned long count; - const char * input; - int size; -}; - -static void * bc_salt_nogvl(void * ptr) { - struct bc_salt_args * args = ptr; - - return crypt_gensalt_ra(args->prefix, args->count, args->input, args->size); -} - /* Given a logarithmic cost parameter, generates a salt for use with +bc_crypt+. */ static VALUE bc_salt(VALUE self, VALUE prefix, VALUE count, VALUE input) { char * salt; VALUE str_salt; - struct bc_salt_args args; - - /* duplicate the parameters for thread safety. If another thread has a - * reference to the parameters and mutates them while we are working, - * that would be very bad. Duping the strings means that the reference - * isn't shared. */ - prefix = rb_str_new_frozen(prefix); - input = rb_str_new_frozen(input); - - args.prefix = StringValueCStr(prefix); - args.count = NUM2ULONG(count); - args.input = NIL_P(input) ? NULL : StringValuePtr(input); - args.size = NIL_P(input) ? 0 : RSTRING_LEN(input); - -#ifdef HAVE_RUBY_THREAD_H - salt = rb_thread_call_without_gvl(bc_salt_nogvl, &args, NULL, NULL); -#else - salt = bc_salt_nogvl((void *)&args); -#endif + + salt = crypt_gensalt_ra( + StringValuePtr(prefix), + NUM2ULONG(count), + NIL_P(input) ? NULL : StringValuePtr(input), + NIL_P(input) ? 0 : RSTRING_LEN(input)); if(!salt) return Qnil; @@ -54,52 +24,30 @@ static VALUE bc_salt(VALUE self, VALUE prefix, VALUE count, VALUE input) { return str_salt; } -struct bc_crypt_args { - const char * key; - const char * setting; - void * data; - int size; -}; - -static void * bc_crypt_nogvl(void * ptr) { - struct bc_crypt_args * args = ptr; - - return crypt_ra(args->key, args->setting, &args->data, &args->size); -} - /* Given a secret and a salt, generates a salted hash (which you can then store safely). */ static VALUE bc_crypt(VALUE self, VALUE key, VALUE setting) { char * value; + void * data; + int size; VALUE out; - struct bc_crypt_args args; + data = NULL; + size = 0xDEADBEEF; if(NIL_P(key) || NIL_P(setting)) return Qnil; - /* duplicate the parameters for thread safety. If another thread has a - * reference to the parameters and mutates them while we are working, - * that would be very bad. Duping the strings means that the reference - * isn't shared. */ - key = rb_str_new_frozen(key); - setting = rb_str_new_frozen(setting); - - args.data = NULL; - args.size = 0xDEADBEEF; - args.key = NIL_P(key) ? NULL : StringValueCStr(key); - args.setting = NIL_P(setting) ? NULL : StringValueCStr(setting); - -#ifdef HAVE_RUBY_THREAD_H - value = rb_thread_call_without_gvl(bc_crypt_nogvl, &args, NULL, NULL); -#else - value = bc_crypt_nogvl((void *)&args); -#endif + value = crypt_ra( + NIL_P(key) ? NULL : StringValuePtr(key), + NIL_P(setting) ? NULL : StringValuePtr(setting), + &data, + &size); - if(!value || !args.data) return Qnil; + if(!value || !data) return Qnil; - out = rb_str_new(args.data, args.size - 1); + out = rb_str_new2(value); - free(args.data); + xfree(data); return out; } From 7460f0b57b2f93862001ce9d2c4df1c94bd67697 Mon Sep 17 00:00:00 2001 From: Adam Grare Date: Tue, 21 Jul 2020 17:14:47 -0400 Subject: [PATCH 22/92] Install a recent bundler version --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index c838727..712c07f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,6 @@ language: ruby before_install: - "echo 'gem: --no-rdoc --no-ri' > ~/.gemrc" - - gem update --system 2.7.8 - - gem install bundler -v 1.17.3 rvm: - 2.0 - 2.1 From ef6efb20a1f0e7247cf97726db979cff514255ee Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 21 Jul 2020 14:21:00 -0700 Subject: [PATCH 23/92] bump version --- CHANGELOG | 3 +++ bcrypt.gemspec | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 90c40df..be2b274 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +3.1.15 July 21 2020 + - Remove GVL optimization. Apparently it breaks things [GH #230] + 3.1.14 July 21 2020 - Start calibration from the minimum cost supported by the algorithm [GH #206 by @sergey-alekseev] diff --git a/bcrypt.gemspec b/bcrypt.gemspec index 4323c0b..2a0120e 100644 --- a/bcrypt.gemspec +++ b/bcrypt.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = 'bcrypt' - s.version = '3.1.14' + s.version = '3.1.15' s.summary = "OpenBSD's bcrypt() password hashing algorithm." s.description = <<-EOF From cedc403dc61f621b9ab678337f9f68f784a45439 Mon Sep 17 00:00:00 2001 From: Adam Grare Date: Tue, 21 Jul 2020 17:43:34 -0400 Subject: [PATCH 24/92] Remove Gemfile.lock --- Gemfile.lock | 36 ------------------------------------ 1 file changed, 36 deletions(-) delete mode 100644 Gemfile.lock diff --git a/Gemfile.lock b/Gemfile.lock deleted file mode 100644 index f12d616..0000000 --- a/Gemfile.lock +++ /dev/null @@ -1,36 +0,0 @@ -PATH - remote: . - specs: - bcrypt (3.1.14) - -GEM - remote: https://rubygems.org/ - specs: - diff-lcs (1.4.4) - rake (13.0.1) - rake-compiler (0.9.9) - rake - rspec (3.9.0) - rspec-core (~> 3.9.0) - rspec-expectations (~> 3.9.0) - rspec-mocks (~> 3.9.0) - rspec-core (3.9.2) - rspec-support (~> 3.9.3) - rspec-expectations (3.9.2) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.9.0) - rspec-mocks (3.9.1) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.9.0) - rspec-support (3.9.3) - -PLATFORMS - ruby - -DEPENDENCIES - bcrypt! - rake-compiler (~> 0.9.2) - rspec (>= 3) - -BUNDLED WITH - 2.2.0.dev From 77fa85d25536822543253da63b0bfddf9d41ef57 Mon Sep 17 00:00:00 2001 From: Michel Boaventura Date: Mon, 24 Aug 2020 16:20:15 -0300 Subject: [PATCH 25/92] Fix crypt_r definition Its last argument should be of type `struct crypt_data *`, not `void *` according to https://linux.die.net/man/3/crypt_r --- ext/mri/wrapper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/mri/wrapper.c b/ext/mri/wrapper.c index c88c0bd..cbba882 100644 --- a/ext/mri/wrapper.c +++ b/ext/mri/wrapper.c @@ -179,7 +179,7 @@ char *crypt_ra(const char *key, const char *setting, return _crypt_blowfish_rn(key, setting, (char *)*data, *size); } -char *crypt_r(const char *key, const char *setting, void *data) +char *crypt_r(const char *key, const char *setting, struct crypt_data *data) { return _crypt_retval_magic( crypt_rn(key, setting, data, CRYPT_OUTPUT_SIZE), From abff57ddc6ab6cbdadb486202c2942bfc3025ea6 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 3 Sep 2020 13:45:46 -0700 Subject: [PATCH 26/92] bump version / fix changelog --- CHANGELOG | 3 +++ bcrypt.gemspec | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index be2b274..6c2b465 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +3.1.16 Sep 3 2020 + - Fix compilation on FreeBSD. [GH #234] + 3.1.15 July 21 2020 - Remove GVL optimization. Apparently it breaks things [GH #230] diff --git a/bcrypt.gemspec b/bcrypt.gemspec index 2a0120e..b32cd08 100644 --- a/bcrypt.gemspec +++ b/bcrypt.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = 'bcrypt' - s.version = '3.1.15' + s.version = '3.1.16' s.summary = "OpenBSD's bcrypt() password hashing algorithm." s.description = <<-EOF From 5fba8e4ef4151ba2763da395ef2f58838c127bba Mon Sep 17 00:00:00 2001 From: Michael McCarthy Date: Tue, 29 Sep 2020 22:26:37 -0400 Subject: [PATCH 27/92] additional changelog comment --- CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 6c2b465..dd7ba1c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -16,7 +16,7 @@ 3.1.12 May 16 2018 - Add support for Ruby 2.3, 2.4, and 2.5 in compiled Windows binaries - - Fix compatibility with libxcrypt [GH #164 by @besser82] + - Fix compatibility with libxcrypt - Fixes hash errors in Fedora 28 and Ubuntu 20 [GH #164 by @besser82] 3.1.11 Mar 06 2016 - Add support for Ruby 2.2 in compiled Windows binaries From fc652e5248a4132af2c5f5c0b61eeceff02f4316 Mon Sep 17 00:00:00 2001 From: "T.J. Schuck" Date: Mon, 5 Oct 2020 12:34:29 -0400 Subject: [PATCH 28/92] Make min time difference still x4 https://github.com/codahale/bcrypt-ruby/pull/223/files updated this test and also made the time diff x2 instead of x4. This made it start failing on Windows. Bump back to x4. --- spec/bcrypt/engine_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/bcrypt/engine_spec.rb b/spec/bcrypt/engine_spec.rb index 7c6d6f3..ad9a7e8 100644 --- a/spec/bcrypt/engine_spec.rb +++ b/spec/bcrypt/engine_spec.rb @@ -16,7 +16,7 @@ BCrypt::Password.create("testing testing", :cost => BCrypt::Engine::MIN_COST + 1) min_time_ms = (Time.now - start_time) * 1000 first = BCrypt::Engine.calibrate(min_time_ms) - second = BCrypt::Engine.calibrate(min_time_ms * 2) + second = BCrypt::Engine.calibrate(min_time_ms * 4) expect(second).to be > first end end From ac8fd5ef14364ddac1fe9257229b7e2ac6d23f3d Mon Sep 17 00:00:00 2001 From: timcraft Date: Wed, 6 Jan 2021 14:42:10 +0000 Subject: [PATCH 29/92] Test on ruby 3.0 --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 9842f8d..5cb4461 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,7 @@ rvm: - 2.5 - 2.6 - 2.7 + - 3.0 - ruby-head - jruby-head - rbx-3 From 770faeaa884cb0e4dd3a34f82c25f62a980ae8fe Mon Sep 17 00:00:00 2001 From: shmokmt <32533860+shmokmt@users.noreply.github.com> Date: Fri, 12 Feb 2021 18:03:04 +0900 Subject: [PATCH 30/92] Update version --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9bbc739..fff49a3 100644 --- a/README.md +++ b/README.md @@ -32,8 +32,8 @@ re-hash those passwords. This vulnerability only affected the JRuby gem. The bcrypt gem is available on the following Ruby platforms: * JRuby -* RubyInstaller 2.0 – 2.5 builds on Windows with the DevKit -* Any 2.0 – 2.5 Ruby on a BSD/OS X/Linux system with a compiler +* RubyInstaller 2.0 – 3.0 builds on Windows with the DevKit +* Any 2.0 – 3.0 Ruby on a BSD/OS X/Linux system with a compiler ## How to use `bcrypt()` in your Rails application From beb3e2938af1fd6609d2098207f1046b21ebc97e Mon Sep 17 00:00:00 2001 From: Kenichi Kamiya Date: Tue, 2 Mar 2021 15:42:54 +0900 Subject: [PATCH 31/92] Ignore Gemfile.lock in git --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 3c40c7f..633ad7c 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ tmp *.jar .DS_Store .rbenv-gemsets +Gemfile.lock From acd74603685c351b5135742c875963727ed51576 Mon Sep 17 00:00:00 2001 From: Kenichi Kamiya Date: Sat, 26 Sep 2015 01:41:41 +0900 Subject: [PATCH 32/92] Fix a regex in Bcrypt::Password.valid_hash? and Bcrypt::Engine.valid_salt? --- lib/bcrypt/engine.rb | 2 +- lib/bcrypt/password.rb | 2 +- spec/bcrypt/password_spec.rb | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/bcrypt/engine.rb b/lib/bcrypt/engine.rb index 2204843..ca57da0 100644 --- a/lib/bcrypt/engine.rb +++ b/lib/bcrypt/engine.rb @@ -80,7 +80,7 @@ def self.generate_salt(cost = self.cost) # Returns true if +salt+ is a valid bcrypt() salt, false if not. def self.valid_salt?(salt) - !!(salt =~ /^\$[0-9a-z]{2,}\$[0-9]{2,}\$[A-Za-z0-9\.\/]{22,}$/) + !!(salt =~ /\A\$[0-9a-z]{2,}\$[0-9]{2,}\$[A-Za-z0-9\.\/]{22,}\z/) end # Returns true if +secret+ is a valid bcrypt() secret, false if not. diff --git a/lib/bcrypt/password.rb b/lib/bcrypt/password.rb index 554967c..94bccb2 100644 --- a/lib/bcrypt/password.rb +++ b/lib/bcrypt/password.rb @@ -47,7 +47,7 @@ def create(secret, options = {}) end def valid_hash?(h) - /^\$[0-9a-z]{2}\$[0-9]{2}\$[A-Za-z0-9\.\/]{53}$/ === h + /\A\$[0-9a-z]{2}\$[0-9]{2}\$[A-Za-z0-9\.\/]{53}\z/ === h end end diff --git a/spec/bcrypt/password_spec.rb b/spec/bcrypt/password_spec.rb index f880f1c..a818a7b 100644 --- a/spec/bcrypt/password_spec.rb +++ b/spec/bcrypt/password_spec.rb @@ -108,6 +108,7 @@ describe "Validating a generated salt" do specify "should not accept an invalid salt" do expect(BCrypt::Engine.valid_salt?("invalid")).to eq(false) + expect(BCrypt::Engine.valid_salt?("invalid\n#{BCrypt::Engine.generate_salt}\ninvalid")).to eq(false) end specify "should accept a valid salt" do expect(BCrypt::Engine.valid_salt?(BCrypt::Engine.generate_salt)).to eq(true) @@ -117,6 +118,7 @@ describe "Validating a password hash" do specify "should not accept an invalid password" do expect(BCrypt::Password.valid_hash?("i_am_so_not_valid")).to be(false) + expect(BCrypt::Password.valid_hash?("invalid\n#{BCrypt::Password.create "i_am_so_valid"}\ninvalid")).to be(false) end specify "should accept a valid password" do expect(BCrypt::Password.valid_hash?(BCrypt::Password.create "i_am_so_valid")).to be(true) From 637a0dbb63d42c8a8c214959d17f38fd43ab2b1b Mon Sep 17 00:00:00 2001 From: Josh Cheek Date: Thu, 18 Mar 2021 11:18:14 -0500 Subject: [PATCH 33/92] Make the prefix less sus --- lib/bcrypt/engine.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/bcrypt/engine.rb b/lib/bcrypt/engine.rb index ca57da0..c2b78f8 100644 --- a/lib/bcrypt/engine.rb +++ b/lib/bcrypt/engine.rb @@ -70,8 +70,7 @@ def self.generate_salt(cost = self.cost) if RUBY_PLATFORM == "java" Java.bcrypt_jruby.BCrypt.gensalt(cost) else - prefix = "$2a$05$CCCCCCCCCCCCCCCCCCCCC.E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW" - __bc_salt(prefix, cost, OpenSSL::Random.random_bytes(MAX_SALT_LENGTH)) + __bc_salt("$2a$", cost, OpenSSL::Random.random_bytes(MAX_SALT_LENGTH)) end else raise Errors::InvalidCost.new("cost must be numeric and > 0") From 34e59955f1e18d8c04e4d0ce15e75d2530e4bb66 Mon Sep 17 00:00:00 2001 From: Josh Buker Date: Mon, 29 Mar 2021 08:38:19 -0700 Subject: [PATCH 34/92] Document BCrypt::Password#== edge case/gotcha --- lib/bcrypt/password.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/bcrypt/password.rb b/lib/bcrypt/password.rb index 94bccb2..6902aba 100644 --- a/lib/bcrypt/password.rb +++ b/lib/bcrypt/password.rb @@ -62,6 +62,15 @@ def initialize(raw_hash) end # Compares a potential secret against the hash. Returns true if the secret is the original secret, false otherwise. + # + # Comparison edge case/gotcha: + # + # secret = "my secret" + # @password = BCrypt::Password.create(secret) + # + # @password == secret # => True + # @password == @password.to_s # => False + # @password.to_s == @password.to_s # => True def ==(secret) super(BCrypt::Engine.hash_secret(secret, @salt)) end From cf9bae41c926ab83e7aa6fa8669f9d0552727f78 Mon Sep 17 00:00:00 2001 From: Josh Buker Date: Mon, 29 Mar 2021 08:47:05 -0700 Subject: [PATCH 35/92] Document all possible permutations --- lib/bcrypt/password.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/bcrypt/password.rb b/lib/bcrypt/password.rb index 6902aba..1f902d2 100644 --- a/lib/bcrypt/password.rb +++ b/lib/bcrypt/password.rb @@ -69,7 +69,9 @@ def initialize(raw_hash) # @password = BCrypt::Password.create(secret) # # @password == secret # => True + # @password == @password # => False # @password == @password.to_s # => False + # @password.to_s == @password # => True # @password.to_s == @password.to_s # => True def ==(secret) super(BCrypt::Engine.hash_secret(secret, @salt)) From a0d528f12c41df121ab211f97885b397f42f2e40 Mon Sep 17 00:00:00 2001 From: "T.J. Schuck" Date: Mon, 29 Mar 2021 18:12:46 -0400 Subject: [PATCH 36/92] Some URL updates now that this has moved to an org --- README.md | 4 ++-- bcrypt.gemspec | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fff49a3..6e2088b 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ An easy way to keep your users' passwords secure. -* https://github.com/codahale/bcrypt-ruby/tree/master +* https://github.com/bcrypt-ruby/bcrypt-ruby/tree/master -[![Travis Build Status](https://travis-ci.org/codahale/bcrypt-ruby.svg?branch=master)](https://travis-ci.org/codahale/bcrypt-ruby) +[![Travis Build Status](https://travis-ci.org/bcrypt-ruby/bcrypt-ruby.svg?branch=master)](https://travis-ci.org/bcrypt-ruby/bcrypt-ruby) [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/6fplerx9lnaf0hyo?svg=true)](https://ci.appveyor.com/project/TJSchuck35975/bcrypt-ruby) diff --git a/bcrypt.gemspec b/bcrypt.gemspec index b32cd08..29ef18c 100644 --- a/bcrypt.gemspec +++ b/bcrypt.gemspec @@ -22,6 +22,6 @@ Gem::Specification.new do |s| s.authors = ["Coda Hale"] s.email = "coda.hale@gmail.com" - s.homepage = "https://github.com/codahale/bcrypt-ruby" + s.homepage = "https://github.com/bcrypt-ruby/bcrypt-ruby" s.license = "MIT" end From 2b4abfc130e90c1a8a6a05658ce6352efd140a95 Mon Sep 17 00:00:00 2001 From: Josh Buker Date: Tue, 6 Apr 2021 20:51:31 -0700 Subject: [PATCH 37/92] Add Github Action --- .github/workflows/ruby.yml | 47 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 .github/workflows/ruby.yml diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml new file mode 100644 index 0000000..1441a9a --- /dev/null +++ b/.github/workflows/ruby.yml @@ -0,0 +1,47 @@ +name: Test Suite + +# Run against all commits and pull requests. +on: [ push, pull_request ] + +jobs: + test_matrix: + + strategy: + fail-fast: false + matrix: + os: + - ubuntu-latest + - macos-latest + ruby: + - 2.1 + - 2.2 + - 2.3 + - 2.4 + - 2.5 + - 2.6 + - 2.7 + - 3.0 + - head + - jruby + - jruby-head + - truffleruby + - truffleruby-head + + runs-on: ${{ matrix.os }} + + steps: + - uses: actions/checkout@v2 + - name: Set up Ruby + uses: ruby/setup-ruby@v1.68.0 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + - name: Run tests + run: bundle exec rake spec + + finish: + runs-on: ubuntu-latest + needs: [ test_matrix ] + steps: + - name: Wait for status checks + run: echo "All Green!" From 579b83021b8cfeda237781f44fc6ff7846424488 Mon Sep 17 00:00:00 2001 From: Josh Buker Date: Tue, 6 Apr 2021 20:57:20 -0700 Subject: [PATCH 38/92] Use default rake task --- .github/workflows/ruby.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 1441a9a..16bf217 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -37,7 +37,7 @@ jobs: ruby-version: ${{ matrix.ruby }} bundler-cache: true - name: Run tests - run: bundle exec rake spec + run: bundle exec rake finish: runs-on: ubuntu-latest From 5c08123c1e252205cc088e4c0782b043f677fe9c Mon Sep 17 00:00:00 2001 From: Josh Buker Date: Tue, 6 Apr 2021 21:12:11 -0700 Subject: [PATCH 39/92] Use latest setup-ruby and add mingw/mswin --- .github/workflows/ruby.yml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 16bf217..569b480 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -10,8 +10,8 @@ jobs: fail-fast: false matrix: os: - - ubuntu-latest - - macos-latest + - ubuntu + - macos ruby: - 2.1 - 2.2 @@ -26,18 +26,20 @@ jobs: - jruby-head - truffleruby - truffleruby-head + - mingw + - mswin - runs-on: ${{ matrix.os }} + runs-on: ${{ matrix.os }}-latest steps: - uses: actions/checkout@v2 - name: Set up Ruby - uses: ruby/setup-ruby@v1.68.0 + uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby }} bundler-cache: true - name: Run tests - run: bundle exec rake + run: bundle exec rake default finish: runs-on: ubuntu-latest From 9acc2ee6fc6cbea38d2b2860a9ff38be64d4951d Mon Sep 17 00:00:00 2001 From: Josh Buker Date: Tue, 6 Apr 2021 21:17:39 -0700 Subject: [PATCH 40/92] Add windows to github action and remove jruby from ubuntu matrix --- .github/workflows/ruby.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 569b480..169a2e6 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -12,6 +12,7 @@ jobs: os: - ubuntu - macos + - windows ruby: - 2.1 - 2.2 @@ -28,6 +29,13 @@ jobs: - truffleruby-head - mingw - mswin + include: + - { os: windows, ruby: mingw } + - { os: windows, ruby: mswin } + # It appears Ubuntu doesn't support jruby + exclude: + - { os: ubuntu, ruby: jruby } + - { os: ubuntu, ruby: jruby-head } runs-on: ${{ matrix.os }}-latest From 242467320efcdad9a3ded982c7bfa39c2db1e376 Mon Sep 17 00:00:00 2001 From: Josh Buker Date: Tue, 6 Apr 2021 21:24:12 -0700 Subject: [PATCH 41/92] Fine tune exclusions --- .github/workflows/ruby.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 169a2e6..1f64d22 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -29,13 +29,15 @@ jobs: - truffleruby-head - mingw - mswin - include: - - { os: windows, ruby: mingw } - - { os: windows, ruby: mswin } - # It appears Ubuntu doesn't support jruby exclude: - { os: ubuntu, ruby: jruby } - { os: ubuntu, ruby: jruby-head } + - { os: ubuntu, ruby: mingw } + - { os: ubuntu, ruby: mswin } + - { os: macos, ruby: mingw } + - { os: macos, ruby: mswin } + - { os: windows, ruby: truffleruby } + - { os: windows, ruby: truffleruby-head } runs-on: ${{ matrix.os }}-latest From 9ce55a00714d6c1517db1919e54e3fbf97f2f160 Mon Sep 17 00:00:00 2001 From: Josh Buker Date: Tue, 6 Apr 2021 21:54:33 -0700 Subject: [PATCH 42/92] Remove mswin and try using include instead of exclude for mingw --- .github/workflows/ruby.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 1f64d22..f227058 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -28,14 +28,11 @@ jobs: - truffleruby - truffleruby-head - mingw - - mswin + include: + - { os: windows, ruby: mingw } exclude: - { os: ubuntu, ruby: jruby } - { os: ubuntu, ruby: jruby-head } - - { os: ubuntu, ruby: mingw } - - { os: ubuntu, ruby: mswin } - - { os: macos, ruby: mingw } - - { os: macos, ruby: mswin } - { os: windows, ruby: truffleruby } - { os: windows, ruby: truffleruby-head } From ebae2e36402aec015f66ea0b11fa9b3a64aeeb8b Mon Sep 17 00:00:00 2001 From: Josh Buker Date: Tue, 6 Apr 2021 21:56:06 -0700 Subject: [PATCH 43/92] Include doesn't work as expected --- .github/workflows/ruby.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index f227058..618ac97 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -28,11 +28,11 @@ jobs: - truffleruby - truffleruby-head - mingw - include: - - { os: windows, ruby: mingw } exclude: - - { os: ubuntu, ruby: jruby } - - { os: ubuntu, ruby: jruby-head } + - { os: ubuntu, ruby: jruby } + - { os: ubuntu, ruby: jruby-head } + - { os: ubuntu, ruby: mingw } + - { os: macos, ruby: mingw } - { os: windows, ruby: truffleruby } - { os: windows, ruby: truffleruby-head } From 96698e8c48c2fd903a654d8392c151895a51c489 Mon Sep 17 00:00:00 2001 From: Josh Buker Date: Wed, 28 Apr 2021 11:18:21 -0700 Subject: [PATCH 44/92] Minor whitespace fixes --- README.md | 1 - lib/bcrypt/password.rb | 1 - 2 files changed, 2 deletions(-) diff --git a/README.md b/README.md index 6e2088b..2362817 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,6 @@ An easy way to keep your users' passwords secure. [![Travis Build Status](https://travis-ci.org/bcrypt-ruby/bcrypt-ruby.svg?branch=master)](https://travis-ci.org/bcrypt-ruby/bcrypt-ruby) [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/6fplerx9lnaf0hyo?svg=true)](https://ci.appveyor.com/project/TJSchuck35975/bcrypt-ruby) - ## Why you should use `bcrypt()` If you store user passwords in the clear, then an attacker who steals a copy of your database has a giant list of emails diff --git a/lib/bcrypt/password.rb b/lib/bcrypt/password.rb index 1f902d2..4a2c140 100644 --- a/lib/bcrypt/password.rb +++ b/lib/bcrypt/password.rb @@ -94,5 +94,4 @@ def split_hash(h) return v.to_str, c.to_i, h[0, 29].to_str, mash[-31, 31].to_str end end - end From 81578a782bca1252827382a8502926832136a511 Mon Sep 17 00:00:00 2001 From: Josh Buker Date: Wed, 28 Apr 2021 11:18:39 -0700 Subject: [PATCH 45/92] Remove .travis.yml (unused) --- .travis.yml | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 5cb4461..0000000 --- a/.travis.yml +++ /dev/null @@ -1,27 +0,0 @@ -language: ruby -before_install: - - "echo 'gem: --no-rdoc --no-ri' > ~/.gemrc" -rvm: - - 2.0 - - 2.1 - - 2.2 - - 2.3 - - 2.4 - - 2.5 - - 2.6 - - 2.7 - - 3.0 - - ruby-head - - jruby-head - - rbx-3 - - truffleruby - - truffleruby-head -matrix: - allow_failures: - - rvm: ruby-head - - rvm: jruby-head - - rvm: rbx-3 - - rvm: truffleruby - - rvm: truffleruby-head - fast_finish: true -script: bundle exec rake From d515706197284894814ca46ffd4f349e628126a5 Mon Sep 17 00:00:00 2001 From: Josh Buker Date: Wed, 28 Apr 2021 11:19:03 -0700 Subject: [PATCH 46/92] Update README build status badge We recently moved from TravisCI to Github Actions (GA), but forgot to update the build status badge. This replaces the build badge with its GA equivalent. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2362817..23a4775 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ An easy way to keep your users' passwords secure. * https://github.com/bcrypt-ruby/bcrypt-ruby/tree/master -[![Travis Build Status](https://travis-ci.org/bcrypt-ruby/bcrypt-ruby.svg?branch=master)](https://travis-ci.org/bcrypt-ruby/bcrypt-ruby) +[![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) [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/6fplerx9lnaf0hyo?svg=true)](https://ci.appveyor.com/project/TJSchuck35975/bcrypt-ruby) ## Why you should use `bcrypt()` From 2cb53822f0b3e9ec978dd53b5ed414bdcd49d6a6 Mon Sep 17 00:00:00 2001 From: Alan Savage Date: Wed, 7 Jul 2021 13:00:03 -0700 Subject: [PATCH 47/92] Add a test demonstrating passwords >255 chars fail --- spec/bcrypt/password_spec.rb | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/spec/bcrypt/password_spec.rb b/spec/bcrypt/password_spec.rb index a818a7b..c841568 100644 --- a/spec/bcrypt/password_spec.rb +++ b/spec/bcrypt/password_spec.rb @@ -1,4 +1,5 @@ require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper")) +require 'securerandom' describe "Creating a hashed password" do @@ -26,6 +27,28 @@ expect { BCrypt::Password.create( "" ) }.not_to raise_error expect { BCrypt::Password.create( String.new ) }.not_to raise_error end + + context 'with a 256 character password' do + before :each do + @secret = SecureRandom.hex(256) + @password = BCrypt::Password.create(@secret, :cost => 4) + end + + specify "should return a BCrypt::Password" do + expect(@password).to be_an_instance_of(BCrypt::Password) + end + end + + context 'with a 255 character password' do + before :each do + @secret = SecureRandom.hex(255) + @password = BCrypt::Password.create(@secret, :cost => 4) + end + + specify "should return a BCrypt::Password" do + expect(@password).to be_an_instance_of(BCrypt::Password) + end + end end describe "Reading a hashed password" do From 2649bd72a48b83821f2754de6fb8273574e7addc Mon Sep 17 00:00:00 2001 From: Alan Savage Date: Wed, 7 Jul 2021 13:26:05 -0700 Subject: [PATCH 48/92] Truncate secrets greater than 255 chars in hash_secret --- lib/bcrypt/engine.rb | 7 ++++++- spec/bcrypt/engine_spec.rb | 8 ++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/bcrypt/engine.rb b/lib/bcrypt/engine.rb index ca57da0..e8fcfcf 100644 --- a/lib/bcrypt/engine.rb +++ b/lib/bcrypt/engine.rb @@ -7,6 +7,9 @@ class Engine MIN_COST = 4 # The maximum cost supported by the algorithm. MAX_COST = 31 + # Maximum possible size of bcrypt() secrets. + # https://github.com/bcrypt-ruby/bcrypt-ruby/issues/225#issuecomment-875908425 + MAX_SECRET_LENGTH = 255 # Maximum possible size of bcrypt() salts. MAX_SALT_LENGTH = 16 @@ -50,7 +53,9 @@ def self.hash_secret(secret, salt, _ = nil) if RUBY_PLATFORM == "java" Java.bcrypt_jruby.BCrypt.hashpw(secret.to_s.to_java_bytes, salt.to_s) else - __bc_crypt(secret.to_s, salt) + secret = secret.to_s + secret = secret[0..(MAX_SECRET_LENGTH-1)] if secret && secret.length > MAX_SECRET_LENGTH + __bc_crypt(secret, salt) end else raise Errors::InvalidSalt.new("invalid salt") diff --git a/spec/bcrypt/engine_spec.rb b/spec/bcrypt/engine_spec.rb index ad9a7e8..e9723d5 100644 --- a/spec/bcrypt/engine_spec.rb +++ b/spec/bcrypt/engine_spec.rb @@ -1,4 +1,5 @@ require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper")) +require 'securerandom' describe 'BCrypt::Engine' do describe '.calibrate(upper_time_limit_in_ms)' do @@ -157,4 +158,11 @@ class MyInvalidSecret expect(BCrypt::Engine.hash_secret(secret, salt)).to eql(test_vector) end end + + specify "should truncate secrets that are greater than the maximum length" do + # 'b' as a base triggers the failure at 256 characters, but 'a' does not. + too_long_secret = 'b'*(BCrypt::Engine::MAX_SECRET_LENGTH + 1) + just_right_secret = 'b'*BCrypt::Engine::MAX_SECRET_LENGTH + expect(BCrypt::Engine.hash_secret(too_long_secret, @salt)).to eq(BCrypt::Engine.hash_secret(just_right_secret, @salt)) + end end From c31d9cdec03496ca2e1f49e8c7cc838e0f95cfec Mon Sep 17 00:00:00 2001 From: Alan Savage Date: Wed, 7 Jul 2021 14:07:52 -0700 Subject: [PATCH 49/92] Switch from 255 char max to 72 --- lib/bcrypt/engine.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/bcrypt/engine.rb b/lib/bcrypt/engine.rb index e8fcfcf..9891ee6 100644 --- a/lib/bcrypt/engine.rb +++ b/lib/bcrypt/engine.rb @@ -8,8 +8,13 @@ class Engine # The maximum cost supported by the algorithm. MAX_COST = 31 # Maximum possible size of bcrypt() secrets. + # Older versions of the bcrypt library would truncate passwords longer + # than 72, but newer ones do not. We truncate like the old library for + # forward compatibility. This way users upgrading from Ubuntu 18.04 to 20.04 + # will not have their user passwords invalidated, for example. + # A max secret length greater than 255 leads to bcrypt returning nil. # https://github.com/bcrypt-ruby/bcrypt-ruby/issues/225#issuecomment-875908425 - MAX_SECRET_LENGTH = 255 + MAX_SECRET_LENGTH = 72 # Maximum possible size of bcrypt() salts. MAX_SALT_LENGTH = 16 From a848abb2523764ba8c114fcd6079b17cf5d1fdeb Mon Sep 17 00:00:00 2001 From: Alan Savage Date: Wed, 7 Jul 2021 18:02:02 -0700 Subject: [PATCH 50/92] Truncate based on bytesize instead of number of chars --- lib/bcrypt/engine.rb | 8 ++++---- spec/bcrypt/engine_spec.rb | 14 +++++++++++--- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/lib/bcrypt/engine.rb b/lib/bcrypt/engine.rb index 9891ee6..f6a6ba7 100644 --- a/lib/bcrypt/engine.rb +++ b/lib/bcrypt/engine.rb @@ -9,12 +9,12 @@ class Engine MAX_COST = 31 # Maximum possible size of bcrypt() secrets. # Older versions of the bcrypt library would truncate passwords longer - # than 72, but newer ones do not. We truncate like the old library for + # than 72 bytes, but newer ones do not. We truncate like the old library for # forward compatibility. This way users upgrading from Ubuntu 18.04 to 20.04 # will not have their user passwords invalidated, for example. # A max secret length greater than 255 leads to bcrypt returning nil. # https://github.com/bcrypt-ruby/bcrypt-ruby/issues/225#issuecomment-875908425 - MAX_SECRET_LENGTH = 72 + MAX_SECRET_BYTESIZE = 72 # Maximum possible size of bcrypt() salts. MAX_SALT_LENGTH = 16 @@ -51,7 +51,7 @@ def self.cost=(cost) end # Given a secret and a valid salt (see BCrypt::Engine.generate_salt) calculates - # a bcrypt() password hash. + # a bcrypt() password hash. Secrets longer than 72 bytes are truncated. def self.hash_secret(secret, salt, _ = nil) if valid_secret?(secret) if valid_salt?(salt) @@ -59,7 +59,7 @@ def self.hash_secret(secret, salt, _ = nil) Java.bcrypt_jruby.BCrypt.hashpw(secret.to_s.to_java_bytes, salt.to_s) else secret = secret.to_s - secret = secret[0..(MAX_SECRET_LENGTH-1)] if secret && secret.length > MAX_SECRET_LENGTH + secret = secret.byteslice(0, MAX_SECRET_BYTESIZE) if secret && secret.bytesize > MAX_SECRET_BYTESIZE __bc_crypt(secret, salt) end else diff --git a/spec/bcrypt/engine_spec.rb b/spec/bcrypt/engine_spec.rb index e9723d5..a4c4056 100644 --- a/spec/bcrypt/engine_spec.rb +++ b/spec/bcrypt/engine_spec.rb @@ -159,10 +159,18 @@ class MyInvalidSecret end end - specify "should truncate secrets that are greater than the maximum length" do + specify "should truncate 1-byte character secrets to 72 bytes" do # 'b' as a base triggers the failure at 256 characters, but 'a' does not. - too_long_secret = 'b'*(BCrypt::Engine::MAX_SECRET_LENGTH + 1) - just_right_secret = 'b'*BCrypt::Engine::MAX_SECRET_LENGTH + too_long_secret = 'b'*(BCrypt::Engine::MAX_SECRET_BYTESIZE + 1) + just_right_secret = 'b'*BCrypt::Engine::MAX_SECRET_BYTESIZE + expect(BCrypt::Engine.hash_secret(too_long_secret, @salt)).to eq(BCrypt::Engine.hash_secret(just_right_secret, @salt)) + end + + specify "should truncate multi-byte character secrets to 72 bytes" do + # 256 times causes bcrypt to return nil for libxcrypt > 4.4.18-4. + too_long_secret = '𐐷'*256 + # 𐐷 takes 4 bytes in UTF-8. 18 times is 72 bytes + just_right_secret = '𐐷'*18 expect(BCrypt::Engine.hash_secret(too_long_secret, @salt)).to eq(BCrypt::Engine.hash_secret(just_right_secret, @salt)) end end From 7a411eea3942579675a0075d91e77f4184b44c29 Mon Sep 17 00:00:00 2001 From: Alan Savage Date: Thu, 8 Jul 2021 15:22:54 -0700 Subject: [PATCH 51/92] test: Reword hash_secret specs for clarity --- spec/bcrypt/engine_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/bcrypt/engine_spec.rb b/spec/bcrypt/engine_spec.rb index a4c4056..b527a6b 100644 --- a/spec/bcrypt/engine_spec.rb +++ b/spec/bcrypt/engine_spec.rb @@ -159,14 +159,14 @@ class MyInvalidSecret end end - specify "should truncate 1-byte character secrets to 72 bytes" do + specify "should truncate long 1-byte character secrets to 72 bytes" do # 'b' as a base triggers the failure at 256 characters, but 'a' does not. too_long_secret = 'b'*(BCrypt::Engine::MAX_SECRET_BYTESIZE + 1) just_right_secret = 'b'*BCrypt::Engine::MAX_SECRET_BYTESIZE expect(BCrypt::Engine.hash_secret(too_long_secret, @salt)).to eq(BCrypt::Engine.hash_secret(just_right_secret, @salt)) end - specify "should truncate multi-byte character secrets to 72 bytes" do + specify "should truncate long multi-byte character secrets to 72 bytes" do # 256 times causes bcrypt to return nil for libxcrypt > 4.4.18-4. too_long_secret = '𐐷'*256 # 𐐷 takes 4 bytes in UTF-8. 18 times is 72 bytes From 7ed2fa8c69c7b9555e0e8be6aac14d52f2b0befd Mon Sep 17 00:00:00 2001 From: Alan Savage Date: Thu, 8 Jul 2021 15:23:47 -0700 Subject: [PATCH 52/92] test: Simplify password create tests for long secrets --- spec/bcrypt/password_spec.rb | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/spec/bcrypt/password_spec.rb b/spec/bcrypt/password_spec.rb index c841568..1899221 100644 --- a/spec/bcrypt/password_spec.rb +++ b/spec/bcrypt/password_spec.rb @@ -28,26 +28,8 @@ expect { BCrypt::Password.create( String.new ) }.not_to raise_error end - context 'with a 256 character password' do - before :each do - @secret = SecureRandom.hex(256) - @password = BCrypt::Password.create(@secret, :cost => 4) - end - - specify "should return a BCrypt::Password" do - expect(@password).to be_an_instance_of(BCrypt::Password) - end - end - - context 'with a 255 character password' do - before :each do - @secret = SecureRandom.hex(255) - @password = BCrypt::Password.create(@secret, :cost => 4) - end - - specify "should return a BCrypt::Password" do - expect(@password).to be_an_instance_of(BCrypt::Password) - end + specify "should tolerate very long string secrets" do + expect { BCrypt::Password.create("abcd"*1024) }.not_to raise_error end end From d83b916219145893dbac5106e8a77edd05af74ac Mon Sep 17 00:00:00 2001 From: Peter Goldstein Date: Mon, 24 Jan 2022 11:25:02 -0800 Subject: [PATCH 53/92] Add Ruby 3.1 to CI --- .github/workflows/ruby.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 618ac97..54a1561 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -21,7 +21,8 @@ jobs: - 2.5 - 2.6 - 2.7 - - 3.0 + - '3.0' + - 3.1 - head - jruby - jruby-head From 5bf36393d330947e055af635687b32719a8df668 Mon Sep 17 00:00:00 2001 From: "T.J. Schuck" Date: Mon, 14 Mar 2022 15:11:18 -0400 Subject: [PATCH 54/92] Update for release --- CHANGELOG | 5 +++++ bcrypt.gemspec | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index dd7ba1c..dbc2d82 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,8 @@ +3.1.17 Mar 14 2022 +- Fix regex in validators to use \A and \z instead of ^ and $ [GH #121] +- Truncate secrets greater than 72 bytes in hash_secret [GH #255] +- Assorted test and doc improvements + 3.1.16 Sep 3 2020 - Fix compilation on FreeBSD. [GH #234] diff --git a/bcrypt.gemspec b/bcrypt.gemspec index 29ef18c..5971af1 100644 --- a/bcrypt.gemspec +++ b/bcrypt.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = 'bcrypt' - s.version = '3.1.16' + s.version = '3.1.17' s.summary = "OpenBSD's bcrypt() password hashing algorithm." s.description = <<-EOF From 49161d9f68b90211661838f28fe2d5cf128a8b96 Mon Sep 17 00:00:00 2001 From: Nate Smith Date: Fri, 29 Apr 2022 14:08:00 -0400 Subject: [PATCH 55/92] Use `free` instead of `xfree` This was clobbered in the revert. --- ext/mri/bcrypt_ext.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/mri/bcrypt_ext.c b/ext/mri/bcrypt_ext.c index c8db933..189e0e8 100644 --- a/ext/mri/bcrypt_ext.c +++ b/ext/mri/bcrypt_ext.c @@ -47,7 +47,7 @@ static VALUE bc_crypt(VALUE self, VALUE key, VALUE setting) { out = rb_str_new2(value); - xfree(data); + free(data); return out; } From aec1265e6c0ff8622085fd6c40fbd4d039e992ef Mon Sep 17 00:00:00 2001 From: Nate Smith Date: Fri, 29 Apr 2022 11:17:10 -0400 Subject: [PATCH 56/92] Re-introduce GVL unlock Re-introduce the change from e1320b0 but with a fix for the bug causing bad hashes on Linux. The original patch was incorrectly copying the `data` struct into the string returned by the function. --- ext/mri/bcrypt_ext.c | 84 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 69 insertions(+), 15 deletions(-) diff --git a/ext/mri/bcrypt_ext.c b/ext/mri/bcrypt_ext.c index 189e0e8..6c68504 100644 --- a/ext/mri/bcrypt_ext.c +++ b/ext/mri/bcrypt_ext.c @@ -1,20 +1,50 @@ #include #include +#ifdef HAVE_RUBY_THREAD_H +#include +#endif + static VALUE mBCrypt; static VALUE cBCryptEngine; +struct bc_salt_args { + const char * prefix; + unsigned long count; + const char * input; + int size; +}; + +static void * bc_salt_nogvl(void * ptr) { + struct bc_salt_args * args = ptr; + + return crypt_gensalt_ra(args->prefix, args->count, args->input, args->size); +} + /* Given a logarithmic cost parameter, generates a salt for use with +bc_crypt+. */ static VALUE bc_salt(VALUE self, VALUE prefix, VALUE count, VALUE input) { char * salt; VALUE str_salt; - - salt = crypt_gensalt_ra( - StringValuePtr(prefix), - NUM2ULONG(count), - NIL_P(input) ? NULL : StringValuePtr(input), - NIL_P(input) ? 0 : RSTRING_LEN(input)); + struct bc_salt_args args; + + /* duplicate the parameters for thread safety. If another thread has a + * reference to the parameters and mutates them while we are working, + * that would be very bad. Duping the strings means that the reference + * isn't shared. */ + prefix = rb_str_new_frozen(prefix); + input = rb_str_new_frozen(input); + + args.prefix = StringValueCStr(prefix); + args.count = NUM2ULONG(count); + args.input = NIL_P(input) ? NULL : StringValuePtr(input); + args.size = NIL_P(input) ? 0 : RSTRING_LEN(input); + +#ifdef HAVE_RUBY_THREAD_H + salt = rb_thread_call_without_gvl(bc_salt_nogvl, &args, NULL, NULL); +#else + salt = bc_salt_nogvl((void *)&args); +#endif if(!salt) return Qnil; @@ -24,6 +54,19 @@ static VALUE bc_salt(VALUE self, VALUE prefix, VALUE count, VALUE input) { return str_salt; } +struct bc_crypt_args { + const char * key; + const char * setting; + void * data; + int size; +}; + +static void * bc_crypt_nogvl(void * ptr) { + struct bc_crypt_args * args = ptr; + + return crypt_ra(args->key, args->setting, &args->data, &args->size); +} + /* Given a secret and a salt, generates a salted hash (which you can then store safely). */ static VALUE bc_crypt(VALUE self, VALUE key, VALUE setting) { @@ -32,22 +75,33 @@ static VALUE bc_crypt(VALUE self, VALUE key, VALUE setting) { int size; VALUE out; - data = NULL; - size = 0xDEADBEEF; + struct bc_crypt_args args; if(NIL_P(key) || NIL_P(setting)) return Qnil; - value = crypt_ra( - NIL_P(key) ? NULL : StringValuePtr(key), - NIL_P(setting) ? NULL : StringValuePtr(setting), - &data, - &size); + /* duplicate the parameters for thread safety. If another thread has a + * reference to the parameters and mutates them while we are working, + * that would be very bad. Duping the strings means that the reference + * isn't shared. */ + key = rb_str_new_frozen(key); + setting = rb_str_new_frozen(setting); + + args.data = NULL; + args.size = 0xDEADBEEF; + args.key = NIL_P(key) ? NULL : StringValueCStr(key); + args.setting = NIL_P(setting) ? NULL : StringValueCStr(setting); + +#ifdef HAVE_RUBY_THREAD_H + value = rb_thread_call_without_gvl(bc_crypt_nogvl, &args, NULL, NULL); +#else + value = bc_crypt_nogvl((void *)&args); +#endif - if(!value || !data) return Qnil; + if(!value || !args.data) return Qnil; out = rb_str_new2(value); - free(data); + free(args.data); return out; } From f78b1763505d435f349a0d6dc8be18dc09418aac Mon Sep 17 00:00:00 2001 From: Nate Smith Date: Mon, 16 May 2022 12:19:28 -0400 Subject: [PATCH 57/92] Work around bug in JDK for JRuby tests --- .github/workflows/ruby.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 54a1561..47a6651 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -30,8 +30,6 @@ jobs: - truffleruby-head - mingw exclude: - - { os: ubuntu, ruby: jruby } - - { os: ubuntu, ruby: jruby-head } - { os: ubuntu, ruby: mingw } - { os: macos, ruby: mingw } - { os: windows, ruby: truffleruby } @@ -46,8 +44,12 @@ jobs: with: ruby-version: ${{ matrix.ruby }} bundler-cache: true + env: + JAVA_OPTS: -Djdk.io.File.enableADS=true - name: Run tests run: bundle exec rake default + env: + JAVA_OPTS: -Djdk.io.File.enableADS=true finish: runs-on: ubuntu-latest From cc28f9efdc40316467e8d82095f9f8def7d0dfc2 Mon Sep 17 00:00:00 2001 From: Nate Smith Date: Mon, 16 May 2022 12:25:52 -0400 Subject: [PATCH 58/92] Update rake-compiler --- bcrypt.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bcrypt.gemspec b/bcrypt.gemspec index 5971af1..3a4487e 100644 --- a/bcrypt.gemspec +++ b/bcrypt.gemspec @@ -12,7 +12,7 @@ Gem::Specification.new do |s| s.files = `git ls-files`.split("\n") s.require_path = 'lib' - s.add_development_dependency 'rake-compiler', '~> 0.9.2' + s.add_development_dependency 'rake-compiler', '~> 1.2.0' s.add_development_dependency 'rspec', '>= 3' s.rdoc_options += ['--title', 'bcrypt-ruby', '--line-numbers', '--inline-source', '--main', 'README.md'] From 6d051de5ac04f08cc1e681e045c582dc61555c2a Mon Sep 17 00:00:00 2001 From: Nate Smith Date: Mon, 16 May 2022 14:19:03 -0400 Subject: [PATCH 59/92] Fix compiler warnings --- ext/mri/bcrypt_ext.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/ext/mri/bcrypt_ext.c b/ext/mri/bcrypt_ext.c index 6c68504..2366185 100644 --- a/ext/mri/bcrypt_ext.c +++ b/ext/mri/bcrypt_ext.c @@ -71,8 +71,6 @@ static void * bc_crypt_nogvl(void * ptr) { */ static VALUE bc_crypt(VALUE self, VALUE key, VALUE setting) { char * value; - void * data; - int size; VALUE out; struct bc_crypt_args args; From 87f132256456eb7cb3d403ffba245e9906bd9531 Mon Sep 17 00:00:00 2001 From: Nate Smith Date: Mon, 16 May 2022 16:20:41 -0400 Subject: [PATCH 60/92] Remove AppVeyor configuration --- README.md | 1 - appveyor.yml | 50 -------------------------------------------------- 2 files changed, 51 deletions(-) delete mode 100644 appveyor.yml diff --git a/README.md b/README.md index 23a4775..dd55971 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,6 @@ An easy way to keep your users' passwords secure. * https://github.com/bcrypt-ruby/bcrypt-ruby/tree/master [![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) -[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/6fplerx9lnaf0hyo?svg=true)](https://ci.appveyor.com/project/TJSchuck35975/bcrypt-ruby) ## Why you should use `bcrypt()` diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index e832e22..0000000 --- a/appveyor.yml +++ /dev/null @@ -1,50 +0,0 @@ -version: "{branch}-{build}" -build: off -clone_depth: 1 - -init: - # Install Ruby head - - if %RUBY_VERSION%==head ( - appveyor DownloadFile https://github.com/oneclick/rubyinstaller2/releases/download/rubyinstaller-head/rubyinstaller-head-x86.exe -FileName C:\head_x86.exe & - C:\head_x86.exe /verysilent /dir=C:\Ruby%RUBY_VERSION% - ) - - if %RUBY_VERSION%==head-x64 ( - appveyor DownloadFile https://github.com/oneclick/rubyinstaller2/releases/download/rubyinstaller-head/rubyinstaller-head-x64.exe -FileName C:\head_x64.exe & - C:\head_x64.exe /verysilent /dir=C:\Ruby%RUBY_VERSION% - ) - - # Add Ruby to the path - - set PATH=C:\Ruby%RUBY_VERSION%\bin;%PATH% - -environment: - matrix: - - RUBY_VERSION: "head" - - RUBY_VERSION: "head-x64" - - RUBY_VERSION: "25" - - RUBY_VERSION: "25-x64" - - RUBY_VERSION: "24" - - RUBY_VERSION: "24-x64" - - RUBY_VERSION: "23" - - RUBY_VERSION: "23-x64" - - RUBY_VERSION: "22" - - RUBY_VERSION: "22-x64" - - RUBY_VERSION: "21" - - RUBY_VERSION: "21-x64" - - RUBY_VERSION: "200" - - RUBY_VERSION: "200-x64" - -install: - - ps: "Set-Content -Value 'gem: --no-ri --no-rdoc ' -Path C:\\ProgramData\\gemrc" - - if %RUBY_VERSION%==head ( gem install bundler -v'< 2' ) - - if %RUBY_VERSION%==head-x64 ( gem install bundler -v'< 2' ) - - bundle install - -before_build: - - ruby -v - - gem -v - -build_script: - - bundle exec rake compile -rdevkit - -test_script: - - bundle exec rake spec From e799c279b0575e87940026100c3217d0b008ab1c Mon Sep 17 00:00:00 2001 From: Nate Smith Date: Mon, 16 May 2022 16:26:10 -0400 Subject: [PATCH 61/92] Update for release --- CHANGELOG | 4 ++++ bcrypt.gemspec | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index dbc2d82..dc03826 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,7 @@ +3.1.18 May 16 2022 + - Unlock GVL when calculating hashes and salts [GH #260] + - Fix compilation warnings in `ext/mri/bcrypt_ext.c` [GH #261] + 3.1.17 Mar 14 2022 - Fix regex in validators to use \A and \z instead of ^ and $ [GH #121] - Truncate secrets greater than 72 bytes in hash_secret [GH #255] diff --git a/bcrypt.gemspec b/bcrypt.gemspec index 5971af1..3c63b5d 100644 --- a/bcrypt.gemspec +++ b/bcrypt.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = 'bcrypt' - s.version = '3.1.17' + s.version = '3.1.18' s.summary = "OpenBSD's bcrypt() password hashing algorithm." s.description = <<-EOF From df27ee50c9c9d639c8eb30536fcbecf371a7b484 Mon Sep 17 00:00:00 2001 From: Sergey Alekseev Date: Sat, 6 Jul 2019 13:10:09 +0300 Subject: [PATCH 62/92] deprecate passing the third argument to `BCrypt::Engine.hash_secret` Re https://github.com/codahale/bcrypt-ruby/pull/74#issuecomment-492277126. --- CHANGELOG | 3 +++ lib/bcrypt/engine.rb | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index dc03826..d2bf07d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Unreleased: + - Deprecate passing the third argument to `BCrypt::Engine.hash_secret` [GH #207 by @sergey-alekseev] + 3.1.18 May 16 2022 - Unlock GVL when calculating hashes and salts [GH #260] - Fix compilation warnings in `ext/mri/bcrypt_ext.c` [GH #261] diff --git a/lib/bcrypt/engine.rb b/lib/bcrypt/engine.rb index 552b7b0..1a253b3 100644 --- a/lib/bcrypt/engine.rb +++ b/lib/bcrypt/engine.rb @@ -53,6 +53,13 @@ def self.cost=(cost) # Given a secret and a valid salt (see BCrypt::Engine.generate_salt) calculates # a bcrypt() password hash. Secrets longer than 72 bytes are truncated. def self.hash_secret(secret, salt, _ = nil) + unless _.nil? + warn "[DEPRECATION] Passing the third argument to " \ + "`BCrypt::Engine.hash_secret` is deprecated. " \ + "Please do not pass the third argument which " \ + "is currently not used." + end + if valid_secret?(secret) if valid_salt?(salt) if RUBY_PLATFORM == "java" From 477f290b0893a87d2d5183e473f1995c2aa05c7f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 4 Jan 2023 17:05:42 -0800 Subject: [PATCH 63/92] Add a test for passwords with null bytes Raise an exception when passwords contain null bytes. This was already fixed (inadvertently I think?) in aec1265e. StringValueCStr will raise an exception if the string buffer it's unwrapping contains null bytes. Fixes #115 Fixes #114 --- spec/bcrypt/password_spec.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spec/bcrypt/password_spec.rb b/spec/bcrypt/password_spec.rb index 1899221..5a93cbd 100644 --- a/spec/bcrypt/password_spec.rb +++ b/spec/bcrypt/password_spec.rb @@ -31,6 +31,12 @@ specify "should tolerate very long string secrets" do expect { BCrypt::Password.create("abcd"*1024) }.not_to raise_error end + + specify "blows up when null bytes are in the string" do + # JRuby can handle the null bytes + skip if RUBY_ENGINE == 'jruby' + expect { BCrypt::Password.create( "foo\0bar".chop ) }.to raise_error + end end describe "Reading a hashed password" do From 53ec1e1bea1fa75c847b9af468ca937b83d1b417 Mon Sep 17 00:00:00 2001 From: Peter Arato Date: Thu, 22 Jun 2023 09:53:58 -0400 Subject: [PATCH 64/92] Fixing a rare bug when calling BCrypt::Engine#hash_secret - which produces nil accidentally 1 out of 500 cases in TruffleRuby. Co-authored-by: Benoit Daloze Co-authored-by: Peter Arato --- ext/mri/bcrypt_ext.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ext/mri/bcrypt_ext.c b/ext/mri/bcrypt_ext.c index 2366185..757b068 100644 --- a/ext/mri/bcrypt_ext.c +++ b/ext/mri/bcrypt_ext.c @@ -49,6 +49,9 @@ static VALUE bc_salt(VALUE self, VALUE prefix, VALUE count, VALUE input) { if(!salt) return Qnil; str_salt = rb_str_new2(salt); + + RB_GC_GUARD(prefix); + RB_GC_GUARD(input); free(salt); return str_salt; @@ -99,6 +102,8 @@ static VALUE bc_crypt(VALUE self, VALUE key, VALUE setting) { out = rb_str_new2(value); + RB_GC_GUARD(key); + RB_GC_GUARD(setting); free(args.data); return out; From 31458e76f6975aad88dcd09f533fff23bb54c4f6 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 22 Jun 2023 09:46:43 -0700 Subject: [PATCH 65/92] bumping version / updating changelog --- CHANGELOG | 3 ++- bcrypt.gemspec | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index d2bf07d..9f3e624 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,6 @@ -Unreleased: +3.1.19 June 22 2023 - Deprecate passing the third argument to `BCrypt::Engine.hash_secret` [GH #207 by @sergey-alekseev] + - Add GC guards so the C compiler won't optimize out references [GH #270] 3.1.18 May 16 2022 - Unlock GVL when calculating hashes and salts [GH #260] diff --git a/bcrypt.gemspec b/bcrypt.gemspec index 7dc6abf..506d8bf 100644 --- a/bcrypt.gemspec +++ b/bcrypt.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = 'bcrypt' - s.version = '3.1.18' + s.version = '3.1.19' s.summary = "OpenBSD's bcrypt() password hashing algorithm." s.description = <<-EOF From 863cfbd80451af0521217bfbb92c80d7a9b824a0 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 22 Jun 2023 11:39:05 -0700 Subject: [PATCH 66/92] bumping Java version https://github.com/rake-compiler/rake-compiler/pull/172 --- Rakefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Rakefile b/Rakefile index a47ce55..58b51fe 100644 --- a/Rakefile +++ b/Rakefile @@ -50,8 +50,8 @@ end if RUBY_PLATFORM =~ /java/ Rake::JavaExtensionTask.new('bcrypt_ext', GEMSPEC) do |ext| ext.ext_dir = 'ext/jruby' - ext.source_version = "1.7" - ext.target_version = "1.7" + ext.source_version = "1.8" + ext.target_version = "1.8" end else Rake::ExtensionTask.new("bcrypt_ext", GEMSPEC) do |ext| From d9ed4e21c95ba13239593250ed4cd1b225117173 Mon Sep 17 00:00:00 2001 From: Piotr Usewicz Date: Fri, 17 Nov 2023 10:08:37 +0100 Subject: [PATCH 67/92] Limit packaged files Limit files included in the gem to the ones that are necessary. This skips shipping the gem with directories such as `.github`, `spec` and other files that are not normally accessible and arguably should be skipped. This saves us some bytes in transfer and disk space on all the computers these gems are downloaded to. --- bcrypt.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bcrypt.gemspec b/bcrypt.gemspec index 506d8bf..01db5e1 100644 --- a/bcrypt.gemspec +++ b/bcrypt.gemspec @@ -9,7 +9,7 @@ Gem::Specification.new do |s| passwords. EOF - s.files = `git ls-files`.split("\n") + s.files = Dir['CHANGELOG', 'COPYING', 'README.md', 'lib/**/*.rb', 'ext/**/*.*'] s.require_path = 'lib' s.add_development_dependency 'rake-compiler', '~> 1.2.0' From b8dbc8524fa598503fd06b94a8a95ff2ba3525ec Mon Sep 17 00:00:00 2001 From: "T.J. Schuck" Date: Fri, 17 Nov 2023 11:02:01 -0500 Subject: [PATCH 68/92] Add 3.2 to the test matrix --- .github/workflows/ruby.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 47a6651..2f06236 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -23,6 +23,7 @@ jobs: - 2.7 - '3.0' - 3.1 + - 3.2 - head - jruby - jruby-head From b23e4bd8b64ea8424d9d68f6df5f04e46f4ba0d7 Mon Sep 17 00:00:00 2001 From: "T.J. Schuck" Date: Fri, 17 Nov 2023 11:37:38 -0500 Subject: [PATCH 69/92] Run old rubies on Ubuntu 20.04 See https://github.com/ruby/setup-ruby/issues/496 --- .github/workflows/ruby.yml | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 2f06236..82c49b3 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -5,7 +5,6 @@ on: [ push, pull_request ] jobs: test_matrix: - strategy: fail-fast: false matrix: @@ -31,6 +30,8 @@ jobs: - truffleruby-head - mingw exclude: + - { os: ubuntu, ruby: 2.1 } + - { os: ubuntu, ruby: 2.2 } - { os: ubuntu, ruby: mingw } - { os: macos, ruby: mingw } - { os: windows, ruby: truffleruby } @@ -52,6 +53,26 @@ jobs: env: JAVA_OPTS: -Djdk.io.File.enableADS=true + test_matrix_old_rubies: + strategy: + fail-fast: false + matrix: + ruby: + - 2.1 + - 2.2 + + runs-on: ubuntu-20.04 + + steps: + - uses: actions/checkout@v2 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + - name: Run tests + run: bundle exec rake default + finish: runs-on: ubuntu-latest needs: [ test_matrix ] From 58f8afd33d8813e84706b938815bb1aa08d0b470 Mon Sep 17 00:00:00 2001 From: "T.J. Schuck" Date: Fri, 17 Nov 2023 11:58:28 -0500 Subject: [PATCH 70/92] Bump version/changelog --- CHANGELOG | 3 +++ bcrypt.gemspec | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 9f3e624..92a8114 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +3.1.20 Nov 17 2023 + - Limit packaged files -- decrease gem filesize by ~28% [GH #272 by @pusewicz] + 3.1.19 June 22 2023 - Deprecate passing the third argument to `BCrypt::Engine.hash_secret` [GH #207 by @sergey-alekseev] - Add GC guards so the C compiler won't optimize out references [GH #270] diff --git a/bcrypt.gemspec b/bcrypt.gemspec index 01db5e1..68a31ea 100644 --- a/bcrypt.gemspec +++ b/bcrypt.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = 'bcrypt' - s.version = '3.1.19' + s.version = '3.1.20' s.summary = "OpenBSD's bcrypt() password hashing algorithm." s.description = <<-EOF From 49f935c57d16dce78efd54518d6522174ab1d1f7 Mon Sep 17 00:00:00 2001 From: Mark Young Date: Wed, 20 Dec 2023 14:14:48 +0000 Subject: [PATCH 71/92] Provide a 'Changelog' link on rubygems.org/gems/bcrypt By providing a 'changelog_uri' in the metadata of the gemspec a 'Changelog' link will be shown on https://rubygems.org/gems/bcrypt which makes it quick and easy for someone to check on the changes introduced with a new version. --- bcrypt.gemspec | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bcrypt.gemspec b/bcrypt.gemspec index 68a31ea..c425529 100644 --- a/bcrypt.gemspec +++ b/bcrypt.gemspec @@ -24,4 +24,6 @@ Gem::Specification.new do |s| s.email = "coda.hale@gmail.com" s.homepage = "https://github.com/bcrypt-ruby/bcrypt-ruby" s.license = "MIT" + + s.metadata["changelog_uri"] = s.homepage + "/blob/master/CHANGELOG" end From 985e6d0579eba5cb534ac388179916fdab5adb9b Mon Sep 17 00:00:00 2001 From: m-nakamura145 Date: Tue, 21 May 2024 22:48:40 +0900 Subject: [PATCH 72/92] Support ruby 3.3 and 3.4.0-preview1 --- .github/workflows/ruby.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 82c49b3..a93f979 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -23,6 +23,8 @@ jobs: - '3.0' - 3.1 - 3.2 + - 3.3 + - 3.4.0-preview1 - head - jruby - jruby-head From 9a3a85ca9de4557b22aa8836bc7c1b9c387c024b Mon Sep 17 00:00:00 2001 From: "T.J. Schuck" Date: Tue, 21 May 2024 09:58:48 -0400 Subject: [PATCH 73/92] Update README to remove specific Ruby version mentions So we don't have to update this in lockstep with the CI matrix --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index dd55971..88598ad 100644 --- a/README.md +++ b/README.md @@ -30,8 +30,8 @@ re-hash those passwords. This vulnerability only affected the JRuby gem. The bcrypt gem is available on the following Ruby platforms: * JRuby -* RubyInstaller 2.0 – 3.0 builds on Windows with the DevKit -* Any 2.0 – 3.0 Ruby on a BSD/OS X/Linux system with a compiler +* RubyInstaller builds on Windows with the DevKit +* Any modern Ruby on a BSD/OS X/Linux system with a compiler ## How to use `bcrypt()` in your Rails application From a75cc698c4733a79c213c8a9609563abedc450bc Mon Sep 17 00:00:00 2001 From: "T.J. Schuck" Date: Wed, 22 May 2024 17:08:30 -0400 Subject: [PATCH 74/92] Ruby 3.4.0.-preview1 is not available on Windows See https://github.com/ruby/setup-ruby and https://github.com/ruby/setup-ruby/blob/master/windows-versions.json --- .github/workflows/ruby.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index a93f979..9111c87 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -38,6 +38,7 @@ jobs: - { os: macos, ruby: mingw } - { os: windows, ruby: truffleruby } - { os: windows, ruby: truffleruby-head } + - { os: windows, ruby: 3.4.0-preview1 } runs-on: ${{ matrix.os }}-latest From b8a167ab23959d1f37983b9228e9f01c03c726fd Mon Sep 17 00:00:00 2001 From: "T.J. Schuck" Date: Wed, 22 May 2024 17:18:47 -0400 Subject: [PATCH 75/92] Test old Rubies on older x64 macOS --- .github/workflows/ruby.yml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 9111c87..e940a81 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -36,6 +36,11 @@ jobs: - { os: ubuntu, ruby: 2.2 } - { os: ubuntu, ruby: mingw } - { os: macos, ruby: mingw } + - { os: macos, ruby: 2.1 } + - { os: macos, ruby: 2.2 } + - { os: macos, ruby: 2.3 } + - { os: macos, ruby: 2.4 } + - { os: macos, ruby: 2.5 } - { os: windows, ruby: truffleruby } - { os: windows, ruby: truffleruby-head } - { os: windows, ruby: 3.4.0-preview1 } @@ -60,11 +65,17 @@ jobs: strategy: fail-fast: false matrix: + os: + - ubuntu-20.04 + - macos-13 ruby: - 2.1 - 2.2 + - 2.3 + - 2.4 + - 2.5 - runs-on: ubuntu-20.04 + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 From ff9084a3f5e993b1ba9609e2326494fd97db61dc Mon Sep 17 00:00:00 2001 From: Federico Date: Sat, 13 Jul 2024 22:15:49 -0300 Subject: [PATCH 76/92] Add == gotcha that can be unintuitive at first --- lib/bcrypt/password.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/bcrypt/password.rb b/lib/bcrypt/password.rb index 4a2c140..3160c9b 100644 --- a/lib/bcrypt/password.rb +++ b/lib/bcrypt/password.rb @@ -73,6 +73,8 @@ def initialize(raw_hash) # @password == @password.to_s # => False # @password.to_s == @password # => True # @password.to_s == @password.to_s # => True + # + # secret == @password # => probably False, because the secret is not a BCrypt::Password instance. def ==(secret) super(BCrypt::Engine.hash_secret(secret, @salt)) end From 7277821447a7f40e605d9ff17a6b3b2b68e5c286 Mon Sep 17 00:00:00 2001 From: Mohamed Hafez Date: Wed, 18 Sep 2024 17:02:41 +0200 Subject: [PATCH 77/92] Mark as ractor-safe --- ext/mri/bcrypt_ext.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ext/mri/bcrypt_ext.c b/ext/mri/bcrypt_ext.c index 757b068..3e5ac1c 100644 --- a/ext/mri/bcrypt_ext.c +++ b/ext/mri/bcrypt_ext.c @@ -111,6 +111,10 @@ static VALUE bc_crypt(VALUE self, VALUE key, VALUE setting) { /* Create the BCrypt and BCrypt::Engine modules, and populate them with methods. */ void Init_bcrypt_ext(){ +#ifdef HAVE_RB_EXT_RACTOR_SAFE + rb_ext_ractor_safe(true); +#endif + mBCrypt = rb_define_module("BCrypt"); cBCryptEngine = rb_define_class_under(mBCrypt, "Engine", rb_cObject); From 9597533827b5274a1947da56000728c20af397e7 Mon Sep 17 00:00:00 2001 From: Griffin Smith Date: Thu, 6 Aug 2015 14:06:03 -0400 Subject: [PATCH 78/92] Use a constant-time secure comparison for passwords Use a constant-time byte-by-byte secure comparison to compare potential password hashes rather than `String#==`, which uses strcmp under the hood and stops as soon as there's an unmatched byte. --- lib/bcrypt/password.rb | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/bcrypt/password.rb b/lib/bcrypt/password.rb index 3160c9b..db09009 100644 --- a/lib/bcrypt/password.rb +++ b/lib/bcrypt/password.rb @@ -76,7 +76,14 @@ def initialize(raw_hash) # # secret == @password # => probably False, because the secret is not a BCrypt::Password instance. def ==(secret) - super(BCrypt::Engine.hash_secret(secret, @salt)) + hash = BCrypt::Engine.hash_secret(secret, @salt) + + return false if hash.strip.empty? || strip.empty? || hash.bytesize != bytesize + l = hash.unpack "C#{hash.bytesize}" + + res = 0 + each_byte { |byte| res |= byte ^ l.shift } + res == 0 end alias_method :is_password?, :== From a7a868e12d80c6e0a75d81acdfdc3c4a763a622b Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 29 Oct 2024 16:04:46 -0700 Subject: [PATCH 79/92] Lets not allocate anything --- lib/bcrypt/password.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/bcrypt/password.rb b/lib/bcrypt/password.rb index db09009..0c432d6 100644 --- a/lib/bcrypt/password.rb +++ b/lib/bcrypt/password.rb @@ -79,10 +79,10 @@ def ==(secret) hash = BCrypt::Engine.hash_secret(secret, @salt) return false if hash.strip.empty? || strip.empty? || hash.bytesize != bytesize - l = hash.unpack "C#{hash.bytesize}" + # Constant time comparison so they can't tell the length. res = 0 - each_byte { |byte| res |= byte ^ l.shift } + bytesize.times { |i| res |= getbyte(i) ^ hash.getbyte(i) } res == 0 end alias_method :is_password?, :== From 27dbab3080c2dbd22ae0652b36fd37eba69dda30 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 31 Dec 2025 10:14:07 -0800 Subject: [PATCH 80/92] Declare development dependencies --- bcrypt.gemspec | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bcrypt.gemspec b/bcrypt.gemspec index c425529..bae0473 100644 --- a/bcrypt.gemspec +++ b/bcrypt.gemspec @@ -14,6 +14,8 @@ Gem::Specification.new do |s| s.add_development_dependency 'rake-compiler', '~> 1.2.0' s.add_development_dependency 'rspec', '>= 3' + s.add_development_dependency 'rdoc', '>= 7.0.3' + s.add_development_dependency 'benchmark', '>= 0.5.0' s.rdoc_options += ['--title', 'bcrypt-ruby', '--line-numbers', '--inline-source', '--main', 'README.md'] s.extra_rdoc_files += ['README.md', 'COPYING', 'CHANGELOG', *Dir['lib/**/*.rb']] From c1562549b901349c79fb5e96d16c32e25caa7938 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 31 Dec 2025 10:14:19 -0800 Subject: [PATCH 81/92] Modernize CI --- .github/workflows/ruby.yml | 111 ++++++++++++------------------------- 1 file changed, 34 insertions(+), 77 deletions(-) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index e940a81..c5fb94b 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -3,93 +3,50 @@ name: Test Suite # Run against all commits and pull requests. on: [ push, pull_request ] +env: + JAVA_OPTS: '-Xms60M -Xmx1G' + jobs: - test_matrix: + ruby-versions: + uses: ruby/actions/.github/workflows/ruby_versions.yml@master + with: + engine: cruby + min_version: 3.1 + + test: + needs: ruby-versions + runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: - os: - - ubuntu - - macos - - windows - ruby: - - 2.1 - - 2.2 - - 2.3 - - 2.4 - - 2.5 - - 2.6 - - 2.7 - - '3.0' - - 3.1 - - 3.2 - - 3.3 - - 3.4.0-preview1 - - head - - jruby - - jruby-head - - truffleruby - - truffleruby-head - - mingw - exclude: - - { os: ubuntu, ruby: 2.1 } - - { os: ubuntu, ruby: 2.2 } - - { os: ubuntu, ruby: mingw } - - { os: macos, ruby: mingw } - - { os: macos, ruby: 2.1 } - - { os: macos, ruby: 2.2 } - - { os: macos, ruby: 2.3 } - - { os: macos, ruby: 2.4 } - - { os: macos, ruby: 2.5 } - - { os: windows, ruby: truffleruby } - - { os: windows, ruby: truffleruby-head } - - { os: windows, ruby: 3.4.0-preview1 } - - runs-on: ${{ matrix.os }}-latest + ruby: ${{ fromJson(needs.ruby-versions.outputs.versions) }} + os: [ ubuntu-latest, macos-latest, windows-latest ] + include: + - { os: windows-latest, ruby: jruby-head } + - { os: macos-latest, ruby: jruby-head } + - { os: ubuntu-latest, ruby: jruby-head } + - { os: windows-latest, ruby: ucrt } + - { os: windows-latest, ruby: mingw } steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 + - name: Set up Ruby - uses: ruby/setup-ruby@v1 + uses: ruby/setup-ruby-pkgs@v1 with: ruby-version: ${{ matrix.ruby }} - bundler-cache: true - env: - JAVA_OPTS: -Djdk.io.File.enableADS=true - - name: Run tests - run: bundle exec rake default - env: - JAVA_OPTS: -Djdk.io.File.enableADS=true + apt-get: "haveged libyaml-dev" + brew: libyaml + vcpkg: libyaml - test_matrix_old_rubies: - strategy: - fail-fast: false - matrix: - os: - - ubuntu-20.04 - - macos-13 - ruby: - - 2.1 - - 2.2 - - 2.3 - - 2.4 - - 2.5 + - name: Set JRuby ENV vars + run: | + echo 'JAVA_OPTS=-Xmx1g' >> $GITHUB_ENV + if: ${{ ! startsWith(matrix.ruby, 'jruby') }} - runs-on: ${{ matrix.os }} + - name: Install dependencies + run: bundle install --jobs 1 - steps: - - uses: actions/checkout@v2 - - name: Set up Ruby - uses: ruby/setup-ruby@v1 - with: - ruby-version: ${{ matrix.ruby }} - bundler-cache: true - name: Run tests - run: bundle exec rake default - - finish: - runs-on: ubuntu-latest - needs: [ test_matrix ] - steps: - - name: Wait for status checks - run: echo "All Green!" + run: bundle exec rake + continue-on-error: ${{ matrix.ruby == 'jruby-head' }} From d94041a0d2972f4dba1d831a9ebdefad398fe604 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 31 Dec 2025 10:39:17 -0800 Subject: [PATCH 82/92] Try to deal with flaky tests We have a test that tries to test the "calibration" function in BCrypt. This function is supposed to return a "cost" based on some number of milliseconds passed in. We're trying to make the cost relative to some beginning cost (MIN_COST + 1), time that, then use it as the "relative time". The problem is that the time this takes in CI is not constant, so even `min_time_ms * 4` may fit inside the same "cost" as the original. I'm bumping the factor to `5` to hopefully reduce the flakiness. It seems like we just want to test that "some time deadline" returns a greater cost than a different time deadline, so I think bumping the factor to 5 is a legit fix --- spec/bcrypt/engine_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/bcrypt/engine_spec.rb b/spec/bcrypt/engine_spec.rb index b527a6b..8abbe9f 100644 --- a/spec/bcrypt/engine_spec.rb +++ b/spec/bcrypt/engine_spec.rb @@ -17,7 +17,7 @@ BCrypt::Password.create("testing testing", :cost => BCrypt::Engine::MIN_COST + 1) min_time_ms = (Time.now - start_time) * 1000 first = BCrypt::Engine.calibrate(min_time_ms) - second = BCrypt::Engine.calibrate(min_time_ms * 4) + second = BCrypt::Engine.calibrate(min_time_ms * 5) expect(second).to be > first end end From 344ca599eed0fc311e3a5be80441ddb85540f34f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 31 Dec 2025 11:33:52 -0800 Subject: [PATCH 83/92] Configure trusted publishing This way we can just push a tag and let GitHub actions do the release --- .github/workflows/release.yml | 62 +++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..1325988 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,62 @@ +name: Publish gem to rubygems.org + +on: + push: + tags: + - 'v*' + +permissions: + contents: read + +jobs: + push: + if: github.repository == 'bcrypt-ruby/bcrypt-ruby' + runs-on: ubuntu-latest + + environment: + name: rubygems.org + url: https://rubygems.org/gems/bcrypt-ruby + + permissions: + contents: write + id-token: write + + strategy: + matrix: + ruby: ["ruby", "jruby"] + + steps: + - name: Harden Runner + uses: step-security/harden-runner@v2 + with: + egress-policy: audit + + - uses: actions/checkout@v4 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + + # https://github.com/rubygems/rubygems/issues/5882 + - name: Install dependencies and build for JRuby + run: | + sudo apt install default-jdk maven + gem update --system + gem install ruby-maven rake-compiler --no-document + rake compile + if: matrix.ruby == 'jruby' + + - name: Install dependencies + run: bundle install --jobs 4 --retry 3 + + - name: Publish to RubyGems + uses: rubygems/release-gem@v1 + + - name: Create GitHub release + run: | + tag_name="$(git describe --tags --abbrev=0)" + gh release create "${tag_name}" --verify-tag --generate-notes + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + if: matrix.ruby != 'jruby' From 64605fc1de894ba125de6a7eb61dd8cceb9bc65d Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 31 Dec 2025 11:39:38 -0800 Subject: [PATCH 84/92] bump version --- CHANGELOG | 4 ++++ bcrypt.gemspec | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 92a8114..1682923 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,7 @@ +3.1.21 Dec 31 2025 + - Use constant time comparisons + - Mark as Ractor safe + 3.1.20 Nov 17 2023 - Limit packaged files -- decrease gem filesize by ~28% [GH #272 by @pusewicz] diff --git a/bcrypt.gemspec b/bcrypt.gemspec index bae0473..e35a402 100644 --- a/bcrypt.gemspec +++ b/bcrypt.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = 'bcrypt' - s.version = '3.1.20' + s.version = '3.1.21' s.summary = "OpenBSD's bcrypt() password hashing algorithm." s.description = <<-EOF From 4b1fc736c0f4f66d5e2dd4a5c28bd4f3f51aea93 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 31 Dec 2025 11:41:44 -0800 Subject: [PATCH 85/92] add bundler tasks --- Rakefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Rakefile b/Rakefile index 58b51fe..95e22a5 100644 --- a/Rakefile +++ b/Rakefile @@ -5,6 +5,8 @@ require 'rake/javaextensiontask' require 'rake/clean' require 'rdoc/task' require 'benchmark' +require "bundler" +Bundler::GemHelper.install_tasks CLEAN.include( "tmp", From 01cc68835f0bcdd7ef16de477471c112adb417da Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 31 Dec 2025 12:02:49 -0800 Subject: [PATCH 86/92] Move compilation after bundle install The Rakefile depends on gems being installed. Hopefully this will fix JRuby releases on trusted publishing --- .github/workflows/release.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1325988..10d91ed 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -44,12 +44,16 @@ jobs: sudo apt install default-jdk maven gem update --system gem install ruby-maven rake-compiler --no-document - rake compile if: matrix.ruby == 'jruby' - name: Install dependencies run: bundle install --jobs 4 --retry 3 + - name: Compile on JRuby + run: | + rake compile + if: matrix.ruby == 'jruby' + - name: Publish to RubyGems uses: rubygems/release-gem@v1 From 4d1d95b8ec624d0cf8ed1099402a7edd2f308da2 Mon Sep 17 00:00:00 2001 From: "T.J. Schuck" Date: Thu, 29 Jan 2026 10:12:24 -0500 Subject: [PATCH 87/92] Add TruffleRuby in CI Co-authored-by: Benoit Daloze --- .github/workflows/ruby.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index c5fb94b..176faa0 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -27,6 +27,10 @@ jobs: - { os: ubuntu-latest, ruby: jruby-head } - { os: windows-latest, ruby: ucrt } - { os: windows-latest, ruby: mingw } + - { os: macos-latest, ruby: truffleruby } + - { os: ubuntu-latest, ruby: truffleruby } + - { os: macos-latest, ruby: truffleruby-head } + - { os: ubuntu-latest, ruby: truffleruby-head } steps: - uses: actions/checkout@v4 From 01f947a66ad8c5e20d8c89d9adbc7e3bd49afb70 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 18 Mar 2026 13:07:19 -0700 Subject: [PATCH 88/92] fix env url --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 10d91ed..3389e52 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,7 +15,7 @@ jobs: environment: name: rubygems.org - url: https://rubygems.org/gems/bcrypt-ruby + url: https://rubygems.org/gems/bcrypt permissions: contents: write From 5faa2748331d3edc661c127ef2fbb3afcb6b02a4 Mon Sep 17 00:00:00 2001 From: Kevin Farrell Date: Wed, 18 Mar 2026 16:43:13 +0000 Subject: [PATCH 89/92] Fix integer overflow in JRuby BCrypt rounds calculation [CVE-2026-33306] --- ext/jruby/bcrypt_jruby/BCrypt.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ext/jruby/bcrypt_jruby/BCrypt.java b/ext/jruby/bcrypt_jruby/BCrypt.java index 86db91b..bf987d9 100644 --- a/ext/jruby/bcrypt_jruby/BCrypt.java +++ b/ext/jruby/bcrypt_jruby/BCrypt.java @@ -688,20 +688,21 @@ static long roundsForLogRounds(int log_rounds) { */ private byte[] crypt_raw(byte password[], byte salt[], int log_rounds, boolean sign_ext_bug, int safety) { - int rounds, i, j; + long rounds; + int i, j; int cdata[] = bf_crypt_ciphertext.clone(); int clen = cdata.length; byte ret[]; if (log_rounds < 4 || log_rounds > 31) throw new IllegalArgumentException ("Bad number of rounds"); - rounds = 1 << log_rounds; + rounds = roundsForLogRounds(log_rounds); if (salt.length != BCRYPT_SALT_LEN) throw new IllegalArgumentException ("Bad salt length"); init_key(); ekskey(salt, password, sign_ext_bug, safety); - for (i = 0; i < rounds; i++) { + for (long r = 0; r < rounds; r++) { key(password, sign_ext_bug, safety); key(salt, false, safety); } From 32e687ec5f62baad01a62e4634e41d97f8432a61 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 18 Mar 2026 15:42:34 -0700 Subject: [PATCH 90/92] bump version update changelog --- CHANGELOG | 3 +++ bcrypt.gemspec | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 1682923..a2c9982 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +3.1.22 Mar 18 2026 + - [CVE-2026-33306] Fix integer overflow in Java extension + 3.1.21 Dec 31 2025 - Use constant time comparisons - Mark as Ractor safe diff --git a/bcrypt.gemspec b/bcrypt.gemspec index e35a402..b848c01 100644 --- a/bcrypt.gemspec +++ b/bcrypt.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = 'bcrypt' - s.version = '3.1.21' + s.version = '3.1.22' s.summary = "OpenBSD's bcrypt() password hashing algorithm." s.description = <<-EOF From 44bc362c9c3d98a1225a10fd07f7631b39f7e65d Mon Sep 17 00:00:00 2001 From: Olle Jonsson Date: Thu, 26 Mar 2026 16:45:18 +0100 Subject: [PATCH 91/92] CI: Tell dependabot to update GH Actions --- .github/dependabot.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..b18fd29 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: 'github-actions' + directory: '/' + schedule: + interval: 'weekly' From 9b1d071fbc9928be9d6d733037d5c95fe54efed2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Mar 2026 19:33:14 +0000 Subject: [PATCH 92/92] Bump actions/checkout from 4 to 6 Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/release.yml | 2 +- .github/workflows/ruby.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3389e52..1905ff8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -31,7 +31,7 @@ jobs: with: egress-policy: audit - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Ruby uses: ruby/setup-ruby@v1 diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 176faa0..f0f2e10 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -33,7 +33,7 @@ jobs: - { os: ubuntu-latest, ruby: truffleruby-head } steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Ruby uses: ruby/setup-ruby-pkgs@v1