From 2a7caff07e0fede959fe5824f55acf9d5fdfbf30 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 24 Apr 2018 16:02:43 -0700 Subject: [PATCH 001/126] Update lockfile so newer Ruby works with JSON gem --- Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 367b3de..b858a1b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -7,8 +7,8 @@ GEM remote: https://rubygems.org/ specs: diff-lcs (1.2.5) - json (1.8.3) - json (1.8.3-java) + json (1.8.6) + json (1.8.6-java) rake (10.4.2) rake-compiler (0.9.5) rake From aa4015f82cd3d3e7d5f6fea0daee76109e9a335f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Esser?= Date: Fri, 16 Feb 2018 09:14:27 +0100 Subject: [PATCH 002/126] bcrypt_ext: Add compatibility with libxcrypt --- 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 13f5e4e..b2edd1d 100644 --- a/ext/mri/bcrypt_ext.c +++ b/ext/mri/bcrypt_ext.c @@ -45,7 +45,7 @@ static VALUE bc_crypt(VALUE self, VALUE key, VALUE setting) { if(!value) return Qnil; - out = rb_str_new(data, size - 1); + out = rb_str_new2(value); xfree(data); From 45eb8c52cc40a46e1bfa1781a5e39f9a93935c89 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 25 Apr 2018 11:57:03 -0700 Subject: [PATCH 003/126] Update RG and see if that fixes the build --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index c2661ee..48ff754 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,6 @@ language: ruby +before_install: + - gem update --system rvm: - 1.8.7 - 1.9.2 From 06cee16385eebab8cd6ed673e1086d13828692a5 Mon Sep 17 00:00:00 2001 From: "T.J. Schuck" Date: Wed, 25 Apr 2018 18:23:08 -0400 Subject: [PATCH 004/126] Test on more Rubies in CI; looser version definition --- .travis.yml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index c2661ee..c6b55d1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,12 +1,14 @@ language: ruby rvm: - - 1.8.7 - - 1.9.2 - - 1.9.3 - - 2.0.0 - - 2.1.0 - - 2.2.0 - - 2.3.0 + - 1.8 + - 1.9 + - 2.0 + - 2.1 + - 2.2 + - 2.3 + - 2.4 + - 2.5 + - 2.6 - ruby-head - jruby-18mode - jruby-19mode From de31afeeb665e927515e76fa67501fbb9b6639e4 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 26 Apr 2018 09:29:33 -0700 Subject: [PATCH 005/126] Try updating Bundler too --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 7bbe31a..d5ef50b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ language: ruby before_install: - gem update --system + - gem install bundler rvm: - 1.8 - 1.9 From 5c51cee14ee7fbb91492729c25afe0ec24a10929 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 26 Apr 2018 10:49:49 -0700 Subject: [PATCH 006/126] Use RBX 3 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d5ef50b..b572547 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,6 +16,6 @@ rvm: - jruby-18mode - jruby-19mode - jruby-head - - rbx-2 + - rbx-3 - ree script: bundle exec rake From 59560e6933c69ca43c116f7873f3a7cb772be830 Mon Sep 17 00:00:00 2001 From: "T.J. Schuck" Date: Thu, 3 May 2018 16:02:27 -0400 Subject: [PATCH 007/126] Use AppVeyor for testing Windows gem installs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Notably, this is _not_ using AppVeyor for running the tests like you'd typically expect from CI. Our big issue with Windows historically isn't running the tests, it's actually installing the gem. This just leverages AppVeyor's infrastructure to let us try to install the bcrypt gem on Windows across all versions of Ruby that we intend to support. See: - https://github.com/codahale/bcrypt-ruby/issues/139 - https://github.com/codahale/bcrypt-ruby/issues/141 - https://github.com/codahale/bcrypt-ruby/issues/142 - https://github.com/codahale/bcrypt-ruby/issues/149 - ...plus countless others 😓 This doesn't actually fix the issue (that comes from me repackaging the gem and pushing the versions with new binaries), but it _does_ give us an indication that it's working. I made this intentionally work with "prerelease" versions of the gem, so I can push up `.rc` versions to test without fully pushing out (possibly still broken) new versions. --- appveyor.yml | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 appveyor.yml diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..ce7133f --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,50 @@ +############################################################################### +# +# This AppVeyor config is *NOT* for running the tests on Windows. +# +# This is to ensure that the latest version of the bcrypt gem can be installed +# on Windows across all of the currently supported versions of Ruby. +# +############################################################################### + +version: "{branch}-{build}" +build: off +clone_depth: 1 + +init: + # Install Ruby 1.8.7 + - if %RUBY_VERSION%==187 ( + appveyor DownloadFile https://dl.bintray.com/oneclick/rubyinstaller/rubyinstaller-1.8.7-p374.exe -FileName C:\ruby_187.exe & + C:\ruby_187.exe /verysilent /dir=C:\Ruby%RUBY_VERSION% + ) + +environment: + matrix: + - RUBY_VERSION: "187" + - RUBY_VERSION: "193" + - RUBY_VERSION: "200" + - RUBY_VERSION: "200-x64" + - RUBY_VERSION: "21" + - RUBY_VERSION: "21-x64" + - RUBY_VERSION: "22" + - RUBY_VERSION: "22-x64" + - RUBY_VERSION: "23" + - RUBY_VERSION: "23-x64" + - RUBY_VERSION: "24" + - RUBY_VERSION: "24-x64" + - RUBY_VERSION: "25" + - RUBY_VERSION: "25-x64" + +install: + - set PATH=C:\Ruby%RUBY_VERSION%\bin;%PATH% + - if %RUBY_VERSION%==187 ( + gem update --system 2.0.17 + ) + +before_test: + - ruby -v + - gem -v + +test_script: + - gem install bcrypt --prerelease --no-ri --no-rdoc + - ruby -e "require 'rubygems'; require 'bcrypt'" From c92c5a88023bbc1a8131c87a9d999c4b761a9df3 Mon Sep 17 00:00:00 2001 From: "T.J. Schuck" Date: Tue, 15 May 2018 15:24:50 -0400 Subject: [PATCH 008/126] RC for 3.1.12 release With support for 2.3-2.5 on Windows and Fedora 28 with libxcrypt --- CHANGELOG | 4 ++++ Gemfile.lock | 4 ++-- README.md | 4 ++-- Rakefile | 4 ++++ bcrypt.gemspec | 2 +- 5 files changed, 13 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 22d41a4..fbf386d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -82,3 +82,7 @@ 3.1.11 Mar 06 2016 - Add support for Ruby 2.2 in compiled Windows binaries + +3.1.12 May 15 2018 + - Add support for Ruby 2.3, 2.4, and 2.5 in compiled Windows binaries + - Fix compatibility with libxcrypt [GH #164 by @besser82] diff --git a/Gemfile.lock b/Gemfile.lock index b858a1b..8d77688 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - bcrypt (3.1.11) + bcrypt (3.1.12.rc1) GEM remote: https://rubygems.org/ @@ -41,4 +41,4 @@ DEPENDENCIES rspec (>= 3) BUNDLED WITH - 1.11.2 + 1.16.1 diff --git a/README.md b/README.md index efa987a..c2373c8 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 1.8, 1.9, 2.0, 2.1, and 2.2 builds on win32 -* Any 1.8, 1.9, 2.0, 2.1, 2.2, or 2.3 Ruby on a BSD/OS X/Linux system with a compiler +* RubyInstaller 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, and 2.5 builds on Windows +* Any 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, or 2.5 Ruby on a BSD/OS X/Linux system with a compiler ## How to use `bcrypt()` in your Rails application diff --git a/Rakefile b/Rakefile index 1d6c47b..c3f5b6c 100644 --- a/Rakefile +++ b/Rakefile @@ -12,6 +12,10 @@ CLEAN.include( "lib/1.9", "lib/2.0", "lib/2.1", + "lib/2.2", + "lib/2.3", + "lib/2.4", + "lib/2.5", "lib/bcrypt_ext.jar", "lib/bcrypt_ext.so" ) diff --git a/bcrypt.gemspec b/bcrypt.gemspec index 8cf4a17..cf5dc4a 100644 --- a/bcrypt.gemspec +++ b/bcrypt.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = 'bcrypt' - s.version = '3.1.11' + s.version = '3.1.12.rc1' s.summary = "OpenBSD's bcrypt() password hashing algorithm." s.description = <<-EOF From e8b906a1b3dbb209e5d0665caf7e6bfcb8d0c476 Mon Sep 17 00:00:00 2001 From: "T.J. Schuck" Date: Wed, 16 May 2018 16:03:16 -0400 Subject: [PATCH 009/126] 3.1.12 final --- CHANGELOG | 2 +- Gemfile.lock | 2 +- bcrypt.gemspec | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index fbf386d..229ba62 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -83,6 +83,6 @@ 3.1.11 Mar 06 2016 - Add support for Ruby 2.2 in compiled Windows binaries -3.1.12 May 15 2018 +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] diff --git a/Gemfile.lock b/Gemfile.lock index 8d77688..78dc153 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - bcrypt (3.1.12.rc1) + bcrypt (3.1.12) GEM remote: https://rubygems.org/ diff --git a/bcrypt.gemspec b/bcrypt.gemspec index cf5dc4a..0170428 100644 --- a/bcrypt.gemspec +++ b/bcrypt.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = 'bcrypt' - s.version = '3.1.12.rc1' + s.version = '3.1.12' s.summary = "OpenBSD's bcrypt() password hashing algorithm." s.description = <<-EOF From 0073fb818ea040248482db8facecfce70166cabc Mon Sep 17 00:00:00 2001 From: "T.J. Schuck" Date: Thu, 17 May 2018 15:41:57 -0400 Subject: [PATCH 010/126] Windows CI: run tests instead of install --- appveyor.yml | 72 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 47 insertions(+), 25 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index ce7133f..6006b02 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,12 +1,3 @@ -############################################################################### -# -# This AppVeyor config is *NOT* for running the tests on Windows. -# -# This is to ensure that the latest version of the bcrypt gem can be installed -# on Windows across all of the currently supported versions of Ruby. -# -############################################################################### - version: "{branch}-{build}" build: off clone_depth: 1 @@ -18,33 +9,64 @@ init: C:\ruby_187.exe /verysilent /dir=C:\Ruby%RUBY_VERSION% ) + # 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% + + # Install DevKit 4.5.2 for Ruby 1.8.7 + - if %RUBY_VERSION%==187 ( + mkdir C:\DevKit452 & + appveyor DownloadFile https://dl.bintray.com/oneclick/rubyinstaller/defunct/DevKit-tdm-32-4.5.2-20110712-1620-sfx.exe -FileName C:\DevKit452\devkit_452.exe & + cd C:\DevKit452 & + 7z x devkit_452.exe & + ruby dk.rb init & + ruby dk.rb install & + cd C:\projects\bcrypt-ruby + ) + environment: matrix: - - RUBY_VERSION: "187" - - RUBY_VERSION: "193" - - RUBY_VERSION: "200" - - RUBY_VERSION: "200-x64" - - RUBY_VERSION: "21" - - RUBY_VERSION: "21-x64" - - RUBY_VERSION: "22" - - RUBY_VERSION: "22-x64" - - RUBY_VERSION: "23" - - RUBY_VERSION: "23-x64" - - RUBY_VERSION: "24" - - RUBY_VERSION: "24-x64" + - 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" + - RUBY_VERSION: "193" + - RUBY_VERSION: "187" install: - - set PATH=C:\Ruby%RUBY_VERSION%\bin;%PATH% - if %RUBY_VERSION%==187 ( - gem update --system 2.0.17 + gem update --system 2.0.17 & + C:\DevKit452\devkitvars.bat ) + - if %RUBY_VERSION%==head ( gem install bundler ) + - if %RUBY_VERSION%==head-x64 ( gem install bundler ) + - bundle install before_test: - ruby -v - gem -v +build_script: + - bundle exec rake compile -rdevkit + test_script: - - gem install bcrypt --prerelease --no-ri --no-rdoc - - ruby -e "require 'rubygems'; require 'bcrypt'" + - bundle exec rake spec From b06b10b3b963bfc8a7b64a4c98d440777810b9bc Mon Sep 17 00:00:00 2001 From: "T.J. Schuck" Date: Mon, 21 May 2018 19:24:56 -0400 Subject: [PATCH 011/126] No longer cross-compile fat binaries for Windows --- Gemfile.lock | 2 -- README.md | 6 +++--- Rakefile | 27 --------------------------- lib/bcrypt.rb | 7 +------ 4 files changed, 4 insertions(+), 38 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 78dc153..4b022d8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -31,8 +31,6 @@ GEM PLATFORMS java ruby - x64-mingw32 - x86-mingw32 DEPENDENCIES bcrypt! diff --git a/README.md b/README.md index c2373c8..af6ce3c 100644 --- a/README.md +++ b/README.md @@ -27,11 +27,11 @@ re-hash those passwords. This vulnerability only affected the JRuby gem. gem install bcrypt -The bcrypt gem is available on the following ruby platforms: +The bcrypt gem is available on the following Ruby platforms: * JRuby -* RubyInstaller 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, and 2.5 builds on Windows -* Any 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, or 2.5 Ruby on a BSD/OS X/Linux system with a compiler +* RubyInstaller 1.8 – 2.5 builds on Windows with the DevKit +* Any 1.8 – 2.5 Ruby on a BSD/OS X/Linux system with a compiler ## How to use `bcrypt()` in your Rails application diff --git a/Rakefile b/Rakefile index c3f5b6c..98ed63b 100644 --- a/Rakefile +++ b/Rakefile @@ -8,14 +8,6 @@ require 'benchmark' CLEAN.include( "tmp", - "lib/1.8", - "lib/1.9", - "lib/2.0", - "lib/2.1", - "lib/2.2", - "lib/2.3", - "lib/2.4", - "lib/2.5", "lib/bcrypt_ext.jar", "lib/bcrypt_ext.so" ) @@ -62,25 +54,6 @@ if RUBY_PLATFORM =~ /java/ else Rake::ExtensionTask.new("bcrypt_ext", GEMSPEC) do |ext| ext.ext_dir = 'ext/mri' - ext.cross_compile = true - ext.cross_platform = ['x86-mingw32', 'x64-mingw32'] - end - - ENV['RUBY_CC_VERSION'].to_s.split(':').each do |ruby_version| - platforms = { - "x86-mingw32" => "i686-w64-mingw32", - "x64-mingw32" => "x86_64-w64-mingw32" - } - platforms.each do |platform, prefix| - task "copy:bcrypt_ext:#{platform}:#{ruby_version}" do |t| - %w[lib tmp/#{platform}/stage/lib].each do |dir| - so_file = "#{dir}/#{ruby_version[/^\d+\.\d+/]}/bcrypt_ext.so" - if File.exists?(so_file) - sh "#{prefix}-strip -S #{so_file}" - end - end - end - end end end diff --git a/lib/bcrypt.rb b/lib/bcrypt.rb index 8a3ecf3..c1b9e47 100644 --- a/lib/bcrypt.rb +++ b/lib/bcrypt.rb @@ -9,12 +9,7 @@ module BCrypt require "openssl" end -begin - RUBY_VERSION =~ /(\d+.\d+)/ - require "#{$1}/bcrypt_ext" -rescue LoadError - require "bcrypt_ext" -end +require "bcrypt_ext" require 'bcrypt/error' require 'bcrypt/engine' From 6a61bafce349fde87ecda02a26fc144128cb2cdd Mon Sep 17 00:00:00 2001 From: "T.J. Schuck" Date: Mon, 21 May 2018 19:25:06 -0400 Subject: [PATCH 012/126] Changelog entry --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 229ba62..89da1bc 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -86,3 +86,6 @@ 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] + +[DRAFT] 4.0.0 MMM DD YYYY + - No longer include compiled binaries for Windows. See GH #173. From 6b3821abaf6e54144bc88a56321908cfee610e8e Mon Sep 17 00:00:00 2001 From: Bart de Water Date: Mon, 3 Sep 2018 12:42:29 -0400 Subject: [PATCH 013/126] Bump default cost to 12 The default cost has not changed since the initial checkin of the code in 2007. Computers have gotten faster in general and GPGPU password cracking became a thing. BCrypt::Engine.calibrate(250) returns 12 on my Intel Core i7-4870HQ. --- README.md | 10 +++++----- lib/bcrypt/engine.rb | 6 +++--- lib/bcrypt/password.rb | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index c2373c8..9203255 100644 --- a/README.md +++ b/README.md @@ -81,14 +81,14 @@ end require 'bcrypt' my_password = BCrypt::Password.create("my password") -#=> "$2a$10$vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa" +#=> "$2a$12$K0ByB.6YI2/OYrB4fQOYLe6Tv0datUVf6VZ/2Jzwm879BW5K1cHey" my_password.version #=> "2a" -my_password.cost #=> 10 +my_password.cost #=> 12 my_password == "my password" #=> true my_password == "not my password" #=> false -my_password = BCrypt::Password.new("$2a$10$vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa") +my_password = BCrypt::Password.new("$2a$12$K0ByB.6YI2/OYrB4fQOYLe6Tv0datUVf6VZ/2Jzwm879BW5K1cHey") my_password == "my password" #=> true my_password == "not my password" #=> false ``` @@ -155,14 +155,14 @@ If an attacker was using Ruby to check each password, they could check ~140,000 In addition, `bcrypt()` allows you to increase the amount of work required to hash a password as computers get faster. Old passwords will still work fine, but new passwords can keep up with the times. -The default cost factor used by bcrypt-ruby is 10, which is fine for session-based authentication. If you are using a +The default cost factor used by bcrypt-ruby is 12, which is fine for session-based authentication. If you are using a stateless authentication architecture (e.g., HTTP Basic Auth), you will want to lower the cost factor to reduce your server load and keep your request times down. This will lower the security provided you, but there are few alternatives. To change the default cost factor used by bcrypt-ruby, use `BCrypt::Engine.cost = new_value`: ```ruby BCrypt::Password.create('secret').cost - #=> 10, the default provided by bcrypt-ruby + #=> 12, the default provided by bcrypt-ruby # set a new default cost BCrypt::Engine.cost = 8 diff --git a/lib/bcrypt/engine.rb b/lib/bcrypt/engine.rb index abde3dd..85e9ab6 100644 --- a/lib/bcrypt/engine.rb +++ b/lib/bcrypt/engine.rb @@ -2,7 +2,7 @@ module BCrypt # A Ruby wrapper for the bcrypt() C extension calls and the Java calls. class Engine # The default computational expense parameter. - DEFAULT_COST = 10 + DEFAULT_COST = 12 # The minimum cost supported by the algorithm. MIN_COST = 4 # Maximum possible size of bcrypt() salts. @@ -28,8 +28,8 @@ def self.cost # # Example: # - # BCrypt::Engine::DEFAULT_COST #=> 10 - # BCrypt::Password.create('secret').cost #=> 10 + # BCrypt::Engine::DEFAULT_COST #=> 12 + # BCrypt::Password.create('secret').cost #=> 12 # # BCrypt::Engine.cost = 8 # BCrypt::Password.create('secret').cost #=> 8 diff --git a/lib/bcrypt/password.rb b/lib/bcrypt/password.rb index fd19b47..509a8d9 100644 --- a/lib/bcrypt/password.rb +++ b/lib/bcrypt/password.rb @@ -7,7 +7,7 @@ module BCrypt # # # hash a user's password # @password = Password.create("my grand secret") - # @password #=> "$2a$10$GtKs1Kbsig8ULHZzO1h2TetZfhO4Fmlxphp8bVKnUlZCBYYClPohG" + # @password #=> "$2a$12$C5.FIvVDS9W4AYZ/Ib37YuWd/7ozp1UaMhU28UKrfSxp2oDchbi3K" # # # store it safely # @user.update_attribute(:password, @password) From d19ea481618420922b533a8b0ed049109404cb13 Mon Sep 17 00:00:00 2001 From: Florin Onica Date: Tue, 23 Oct 2018 21:48:38 +0300 Subject: [PATCH 014/126] update blowfish imprementation to latest version (1.3) --- ext/jruby/bcrypt_jruby/BCrypt.java | 875 +++++++++++++++++------------ ext/mri/crypt.h | 13 +- ext/mri/crypt_blowfish.c | 409 +++++++++----- ext/mri/crypt_blowfish.h | 27 + ext/mri/crypt_gensalt.c | 39 +- ext/mri/crypt_gensalt.h | 30 + ext/mri/ow-crypt.h | 42 +- ext/mri/wrapper.c | 381 +++++++++++-- lib/bcrypt/engine.rb | 2 +- spec/bcrypt/engine_spec.rb | 26 +- 10 files changed, 1270 insertions(+), 574 deletions(-) create mode 100644 ext/mri/crypt_blowfish.h create mode 100644 ext/mri/crypt_gensalt.h diff --git a/ext/jruby/bcrypt_jruby/BCrypt.java b/ext/jruby/bcrypt_jruby/BCrypt.java index 0846005..86db91b 100644 --- a/ext/jruby/bcrypt_jruby/BCrypt.java +++ b/ext/jruby/bcrypt_jruby/BCrypt.java @@ -11,11 +11,10 @@ // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - package bcrypt_jruby; import java.io.UnsupportedEncodingException; - +import java.util.Arrays; import java.security.SecureRandom; /** @@ -54,12 +53,12 @@ * String stronger_salt = BCrypt.gensalt(12)
* *

