BCrypt::Errors::InvalidHash: invalid hash

I have an old Ruby on Rails app, Ruby 2.5 and Rails 3.2, that I finally got around to switching to the next generation Circle docker images, but I’m getting an error on the first test build.

bundle _1.17.3_ exec rake db:migrate db:seed

rake aborted!
BCrypt::Errors::InvalidHash: invalid hash
/home/circleci/project/vendor/bundle/gems/bcrypt-ruby-3.0.1/lib/bcrypt.rb:171:in `initialize'
/home/circleci/project/vendor/bundle/gems/bcrypt-ruby-3.0.1/lib/bcrypt.rb:161:in `new'
/home/circleci/project/vendor/bundle/gems/bcrypt-ruby-3.0.1/lib/bcrypt.rb:161:in `create'
/home/circleci/project/vendor/bundle/gems/activemodel-3.2.22.5/lib/active_model/secure_password.rb:69:in `password='
/home/circleci/project/vendor/bundle/gems/activerecord-3.2.22.5/lib/active_record/attribute_assignment.rb:85:in `block in assign_attributes'
/home/circleci/project/vendor/bundle/gems/activerecord-3.2.22.5/lib/active_record/attribute_assignment.rb:78:in `each'
/home/circleci/project/vendor/bundle/gems/activerecord-3.2.22.5/lib/active_record/attribute_assignment.rb:78:in `assign_attributes'
/home/circleci/project/vendor/bundle/gems/activerecord-3.2.22.5/lib/active_record/base.rb:498:in `initialize'
/home/circleci/project/vendor/bundle/gems/activerecord-3.2.22.5/lib/active_record/validations.rb:39:in `new'
/home/circleci/project/vendor/bundle/gems/activerecord-3.2.22.5/lib/active_record/validations.rb:39:in `create!'
/home/circleci/project/db/seeds.rb:9:in `<top (required)>'
/home/circleci/project/vendor/bundle/gems/activesupport-3.2.22.5/lib/active_support/dependencies.rb:245:in `load'
/home/circleci/project/vendor/bundle/gems/activesupport-3.2.22.5/lib/active_support/dependencies.rb:245:in `block in load'
/home/circleci/project/vendor/bundle/gems/activesupport-3.2.22.5/lib/active_support/dependencies.rb:236:in `load_dependency'
/home/circleci/project/vendor/bundle/gems/activesupport-3.2.22.5/lib/active_support/dependencies.rb:245:in `load'
/home/circleci/project/vendor/bundle/gems/railties-3.2.22.5/lib/rails/engine.rb:525:in `load_seed'
/home/circleci/project/vendor/bundle/gems/activerecord-3.2.22.5/lib/active_record/railties/databases.rake:347:in `block (2 levels) in <top (required)>'
/home/circleci/project/vendor/bundle/gems/rake-11.3.0/exe/rake:27:in `<top (required)>'
/home/circleci/.rubygems/gems/bundler-1.17.3/lib/bundler/cli/exec.rb:74:in `load'
/home/circleci/.rubygems/gems/bundler-1.17.3/lib/bundler/cli/exec.rb:74:in `kernel_load'
/home/circleci/.rubygems/gems/bundler-1.17.3/lib/bundler/cli/exec.rb:28:in `run'
/home/circleci/.rubygems/gems/bundler-1.17.3/lib/bundler/cli.rb:463:in `exec'
/home/circleci/.rubygems/gems/bundler-1.17.3/lib/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
/home/circleci/.rubygems/gems/bundler-1.17.3/lib/bundler/vendor/thor/lib/thor/invocation.rb:126:in `invoke_command'
/home/circleci/.rubygems/gems/bundler-1.17.3/lib/bundler/vendor/thor/lib/thor.rb:387:in `dispatch'
/home/circleci/.rubygems/gems/bundler-1.17.3/lib/bundler/cli.rb:27:in `dispatch'
/home/circleci/.rubygems/gems/bundler-1.17.3/lib/bundler/vendor/thor/lib/thor/base.rb:466:in `start'
/home/circleci/.rubygems/gems/bundler-1.17.3/lib/bundler/cli.rb:18:in `start'
/home/circleci/.rubygems/gems/bundler-1.17.3/exe/bundle:30:in `block in <top (required)>'
/home/circleci/.rubygems/gems/bundler-1.17.3/lib/bundler/friendly_errors.rb:124:in `with_friendly_errors'
/home/circleci/.rubygems/gems/bundler-1.17.3/exe/bundle:22:in `<top (required)>'
/home/circleci/.rubygems/bin/bundle:23:in `load'
/home/circleci/.rubygems/bin/bundle:23:in `<main>'
Tasks: TOP => db:seed

It’s happening when it tries to seed the database with test users. The bcrypt-ruby gem complains that the hash is invalid. This didn’t happen with the old Circle image. I can’t reproduce locally. Searching around, it sounds like the root cause may be the underlying bcrypt library in Ubuntu may be returning different values. Unfortunately, I can’t upgrade the bcrypt-ruby gem to fix this. It’s not an option with Rails 3. But I was confused why this came up when switching Circle images. I assumed that the new images would be “direct replacements” and largely be the same.

Here’s a minimal reproduction:

Here’s the full Circle config.yml:

version: 2.1
jobs:
  rails:
    docker:
      - image: cimg/ruby:2.5.9-node
        environment:
          BUNDLE_FROZEN: "true"
          BUNDLE_JOBS: 3
          BUNDLE_RETRY: 3
          BUNDLE_PATH: vendor/bundle
          RAILS_ENV: test
          RACK_ENV: test
      - image: postgres:11
        environment:
          POSTGRES_USER: ubuntu
          POSTGRES_HOST_AUTH_METHOD: trust
          POSTGRES_DB: circle_ruby_test
    resource_class: small
    working_directory: ~/project
    steps:
      - restore_cache:
          keys:
            - source-v1-{{ .Branch }}-{{ .Revision }}
            - source-v1-{{ .Branch }}-
            - source-v1-
      - checkout
      - run: sudo apt-get update
      - run: sudo apt-get install libsqlite3-dev
      - save_cache:
          key: source-v1-{{ .Branch }}-{{ .Revision }}
          paths:
            - .git
      - restore_cache:
          key: gem-dep-v2-{{ checksum "Gemfile.lock" }}
      - run: ruby -v
      - run: gem install --no-document bundler -v 1.17.3
      - run: gem list bundler
      - run: bundle _1.17.3_ -v
      - run: bundle _1.17.3_ check || bundle _1.17.3_ install
      - save_cache:
          key: gem-dep-v2-{{ checksum "Gemfile.lock" }}
          paths:
            - vendor/bundle
            - ~/.bundle
      - run: |-
          mkdir -p config && echo 'test:
            adapter: postgresql
            database: circle_ruby_test
            username: ubuntu
            host: localhost
          ' > config/database.yml
      - run: bundle _1.17.3_ exec rake db:create db:schema:load --trace
      - run: bundle _1.17.3_ exec rake db:migrate db:seed
workflows:
  build:
    jobs:
      - rails

Hi. Have you tried a complete pipeline run without using cache?

Sure, that’s worth a try.

https://app.circleci.com/pipelines/github/ashawley/rails32-circleci/20

Restoring cache
No cache is found for key: gem-dep-v3-KyzdYImREBnx+LUsFJcYB3XnOK3QBZELbr2JUHwf8DU=

Modified the cache key value in config.yml, but it still failed:

BCrypt::Errors::InvalidHash: invalid hash

Revisited this and wrote a unit test and it appears the underlying C code is adding trailing nulls.

Failures:

  1) BCrypt Engine hash_secret
     Failure/Error: expect(hash).to eq('$2a$10$xxxxxxxxxxxxxxxxxxxxxul/XYj4HKy6ex7YlfZ4IiEN5ri.5eCiG')
       
       expected: "$2a$10$xxxxxxxxxxxxxxxxxxxxxul/XYj4HKy6ex7YlfZ4IiEN5ri.5eCiG"
            got: "$2a$10$xxxxxxxxxxxxxxxxxxxxxul/XYj4HKy6ex7YlfZ4IiEN5ri.5eCiG\x00\x00\x00\x00\x18\x00\x04.\x00\x00\x00\x00\n\xA4> \x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x18\x00\x04\x00\x00..\x00\x00\x00"
       
       (compared using ==)
       
       Diff:
       @@ -1,2 +1,3 @@
       -$2a$10$xxxxxxxxxxxxxxxxxxxxxul/XYj4HKy6ex7YlfZ4IiEN5ri.5eCiG
       +$2a$10$xxxxxxxxxxxxxxxxxxxxxul/XYj4HKy6ex7YlfZ4IiEN5ri.5eCiG^X^D.
       +�> ^B^X^D..
       
     # ./spec/bcrypt_spec.rb:26:in `block (3 levels) in <top (required)>'

  2) BCrypt Password create
     Failure/Error: hash = BCrypt::Password.create('Password0', :cost => BCrypt::Engine::DEFAULT_COST)
     BCrypt::Errors::InvalidHash:
       invalid hash
     # ./spec/bcrypt_spec.rb:11:in `block (3 levels) in <top (required)>'

Pull request with test and build Circle failures: Add bcyrpt unit test by ashawley · Pull Request #2 · ashawley/rails32-circleci · GitHub

This is the unit tests:

require 'bcrypt'

describe BCrypt do

  describe 'Password' do

    it 'create' do 
      hash = BCrypt::Password.create('Password0', :cost => BCrypt::Engine::DEFAULT_COST)
      expect(hash.to_s).to start_with('$2a$10$')
    end
  end

  describe 'Engine' do

    it 'generate_salt' do 
      salt = BCrypt::Engine.generate_salt(BCrypt::Engine::DEFAULT_COST)
      expect(salt).to start_with('$2a$10$')
    end

    it 'hash_secret' do
      salt = '$2a$10$xxxxxxxxxxxxxxxxxxxxxx'
      hash = BCrypt::Engine.hash_secret('Password0', salt)
      expect(hash).to eq('$2a$10$xxxxxxxxxxxxxxxxxxxxxul/XYj4HKy6ex7YlfZ4IiEN5ri.5eCiG')
    end
  end

end

FWIW, we use a forked version of Rails 3, and so are now able to upgrade to BCrypt 3.1.5 gem and that fixed it. I’m not sure why the new CircleCI image was different in this case, but it’s probably not worth worrying about. Better to just move ahead with Ubuntu upgrades and this new xcrypt library.

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.