- * The amount of work increases exponentially (2**log_rounds), so + * The amount of work increases exponentially (2**log_rounds), so * each increment is twice as much work. The default log_rounds is * 10, and the valid range is 4 to 31. * * @author Damien Miller - * @version 0.2 + * @version 0.3 */ public class BCrypt { // BCrypt parameters @@ -71,326 +70,328 @@ public class BCrypt { // Initial contents of key schedule private static final int P_orig[] = { - 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, - 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, - 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, - 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, - 0x9216d5d9, 0x8979fb1b + 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, + 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, + 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, + 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, + 0x9216d5d9, 0x8979fb1b }; private static final int S_orig[] = { - 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, - 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, - 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, - 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, - 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, - 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, - 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, - 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, - 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, - 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, - 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, - 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, - 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, - 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, - 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, - 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, - 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, - 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, - 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, - 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, - 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, - 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, - 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, - 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, - 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, - 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, - 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, - 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, - 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, - 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, - 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, - 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, - 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, - 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, - 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, - 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, - 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, - 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, - 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, - 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, - 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, - 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, - 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, - 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, - 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, - 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, - 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, - 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, - 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, - 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, - 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, - 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, - 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, - 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, - 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, - 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, - 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, - 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, - 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, - 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, - 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, - 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, - 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, - 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a, - 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, - 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, - 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, - 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, - 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, - 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, - 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, - 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, - 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, - 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, - 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, - 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, - 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, - 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, - 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, - 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, - 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, - 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, - 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, - 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, - 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, - 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, - 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, - 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, - 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, - 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, - 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, - 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, - 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, - 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, - 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, - 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, - 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, - 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, - 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, - 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, - 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, - 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, - 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, - 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, - 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, - 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, - 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, - 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, - 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, - 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, - 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, - 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, - 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, - 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, - 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, - 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, - 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, - 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, - 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, - 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, - 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, - 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, - 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, - 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, - 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, - 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, - 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, - 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7, - 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, - 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, - 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, - 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, - 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, - 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, - 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, - 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, - 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, - 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, - 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, - 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, - 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, - 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, - 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, - 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, - 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, - 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, - 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, - 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, - 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, - 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, - 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, - 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, - 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, - 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, - 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, - 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, - 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, - 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, - 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, - 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, - 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, - 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, - 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, - 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, - 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, - 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, - 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, - 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, - 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, - 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, - 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, - 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, - 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, - 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, - 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, - 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, - 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, - 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, - 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, - 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, - 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, - 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, - 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, - 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, - 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, - 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, - 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, - 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, - 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, - 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, - 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, - 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0, - 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, - 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, - 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, - 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, - 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, - 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, - 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, - 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, - 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, - 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, - 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, - 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, - 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, - 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, - 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, - 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, - 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, - 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, - 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, - 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, - 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, - 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, - 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, - 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, - 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, - 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, - 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, - 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, - 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, - 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, - 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, - 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, - 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, - 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, - 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, - 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, - 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, - 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, - 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, - 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, - 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, - 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, - 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, - 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, - 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, - 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, - 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, - 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, - 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, - 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, - 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, - 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, - 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, - 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, - 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, - 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, - 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, - 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, - 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, - 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, - 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, - 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, - 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, - 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 + 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, + 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, + 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, + 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, + 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, + 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, + 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, + 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, + 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, + 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, + 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, + 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, + 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, + 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, + 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, + 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, + 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, + 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, + 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, + 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, + 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, + 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, + 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, + 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, + 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, + 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, + 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, + 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, + 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, + 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, + 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, + 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, + 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, + 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, + 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, + 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, + 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, + 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, + 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, + 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, + 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, + 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, + 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, + 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, + 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, + 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, + 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, + 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, + 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, + 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, + 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, + 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, + 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, + 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, + 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, + 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, + 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, + 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, + 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, + 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, + 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, + 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, + 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, + 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a, + 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, + 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, + 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, + 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, + 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, + 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, + 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, + 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, + 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, + 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, + 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, + 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, + 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, + 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, + 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, + 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, + 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, + 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, + 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, + 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, + 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, + 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, + 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, + 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, + 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, + 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, + 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, + 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, + 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, + 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, + 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, + 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, + 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, + 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, + 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, + 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, + 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, + 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, + 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, + 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, + 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, + 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, + 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, + 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, + 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, + 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, + 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, + 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, + 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, + 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, + 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, + 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, + 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, + 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, + 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, + 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, + 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, + 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, + 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, + 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, + 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, + 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, + 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, + 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7, + 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, + 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, + 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, + 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, + 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, + 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, + 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, + 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, + 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, + 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, + 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, + 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, + 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, + 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, + 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, + 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, + 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, + 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, + 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, + 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, + 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, + 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, + 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, + 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, + 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, + 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, + 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, + 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, + 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, + 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, + 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, + 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, + 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, + 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, + 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, + 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, + 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, + 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, + 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, + 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, + 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, + 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, + 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, + 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, + 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, + 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, + 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, + 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, + 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, + 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, + 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, + 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, + 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, + 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, + 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, + 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, + 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, + 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, + 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, + 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, + 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, + 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, + 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, + 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0, + 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, + 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, + 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, + 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, + 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, + 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, + 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, + 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, + 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, + 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, + 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, + 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, + 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, + 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, + 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, + 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, + 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, + 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, + 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, + 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, + 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, + 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, + 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, + 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, + 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, + 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, + 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, + 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, + 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, + 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, + 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, + 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, + 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, + 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, + 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, + 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, + 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, + 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, + 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, + 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, + 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, + 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, + 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, + 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, + 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, + 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, + 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, + 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, + 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, + 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, + 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, + 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, + 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, + 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, + 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, + 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, + 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, + 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, + 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, + 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, + 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, + 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, + 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, + 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 }; // bcrypt IV: "OrpheanBeholderScryDoubt" static private final int bf_crypt_ciphertext[] = { - 0x4f727068, 0x65616e42, 0x65686f6c, - 0x64657253, 0x63727944, 0x6f756274 + 0x4f727068, 0x65616e42, 0x65686f6c, + 0x64657253, 0x63727944, 0x6f756274 }; // Table for Base64 encoding static private final char base64_code[] = { - '.', '/', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', - 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', - 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', - 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', - 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', - '6', '7', '8', '9' + '.', '/', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', + 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', + 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', + 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', + 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', + '6', '7', '8', '9' }; // Table for Base64 decoding static private final byte index_64[] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 0, 1, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63, -1, -1, - -1, -1, -1, -1, -1, 2, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - -1, -1, -1, -1, -1, -1, 28, 29, 30, - 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, - 51, 52, 53, -1, -1, -1, -1, -1 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 0, 1, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, -1, -1, + -1, -1, -1, -1, -1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + -1, -1, -1, -1, -1, -1, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, -1, -1, -1, -1, -1 }; + static final int MIN_LOG_ROUNDS = 4; + static final int MAX_LOG_ROUNDS = 31; // Expanded Blowfish key private int P[]; private int S[]; /** - * Encode a byte array using bcrypt's slightly-modified base64 - * encoding scheme. Note that this is *not* compatible with - * the standard MIME-base64 encoding. + * Encode a byte array using bcrypt's slightly-modified base64 encoding scheme. Note + * that this is not compatible with the standard MIME-base64 + * encoding. * - * @param d the byte array to encode - * @param len the number of bytes to encode - * @return base64-encoded string + * @param d the byte array to encode + * @param len the number of bytes to encode + * @param rs the destination buffer for the base64-encoded string * @exception IllegalArgumentException if the length is invalid */ - private static String encode_base64(byte d[], int len) - throws IllegalArgumentException { + static void encode_base64(byte d[], int len, StringBuilder rs) + throws IllegalArgumentException { int off = 0; - StringBuilder rs = new StringBuilder(); int c1, c2; - if (len <= 0 || len > d.length) - throw new IllegalArgumentException ("Invalid len"); + if (len <= 0 || len > d.length) { + throw new IllegalArgumentException("Invalid len"); + } while (off < len) { c1 = d[off++] & 0xff; @@ -413,7 +414,6 @@ private static String encode_base64(byte d[], int len) rs.append(base64_code[c1 & 0x3f]); rs.append(base64_code[c2 & 0x3f]); } - return rs.toString(); } /** @@ -423,9 +423,9 @@ private static String encode_base64(byte d[], int len) * @return the decoded value of x */ private static byte char64(char x) { - if ((int)x < 0 || (int)x > index_64.length) + if ((int) x < 0 || (int) x >= index_64.length) return -1; - return index_64[(int)x]; + return index_64[(int) x]; } /** @@ -437,8 +437,8 @@ private static byte char64(char x) { * @return an array containing the decoded bytes * @throws IllegalArgumentException if maxolen is invalid */ - private static byte[] decode_base64(String s, int maxolen) - throws IllegalArgumentException { + static byte[] decode_base64(String s, int maxolen) + throws IllegalArgumentException { StringBuilder rs = new StringBuilder(); int off = 0, slen = s.length(), olen = 0; byte ret[]; @@ -452,29 +452,29 @@ private static byte[] decode_base64(String s, int maxolen) c2 = char64(s.charAt(off++)); if (c1 == -1 || c2 == -1) break; - o = (byte)(c1 << 2); + o = (byte) (c1 << 2); o |= (c2 & 0x30) >> 4; - rs.append((char)o); + rs.append((char) o); if (++olen >= maxolen || off >= slen) break; c3 = char64(s.charAt(off++)); if (c3 == -1) break; - o = (byte)((c2 & 0x0f) << 4); + o = (byte) ((c2 & 0x0f) << 4); o |= (c3 & 0x3c) >> 2; - rs.append((char)o); + rs.append((char) o); if (++olen >= maxolen || off >= slen) break; c4 = char64(s.charAt(off++)); - o = (byte)((c3 & 0x03) << 6); + o = (byte) ((c3 & 0x03) << 6); o |= c4; - rs.append((char)o); + rs.append((char) o); ++olen; } ret = new byte[olen]; for (off = 0; off < olen; off++) - ret[off] = (byte)rs.charAt(off); + ret[off] = (byte) rs.charAt(off); return ret; } @@ -512,42 +512,77 @@ private final void encipher(int lr[], int off) { * @param data the string to extract the data from * @param offp a "pointer" (as a one-entry array) to the * current offset into data - * @return the next word of material from data + * @param signp a "pointer" (as a one-entry array) to the + * cumulative flag for non-benign sign extension + * @return correct and buggy next word of material from data as int[2] */ - private static int streamtoword(byte data[], int offp[]) { + private static int[] streamtowords(byte data[], int offp[], int signp[]) { int i; - int word = 0; + int words[] = { 0, 0 }; int off = offp[0]; + int sign = signp[0]; for (i = 0; i < 4; i++) { - word = (word << 8) | (data[off] & 0xff); + words[0] = (words[0] << 8) | (data[off] & 0xff); + words[1] = (words[1] << 8) | (int) data[off]; // sign extension bug + if (i > 0) sign |= words[1] & 0x80; off = (off + 1) % data.length; } offp[0] = off; - return word; + signp[0] = sign; + return words; + } + + /** + * Cycically extract a word of key material + * @param data the string to extract the data from + * @param offp a "pointer" (as a one-entry array) to the + * current offset into data + * @return the next word of material from data + */ + private static int streamtoword(byte data[], int offp[]) { + int signp[] = { 0 }; + return streamtowords(data, offp, signp)[0]; + } + + /** + * Cycically extract a word of key material, with sign-extension bug + * @param data the string to extract the data from + * @param offp a "pointer" (as a one-entry array) to the + * current offset into data + * @return the next word of material from data + */ + private static int streamtoword_bug(byte data[], int offp[]) { + int signp[] = { 0 }; + return streamtowords(data, offp, signp)[1]; } /** * Initialise the Blowfish key schedule */ private void init_key() { - P = (int[])P_orig.clone(); - S = (int[])S_orig.clone(); + P = P_orig.clone(); + S = S_orig.clone(); } /** * Key the Blowfish cipher * @param key an array containing the key + * @param sign_ext_bug true to implement the 2x bug + * @param safety bit 16 is set when the safety measure is requested */ - private void key(byte key[]) { + private void key(byte key[], boolean sign_ext_bug, int safety) { int i; int koffp[] = { 0 }; int lr[] = { 0, 0 }; int plen = P.length, slen = S.length; for (i = 0; i < plen; i++) - P[i] = P[i] ^ streamtoword(key, koffp); + if (!sign_ext_bug) + P[i] = P[i] ^ streamtoword(key, koffp); + else + P[i] = P[i] ^ streamtoword_bug(key, koffp); for (i = 0; i < plen; i += 2) { encipher(lr, 0); @@ -568,15 +603,53 @@ private void key(byte key[]) { * http://www.openbsd.org/papers/bcrypt-paper.ps * @param data salt information * @param key password information + * @param sign_ext_bug true to implement the 2x bug + * @param safety bit 16 is set when the safety measure is requested */ - private void ekskey(byte data[], byte key[]) { + private void ekskey(byte data[], byte key[], + boolean sign_ext_bug, int safety) { int i; int koffp[] = { 0 }, doffp[] = { 0 }; int lr[] = { 0, 0 }; int plen = P.length, slen = S.length; + int signp[] = { 0 }; // non-benign sign-extension flag + int diff = 0; // zero iff correct and buggy are same - for (i = 0; i < plen; i++) - P[i] = P[i] ^ streamtoword(key, koffp); + for (i = 0; i < plen; i++) { + int words[] = streamtowords(key, koffp, signp); + diff |= words[0] ^ words[1]; + P[i] = P[i] ^ words[sign_ext_bug ? 1 : 0]; + } + + int sign = signp[0]; + + /* + * At this point, "diff" is zero iff the correct and buggy algorithms produced + * exactly the same result. If so and if "sign" is non-zero, which indicates + * that there was a non-benign sign extension, this means that we have a + * collision between the correctly computed hash for this password and a set of + * passwords that could be supplied to the buggy algorithm. Our safety measure + * is meant to protect from such many-buggy to one-correct collisions, by + * deviating from the correct algorithm in such cases. Let's check for this. + */ + diff |= diff >> 16; /* still zero iff exact match */ + diff &= 0xffff; /* ditto */ + diff += 0xffff; /* bit 16 set iff "diff" was non-zero (on non-match) */ + sign <<= 9; /* move the non-benign sign extension flag to bit 16 */ + sign &= ~diff & safety; /* action needed? */ + + /* + * If we have determined that we need to deviate from the correct algorithm, + * flip bit 16 in initial expanded key. (The choice of 16 is arbitrary, but + * let's stick to it now. It came out of the approach we used above, and it's + * not any worse than any other choice we could make.) + * + * It is crucial that we don't do the same to the expanded key used in the main + * Eksblowfish loop. By doing it to only one of these two, we deviate from a + * state that could be directly specified by a password to the buggy algorithm + * (and to the fully correct one as well, but that's a side-effect). + */ + P[0] ^= sign; for (i = 0; i < plen; i += 2) { lr[0] ^= streamtoword(data, doffp); @@ -595,6 +668,13 @@ private void ekskey(byte data[], byte key[]) { } } + static long roundsForLogRounds(int log_rounds) { + if (log_rounds < 4 || log_rounds > 31) { + throw new IllegalArgumentException("Bad number of rounds"); + } + return 1L << log_rounds; + } + /** * Perform the central password hashing step in the * bcrypt scheme @@ -602,11 +682,14 @@ private void ekskey(byte data[], byte key[]) { * @param salt the binary salt to hash with the password * @param log_rounds the binary logarithm of the number * of rounds of hashing to apply + * @param sign_ext_bug true to implement the 2x bug + * @param safety bit 16 is set when the safety measure is requested * @return an array containing the binary hashed password */ - private byte[] crypt_raw(byte password[], byte salt[], int log_rounds) { + private byte[] crypt_raw(byte password[], byte salt[], int log_rounds, + boolean sign_ext_bug, int safety) { int rounds, i, j; - int cdata[] = (int[])bf_crypt_ciphertext.clone(); + int cdata[] = bf_crypt_ciphertext.clone(); int clen = cdata.length; byte ret[]; @@ -617,10 +700,10 @@ private byte[] crypt_raw(byte password[], byte salt[], int log_rounds) { throw new IllegalArgumentException ("Bad salt length"); init_key(); - ekskey(salt, password); + ekskey(salt, password, sign_ext_bug, safety); for (i = 0; i < rounds; i++) { - key(password); - key(salt); + key(password, sign_ext_bug, safety); + key(salt, false, safety); } for (i = 0; i < 64; i++) { @@ -630,10 +713,10 @@ private byte[] crypt_raw(byte password[], byte salt[], int log_rounds) { ret = new byte[clen * 4]; for (i = 0, j = 0; i < clen; i++) { - ret[j++] = (byte)((cdata[i] >> 24) & 0xff); - ret[j++] = (byte)((cdata[i] >> 16) & 0xff); - ret[j++] = (byte)((cdata[i] >> 8) & 0xff); - ret[j++] = (byte)(cdata[i] & 0xff); + ret[j++] = (byte) ((cdata[i] >> 24) & 0xff); + ret[j++] = (byte) ((cdata[i] >> 16) & 0xff); + ret[j++] = (byte) ((cdata[i] >> 8) & 0xff); + ret[j++] = (byte) (cdata[i] & 0xff); } return ret; } @@ -646,20 +729,50 @@ private byte[] crypt_raw(byte password[], byte salt[], int log_rounds) { * @return the hashed password */ public static String hashpw(String password, String salt) { + byte passwordb[]; + + try { + passwordb = password.getBytes("UTF-8"); + } catch (UnsupportedEncodingException uee) { + throw new AssertionError("UTF-8 is not supported"); + } + + return hashpw(passwordb, salt); + } + + /** + * Hash a password using the OpenBSD bcrypt scheme + * @param passwordb the password to hash, as a byte array + * @param salt the salt to hash with (perhaps generated + * using BCrypt.gensalt) + * @return the hashed password + */ + public static String hashpw(byte passwordb[], String salt) { BCrypt B; String real_salt; - byte passwordb[], saltb[], hashed[]; - char minor = (char)0; - int rounds, off = 0; + byte saltb[], hashed[]; + char minor = (char) 0; + int rounds, off; StringBuilder rs = new StringBuilder(); + if (salt == null) { + throw new IllegalArgumentException("salt cannot be null"); + } + + int saltLength = salt.length(); + + if (saltLength < 28) { + throw new IllegalArgumentException("Invalid salt"); + } + if (salt.charAt(0) != '$' || salt.charAt(1) != '2') throw new IllegalArgumentException ("Invalid salt version"); if (salt.charAt(2) == '$') off = 3; else { minor = salt.charAt(2); - if (minor != 'a' || salt.charAt(3) != '$') + if ((minor != 'a' && minor != 'x' && minor != 'y' && minor != 'b') + || salt.charAt(3) != '$') throw new IllegalArgumentException ("Invalid salt revision"); off = 4; } @@ -670,16 +783,13 @@ public static String hashpw(String password, String salt) { rounds = Integer.parseInt(salt.substring(off, off + 2)); real_salt = salt.substring(off + 3, off + 25); - try { - passwordb = (password + (minor >= 'a' ? "\000" : "")).getBytes("UTF-8"); - } catch (UnsupportedEncodingException uee) { - throw new AssertionError("UTF-8 is not supported"); - } - saltb = decode_base64(real_salt, BCRYPT_SALT_LEN); + if (minor >= 'a') // add null terminator + passwordb = Arrays.copyOf(passwordb, passwordb.length + 1); + B = new BCrypt(); - hashed = B.crypt_raw(passwordb, saltb, rounds); + hashed = B.crypt_raw(passwordb, saltb, rounds, minor == 'x', minor == 'a' ? 0x10000 : 0); rs.append("$2"); if (minor >= 'a') @@ -687,48 +797,95 @@ public static String hashpw(String password, String salt) { rs.append("$"); if (rounds < 10) rs.append("0"); - rs.append(Integer.toString(rounds)); + rs.append(rounds); rs.append("$"); - rs.append(encode_base64(saltb, saltb.length)); - rs.append(encode_base64(hashed, - bf_crypt_ciphertext.length * 4 - 1)); + encode_base64(saltb, saltb.length, rs); + encode_base64(hashed, bf_crypt_ciphertext.length * 4 - 1, rs); return rs.toString(); } /** * Generate a salt for use with the BCrypt.hashpw() method + * @param prefix the prefix value (default $2a) * @param log_rounds the log2 of the number of rounds of * hashing to apply - the work factor therefore increases as * 2**log_rounds. * @param random an instance of SecureRandom to use * @return an encoded salt value + * @exception IllegalArgumentException if prefix or log_rounds is invalid */ - public static String gensalt(int log_rounds, SecureRandom random) { + public static String gensalt(String prefix, int log_rounds, SecureRandom random) + throws IllegalArgumentException { StringBuilder rs = new StringBuilder(); byte rnd[] = new byte[BCRYPT_SALT_LEN]; + if (!prefix.startsWith("$2") || + (prefix.charAt(2) != 'a' && prefix.charAt(2) != 'y' && + prefix.charAt(2) != 'b')) { + throw new IllegalArgumentException ("Invalid prefix"); + } + if (log_rounds < 4 || log_rounds > 31) { + throw new IllegalArgumentException ("Invalid log_rounds"); + } + random.nextBytes(rnd); - rs.append("$2a$"); + rs.append("$2"); + rs.append(prefix.charAt(2)); + rs.append("$"); if (log_rounds < 10) rs.append("0"); - rs.append(Integer.toString(log_rounds)); + rs.append(log_rounds); rs.append("$"); - rs.append(encode_base64(rnd, rnd.length)); + encode_base64(rnd, rnd.length, rs); return rs.toString(); } /** * Generate a salt for use with the BCrypt.hashpw() method + * @param prefix the prefix value (default $2a) * @param log_rounds the log2 of the number of rounds of * hashing to apply - the work factor therefore increases as * 2**log_rounds. * @return an encoded salt value + * @exception IllegalArgumentException if prefix or log_rounds is invalid */ - public static String gensalt(int log_rounds) { + public static String gensalt(String prefix, int log_rounds) + throws IllegalArgumentException { + return gensalt(prefix, log_rounds, new SecureRandom()); + } + + /** + * Generate a salt for use with the BCrypt.hashpw() method + * @param log_rounds the log2 of the number of rounds of + * hashing to apply - the work factor therefore increases as + * 2**log_rounds. + * @param random an instance of SecureRandom to use + * @return an encoded salt value + * @exception IllegalArgumentException if log_rounds is invalid + */ + public static String gensalt(int log_rounds, SecureRandom random) + throws IllegalArgumentException { + return gensalt("$2a", log_rounds, random); + } + + /** + * Generate a salt for use with the BCrypt.hashpw() method + * @param log_rounds the log2 of the number of rounds of + * hashing to apply - the work factor therefore increases as + * 2**log_rounds. + * @return an encoded salt value + * @exception IllegalArgumentException if log_rounds is invalid + */ + public static String gensalt(int log_rounds) + throws IllegalArgumentException { return gensalt(log_rounds, new SecureRandom()); } + public static String gensalt(String prefix) { + return gensalt(prefix, GENSALT_DEFAULT_LOG2_ROUNDS); + } + /** * Generate a salt for use with the BCrypt.hashpw() method, * selecting a reasonable default for the number of hashing @@ -747,6 +904,22 @@ public static String gensalt() { * @return true if the passwords match, false otherwise */ public static boolean checkpw(String plaintext, String hashed) { - return (hashed.compareTo(hashpw(plaintext, hashed)) == 0); + return equalsNoEarlyReturn(hashed, hashpw(plaintext, hashed)); + } + + static boolean equalsNoEarlyReturn(String a, String b) { + char[] caa = a.toCharArray(); + char[] cab = b.toCharArray(); + + if (caa.length != cab.length) { + return false; + } + + byte ret = 0; + for (int i = 0; i < caa.length; i++) { + ret |= caa[i] ^ cab[i]; + } + return ret == 0; } } + diff --git a/ext/mri/crypt.h b/ext/mri/crypt.h index c923fa4..12e6705 100644 --- a/ext/mri/crypt.h +++ b/ext/mri/crypt.h @@ -1,5 +1,16 @@ /* - * Written by Solar Designer and placed in the public domain. + * Written by Solar Designer in 2000-2002. + * No copyright is claimed, and the software is hereby placed in the public + * domain. In case this attempt to disclaim copyright and place the software + * in the public domain is deemed null and void, then the software is + * Copyright (c) 2000-2002 Solar Designer and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * * See crypt_blowfish.c for more information. */ diff --git a/ext/mri/crypt_blowfish.c b/ext/mri/crypt_blowfish.c index cf96c17..9d3f3be 100644 --- a/ext/mri/crypt_blowfish.c +++ b/ext/mri/crypt_blowfish.c @@ -1,26 +1,38 @@ /* + * The crypt_blowfish homepage is: + * + * http://www.openwall.com/crypt/ + * * This code comes from John the Ripper password cracker, with reentrant * and crypt(3) interfaces added, but optimizations specific to password * cracking removed. * - * Written by Solar Designer in 1998-2002 and - * placed in the public domain. Quick self-test added in 2011 and also - * placed in the public domain. + * Written by Solar Designer in 1998-2014. + * No copyright is claimed, and the software is hereby placed in the public + * domain. In case this attempt to disclaim copyright and place the software + * in the public domain is deemed null and void, then the software is + * Copyright (c) 1998-2014 Solar Designer and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. * - * There's absolutely no warranty. + * There's ABSOLUTELY NO WARRANTY, express or implied. * * It is my intent that you should be able to use this on your system, - * as a part of a software package, or anywhere else to improve security, + * as part of a software package, or anywhere else to improve security, * ensure compatibility, or for any other purpose. I would appreciate * it if you give credit where it is due and keep your modifications in * the public domain as well, but I don't require that in order to let * you place this code and any modifications you make under a license * of your choice. * - * This implementation is compatible with OpenBSD bcrypt.c (version 2a) - * by Niels Provos , and uses some of his - * ideas. The password hashing algorithm was designed by David Mazieres - * . + * This implementation is fully compatible with OpenBSD's bcrypt.c for prefix + * "$2b$", originally by Niels Provos , and it uses + * some of his ideas. The password hashing algorithm was designed by David + * Mazieres . For information on the level of + * compatibility for bcrypt hash prefixes other than "$2b$", please refer to + * the comments in BF_set_key() below and to the included crypt(3) man page. * * There's a paper on the algorithm that explains its design decisions: * @@ -38,21 +50,13 @@ #define __set_errno(val) errno = (val) #endif -#undef __CONST -#ifdef __GNUC__ -#define __CONST __const -#else -#define __CONST -#endif +/* Just to make sure the prototypes match the actual definitions */ +#include "crypt_blowfish.h" -/* - * Please keep this enabled. We really don't want incompatible hashes to be - * produced. The performance cost of this quick self-test is around 0.6% at - * the "$2a$08" setting. - */ -#define BF_SELF_TEST - -#if defined(__x86_64__) || defined(__alpha__) || defined(__hppa__) +#ifdef __i386__ +#define BF_ASM 1 +#define BF_SCALE 1 +#elif defined(__x86_64__) || defined(__alpha__) || defined(__hppa__) #define BF_ASM 0 #define BF_SCALE 1 #else @@ -369,14 +373,6 @@ static unsigned char BF_atoi64[0x60] = { 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 64, 64, 64, 64, 64 }; -/* - * This may be optimized out if built with function inlining and no BF_ASM. - */ -static void clean(void *data, int size) -{ - memset(data, 0, size); -} - #define BF_safe_atoi64(dst, src) \ { \ tmp = (unsigned char)(src); \ @@ -386,11 +382,11 @@ static void clean(void *data, int size) (dst) = tmp; \ } -static int BF_decode(BF_word *dst, __CONST char *src, int size) +static int BF_decode(BF_word *dst, const char *src, int size) { unsigned char *dptr = (unsigned char *)dst; unsigned char *end = dptr + size; - unsigned char *sptr = (unsigned char *)src; + const unsigned char *sptr = (const unsigned char *)src; unsigned int tmp, c1, c2, c3, c4; do { @@ -410,10 +406,10 @@ static int BF_decode(BF_word *dst, __CONST char *src, int size) return 0; } -static void BF_encode(char *dst, __CONST BF_word *src, int size) +static void BF_encode(char *dst, const BF_word *src, int size) { - unsigned char *sptr = (unsigned char *)src; - unsigned char *end = sptr + 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; @@ -521,6 +517,10 @@ static void BF_swap(BF_word *x, int count) R = L; \ L = tmp4 ^ data.ctx.P[BF_N + 1]; +#if BF_ASM +#define BF_body() \ + _BF_body_r(&data.ctx); +#else #define BF_body() \ L = R = 0; \ ptr = data.ctx.P; \ @@ -538,35 +538,121 @@ static void BF_swap(BF_word *x, int count) *(ptr - 2) = L; \ *(ptr - 1) = R; \ } while (ptr < &data.ctx.S[3][0xFF]); +#endif -static void BF_set_key(__CONST char *key, BF_key expanded, BF_key initial, - int sign_extension_bug) +static void BF_set_key(const char *key, BF_key expanded, BF_key initial, + unsigned char flags) { - __CONST char *ptr = key; - int i, j; - BF_word tmp; + const char *ptr = key; + unsigned int bug, i, j; + BF_word safety, sign, diff, tmp[2]; + +/* + * There was a sign extension bug in older revisions of this function. While + * we would have liked to simply fix the bug and move on, we have to provide + * a backwards compatibility feature (essentially the bug) for some systems and + * a safety measure for some others. The latter is needed because for certain + * multiple inputs to the buggy algorithm there exist easily found inputs to + * the correct algorithm that produce the same hash. Thus, we optionally + * deviate from the correct algorithm just enough to avoid such collisions. + * While the bug itself affected the majority of passwords containing + * characters with the 8th bit set (although only a percentage of those in a + * collision-producing way), the anti-collision safety measure affects + * only a subset of passwords containing the '\xff' character (not even all of + * those passwords, just some of them). This character is not found in valid + * UTF-8 sequences and is rarely used in popular 8-bit character encodings. + * Thus, the safety measure is unlikely to cause much annoyance, and is a + * reasonable tradeoff to use when authenticating against existing hashes that + * are not reliably known to have been computed with the correct algorithm. + * + * We use an approach that tries to minimize side-channel leaks of password + * information - that is, we mostly use fixed-cost bitwise operations instead + * of branches or table lookups. (One conditional branch based on password + * length remains. It is not part of the bug aftermath, though, and is + * difficult and possibly unreasonable to avoid given the use of C strings by + * the caller, which results in similar timing leaks anyway.) + * + * For actual implementation, we set an array index in the variable "bug" + * (0 means no bug, 1 means sign extension bug emulation) and a flag in the + * variable "safety" (bit 16 is set when the safety measure is requested). + * Valid combinations of settings are: + * + * Prefix "$2a$": bug = 0, safety = 0x10000 + * Prefix "$2b$": bug = 0, safety = 0 + * Prefix "$2x$": bug = 1, safety = 0 + * Prefix "$2y$": bug = 0, safety = 0 + */ + bug = (unsigned int)flags & 1; + safety = ((BF_word)flags & 2) << 15; + + sign = diff = 0; for (i = 0; i < BF_N + 2; i++) { - tmp = 0; + tmp[0] = tmp[1] = 0; for (j = 0; j < 4; j++) { - tmp <<= 8; - if (sign_extension_bug) - tmp |= (BF_word_signed)(signed char)*ptr; + tmp[0] <<= 8; + tmp[0] |= (unsigned char)*ptr; /* correct */ + tmp[1] <<= 8; + tmp[1] |= (BF_word_signed)(signed char)*ptr; /* bug */ +/* + * Sign extension in the first char has no effect - nothing to overwrite yet, + * and those extra 24 bits will be fully shifted out of the 32-bit word. For + * chars 2, 3, 4 in each four-char block, we set bit 7 of "sign" if sign + * extension in tmp[1] occurs. Once this flag is set, it remains set. + */ + if (j) + sign |= tmp[1] & 0x80; + if (!*ptr) + ptr = key; else - tmp |= (unsigned char)*ptr; - - if (!*ptr) ptr = key; else ptr++; + ptr++; } + diff |= tmp[0] ^ tmp[1]; /* Non-zero on any differences */ - expanded[i] = tmp; - initial[i] = BF_init_state.P[i] ^ tmp; + expanded[i] = tmp[bug]; + initial[i] = BF_init_state.P[i] ^ tmp[bug]; } + +/* + * At this point, "diff" is zero iff the correct and buggy algorithms produced + * exactly the same result. If so and if "sign" is non-zero, which indicates + * that there was a non-benign sign extension, this means that we have a + * collision between the correctly computed hash for this password and a set of + * passwords that could be supplied to the buggy algorithm. Our safety measure + * is meant to protect from such many-buggy to one-correct collisions, by + * deviating from the correct algorithm in such cases. Let's check for this. + */ + diff |= diff >> 16; /* still zero iff exact match */ + diff &= 0xffff; /* ditto */ + diff += 0xffff; /* bit 16 set iff "diff" was non-zero (on non-match) */ + sign <<= 9; /* move the non-benign sign extension flag to bit 16 */ + sign &= ~diff & safety; /* action needed? */ + +/* + * If we have determined that we need to deviate from the correct algorithm, + * flip bit 16 in initial expanded key. (The choice of 16 is arbitrary, but + * let's stick to it now. It came out of the approach we used above, and it's + * not any worse than any other choice we could make.) + * + * It is crucial that we don't do the same to the expanded key used in the main + * Eksblowfish loop. By doing it to only one of these two, we deviate from a + * state that could be directly specified by a password to the buggy algorithm + * (and to the fully correct one as well, but that's a side-effect). + */ + initial[0] ^= sign; } -static char *BF_crypt(__CONST char *key, __CONST char *setting, +static const unsigned char flags_by_subtype[26] = + {2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0}; + +static char *BF_crypt(const char *key, const char *setting, char *output, int size, BF_word min) { +#if BF_ASM + extern void _BF_body_r(BF_ctx *ctx); +#endif struct { BF_ctx ctx; BF_key expanded_key; @@ -588,7 +674,8 @@ static char *BF_crypt(__CONST char *key, __CONST char *setting, if (setting[0] != '$' || setting[1] != '2' || - (setting[2] != 'a' && setting[2] != 'x') || + setting[2] < 'a' || setting[2] > 'z' || + !flags_by_subtype[(unsigned int)(unsigned char)setting[2] - 'a'] || setting[3] != '$' || setting[4] < '0' || setting[4] > '3' || setting[5] < '0' || setting[5] > '9' || @@ -600,13 +687,13 @@ static char *BF_crypt(__CONST char *key, __CONST char *setting, count = (BF_word)1 << ((setting[4] - '0') * 10 + (setting[5] - '0')); if (count < min || BF_decode(data.binary.salt, &setting[7], 16)) { - clean(data.binary.salt, sizeof(data.binary.salt)); __set_errno(EINVAL); return NULL; } BF_swap(data.binary.salt, 4); - BF_set_key(key, data.expanded_key, data.ctx.P, setting[2] == 'x'); + BF_set_key(key, data.expanded_key, data.ctx.P, + flags_by_subtype[(unsigned int)(unsigned char)setting[2] - 'a']); memcpy(data.ctx.S, BF_init_state.S, sizeof(data.ctx.S)); @@ -636,51 +723,33 @@ static char *BF_crypt(__CONST char *key, __CONST char *setting, } while (ptr < &data.ctx.S[3][0xFF]); do { - data.ctx.P[0] ^= data.expanded_key[0]; - data.ctx.P[1] ^= data.expanded_key[1]; - data.ctx.P[2] ^= data.expanded_key[2]; - data.ctx.P[3] ^= data.expanded_key[3]; - data.ctx.P[4] ^= data.expanded_key[4]; - data.ctx.P[5] ^= data.expanded_key[5]; - data.ctx.P[6] ^= data.expanded_key[6]; - data.ctx.P[7] ^= data.expanded_key[7]; - data.ctx.P[8] ^= data.expanded_key[8]; - data.ctx.P[9] ^= data.expanded_key[9]; - data.ctx.P[10] ^= data.expanded_key[10]; - data.ctx.P[11] ^= data.expanded_key[11]; - data.ctx.P[12] ^= data.expanded_key[12]; - data.ctx.P[13] ^= data.expanded_key[13]; - data.ctx.P[14] ^= data.expanded_key[14]; - data.ctx.P[15] ^= data.expanded_key[15]; - data.ctx.P[16] ^= data.expanded_key[16]; - data.ctx.P[17] ^= data.expanded_key[17]; - - BF_body(); - - tmp1 = data.binary.salt[0]; - tmp2 = data.binary.salt[1]; - tmp3 = data.binary.salt[2]; - tmp4 = data.binary.salt[3]; - data.ctx.P[0] ^= tmp1; - data.ctx.P[1] ^= tmp2; - data.ctx.P[2] ^= tmp3; - data.ctx.P[3] ^= tmp4; - data.ctx.P[4] ^= tmp1; - data.ctx.P[5] ^= tmp2; - data.ctx.P[6] ^= tmp3; - data.ctx.P[7] ^= tmp4; - data.ctx.P[8] ^= tmp1; - data.ctx.P[9] ^= tmp2; - data.ctx.P[10] ^= tmp3; - data.ctx.P[11] ^= tmp4; - data.ctx.P[12] ^= tmp1; - data.ctx.P[13] ^= tmp2; - data.ctx.P[14] ^= tmp3; - data.ctx.P[15] ^= tmp4; - data.ctx.P[16] ^= tmp1; - data.ctx.P[17] ^= tmp2; - - BF_body(); + int done; + + for (i = 0; i < BF_N + 2; i += 2) { + data.ctx.P[i] ^= data.expanded_key[i]; + data.ctx.P[i + 1] ^= data.expanded_key[i + 1]; + } + + done = 0; + do { + BF_body(); + if (done) + break; + done = 1; + + tmp1 = data.binary.salt[0]; + tmp2 = data.binary.salt[1]; + tmp3 = data.binary.salt[2]; + tmp4 = data.binary.salt[3]; + for (i = 0; i < BF_N; i += 4) { + data.ctx.P[i] ^= tmp1; + data.ctx.P[i + 1] ^= tmp2; + data.ctx.P[i + 2] ^= tmp3; + data.ctx.P[i + 3] ^= tmp4; + } + data.ctx.P[16] ^= tmp1; + data.ctx.P[17] ^= tmp2; + } while (1); } while (--count); for (i = 0; i < 6; i += 2) { @@ -706,64 +775,116 @@ static char *BF_crypt(__CONST char *key, __CONST char *setting, BF_encode(&output[7 + 22], data.binary.output, 23); output[7 + 22 + 31] = '\0'; -#ifndef BF_SELF_TEST -/* Overwrite the most obvious sensitive data we have on the stack. Note - * that this does not guarantee there's no sensitive data left on the - * stack and/or in registers; I'm not aware of portable code that does. */ - clean(&data, sizeof(data)); -#endif - return output; } -char *_crypt_blowfish_rn(__CONST char *key, __CONST char *setting, +int _crypt_output_magic(const char *setting, char *output, int size) +{ + if (size < 3) + return -1; + + output[0] = '*'; + output[1] = '0'; + output[2] = '\0'; + + if (setting[0] == '*' && setting[1] == '0') + output[1] = '1'; + + return 0; +} + +/* + * Please preserve the runtime self-test. It serves two purposes at once: + * + * 1. We really can't afford the risk of producing incompatible hashes e.g. + * when there's something like gcc bug 26587 again, whereas an application or + * library integrating this code might not also integrate our external tests or + * it might not run them after every build. Even if it does, the miscompile + * might only occur on the production build, but not on a testing build (such + * as because of different optimization settings). It is painful to recover + * from incorrectly-computed hashes - merely fixing whatever broke is not + * enough. Thus, a proactive measure like this self-test is needed. + * + * 2. We don't want to leave sensitive data from our actual password hash + * computation on the stack or in registers. Previous revisions of the code + * would do explicit cleanups, but simply running the self-test after hash + * computation is more reliable. + * + * The performance cost of this quick self-test is around 0.6% at the "$2a$08" + * setting. + */ +char *_crypt_blowfish_rn(const char *key, const char *setting, char *output, int size) { -#ifdef BF_SELF_TEST - __CONST char *test_key = "8b \xd0\xc1\xd2\xcf\xcc\xd8"; - __CONST char *test_2a = - "$2a$00$abcdefghijklmnopqrstuui1D709vfamulimlGcq0qq3UvuUasvEa" - "\0" - "canary"; - __CONST char *test_2x = - "$2x$00$abcdefghijklmnopqrstuuVUrPmXD6q/nVSSp7pNDhCR9071IfIRe" - "\0" - "canary"; - __CONST char *test_hash, *p; - int ok; - char buf[7 + 22 + 31 + 1 + 6 + 1]; - - output = BF_crypt(key, setting, output, size, 16); - -/* Do a quick self-test. This also happens to overwrite BF_crypt()'s data. */ - test_hash = (setting[2] == 'x') ? test_2x : test_2a; - memcpy(buf, test_hash, sizeof(buf)); - memset(buf, -1, sizeof(buf) - (6 + 1)); /* keep "canary" only */ - p = BF_crypt(test_key, test_hash, buf, sizeof(buf) - 6, 1); - - ok = (p == buf && !memcmp(p, test_hash, sizeof(buf))); - -/* This could reveal what hash type we were using last. Unfortunately, we - * can't reliably clean the test_hash pointer. */ - clean(&buf, sizeof(buf)); + const char *test_key = "8b \xd0\xc1\xd2\xcf\xcc\xd8"; + const char *test_setting = "$2a$00$abcdefghijklmnopqrstuu"; + static const char * const test_hashes[2] = + {"i1D709vfamulimlGcq0qq3UvuUasvEa\0\x55", /* 'a', 'b', 'y' */ + "VUrPmXD6q/nVSSp7pNDhCR9071IfIRe\0\x55"}; /* 'x' */ + const char *test_hash = test_hashes[0]; + char *retval; + const char *p; + int save_errno, ok; + struct { + char s[7 + 22 + 1]; + char o[7 + 22 + 31 + 1 + 1 + 1]; + } buf; + +/* Hash the supplied password */ + _crypt_output_magic(setting, output, size); + retval = BF_crypt(key, setting, output, size, 16); + save_errno = errno; + +/* + * Do a quick self-test. It is important that we make both calls to BF_crypt() + * from the same scope such that they likely use the same stack locations, + * which makes the second call overwrite the first call's sensitive data on the + * stack and makes it more likely that any alignment related issues would be + * detected by the self-test. + */ + memcpy(buf.s, test_setting, sizeof(buf.s)); + if (retval) { + unsigned int flags = flags_by_subtype[ + (unsigned int)(unsigned char)setting[2] - 'a']; + test_hash = test_hashes[flags & 1]; + buf.s[2] = setting[2]; + } + memset(buf.o, 0x55, sizeof(buf.o)); + buf.o[sizeof(buf.o) - 1] = 0; + p = BF_crypt(test_key, buf.s, buf.o, sizeof(buf.o) - (1 + 1), 1); + + ok = (p == buf.o && + !memcmp(p, buf.s, 7 + 22) && + !memcmp(p + (7 + 22), test_hash, 31 + 1 + 1 + 1)); + + { + const char *k = "\xff\xa3" "34" "\xff\xff\xff\xa3" "345"; + BF_key ae, ai, ye, yi; + BF_set_key(k, ae, ai, 2); /* $2a$ */ + BF_set_key(k, ye, yi, 4); /* $2y$ */ + ai[0] ^= 0x10000; /* undo the safety (for comparison) */ + ok = ok && ai[0] == 0xdb9c59bc && ye[17] == 0x33343500 && + !memcmp(ae, ye, sizeof(ae)) && + !memcmp(ai, yi, sizeof(ai)); + } + __set_errno(save_errno); if (ok) - return output; + return retval; /* Should not happen */ + _crypt_output_magic(setting, output, size); __set_errno(EINVAL); /* pretend we don't support this hash type */ return NULL; -#else -#warning Self-test is disabled, please enable - return BF_crypt(key, setting, output, size, 16); -#endif } -char *_crypt_gensalt_blowfish_rn(unsigned long count, - __CONST char *input, int size, char *output, int output_size) +char *_crypt_gensalt_blowfish_rn(const char *prefix, unsigned long count, + const char *input, int size, char *output, int output_size) { if (size < 16 || output_size < 7 + 22 + 1 || - (count && (count < 4 || count > 31))) { + (count && (count < 4 || count > 31)) || + prefix[0] != '$' || prefix[1] != '2' || + (prefix[2] != 'a' && prefix[2] != 'b' && prefix[2] != 'y')) { if (output_size > 0) output[0] = '\0'; __set_errno((output_size < 7 + 22 + 1) ? ERANGE : EINVAL); return NULL; @@ -773,13 +894,13 @@ char *_crypt_gensalt_blowfish_rn(unsigned long count, output[0] = '$'; output[1] = '2'; - output[2] = 'a'; + output[2] = prefix[2]; output[3] = '$'; output[4] = '0' + count / 10; output[5] = '0' + count % 10; output[6] = '$'; - BF_encode(&output[7], (BF_word *)input, 16); + BF_encode(&output[7], (const BF_word *)input, 16); output[7 + 22] = '\0'; return output; diff --git a/ext/mri/crypt_blowfish.h b/ext/mri/crypt_blowfish.h new file mode 100644 index 0000000..2ee0d8c --- /dev/null +++ b/ext/mri/crypt_blowfish.h @@ -0,0 +1,27 @@ +/* + * Written by Solar Designer in 2000-2011. + * No copyright is claimed, and the software is hereby placed in the public + * domain. In case this attempt to disclaim copyright and place the software + * in the public domain is deemed null and void, then the software is + * Copyright (c) 2000-2011 Solar Designer and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * See crypt_blowfish.c for more information. + */ + +#ifndef _CRYPT_BLOWFISH_H +#define _CRYPT_BLOWFISH_H + +extern int _crypt_output_magic(const char *setting, char *output, int size); +extern char *_crypt_blowfish_rn(const char *key, const char *setting, + char *output, int size); +extern char *_crypt_gensalt_blowfish_rn(const char *prefix, + unsigned long count, + const char *input, int size, char *output, int output_size); + +#endif diff --git a/ext/mri/crypt_gensalt.c b/ext/mri/crypt_gensalt.c index dce9f63..73c15a1 100644 --- a/ext/mri/crypt_gensalt.c +++ b/ext/mri/crypt_gensalt.c @@ -1,5 +1,16 @@ /* - * Written by Solar Designer and placed in the public domain. + * Written by Solar Designer in 2000-2011. + * No copyright is claimed, and the software is hereby placed in the public + * domain. In case this attempt to disclaim copyright and place the software + * in the public domain is deemed null and void, then the software is + * Copyright (c) 2000-2011 Solar Designer and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * * See crypt_blowfish.c for more information. * * This file contains salt generation functions for the traditional and @@ -14,19 +25,17 @@ #define __set_errno(val) errno = (val) #endif -#undef __CONST -#ifdef __GNUC__ -#define __CONST __const -#else -#define __CONST -#endif +/* Just to make sure the prototypes match the actual definitions */ +#include "crypt_gensalt.h" unsigned char _crypt_itoa64[64 + 1] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; -char *_crypt_gensalt_traditional_rn(unsigned long count, - __CONST char *input, int size, char *output, int output_size) +char *_crypt_gensalt_traditional_rn(const char *prefix, unsigned long count, + const char *input, int size, char *output, int output_size) { + (void) prefix; + if (size < 2 || output_size < 2 + 1 || (count && count != 25)) { if (output_size > 0) output[0] = '\0'; __set_errno((output_size < 2 + 1) ? ERANGE : EINVAL); @@ -40,11 +49,13 @@ char *_crypt_gensalt_traditional_rn(unsigned long count, return output; } -char *_crypt_gensalt_extended_rn(unsigned long count, - __CONST char *input, int size, char *output, int output_size) +char *_crypt_gensalt_extended_rn(const char *prefix, unsigned long count, + const char *input, int size, char *output, int output_size) { unsigned long value; + (void) prefix; + /* Even iteration counts make it easier to detect weak DES keys from a look * at the hash, so they should be avoided */ if (size < 3 || output_size < 1 + 4 + 4 + 1 || @@ -73,11 +84,13 @@ char *_crypt_gensalt_extended_rn(unsigned long count, return output; } -char *_crypt_gensalt_md5_rn(unsigned long count, - __CONST char *input, int size, char *output, int output_size) +char *_crypt_gensalt_md5_rn(const char *prefix, unsigned long count, + const char *input, int size, char *output, int output_size) { unsigned long value; + (void) prefix; + if (size < 3 || output_size < 3 + 4 + 1 || (count && count != 1000)) { if (output_size > 0) output[0] = '\0'; __set_errno((output_size < 3 + 4 + 1) ? ERANGE : EINVAL); diff --git a/ext/mri/crypt_gensalt.h b/ext/mri/crypt_gensalt.h new file mode 100644 index 0000000..457bbfe --- /dev/null +++ b/ext/mri/crypt_gensalt.h @@ -0,0 +1,30 @@ +/* + * Written by Solar Designer in 2000-2011. + * No copyright is claimed, and the software is hereby placed in the public + * domain. In case this attempt to disclaim copyright and place the software + * in the public domain is deemed null and void, then the software is + * Copyright (c) 2000-2011 Solar Designer and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * See crypt_blowfish.c for more information. + */ + +#ifndef _CRYPT_GENSALT_H +#define _CRYPT_GENSALT_H + +extern 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); +extern char *_crypt_gensalt_extended_rn(const char *prefix, + unsigned long count, + const char *input, int size, char *output, int output_size); +extern char *_crypt_gensalt_md5_rn(const char *prefix, unsigned long count, + const char *input, int size, char *output, int output_size); + +#endif diff --git a/ext/mri/ow-crypt.h b/ext/mri/ow-crypt.h index 8dca108..2e48794 100644 --- a/ext/mri/ow-crypt.h +++ b/ext/mri/ow-crypt.h @@ -1,35 +1,43 @@ /* - * Written by Solar Designer and placed in the public domain. + * Written by Solar Designer in 2000-2011. + * No copyright is claimed, and the software is hereby placed in the public + * domain. In case this attempt to disclaim copyright and place the software + * in the public domain is deemed null and void, then the software is + * Copyright (c) 2000-2011 Solar Designer and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * * See crypt_blowfish.c for more information. */ #ifndef _OW_CRYPT_H #define _OW_CRYPT_H -#undef __CONST -#if defined __GNUC__ -#define __CONST __const -#elif defined _MSC_VER -#define __CONST const -#else +#ifndef __GNUC__ +#undef __const +#define __const const #endif #ifndef __SKIP_GNU -extern char *crypt(__CONST char *key, __CONST char *setting); -extern char *crypt_r(__CONST char *key, __CONST char *setting, void *data); +extern char *crypt(__const char *key, __const char *setting); +extern char *crypt_r(__const char *key, __const char *setting, void *data); #endif #ifndef __SKIP_OW -extern char *crypt_rn(__CONST char *key, __CONST char *setting, +extern char *crypt_rn(__const char *key, __const char *setting, void *data, int size); -extern char *crypt_ra(__CONST char *key, __CONST char *setting, +extern char *crypt_ra(__const char *key, __const char *setting, void **data, int *size); -extern char *crypt_gensalt(__CONST char *prefix, unsigned long count, - __CONST char *input, int size); -extern char *crypt_gensalt_rn(__CONST char *prefix, unsigned long count, - __CONST char *input, int size, char *output, int output_size); -extern char *crypt_gensalt_ra(__CONST char *prefix, unsigned long count, - __CONST char *input, int size); +extern char *crypt_gensalt(__const char *prefix, unsigned long count, + __const char *input, int size); +extern char *crypt_gensalt_rn(__const char *prefix, unsigned long count, + __const char *input, int size, char *output, int output_size); +extern char *crypt_gensalt_ra(__const char *prefix, unsigned long count, + __const char *input, int size); #endif #endif diff --git a/ext/mri/wrapper.c b/ext/mri/wrapper.c index fe832db..1e49c90 100644 --- a/ext/mri/wrapper.c +++ b/ext/mri/wrapper.c @@ -1,5 +1,16 @@ /* - * Written by Solar Designer and placed in the public domain. + * Written by Solar Designer in 2000-2014. + * No copyright is claimed, and the software is hereby placed in the public + * domain. In case this attempt to disclaim copyright and place the software + * in the public domain is deemed null and void, then the software is + * Copyright (c) 2000-2014 Solar Designer and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * * See crypt_blowfish.c for more information. */ @@ -23,13 +34,6 @@ #endif #endif -#include -#ifdef HAVE_RUBY_UTIL_H -#include -#else -#include -#endif - #define CRYPT_OUTPUT_SIZE (7 + 22 + 31 + 1) #define CRYPT_GENSALT_OUTPUT_SIZE (7 + 22 + 1) @@ -38,18 +42,8 @@ #endif #include "ow-crypt.h" -extern char *_crypt_blowfish_rn(__CONST char *key, __CONST char *setting, - char *output, int size); -extern char *_crypt_gensalt_blowfish_rn(unsigned long count, - __CONST char *input, int size, char *output, int output_size); - -extern unsigned char _crypt_itoa64[]; -extern char *_crypt_gensalt_traditional_rn(unsigned long count, - __CONST char *input, int size, char *output, int output_size); -extern char *_crypt_gensalt_extended_rn(unsigned long count, - __CONST char *input, int size, char *output, int output_size); -extern char *_crypt_gensalt_md5_rn(unsigned long count, - __CONST char *input, int size, char *output, int output_size); +#include "crypt_blowfish.h" +#include "crypt_gensalt.h" #if defined(__GLIBC__) && defined(_LIBC) /* crypt.h from glibc-crypt-2.1 will define struct crypt_data for us */ @@ -90,17 +84,14 @@ static int _crypt_data_alloc(void **data, int *size, int need) return 0; } -static char *_crypt_retval_magic(char *retval, __CONST char *setting, - char *output) +static char *_crypt_retval_magic(char *retval, const char *setting, + char *output, int size) { - if (retval) return retval; + if (retval) + return retval; - output[0] = '*'; - output[1] = '0'; - output[2] = '\0'; - - if (setting[0] == '*' && setting[1] == '0') - output[1] = '1'; + if (_crypt_output_magic(setting, output, size)) + return NULL; /* shouldn't happen */ return output; } @@ -162,22 +153,22 @@ char *__crypt_r(__const char *key, __const char *setting, { return _crypt_retval_magic( __crypt_rn(key, setting, data, sizeof(*data)), - setting, (char *)data); + setting, (char *)data, sizeof(*data)); } char *__crypt(__const char *key, __const char *setting) { return _crypt_retval_magic( __crypt_rn(key, setting, &_ufc_foobar, sizeof(_ufc_foobar)), - setting, (char *)&_ufc_foobar); + setting, (char *)&_ufc_foobar, sizeof(_ufc_foobar)); } #else -char *crypt_rn(__CONST char *key, __CONST char *setting, void *data, int size) +char *crypt_rn(const char *key, const char *setting, void *data, int size) { return _crypt_blowfish_rn(key, setting, (char *)data, size); } -char *crypt_ra(__CONST char *key, __CONST char *setting, +char *crypt_ra(const char *key, const char *setting, void **data, int *size) { if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE)) @@ -185,11 +176,20 @@ 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, void *data) { return _crypt_retval_magic( crypt_rn(key, setting, data, CRYPT_OUTPUT_SIZE), - setting, (char *)data); + setting, (char *)data, CRYPT_OUTPUT_SIZE); +} + +char *crypt(const char *key, const char *setting) +{ + static char output[CRYPT_OUTPUT_SIZE]; + + return _crypt_retval_magic( + crypt_rn(key, setting, output, sizeof(output)), + setting, output, sizeof(output)); } #define __crypt_gensalt_rn crypt_gensalt_rn @@ -197,11 +197,12 @@ char *crypt_r(__CONST char *key, __CONST char *setting, void *data) #define __crypt_gensalt crypt_gensalt #endif -char *__crypt_gensalt_rn(__CONST char *prefix, unsigned long count, - __CONST char *input, int size, char *output, int output_size) +char *__crypt_gensalt_rn(const char *prefix, unsigned long count, + const char *input, int size, char *output, int output_size) { - char *(*use)(unsigned long count, - __CONST char *input, int size, char *output, int output_size); + char *(*use)(const char *_prefix, unsigned long _count, + const char *_input, int _size, + char *_output, int _output_size); /* This may be supported on some platforms in the future */ if (!input) { @@ -209,7 +210,8 @@ char *__crypt_gensalt_rn(__CONST char *prefix, unsigned long count, return NULL; } - if (!strncmp(prefix, "$2a$", 4)) + if (!strncmp(prefix, "$2a$", 4) || !strncmp(prefix, "$2b$", 4) || + !strncmp(prefix, "$2y$", 4)) use = _crypt_gensalt_blowfish_rn; else if (!strncmp(prefix, "$1$", 3)) @@ -228,11 +230,11 @@ char *__crypt_gensalt_rn(__CONST char *prefix, unsigned long count, return NULL; } - return use(count, input, size, output, output_size); + return use(prefix, count, input, size, output, output_size); } -char *__crypt_gensalt_ra(__CONST char *prefix, unsigned long count, - __CONST char *input, int size) +char *__crypt_gensalt_ra(const char *prefix, unsigned long count, + const char *input, int size) { char output[CRYPT_GENSALT_OUTPUT_SIZE]; char *retval; @@ -241,7 +243,7 @@ char *__crypt_gensalt_ra(__CONST char *prefix, unsigned long count, input, size, output, sizeof(output)); if (retval) { - retval = ruby_strdup(retval); + retval = strdup(retval); #ifndef __GLIBC__ /* strdup(3) on glibc sets errno, so we don't need to bother */ if (!retval) @@ -252,11 +254,298 @@ char *__crypt_gensalt_ra(__CONST char *prefix, unsigned long count, return retval; } -char *__crypt_gensalt(__CONST char *prefix, unsigned long count, - __CONST char *input, int size) +char *__crypt_gensalt(const char *prefix, unsigned long count, + const char *input, int size) { static char output[CRYPT_GENSALT_OUTPUT_SIZE]; return __crypt_gensalt_rn(prefix, count, input, size, output, sizeof(output)); } + +#if defined(__GLIBC__) && defined(_LIBC) +weak_alias(__crypt_rn, crypt_rn) +weak_alias(__crypt_ra, crypt_ra) +weak_alias(__crypt_r, crypt_r) +weak_alias(__crypt, crypt) +weak_alias(__crypt_gensalt_rn, crypt_gensalt_rn) +weak_alias(__crypt_gensalt_ra, crypt_gensalt_ra) +weak_alias(__crypt_gensalt, crypt_gensalt) +weak_alias(crypt, fcrypt) +#endif + +#ifdef TEST +static const char *tests[][3] = { + {"$2a$05$CCCCCCCCCCCCCCCCCCCCC.E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW", + "U*U"}, + {"$2a$05$CCCCCCCCCCCCCCCCCCCCC.VGOzA784oUp/Z0DY336zx7pLYAy0lwK", + "U*U*"}, + {"$2a$05$XXXXXXXXXXXXXXXXXXXXXOAcXxm9kjPGEMsLznoKqmqw7tc8WCx4a", + "U*U*U"}, + {"$2a$05$abcdefghijklmnopqrstuu5s2v8.iXieOjg/.AySBTTZIIVFJeBui", + "0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + "chars after 72 are ignored"}, + {"$2x$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e", + "\xa3"}, + {"$2x$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e", + "\xff\xff\xa3"}, + {"$2y$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e", + "\xff\xff\xa3"}, + {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.nqd1wy.pTMdcvrRWxyiGL2eMz.2a85.", + "\xff\xff\xa3"}, + {"$2b$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e", + "\xff\xff\xa3"}, + {"$2y$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq", + "\xa3"}, + {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq", + "\xa3"}, + {"$2b$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq", + "\xa3"}, + {"$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi", + "1\xa3" "345"}, + {"$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi", + "\xff\xa3" "345"}, + {"$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi", + "\xff\xa3" "34" "\xff\xff\xff\xa3" "345"}, + {"$2y$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi", + "\xff\xa3" "34" "\xff\xff\xff\xa3" "345"}, + {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.ZC1JEJ8Z4gPfpe1JOr/oyPXTWl9EFd.", + "\xff\xa3" "34" "\xff\xff\xff\xa3" "345"}, + {"$2y$05$/OK.fbVrR/bpIqNJ5ianF.nRht2l/HRhr6zmCp9vYUvvsqynflf9e", + "\xff\xa3" "345"}, + {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.nRht2l/HRhr6zmCp9vYUvvsqynflf9e", + "\xff\xa3" "345"}, + {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS", + "\xa3" "ab"}, + {"$2x$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS", + "\xa3" "ab"}, + {"$2y$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS", + "\xa3" "ab"}, + {"$2x$05$6bNw2HLQYeqHYyBfLMsv/OiwqTymGIGzFsA4hOTWebfehXHNprcAS", + "\xd1\x91"}, + {"$2x$05$6bNw2HLQYeqHYyBfLMsv/O9LIGgn8OMzuDoHfof8AQimSGfcSWxnS", + "\xd0\xc1\xd2\xcf\xcc\xd8"}, + {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.swQOIzjOiJ9GHEPuhEkvqrUyvWhEMx6", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "chars after 72 are ignored as usual"}, + {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.R9xrDjiycxMbQE2bp.vgqlYpW5wx2yy", + "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55" + "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55" + "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55" + "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55" + "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55" + "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"}, + {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.9tQZzcJfm3uj2NvJ/n5xkhpqLrMpWCe", + "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff" + "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff" + "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff" + "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff" + "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff" + "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"}, + {"$2a$05$CCCCCCCCCCCCCCCCCCCCC.7uG0VCzI2bS7j6ymqJi9CdcdxiRTWNy", + ""}, + {"*0", "", "$2a$03$CCCCCCCCCCCCCCCCCCCCC."}, + {"*0", "", "$2a$32$CCCCCCCCCCCCCCCCCCCCC."}, + {"*0", "", "$2c$05$CCCCCCCCCCCCCCCCCCCCC."}, + {"*0", "", "$2z$05$CCCCCCCCCCCCCCCCCCCCC."}, + {"*0", "", "$2`$05$CCCCCCCCCCCCCCCCCCCCC."}, + {"*0", "", "$2{$05$CCCCCCCCCCCCCCCCCCCCC."}, + {"*1", "", "*0"}, + {NULL} +}; + +#define which tests[0] + +static volatile sig_atomic_t running; + +static void handle_timer(int signum) +{ + (void) signum; + running = 0; +} + +static void *run(void *arg) +{ + unsigned long count = 0; + int i = 0; + void *data = NULL; + int size = 0x12345678; + + do { + const char *hash = tests[i][0]; + const char *key = tests[i][1]; + const char *setting = tests[i][2]; + + if (!tests[++i][0]) + i = 0; + + if (setting && strlen(hash) < 30) /* not for benchmark */ + continue; + + if (strcmp(crypt_ra(key, hash, &data, &size), hash)) { + printf("%d: FAILED (crypt_ra/%d/%lu)\n", + (int)((char *)arg - (char *)0), i, count); + free(data); + return NULL; + } + count++; + } while (running); + + free(data); + return count + (char *)0; +} + +int main(void) +{ + struct itimerval it; + struct tms buf; + clock_t clk_tck, start_real, start_virtual, end_real, end_virtual; + unsigned long count; + void *data; + int size; + char *setting1, *setting2; + int i; +#ifdef TEST_THREADS + pthread_t t[TEST_THREADS]; + void *t_retval; +#endif + + data = NULL; + size = 0x12345678; + + for (i = 0; tests[i][0]; i++) { + const char *hash = tests[i][0]; + const char *key = tests[i][1]; + const char *setting = tests[i][2]; + const char *p; + int ok = !setting || strlen(hash) >= 30; + int o_size; + char s_buf[30], o_buf[61]; + if (!setting) { + memcpy(s_buf, hash, sizeof(s_buf) - 1); + s_buf[sizeof(s_buf) - 1] = 0; + setting = s_buf; + } + + __set_errno(0); + p = crypt(key, setting); + if ((!ok && !errno) || strcmp(p, hash)) { + printf("FAILED (crypt/%d)\n", i); + return 1; + } + + if (ok && strcmp(crypt(key, hash), hash)) { + printf("FAILED (crypt/%d)\n", i); + return 1; + } + + for (o_size = -1; o_size <= (int)sizeof(o_buf); o_size++) { + int ok_n = ok && o_size == (int)sizeof(o_buf); + const char *x = "abc"; + strcpy(o_buf, x); + if (o_size >= 3) { + x = "*0"; + if (setting[0] == '*' && setting[1] == '0') + x = "*1"; + } + __set_errno(0); + p = crypt_rn(key, setting, o_buf, o_size); + if ((ok_n && (!p || strcmp(p, hash))) || + (!ok_n && (!errno || p || strcmp(o_buf, x)))) { + printf("FAILED (crypt_rn/%d)\n", i); + return 1; + } + } + + __set_errno(0); + p = crypt_ra(key, setting, &data, &size); + if ((ok && (!p || strcmp(p, hash))) || + (!ok && (!errno || p || strcmp((char *)data, hash)))) { + printf("FAILED (crypt_ra/%d)\n", i); + return 1; + } + } + + setting1 = crypt_gensalt(which[0], 12, data, size); + if (!setting1 || strncmp(setting1, "$2a$12$", 7)) { + puts("FAILED (crypt_gensalt)\n"); + return 1; + } + + setting2 = crypt_gensalt_ra(setting1, 12, data, size); + if (strcmp(setting1, setting2)) { + puts("FAILED (crypt_gensalt_ra/1)\n"); + return 1; + } + + (*(char *)data)++; + setting1 = crypt_gensalt_ra(setting2, 12, data, size); + if (!strcmp(setting1, setting2)) { + puts("FAILED (crypt_gensalt_ra/2)\n"); + return 1; + } + + free(setting1); + free(setting2); + free(data); + +#if defined(_SC_CLK_TCK) || !defined(CLK_TCK) + clk_tck = sysconf(_SC_CLK_TCK); +#else + clk_tck = CLK_TCK; +#endif + + running = 1; + signal(SIGALRM, handle_timer); + + memset(&it, 0, sizeof(it)); + it.it_value.tv_sec = 5; + setitimer(ITIMER_REAL, &it, NULL); + + start_real = times(&buf); + start_virtual = buf.tms_utime + buf.tms_stime; + + count = (char *)run((char *)0) - (char *)0; + + end_real = times(&buf); + end_virtual = buf.tms_utime + buf.tms_stime; + if (end_virtual == start_virtual) end_virtual++; + + printf("%.1f c/s real, %.1f c/s virtual\n", + (float)count * clk_tck / (end_real - start_real), + (float)count * clk_tck / (end_virtual - start_virtual)); + +#ifdef TEST_THREADS + running = 1; + it.it_value.tv_sec = 60; + setitimer(ITIMER_REAL, &it, NULL); + start_real = times(&buf); + + for (i = 0; i < TEST_THREADS; i++) + if (pthread_create(&t[i], NULL, run, i + (char *)0)) { + perror("pthread_create"); + return 1; + } + + for (i = 0; i < TEST_THREADS; i++) { + if (pthread_join(t[i], &t_retval)) { + perror("pthread_join"); + continue; + } + if (!t_retval) continue; + count = (char *)t_retval - (char *)0; + end_real = times(&buf); + printf("%d: %.1f c/s real\n", i, + (float)count * clk_tck / (end_real - start_real)); + } +#endif + + return 0; +} +#endif diff --git a/lib/bcrypt/engine.rb b/lib/bcrypt/engine.rb index abde3dd..b521a82 100644 --- a/lib/bcrypt/engine.rb +++ b/lib/bcrypt/engine.rb @@ -46,7 +46,7 @@ def self.hash_secret(secret, salt, _ = nil) if valid_secret?(secret) if valid_salt?(salt) if RUBY_PLATFORM == "java" - Java.bcrypt_jruby.BCrypt.hashpw(secret.to_s, salt.to_s) + Java.bcrypt_jruby.BCrypt.hashpw(secret.to_s.to_java_bytes, salt.to_s) else __bc_crypt(secret.to_s, salt) end diff --git a/spec/bcrypt/engine_spec.rb b/spec/bcrypt/engine_spec.rb index 11ec907..d99044f 100644 --- a/spec/bcrypt/engine_spec.rb +++ b/spec/bcrypt/engine_spec.rb @@ -73,7 +73,31 @@ class MyInvalidSecret ["U*U*", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.VGOzA784oUp/Z0DY336zx7pLYAy0lwK"], ["U*U*U", "$2a$05$XXXXXXXXXXXXXXXXXXXXXO", "$2a$05$XXXXXXXXXXXXXXXXXXXXXOAcXxm9kjPGEMsLznoKqmqw7tc8WCx4a"], ["", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.7uG0VCzI2bS7j6ymqJi9CdcdxiRTWNy"], - ["0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", "$2a$05$abcdefghijklmnopqrstuu", "$2a$05$abcdefghijklmnopqrstuu5s2v8.iXieOjg/.AySBTTZIIVFJeBui"] + ["0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", "$2a$05$abcdefghijklmnopqrstuu", "$2a$05$abcdefghijklmnopqrstuu5s2v8.iXieOjg/.AySBTTZIIVFJeBui"], + ["\xa3", "$2x$05$/OK.fbVrR/bpIqNJ5ianF.", "$2x$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e"], + ["\xff\xff\xa3", "$2x$05$/OK.fbVrR/bpIqNJ5ianF.", "$2x$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e"], + ["\xff\xff\xa3", "$2y$05$/OK.fbVrR/bpIqNJ5ianF.", "$2y$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e"], + ["\xff\xff\xa3", "$2a$05$/OK.fbVrR/bpIqNJ5ianF.", "$2a$05$/OK.fbVrR/bpIqNJ5ianF.nqd1wy.pTMdcvrRWxyiGL2eMz.2a85."], + ["\xff\xff\xa3", "$2b$05$/OK.fbVrR/bpIqNJ5ianF.", "$2b$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e"], + ["\xa3", "$2y$05$/OK.fbVrR/bpIqNJ5ianF.", "$2y$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq"], + ["\xa3", "$2a$05$/OK.fbVrR/bpIqNJ5ianF.", "$2a$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq"], + ["\xa3", "$2b$05$/OK.fbVrR/bpIqNJ5ianF.", "$2b$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq"], + ["1\xa3" "345", "$2x$05$/OK.fbVrR/bpIqNJ5ianF.", "$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi"], + ["\xff\xa3" "345", "$2x$05$/OK.fbVrR/bpIqNJ5ianF.", "$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi"], + ["\xff\xa3" "34" "\xff\xff\xff\xa3" "345", "$2x$05$/OK.fbVrR/bpIqNJ5ianF.", "$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi"], + ["\xff\xa3" "34" "\xff\xff\xff\xa3" "345", "$2y$05$/OK.fbVrR/bpIqNJ5ianF.", "$2y$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi"], + ["\xff\xa3" "34" "\xff\xff\xff\xa3" "345", "$2a$05$/OK.fbVrR/bpIqNJ5ianF.", "$2a$05$/OK.fbVrR/bpIqNJ5ianF.ZC1JEJ8Z4gPfpe1JOr/oyPXTWl9EFd."], + ["\xff\xa3" "345", "$2y$05$/OK.fbVrR/bpIqNJ5ianF.", "$2y$05$/OK.fbVrR/bpIqNJ5ianF.nRht2l/HRhr6zmCp9vYUvvsqynflf9e"], + ["\xff\xa3" "345", "$2a$05$/OK.fbVrR/bpIqNJ5ianF.", "$2a$05$/OK.fbVrR/bpIqNJ5ianF.nRht2l/HRhr6zmCp9vYUvvsqynflf9e"], + ["\xa3" "ab", "$2a$05$/OK.fbVrR/bpIqNJ5ianF.", "$2a$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS"], + ["\xa3" "ab", "$2x$05$/OK.fbVrR/bpIqNJ5ianF.", "$2x$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS"], + ["\xa3" "ab", "$2y$05$/OK.fbVrR/bpIqNJ5ianF.", "$2y$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS"], + ["\xd1\x91", "$2x$05$6bNw2HLQYeqHYyBfLMsv/O", "$2x$05$6bNw2HLQYeqHYyBfLMsv/OiwqTymGIGzFsA4hOTWebfehXHNprcAS"], + ["\xd0\xc1\xd2\xcf\xcc\xd8", "$2x$05$6bNw2HLQYeqHYyBfLMsv/O", "$2x$05$6bNw2HLQYeqHYyBfLMsv/O9LIGgn8OMzuDoHfof8AQimSGfcSWxnS"], + ["\xaa"*72+"chars after 72 are ignored as usual", "$2a$05$/OK.fbVrR/bpIqNJ5ianF.", "$2a$05$/OK.fbVrR/bpIqNJ5ianF.swQOIzjOiJ9GHEPuhEkvqrUyvWhEMx6"], + ["\xaa\x55"*36, "$2a$05$/OK.fbVrR/bpIqNJ5ianF.", "$2a$05$/OK.fbVrR/bpIqNJ5ianF.R9xrDjiycxMbQE2bp.vgqlYpW5wx2yy"], + ["\x55\xaa\xff"*24, "$2a$05$/OK.fbVrR/bpIqNJ5ianF.", "$2a$05$/OK.fbVrR/bpIqNJ5ianF.9tQZzcJfm3uj2NvJ/n5xkhpqLrMpWCe"], + ["", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.7uG0VCzI2bS7j6ymqJi9CdcdxiRTWNy"] ] for secret, salt, test_vector in test_vectors expect(BCrypt::Engine.hash_secret(secret, salt)).to eql(test_vector) From a0fc53bdf7c973d841d1a34974deb4812036693b Mon Sep 17 00:00:00 2001 From: Florin Onica Date: Mon, 29 Oct 2018 13:39:13 +0200 Subject: [PATCH 015/126] don't install docs during travis CI builds --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index b572547..22f7c67 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,6 @@ language: ruby before_install: + - "echo 'gem: --no-rdoc --no-ri' > ~/.gemrc" - gem update --system - gem install bundler rvm: From b47c50c2dfdbd1c00e4dbd56bd39d161f81d16d1 Mon Sep 17 00:00:00 2001 From: "T.J. Schuck" Date: Thu, 8 Nov 2018 18:30:59 -0500 Subject: [PATCH 016/126] Update Travis badge to SVG; add AppVeyor badge --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c2373c8..7628e56 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,9 @@ An easy way to keep your users' passwords secure. * http://github.com/codahale/bcrypt-ruby/tree/master -[![Build Status](https://travis-ci.org/codahale/bcrypt-ruby.png?branch=master)](https://travis-ci.org/codahale/bcrypt-ruby) +[![Travis Build Status](https://travis-ci.org/codahale/bcrypt-ruby.svg?branch=master)](https://travis-ci.org/codahale/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()` From a28449a23fff24f3f28e58f284b24ff4fe635002 Mon Sep 17 00:00:00 2001 From: "T.J. Schuck" Date: Thu, 8 Nov 2018 19:05:01 -0500 Subject: [PATCH 017/126] Changelog entry for #182 --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 89da1bc..e619f78 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -89,3 +89,4 @@ [DRAFT] 4.0.0 MMM DD YYYY - No longer include compiled binaries for Windows. See GH #173. + - Update C and Java implementations to latest versions [GH #182 by @fonica] From ae683139dee8616d36e46166fa780c7a864d6519 Mon Sep 17 00:00:00 2001 From: "T.J. Schuck" Date: Tue, 13 Nov 2018 18:06:02 -0500 Subject: [PATCH 018/126] CHANGELOG entry for #181 --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index e619f78..304f3f3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -90,3 +90,4 @@ [DRAFT] 4.0.0 MMM DD YYYY - 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] From d6b8222e3838c8776a24380dde3558b2cb8ecafd Mon Sep 17 00:00:00 2001 From: "T.J. Schuck" Date: Thu, 15 Nov 2018 12:35:38 -0500 Subject: [PATCH 019/126] Remove explicit support for Rubies 1.8 and 1.9 --- .travis.yml | 4 ---- CHANGELOG | 1 + README.md | 4 ++-- appveyor.yml | 23 ----------------------- 4 files changed, 3 insertions(+), 29 deletions(-) diff --git a/.travis.yml b/.travis.yml index 22f7c67..5a832dd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,8 +4,6 @@ before_install: - gem update --system - gem install bundler rvm: - - 1.8 - - 1.9 - 2.0 - 2.1 - 2.2 @@ -14,8 +12,6 @@ rvm: - 2.5 - 2.6 - ruby-head - - jruby-18mode - - jruby-19mode - jruby-head - rbx-3 - ree diff --git a/CHANGELOG b/CHANGELOG index 304f3f3..8bead60 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -91,3 +91,4 @@ - 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 diff --git a/README.md b/README.md index 26a229b..ff25539 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 1.8 – 2.5 builds on Windows with the DevKit -* Any 1.8 – 2.5 Ruby on a BSD/OS X/Linux system with a compiler +* 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 ## How to use `bcrypt()` in your Rails application diff --git a/appveyor.yml b/appveyor.yml index 6006b02..5fdea8b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,12 +3,6 @@ build: off clone_depth: 1 init: - # Install Ruby 1.8.7 - - if %RUBY_VERSION%==187 ( - appveyor DownloadFile https://dl.bintray.com/oneclick/rubyinstaller/rubyinstaller-1.8.7-p374.exe -FileName C:\ruby_187.exe & - C:\ruby_187.exe /verysilent /dir=C:\Ruby%RUBY_VERSION% - ) - # 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 & @@ -22,17 +16,6 @@ init: # Add Ruby to the path - set PATH=C:\Ruby%RUBY_VERSION%\bin;%PATH% - # Install DevKit 4.5.2 for Ruby 1.8.7 - - if %RUBY_VERSION%==187 ( - mkdir C:\DevKit452 & - appveyor DownloadFile https://dl.bintray.com/oneclick/rubyinstaller/defunct/DevKit-tdm-32-4.5.2-20110712-1620-sfx.exe -FileName C:\DevKit452\devkit_452.exe & - cd C:\DevKit452 & - 7z x devkit_452.exe & - ruby dk.rb init & - ruby dk.rb install & - cd C:\projects\bcrypt-ruby - ) - environment: matrix: - RUBY_VERSION: "head" @@ -49,14 +32,8 @@ environment: - RUBY_VERSION: "21-x64" - RUBY_VERSION: "200" - RUBY_VERSION: "200-x64" - - RUBY_VERSION: "193" - - RUBY_VERSION: "187" install: - - if %RUBY_VERSION%==187 ( - gem update --system 2.0.17 & - C:\DevKit452\devkitvars.bat - ) - if %RUBY_VERSION%==head ( gem install bundler ) - if %RUBY_VERSION%==head-x64 ( gem install bundler ) - bundle install From 4b97854ad663cf56b8f7c6924330fbf322cbd327 Mon Sep 17 00:00:00 2001 From: "T.J. Schuck" Date: Tue, 13 Nov 2018 18:19:10 -0500 Subject: [PATCH 020/126] Include x86.S file from Openwall crypt implementation This is necessary to compile on 32 bit/i386 architectures (currently still supported for the Windows builds) --- ext/mri/x86.S | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 ext/mri/x86.S diff --git a/ext/mri/x86.S b/ext/mri/x86.S new file mode 100644 index 0000000..b0f1cd2 --- /dev/null +++ b/ext/mri/x86.S @@ -0,0 +1,203 @@ +/* + * Written by Solar Designer in 1998-2010. + * No copyright is claimed, and the software is hereby placed in the public + * domain. In case this attempt to disclaim copyright and place the software + * in the public domain is deemed null and void, then the software is + * Copyright (c) 1998-2010 Solar Designer and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * See crypt_blowfish.c for more information. + */ + +#ifdef __i386__ + +#if defined(__OpenBSD__) && !defined(__ELF__) +#define UNDERSCORES +#define ALIGN_LOG +#endif + +#if defined(__CYGWIN32__) || defined(__MINGW32__) +#define UNDERSCORES +#endif + +#ifdef __DJGPP__ +#define UNDERSCORES +#define ALIGN_LOG +#endif + +#ifdef UNDERSCORES +#define _BF_body_r __BF_body_r +#endif + +#ifdef ALIGN_LOG +#define DO_ALIGN(log) .align (log) +#elif defined(DUMBAS) +#define DO_ALIGN(log) .align 1 << log +#else +#define DO_ALIGN(log) .align (1 << (log)) +#endif + +#define BF_FRAME 0x200 +#define ctx %esp + +#define BF_ptr (ctx) + +#define S(N, r) N+BF_FRAME(ctx,r,4) +#ifdef DUMBAS +#define P(N) 0x1000+N+N+N+N+BF_FRAME(ctx) +#else +#define P(N) 0x1000+4*N+BF_FRAME(ctx) +#endif + +/* + * This version of the assembly code is optimized primarily for the original + * Intel Pentium but is also careful to avoid partial register stalls on the + * Pentium Pro family of processors (tested up to Pentium III Coppermine). + * + * It is possible to do 15% faster on the Pentium Pro family and probably on + * many non-Intel x86 processors, but, unfortunately, that would make things + * twice slower for the original Pentium. + * + * An additional 2% speedup may be achieved with non-reentrant code. + */ + +#define L %esi +#define R %edi +#define tmp1 %eax +#define tmp1_lo %al +#define tmp2 %ecx +#define tmp2_hi %ch +#define tmp3 %edx +#define tmp3_lo %dl +#define tmp4 %ebx +#define tmp4_hi %bh +#define tmp5 %ebp + +.text + +#define BF_ROUND(L, R, N) \ + xorl L,tmp2; \ + xorl tmp1,tmp1; \ + movl tmp2,L; \ + shrl $16,tmp2; \ + movl L,tmp4; \ + movb tmp2_hi,tmp1_lo; \ + andl $0xFF,tmp2; \ + movb tmp4_hi,tmp3_lo; \ + andl $0xFF,tmp4; \ + movl S(0,tmp1),tmp1; \ + movl S(0x400,tmp2),tmp5; \ + addl tmp5,tmp1; \ + movl S(0x800,tmp3),tmp5; \ + xorl tmp5,tmp1; \ + movl S(0xC00,tmp4),tmp5; \ + addl tmp1,tmp5; \ + movl 4+P(N),tmp2; \ + xorl tmp5,R + +#define BF_ENCRYPT_START \ + BF_ROUND(L, R, 0); \ + BF_ROUND(R, L, 1); \ + BF_ROUND(L, R, 2); \ + BF_ROUND(R, L, 3); \ + BF_ROUND(L, R, 4); \ + BF_ROUND(R, L, 5); \ + BF_ROUND(L, R, 6); \ + BF_ROUND(R, L, 7); \ + BF_ROUND(L, R, 8); \ + BF_ROUND(R, L, 9); \ + BF_ROUND(L, R, 10); \ + BF_ROUND(R, L, 11); \ + BF_ROUND(L, R, 12); \ + BF_ROUND(R, L, 13); \ + BF_ROUND(L, R, 14); \ + BF_ROUND(R, L, 15); \ + movl BF_ptr,tmp5; \ + xorl L,tmp2; \ + movl P(17),L + +#define BF_ENCRYPT_END \ + xorl R,L; \ + movl tmp2,R + +DO_ALIGN(5) +.globl _BF_body_r +_BF_body_r: + movl 4(%esp),%eax + pushl %ebp + pushl %ebx + pushl %esi + pushl %edi + subl $BF_FRAME-8,%eax + xorl L,L + cmpl %esp,%eax + ja BF_die + xchgl %eax,%esp + xorl R,R + pushl %eax + leal 0x1000+BF_FRAME-4(ctx),%eax + movl 0x1000+BF_FRAME-4(ctx),tmp2 + pushl %eax + xorl tmp3,tmp3 +BF_loop_P: + BF_ENCRYPT_START + addl $8,tmp5 + BF_ENCRYPT_END + leal 0x1000+18*4+BF_FRAME(ctx),tmp1 + movl tmp5,BF_ptr + cmpl tmp5,tmp1 + movl L,-8(tmp5) + movl R,-4(tmp5) + movl P(0),tmp2 + ja BF_loop_P + leal BF_FRAME(ctx),tmp5 + xorl tmp3,tmp3 + movl tmp5,BF_ptr +BF_loop_S: + BF_ENCRYPT_START + BF_ENCRYPT_END + movl P(0),tmp2 + movl L,(tmp5) + movl R,4(tmp5) + BF_ENCRYPT_START + BF_ENCRYPT_END + movl P(0),tmp2 + movl L,8(tmp5) + movl R,12(tmp5) + BF_ENCRYPT_START + BF_ENCRYPT_END + movl P(0),tmp2 + movl L,16(tmp5) + movl R,20(tmp5) + BF_ENCRYPT_START + addl $32,tmp5 + BF_ENCRYPT_END + leal 0x1000+BF_FRAME(ctx),tmp1 + movl tmp5,BF_ptr + cmpl tmp5,tmp1 + movl P(0),tmp2 + movl L,-8(tmp5) + movl R,-4(tmp5) + ja BF_loop_S + movl 4(%esp),%esp + popl %edi + popl %esi + popl %ebx + popl %ebp + ret + +BF_die: +/* Oops, need to re-compile with a larger BF_FRAME. */ + hlt + jmp BF_die + +#endif + +#if defined(__ELF__) && defined(__linux__) +.section .note.GNU-stack,"",@progbits +#endif From 859d42027b4ac47ba84c29e2d7560815252246f7 Mon Sep 17 00:00:00 2001 From: "T.J. Schuck" Date: Wed, 14 Nov 2018 18:03:21 -0500 Subject: [PATCH 021/126] Explicitly enumerate $objs for the generated Makefile Ruby's mkmf generates the $objs for the Makefile by [looping over the files with SRC_EXT extensions](https://github.com/ruby/ruby/blob/9b7d8947df9780c120db7a1407bbe06e2004c511/lib/mkmf.rb#L2224-L2232), which are only [c, m, cc, mm, cxx, and cpp](https://github.com/ruby/ruby/blob/9b7d8947df9780c120db7a1407bbe06e2004c511/lib/mkmf.rb#L75-L88), not the `.S` we need here. This instead explicitly uses the list of object files that Openwall's crypt_blowfish lists in its provided Makefile. See it's Makefile, lines 25-29: ```c BLOWFISH_OBJS = \ crypt_blowfish.o x86.o CRYPT_OBJS = \ $(BLOWFISH_OBJS) crypt_gensalt.o wrapper.o ``` Those are what's passed to Makefile > all on line 41: ```c all: $(CRYPT_OBJS) man ``` This just uses that list plus the name of our actual extension (the `bcrypt_ext.o` entry) to ensure that the x86.S extension gets built in. That extension is only needed for 32-bit x86 systems, but it's fine to include on x64 as well, per the crypt_blowfish README: "you can compile and link it even on a non-x86, it will produce no code in this case". --- ext/mri/extconf.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ext/mri/extconf.rb b/ext/mri/extconf.rb index d6e10b0..f2438b3 100644 --- a/ext/mri/extconf.rb +++ b/ext/mri/extconf.rb @@ -11,6 +11,11 @@ exit 0 else require "mkmf" + + # From Openwall's crypt_blowfish Makefile. + # This is `bcrypt_ext` (our extension) + CRYPT_OBJS from that Makefile. + $objs = %w(bcrypt_ext.o crypt_blowfish.o x86.o crypt_gensalt.o wrapper.o) + dir_config("bcrypt_ext") create_makefile("bcrypt_ext") end From 5de4e439e4c1ae6d1cc5d861a8a0df932c87110f Mon Sep 17 00:00:00 2001 From: "T.J. Schuck" Date: Thu, 15 Nov 2018 13:33:26 -0500 Subject: [PATCH 022/126] Remove REE from matrix REE is a 1.8-compatible Ruby, so drop it along with the rest of the 1.8s and 1.9s in #185 --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5a832dd..4d960cf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,5 +14,4 @@ rvm: - ruby-head - jruby-head - rbx-3 - - ree script: bundle exec rake From ded1f0a5131d1fc6827e7b3398798417ee0bb09b Mon Sep 17 00:00:00 2001 From: "T.J. Schuck" Date: Thu, 8 Nov 2018 18:34:23 -0500 Subject: [PATCH 023/126] =?UTF-8?q?This=20vector=20is=20duplicated=20?= =?UTF-8?q?=E2=80=94=20it=E2=80=99s=20also=20the=20last=20one?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keeping the one at the bottom because that’s where Openwall has it. --- spec/bcrypt/engine_spec.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/bcrypt/engine_spec.rb b/spec/bcrypt/engine_spec.rb index d99044f..50dd554 100644 --- a/spec/bcrypt/engine_spec.rb +++ b/spec/bcrypt/engine_spec.rb @@ -72,7 +72,6 @@ class MyInvalidSecret ["U*U", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW"], ["U*U*", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.VGOzA784oUp/Z0DY336zx7pLYAy0lwK"], ["U*U*U", "$2a$05$XXXXXXXXXXXXXXXXXXXXXO", "$2a$05$XXXXXXXXXXXXXXXXXXXXXOAcXxm9kjPGEMsLznoKqmqw7tc8WCx4a"], - ["", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.7uG0VCzI2bS7j6ymqJi9CdcdxiRTWNy"], ["0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", "$2a$05$abcdefghijklmnopqrstuu", "$2a$05$abcdefghijklmnopqrstuu5s2v8.iXieOjg/.AySBTTZIIVFJeBui"], ["\xa3", "$2x$05$/OK.fbVrR/bpIqNJ5ianF.", "$2x$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e"], ["\xff\xff\xa3", "$2x$05$/OK.fbVrR/bpIqNJ5ianF.", "$2x$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e"], From 05c5605d358b536a6faab3a20bb4473c9b8eec35 Mon Sep 17 00:00:00 2001 From: "T.J. Schuck" Date: Thu, 8 Nov 2018 18:36:11 -0500 Subject: [PATCH 024/126] Add back in missing chars from Openwall test vectors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These were deleted in https://github.com/codahale/bcrypt-ruby/pull/182, but are a part of the Openwall test vectors. They’re important because they’re actually making the string longer than 72 characters, which is the test that the vector is going for. --- 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 50dd554..0000f4e 100644 --- a/spec/bcrypt/engine_spec.rb +++ b/spec/bcrypt/engine_spec.rb @@ -72,7 +72,7 @@ class MyInvalidSecret ["U*U", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW"], ["U*U*", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.VGOzA784oUp/Z0DY336zx7pLYAy0lwK"], ["U*U*U", "$2a$05$XXXXXXXXXXXXXXXXXXXXXO", "$2a$05$XXXXXXXXXXXXXXXXXXXXXOAcXxm9kjPGEMsLznoKqmqw7tc8WCx4a"], - ["0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", "$2a$05$abcdefghijklmnopqrstuu", "$2a$05$abcdefghijklmnopqrstuu5s2v8.iXieOjg/.AySBTTZIIVFJeBui"], + ["0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789chars after 72 are ignored", "$2a$05$abcdefghijklmnopqrstuu", "$2a$05$abcdefghijklmnopqrstuu5s2v8.iXieOjg/.AySBTTZIIVFJeBui"], ["\xa3", "$2x$05$/OK.fbVrR/bpIqNJ5ianF.", "$2x$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e"], ["\xff\xff\xa3", "$2x$05$/OK.fbVrR/bpIqNJ5ianF.", "$2x$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e"], ["\xff\xff\xa3", "$2y$05$/OK.fbVrR/bpIqNJ5ianF.", "$2y$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e"], From 0a9e5c2b845522c765717fec3021ce4e969f533c Mon Sep 17 00:00:00 2001 From: "T.J. Schuck" Date: Thu, 8 Nov 2018 18:44:56 -0500 Subject: [PATCH 025/126] Add the test vectors from the Java implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This should actually cross-check implementations — the Java vectors should pass when using the C implementation, and the C vectors should pass when using the Java implementation. --- spec/bcrypt/engine_spec.rb | 46 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/spec/bcrypt/engine_spec.rb b/spec/bcrypt/engine_spec.rb index 0000f4e..cde842c 100644 --- a/spec/bcrypt/engine_spec.rb +++ b/spec/bcrypt/engine_spec.rb @@ -67,8 +67,8 @@ class MyInvalidSecret end specify "should be interoperable with other implementations" do - # test vectors from the OpenWall implementation test_vectors = [ + # test vectors from the OpenWall implementation , found in wrapper.c ["U*U", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW"], ["U*U*", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.VGOzA784oUp/Z0DY336zx7pLYAy0lwK"], ["U*U*U", "$2a$05$XXXXXXXXXXXXXXXXXXXXXO", "$2a$05$XXXXXXXXXXXXXXXXXXXXXOAcXxm9kjPGEMsLznoKqmqw7tc8WCx4a"], @@ -96,7 +96,49 @@ class MyInvalidSecret ["\xaa"*72+"chars after 72 are ignored as usual", "$2a$05$/OK.fbVrR/bpIqNJ5ianF.", "$2a$05$/OK.fbVrR/bpIqNJ5ianF.swQOIzjOiJ9GHEPuhEkvqrUyvWhEMx6"], ["\xaa\x55"*36, "$2a$05$/OK.fbVrR/bpIqNJ5ianF.", "$2a$05$/OK.fbVrR/bpIqNJ5ianF.R9xrDjiycxMbQE2bp.vgqlYpW5wx2yy"], ["\x55\xaa\xff"*24, "$2a$05$/OK.fbVrR/bpIqNJ5ianF.", "$2a$05$/OK.fbVrR/bpIqNJ5ianF.9tQZzcJfm3uj2NvJ/n5xkhpqLrMpWCe"], - ["", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.7uG0VCzI2bS7j6ymqJi9CdcdxiRTWNy"] + ["", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.7uG0VCzI2bS7j6ymqJi9CdcdxiRTWNy"], + + # test vectors from the Java implementation, found in https://github.com/spring-projects/spring-security/blob/master/crypto/src/test/java/org/springframework/security/crypto/bcrypt/BCryptTests.java + ["", "$2a$06$DCq7YPn5Rq63x1Lad4cll.", "$2a$06$DCq7YPn5Rq63x1Lad4cll.TV4S6ytwfsfvkgY8jIucDrjc8deX1s."], + ["", "$2a$08$HqWuK6/Ng6sg9gQzbLrgb.", "$2a$08$HqWuK6/Ng6sg9gQzbLrgb.Tl.ZHfXLhvt/SgVyWhQqgqcZ7ZuUtye"], + ["", "$2a$10$k1wbIrmNyFAPwPVPSVa/ze", "$2a$10$k1wbIrmNyFAPwPVPSVa/zecw2BCEnBwVS2GbrmgzxFUOqW9dk4TCW"], + ["", "$2a$12$k42ZFHFWqBp3vWli.nIn8u", "$2a$12$k42ZFHFWqBp3vWli.nIn8uYyIkbvYRvodzbfbK18SSsY.CsIQPlxO"], + ["", "$2b$06$8eVN9RiU8Yki430X.wBvN.", "$2b$06$8eVN9RiU8Yki430X.wBvN.LWaqh2962emLVSVXVZIXJvDYLsV0oFu"], + ["", "$2b$06$NlgfNgpIc6GlHciCkMEW8u", "$2b$06$NlgfNgpIc6GlHciCkMEW8uKOBsyvAp7QwlHpysOlKdtyEw50WQua2"], + ["", "$2y$06$mFDtkz6UN7B3GZ2qi2hhaO", "$2y$06$mFDtkz6UN7B3GZ2qi2hhaO3OFWzNEdcY84ELw6iHCPruuQfSAXBLK"], + ["", "$2y$06$88kSqVttBx.e9iXTPCLa5u", "$2y$06$88kSqVttBx.e9iXTPCLa5uFPrVFjfLH4D.KcO6pBiAmvUkvdg0EYy"], + ["a", "$2a$06$m0CrhHm10qJ3lXRY.5zDGO", "$2a$06$m0CrhHm10qJ3lXRY.5zDGO3rS2KdeeWLuGmsfGlMfOxih58VYVfxe"], + ["a", "$2a$08$cfcvVd2aQ8CMvoMpP2EBfe", "$2a$08$cfcvVd2aQ8CMvoMpP2EBfeodLEkkFJ9umNEfPD18.hUF62qqlC/V."], + ["a", "$2a$10$k87L/MF28Q673VKh8/cPi.", "$2a$10$k87L/MF28Q673VKh8/cPi.SUl7MU/rWuSiIDDFayrKk/1tBsSQu4u"], + ["a", "$2a$12$8NJH3LsPrANStV6XtBakCe", "$2a$12$8NJH3LsPrANStV6XtBakCez0cKHXVxmvxIlcz785vxAIZrihHZpeS"], + ["a", "$2b$06$ehKGYiS4wt2HAr7KQXS5z.", "$2b$06$ehKGYiS4wt2HAr7KQXS5z.OaRjB4jHO7rBHJKlGXbqEH3QVJfO7iO"], + ["a", "$2b$06$PWxFFHA3HiCD46TNOZh30e", "$2b$06$PWxFFHA3HiCD46TNOZh30eNto1hg5uM9tHBlI4q/b03SW/gGKUYk6"], + ["a", "$2y$06$LUdD6/aD0e/UbnxVAVbvGu", "$2y$06$LUdD6/aD0e/UbnxVAVbvGuUmIoJ3l/OK94ThhadpMWwKC34LrGEey"], + ["a", "$2y$06$eqgY.T2yloESMZxgp76deO", "$2y$06$eqgY.T2yloESMZxgp76deOROa7nzXDxbO0k.PJvuClTa.Vu1AuemG"], + ["abc", "$2a$06$If6bvum7DFjUnE9p2uDeDu", "$2a$06$If6bvum7DFjUnE9p2uDeDu0YHzrHM6tf.iqN8.yx.jNN1ILEf7h0i"], + ["abc", "$2a$08$Ro0CUfOqk6cXEKf3dyaM7O", "$2a$08$Ro0CUfOqk6cXEKf3dyaM7OhSCvnwM9s4wIX9JeLapehKK5YdLxKcm"], + ["abc", "$2a$10$WvvTPHKwdBJ3uk0Z37EMR.", "$2a$10$WvvTPHKwdBJ3uk0Z37EMR.hLA2W6N9AEBhEgrAOljy2Ae5MtaSIUi"], + ["abc", "$2a$12$EXRkfkdmXn2gzds2SSitu.", "$2a$12$EXRkfkdmXn2gzds2SSitu.MW9.gAVqa9eLS1//RYtYCmB1eLHg.9q"], + ["abc", "$2b$06$5FyQoicpbox1xSHFfhhdXu", "$2b$06$5FyQoicpbox1xSHFfhhdXuR2oxLpO1rYsQh5RTkI/9.RIjtoF0/ta"], + ["abc", "$2b$06$1kJyuho8MCVP3HHsjnRMkO", "$2b$06$1kJyuho8MCVP3HHsjnRMkO1nvCOaKTqLnjG2TX1lyMFbXH/aOkgc."], + ["abc", "$2y$06$ACfku9dT6.H8VjdKb8nhlu", "$2y$06$ACfku9dT6.H8VjdKb8nhluaoBmhJyK7GfoNScEfOfrJffUxoUeCjK"], + ["abc", "$2y$06$9JujYcoWPmifvFA3RUP90e", "$2y$06$9JujYcoWPmifvFA3RUP90e5rSEHAb5Ye6iv3.G9ikiHNv5cxjNEse"], + ["abcdefghijklmnopqrstuvwxyz", "$2a$06$.rCVZVOThsIa97pEDOxvGu", "$2a$06$.rCVZVOThsIa97pEDOxvGuRRgzG64bvtJ0938xuqzv18d3ZpQhstC"], + ["abcdefghijklmnopqrstuvwxyz", "$2a$08$aTsUwsyowQuzRrDqFflhge", "$2a$08$aTsUwsyowQuzRrDqFflhgekJ8d9/7Z3GV3UcgvzQW3J5zMyrTvlz."], + ["abcdefghijklmnopqrstuvwxyz", "$2a$10$fVH8e28OQRj9tqiDXs1e1u", "$2a$10$fVH8e28OQRj9tqiDXs1e1uxpsjN0c7II7YPKXua2NAKYvM6iQk7dq"], + ["abcdefghijklmnopqrstuvwxyz", "$2a$12$D4G5f18o7aMMfwasBL7Gpu", "$2a$12$D4G5f18o7aMMfwasBL7GpuQWuP3pkrZrOAnqP.bmezbMng.QwJ/pG"], + ["abcdefghijklmnopqrstuvwxyz", "$2b$06$O8E89AQPj1zJQA05YvIAU.", "$2b$06$O8E89AQPj1zJQA05YvIAU.hMpj25BXri1bupl/Q7CJMlpLwZDNBoO"], + ["abcdefghijklmnopqrstuvwxyz", "$2b$06$PDqIWr./o/P3EE/P.Q0A/u", "$2b$06$PDqIWr./o/P3EE/P.Q0A/uFg86WL/PXTbaW267TDALEwDylqk00Z."], + ["abcdefghijklmnopqrstuvwxyz", "$2y$06$34MG90ZLah8/ZNr3ltlHCu", "$2y$06$34MG90ZLah8/ZNr3ltlHCuz6bachF8/3S5jTuzF1h2qg2cUk11sFW"], + ["abcdefghijklmnopqrstuvwxyz", "$2y$06$AK.hSLfMyw706iEW24i68u", "$2y$06$AK.hSLfMyw706iEW24i68uKAc2yorPTrB0cimvjJHEBUrPkOq7VvG"], + ["~!@#$%^&*() ~!@#$%^&*()PNBFRD", "$2a$06$fPIsBO8qRqkjj273rfaOI.", "$2a$06$fPIsBO8qRqkjj273rfaOI.HtSV9jLDpTbZn782DC6/t7qT67P6FfO"], + ["~!@#$%^&*() ~!@#$%^&*()PNBFRD", "$2a$08$Eq2r4G/76Wv39MzSX262hu", "$2a$08$Eq2r4G/76Wv39MzSX262huzPz612MZiYHVUJe/OcOql2jo4.9UxTW"], + ["~!@#$%^&*() ~!@#$%^&*()PNBFRD", "$2a$10$LgfYWkbzEvQ4JakH7rOvHe", "$2a$10$LgfYWkbzEvQ4JakH7rOvHe0y8pHKF9OaFgwUZ2q7W2FFZmZzJYlfS"], + ["~!@#$%^&*() ~!@#$%^&*()PNBFRD", "$2a$12$WApznUOJfkEGSmYRfnkrPO", "$2a$12$WApznUOJfkEGSmYRfnkrPOr466oFDCaj4b6HY3EXGvfxm43seyhgC"], + ["~!@#$%^&*() ~!@#$%^&*()PNBFRD", "$2b$06$FGWA8OlY6RtQhXBXuCJ8Wu", "$2b$06$FGWA8OlY6RtQhXBXuCJ8WusVipRI15cWOgJK8MYpBHEkktMfbHRIG"], + ["~!@#$%^&*() ~!@#$%^&*()PNBFRD", "$2b$06$G6aYU7UhUEUDJBdTgq3CRe", "$2b$06$G6aYU7UhUEUDJBdTgq3CRekiopCN4O4sNitFXrf5NUscsVZj3a2r6"], + ["~!@#$%^&*() ~!@#$%^&*()PNBFRD", "$2y$06$sYDFHqOcXTjBgOsqC0WCKe", "$2y$06$sYDFHqOcXTjBgOsqC0WCKeMd3T1UhHuWQSxncLGtXDLMrcE6vFDti"], + ["~!@#$%^&*() ~!@#$%^&*()PNBFRD", "$2y$06$6Xm0gCw4g7ZNDCEp4yTise", "$2y$06$6Xm0gCw4g7ZNDCEp4yTisez0kSdpXEl66MvdxGidnmChIe8dFmMnq"] ] for secret, salt, test_vector in test_vectors expect(BCrypt::Engine.hash_secret(secret, salt)).to eql(test_vector) From 921d6568bd2a1510e423cdc1056afca92e690a2e Mon Sep 17 00:00:00 2001 From: "T.J. Schuck" Date: Thu, 15 Nov 2018 14:30:21 -0500 Subject: [PATCH 026/126] No rdoc or ri on Appveyor to speed it up --- appveyor.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 5fdea8b..43cf601 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -34,11 +34,12 @@ environment: - 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 ) - if %RUBY_VERSION%==head-x64 ( gem install bundler ) - bundle install -before_test: +before_build: - ruby -v - gem -v From b08b6b82b71214f1eff9646d5638d3056247cdf4 Mon Sep 17 00:00:00 2001 From: "T.J. Schuck" Date: Thu, 15 Nov 2018 15:45:54 -0500 Subject: [PATCH 027/126] Fix deprecation warning Before this removal: ``` NOTE: Gem::Specification#has_rdoc= is deprecated with no replacement. It will be removed on or after 2018-12-01. ``` Just making it under the wire! --- bcrypt.gemspec | 1 - 1 file changed, 1 deletion(-) diff --git a/bcrypt.gemspec b/bcrypt.gemspec index 0170428..0a608dc 100644 --- a/bcrypt.gemspec +++ b/bcrypt.gemspec @@ -16,7 +16,6 @@ Gem::Specification.new do |s| s.add_development_dependency 'rspec', '>= 3' s.add_development_dependency 'rdoc', '~> 3.12' - s.has_rdoc = true 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 ec0486831109bc72d0f6e5fed5e3feb7b5bc01e5 Mon Sep 17 00:00:00 2001 From: "T.J. Schuck" Date: Fri, 4 Jan 2019 17:46:35 -0500 Subject: [PATCH 028/126] Peg older versions of rubygems and bundler that work with older Rubies Bundler 2.0 and Rubygems 3.0 both drop support for Rubies older than 2.3. This pegs their versions to the last one that should support all of our current supported Rubies to fix CI. --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4d960cf..621ca7f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,8 @@ language: ruby before_install: - "echo 'gem: --no-rdoc --no-ri' > ~/.gemrc" - - gem update --system - - gem install bundler + - gem update --system 2.7.8 + - gem install bundler -v 1.17.3 rvm: - 2.0 - 2.1 From 613daca044ce0bf2685bbf8350376e24a9f6ca18 Mon Sep 17 00:00:00 2001 From: Adam Daniels Date: Sat, 5 Jan 2019 21:35:19 +0000 Subject: [PATCH 029/126] Define SKIP_GNU token when building extension Openwall's crypt_blowfish library supports patching libc implementations. Part of this includes function definitions for `crypt` and `crypt_r`. Unfortunately, the function definition for `crypt_r` differs on FreeBSD >= 12 (and possibly others), which causes the extension to fail in building. This is due to the nature of how the extension works, where a C->Ruby extension is used, instead of just using a FFI such as Fiddle directly against `crypt_blowfish` and `crypt_gensalt`. The C->Ruby extension includes `ruby.h`, which in turn has a requirement on `unistd.h`, where the `crypt_r` function has already been defined, albeit with the different function signature. Defining the __SKIP_GNU token causes the `ow-crypt.h` header not to attempt defining(redefining) these two function definitions that may conflict with libc. We're not using either of them (only the re-entrant versions) so no harm done by skipping their definitions. --- ext/mri/extconf.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/mri/extconf.rb b/ext/mri/extconf.rb index f2438b3..c2222de 100644 --- a/ext/mri/extconf.rb +++ b/ext/mri/extconf.rb @@ -16,6 +16,7 @@ # This is `bcrypt_ext` (our extension) + CRYPT_OBJS from that Makefile. $objs = %w(bcrypt_ext.o crypt_blowfish.o x86.o crypt_gensalt.o wrapper.o) + $defs << "-D__SKIP_GNU" dir_config("bcrypt_ext") create_makefile("bcrypt_ext") end From 818dbb5a340f910d6b26ebade31d79a2deda9041 Mon Sep 17 00:00:00 2001 From: Felix Date: Sun, 13 Jan 2019 15:17:22 +0100 Subject: [PATCH 030/126] Update Website link in readme s/blog.codahale.com/codahale.com/ --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ff25539..b1ce999 100644 --- a/README.md +++ b/README.md @@ -191,4 +191,4 @@ http://www.schneier.com/book-practical.html # Etc * Author :: Coda Hale -* Website :: http://blog.codahale.com +* Website :: http://codahale.com From b6d7abf2f4f8c1275804a3af0f41d357dd01b77b Mon Sep 17 00:00:00 2001 From: Felix Date: Sun, 13 Jan 2019 15:20:35 +0100 Subject: [PATCH 031/126] Use https for links --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b1ce999..9bbc739 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ An easy way to keep your users' passwords secure. -* http://github.com/codahale/bcrypt-ruby/tree/master +* https://github.com/codahale/bcrypt-ruby/tree/master [![Travis Build Status](https://travis-ci.org/codahale/bcrypt-ruby.svg?branch=master)](https://travis-ci.org/codahale/bcrypt-ruby) [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/6fplerx9lnaf0hyo?svg=true)](https://ci.appveyor.com/project/TJSchuck35975/bcrypt-ruby) @@ -20,7 +20,7 @@ security experts is not a professional response to risk. `bcrypt()` allows you to easily harden your application against these kinds of attacks. *Note*: JRuby versions of the bcrypt gem `<= 2.1.3` had a [security -vulnerability](http://www.mindrot.org/files/jBCrypt/internat.adv) that +vulnerability](https://www.mindrot.org/files/jBCrypt/internat.adv) that was fixed in `>= 2.1.4`. If you used a vulnerable version to hash passwords with international characters in them, you will need to re-hash those passwords. This vulnerability only affected the JRuby gem. @@ -38,7 +38,7 @@ The bcrypt gem is available on the following Ruby platforms: ## How to use `bcrypt()` in your Rails application *Note*: Rails versions >= 3 ship with `ActiveModel::SecurePassword` which uses bcrypt-ruby. -`has_secure_password` [docs](http://api.rubyonrails.org/classes/ActiveModel/SecurePassword/ClassMethods.html#method-i-has_secure_password) +`has_secure_password` [docs](https://api.rubyonrails.org/classes/ActiveModel/SecurePassword/ClassMethods.html#method-i-has_secure_password) implements a similar authentication strategy to the code below. ### The _User_ model @@ -182,13 +182,13 @@ system available. For a more technical explanation of the algorithm and its design criteria, please read Niels Provos and David Mazières' Usenix99 paper: -http://www.usenix.org/events/usenix99/provos.html +https://www.usenix.org/events/usenix99/provos.html If you'd like more down-to-earth advice regarding cryptography, I suggest reading Practical Cryptography by Niels Ferguson and Bruce Schneier: -http://www.schneier.com/book-practical.html +https://www.schneier.com/book-practical.html # Etc * Author :: Coda Hale -* Website :: http://codahale.com +* Website :: https://codahale.com From bd77e3827b9a2b51d51e2a8d8936972f4fe9c537 Mon Sep 17 00:00:00 2001 From: Olle Jonsson Date: Fri, 12 Apr 2019 19:31:11 +0200 Subject: [PATCH 032/126] use Bundler < 2 in Appveyor builds --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 43cf601..e832e22 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -35,8 +35,8 @@ environment: install: - ps: "Set-Content -Value 'gem: --no-ri --no-rdoc ' -Path C:\\ProgramData\\gemrc" - - if %RUBY_VERSION%==head ( gem install bundler ) - - if %RUBY_VERSION%==head-x64 ( gem install bundler ) + - if %RUBY_VERSION%==head ( gem install bundler -v'< 2' ) + - if %RUBY_VERSION%==head-x64 ( gem install bundler -v'< 2' ) - bundle install before_build: From c78dde9a5a9d80ae730eb1f1f92d285a6e598df5 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 31 May 2019 11:25:28 -0700 Subject: [PATCH 033/126] bumping version --- Gemfile.lock | 2 +- bcrypt.gemspec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 4b022d8..03c0af7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - bcrypt (3.1.12) + bcrypt (3.1.13) GEM remote: https://rubygems.org/ diff --git a/bcrypt.gemspec b/bcrypt.gemspec index 0a608dc..5f9a5cf 100644 --- a/bcrypt.gemspec +++ b/bcrypt.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = 'bcrypt' - s.version = '3.1.12' + s.version = '3.1.13' s.summary = "OpenBSD's bcrypt() password hashing algorithm." s.description = <<-EOF From ada5f127b7d386c5d8aefdf3108b54fd96b0936c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 31 May 2019 11:47:13 -0700 Subject: [PATCH 034/126] Removing the dev dep on RDoc RDoc depends on JSON 1.8.6 and I can't seem to get that working on JRuby. Working around it for now by just removing the dependency. --- Gemfile.lock | 33 ++++++++++++++------------------- bcrypt.gemspec | 1 - 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 03c0af7..9981158 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -6,27 +6,23 @@ PATH GEM remote: https://rubygems.org/ specs: - diff-lcs (1.2.5) - json (1.8.6) - json (1.8.6-java) - rake (10.4.2) - rake-compiler (0.9.5) + diff-lcs (1.3) + rake (12.3.2) + rake-compiler (0.9.9) rake - rdoc (3.12.2) - json (~> 1.4) - rspec (3.3.0) - rspec-core (~> 3.3.0) - rspec-expectations (~> 3.3.0) - rspec-mocks (~> 3.3.0) - rspec-core (3.3.2) - rspec-support (~> 3.3.0) - rspec-expectations (3.3.1) + 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) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.3.0) - rspec-mocks (3.3.2) + rspec-support (~> 3.8.0) + rspec-mocks (3.8.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.3.0) - rspec-support (3.3.0) + rspec-support (~> 3.8.0) + rspec-support (3.8.0) PLATFORMS java @@ -35,7 +31,6 @@ PLATFORMS DEPENDENCIES bcrypt! rake-compiler (~> 0.9.2) - rdoc (~> 3.12) rspec (>= 3) BUNDLED WITH diff --git a/bcrypt.gemspec b/bcrypt.gemspec index 5f9a5cf..e67bad2 100644 --- a/bcrypt.gemspec +++ b/bcrypt.gemspec @@ -14,7 +14,6 @@ Gem::Specification.new do |s| s.add_development_dependency 'rake-compiler', '~> 0.9.2' s.add_development_dependency 'rspec', '>= 3' - s.add_development_dependency 'rdoc', '~> 3.12' 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 27e168927a10d0028366fe364c1aafe1b62a25b4 Mon Sep 17 00:00:00 2001 From: Sergey Alekseev Date: Fri, 5 Jul 2019 21:00:31 +0300 Subject: [PATCH 035/126] 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 036/126] 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 037/126] 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 038/126] 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 039/126] 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 040/126] 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 041/126] 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 042/126] 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 043/126] 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 044/126] 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 045/126] 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 046/126] 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 047/126] 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 048/126] 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 049/126] 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 050/126] 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 051/126] 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 052/126] 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 053/126] 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 054/126] 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 055/126] 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 056/126] 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 057/126] 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 058/126] 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 059/126] 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 060/126] 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 061/126] 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 062/126] 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 063/126] 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 064/126] 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 065/126] 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 066/126] 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 067/126] 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 068/126] 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 069/126] 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 070/126] 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 071/126] 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 072/126] 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 073/126] 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 074/126] 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 075/126] 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 076/126] 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 077/126] 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 078/126] 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 079/126] 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 080/126] 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 081/126] 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 082/126] 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 083/126] 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 084/126] 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 085/126] 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 086/126] 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 087/126] 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 088/126] 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 089/126] 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 090/126] 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 091/126] 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 092/126] 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 093/126] 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 094/126] 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 095/126] 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 096/126] 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 097/126] 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 098/126] 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 099/126] 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 100/126] 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 101/126] 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 102/126] 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 103/126] 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 104/126] 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 105/126] 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 106/126] 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 107/126] 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 108/126] 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 109/126] 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 110/126] 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 111/126] 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 112/126] 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 113/126] 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 114/126] 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 115/126] 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 116/126] 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 117/126] 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 118/126] 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 119/126] 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 120/126] 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 121/126] 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 122/126] 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 123/126] 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 124/126] 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 125/126] 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 126/126] 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