bcrypt-ruby 2.1.2 → 2.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of bcrypt-ruby might be problematic. Click here for more details.
- data/.gitignore +7 -0
- data/.rspec +3 -0
- data/Gemfile +2 -0
- data/Rakefile +34 -75
- data/bcrypt-ruby.gemspec +28 -0
- data/ext/mri/bcrypt.c +4 -4
- data/ext/mri/bcrypt.h +2 -2
- data/ext/mri/bcrypt_ext.c +3 -3
- data/lib/bcrypt.rb +34 -35
- data/spec/TestBCrypt.java +175 -0
- data/spec/bcrypt/engine_spec.rb +17 -17
- data/spec/bcrypt/password_spec.rb +16 -13
- data/spec/spec_helper.rb +2 -4
- metadata +50 -16
- data/ext/jruby/bcrypt_jruby/BCrypt.class +0 -0
    
        data/.gitignore
    ADDED
    
    
    
        data/.rspec
    ADDED
    
    
    
        data/Gemfile
    ADDED
    
    
    
        data/Rakefile
    CHANGED
    
    | @@ -1,24 +1,12 @@ | |
| 1 | 
            -
             | 
| 2 | 
            -
            require "spec/rake/spectask"
         | 
| 1 | 
            +
            require 'rspec/core/rake_task'
         | 
| 3 2 | 
             
            require 'rake/gempackagetask'
         | 
| 3 | 
            +
            require 'rake/extensiontask'
         | 
| 4 | 
            +
            require 'rake/javaextensiontask'
         | 
| 4 5 | 
             
            require 'rake/contrib/rubyforgepublisher'
         | 
| 5 6 | 
             
            require 'rake/clean'
         | 
| 6 7 | 
             
            require 'rake/rdoctask'
         | 
| 7 | 
            -
            require  | 
| 8 | 
            +
            require 'benchmark'
         | 
| 8 9 |  | 
| 9 | 
            -
            PKG_NAME = "bcrypt-ruby"
         | 
| 10 | 
            -
            PKG_VERSION   = "2.1.2"
         | 
| 11 | 
            -
            PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
         | 
| 12 | 
            -
            PKG_FILES = FileList[
         | 
| 13 | 
            -
              '[A-Z]*',
         | 
| 14 | 
            -
              'lib/**/*.rb', 
         | 
| 15 | 
            -
              'spec/**/*.rb', 
         | 
| 16 | 
            -
              'ext/mri/*.c',
         | 
| 17 | 
            -
              'ext/mri/*.h',
         | 
| 18 | 
            -
              'ext/mri/*.rb',
         | 
| 19 | 
            -
              'ext/jruby/bcrypt_jruby/BCrypt.java',
         | 
| 20 | 
            -
              'ext/jruby/bcrypt_jruby/BCrypt.class'
         | 
| 21 | 
            -
            ]
         | 
| 22 10 | 
             
            CLEAN.include(
         | 
| 23 11 | 
             
              "ext/mri/*.o",
         | 
| 24 12 | 
             
              "ext/mri/*.bundle",
         | 
| @@ -30,91 +18,62 @@ CLOBBER.include( | |
| 30 18 | 
             
              "doc/coverage",
         | 
| 31 19 | 
             
              "pkg"
         | 
| 32 20 | 
             
            )
         | 
| 21 | 
            +
            GEMSPEC = eval(File.read(File.expand_path("../bcrypt-ruby.gemspec", __FILE__)))
         | 
| 33 22 |  | 
| 34 23 | 
             
            task :default => [:compile, :spec]
         | 
| 35 24 |  | 
| 36 25 | 
             
            desc "Run all specs"
         | 
| 37 | 
            -
             | 
| 38 | 
            -
              t. | 
| 39 | 
            -
              t.spec_opts = ['--color','--backtrace','--diff']
         | 
| 26 | 
            +
            RSpec::Core::RakeTask.new do |t|
         | 
| 27 | 
            +
              t.pattern = 'spec/**/*_spec.rb'
         | 
| 40 28 | 
             
            end
         | 
| 41 29 |  | 
| 42 30 | 
             
            desc "Run all specs, with coverage testing"
         | 
| 43 | 
            -
             | 
| 44 | 
            -
              t. | 
| 45 | 
            -
              t.spec_opts = ['--color','--backtrace','--diff']
         | 
| 31 | 
            +
            RSpec::Core::RakeTask.new(:rcov) do |t|
         | 
| 32 | 
            +
              t.pattern = 'spec/**/*_spec.rb'
         | 
| 46 33 | 
             
              t.rcov = true
         | 
| 47 | 
            -
              t. | 
| 34 | 
            +
              t.rcov_path = 'doc/coverage'
         | 
| 48 35 | 
             
              t.rcov_opts = ['--exclude', 'rspec,diff-lcs,rcov,_spec,_helper']
         | 
| 49 36 | 
             
            end
         | 
| 50 37 |  | 
| 51 38 | 
             
            desc 'Generate RDoc'
         | 
| 52 39 | 
             
            rd = Rake::RDocTask.new do |rdoc|
         | 
| 53 40 | 
             
              rdoc.rdoc_dir = 'doc/rdoc'
         | 
| 54 | 
            -
              rdoc.options  | 
| 41 | 
            +
              rdoc.options += GEMSPEC.rdoc_options
         | 
| 55 42 | 
             
              rdoc.template = ENV['TEMPLATE'] if ENV['TEMPLATE']
         | 
| 56 | 
            -
              rdoc.rdoc_files.include( | 
| 43 | 
            +
              rdoc.rdoc_files.include(*GEMSPEC.extra_rdoc_files)
         | 
| 57 44 | 
             
            end
         | 
| 58 45 |  | 
| 59 | 
            -
             | 
| 60 | 
            -
              s.name = PKG_NAME
         | 
| 61 | 
            -
              s.version = PKG_VERSION
         | 
| 62 | 
            -
              s.summary = "OpenBSD's bcrypt() password hashing algorithm."
         | 
| 63 | 
            -
              s.description = <<-EOF
         | 
| 64 | 
            -
                bcrypt() is a sophisticated and secure hash algorithm designed by The OpenBSD project
         | 
| 65 | 
            -
                for hashing passwords. bcrypt-ruby provides a simple, humane wrapper for safely handling
         | 
| 66 | 
            -
                passwords.
         | 
| 67 | 
            -
              EOF
         | 
| 68 | 
            -
             | 
| 69 | 
            -
              s.files = PKG_FILES.to_a
         | 
| 70 | 
            -
              s.require_path = 'lib'
         | 
| 71 | 
            -
             | 
| 72 | 
            -
              s.has_rdoc = true
         | 
| 73 | 
            -
              s.rdoc_options = rd.options
         | 
| 74 | 
            -
              s.extra_rdoc_files = rd.rdoc_files.to_a
         | 
| 75 | 
            -
              
         | 
| 76 | 
            -
              s.extensions = FileList["ext/mri/extconf.rb"].to_a
         | 
| 77 | 
            -
              
         | 
| 78 | 
            -
              s.authors = ["Coda Hale"]
         | 
| 79 | 
            -
              s.email = "coda.hale@gmail.com"
         | 
| 80 | 
            -
              s.homepage = "http://bcrypt-ruby.rubyforge.org"
         | 
| 81 | 
            -
              s.rubyforge_project = "bcrypt-ruby"
         | 
| 82 | 
            -
            end
         | 
| 83 | 
            -
             | 
| 84 | 
            -
            file 'ext/jruby/bcrypt_jruby/BCrypt.class' => ["ext/jruby/bcrypt_jruby/BCrypt.java"] do
         | 
| 85 | 
            -
              Rake::Task['compile:jruby'].invoke
         | 
| 86 | 
            -
            end
         | 
| 87 | 
            -
             | 
| 88 | 
            -
            Rake::GemPackageTask.new(spec) do |pkg|
         | 
| 46 | 
            +
            Rake::GemPackageTask.new(GEMSPEC) do |pkg|
         | 
| 89 47 | 
             
              pkg.need_zip = true
         | 
| 90 48 | 
             
              pkg.need_tar = true
         | 
| 91 49 | 
             
            end
         | 
| 92 50 |  | 
| 93 | 
            -
             | 
| 94 | 
            -
             | 
| 95 | 
            -
             | 
| 51 | 
            +
            if RUBY_PLATFORM =~ /java/
         | 
| 52 | 
            +
              Rake::JavaExtensionTask.new('bcrypt_ext', GEMSPEC) do |ext|
         | 
| 53 | 
            +
                ext.ext_dir = 'ext/jruby'
         | 
| 54 | 
            +
              end
         | 
| 96 55 | 
             
            else
         | 
| 97 | 
            -
               | 
| 98 | 
            -
             | 
| 56 | 
            +
              Rake::ExtensionTask.new("bcrypt_ext", GEMSPEC) do |ext|
         | 
| 57 | 
            +
                ext.ext_dir = 'ext/mri'
         | 
| 58 | 
            +
                ext.cross_compile = true
         | 
| 59 | 
            +
                ext.cross_platform = ['x86-mingw32', 'x86-mswin32-60']
         | 
| 99 60 |  | 
| 100 | 
            -
             | 
| 101 | 
            -
             | 
| 102 | 
            -
             | 
| 103 | 
            -
              
         | 
| 104 | 
            -
              desc "Clean, then compile the MRI extension"
         | 
| 105 | 
            -
              task :mri => :clean do
         | 
| 106 | 
            -
                Dir.chdir('ext/mri') do
         | 
| 107 | 
            -
                  ruby "extconf.rb"
         | 
| 108 | 
            -
                  sh "make"
         | 
| 61 | 
            +
                # inject 1.8/1.9 pure-ruby entry point
         | 
| 62 | 
            +
                ext.cross_compiling do |spec|
         | 
| 63 | 
            +
                  spec.files += ["lib/#{ext.name}.rb"]
         | 
| 109 64 | 
             
                end
         | 
| 110 65 | 
             
              end
         | 
| 111 | 
            -
             | 
| 112 | 
            -
             | 
| 113 | 
            -
             | 
| 114 | 
            -
             | 
| 115 | 
            -
             | 
| 116 | 
            -
                 | 
| 66 | 
            +
            end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
            # Entry point for fat-binary gems on win32
         | 
| 69 | 
            +
            file("lib/bcrypt_ext.rb") do |t|
         | 
| 70 | 
            +
              File.open(t.name, 'wb') do |f|
         | 
| 71 | 
            +
                f.write <<-eoruby
         | 
| 72 | 
            +
            RUBY_VERSION =~ /(\\d+.\\d+)/
         | 
| 73 | 
            +
            require "\#{$1}/#{File.basename(t.name, '.rb')}"
         | 
| 74 | 
            +
                eoruby
         | 
| 117 75 | 
             
              end
         | 
| 76 | 
            +
              at_exit{ FileUtils.rm t.name if File.exists?(t.name) }
         | 
| 118 77 | 
             
            end
         | 
| 119 78 |  | 
| 120 79 | 
             
            desc "Run a set of benchmarks on the compiled extension."
         | 
    
        data/bcrypt-ruby.gemspec
    ADDED
    
    | @@ -0,0 +1,28 @@ | |
| 1 | 
            +
            Gem::Specification.new do |s|
         | 
| 2 | 
            +
              s.name = 'bcrypt-ruby'
         | 
| 3 | 
            +
              s.version = '2.1.3'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              s.summary = "OpenBSD's bcrypt() password hashing algorithm."
         | 
| 6 | 
            +
              s.description = <<-EOF
         | 
| 7 | 
            +
                bcrypt() is a sophisticated and secure hash algorithm designed by The OpenBSD project
         | 
| 8 | 
            +
                for hashing passwords. bcrypt-ruby provides a simple, humane wrapper for safely handling
         | 
| 9 | 
            +
                passwords.
         | 
| 10 | 
            +
              EOF
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              s.files = `git ls-files`.split("\n")
         | 
| 13 | 
            +
              s.require_path = 'lib'
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              s.add_development_dependency 'rake-compiler'
         | 
| 16 | 
            +
              s.add_development_dependency 'rspec'
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              s.has_rdoc = true
         | 
| 19 | 
            +
              s.rdoc_options += ['--title', 'bcrypt-ruby', '--line-numbers', '--inline-source', '--main', 'README']
         | 
| 20 | 
            +
              s.extra_rdoc_files += ['README', 'COPYING', 'CHANGELOG', *Dir['lib/**/*.rb']]
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              s.extensions = 'ext/mri/extconf.rb'
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              s.authors = ["Coda Hale"]
         | 
| 25 | 
            +
              s.email = "coda.hale@gmail.com"
         | 
| 26 | 
            +
              s.homepage = "http://bcrypt-ruby.rubyforge.org"
         | 
| 27 | 
            +
              s.rubyforge_project = "bcrypt-ruby"
         | 
| 28 | 
            +
            end
         | 
    
        data/ext/mri/bcrypt.c
    CHANGED
    
    | @@ -77,10 +77,10 @@ static void encode_salt(char *, uint8_t *, uint16_t, uint8_t); | |
| 77 77 | 
             
            static void encode_base64(uint8_t *, uint8_t *, uint16_t);
         | 
| 78 78 | 
             
            static void decode_base64(uint8_t *, uint16_t, uint8_t *);
         | 
| 79 79 |  | 
| 80 | 
            -
            const  | 
| 80 | 
            +
            static const uint8_t Base64Code[] =
         | 
| 81 81 | 
             
            "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
         | 
| 82 82 |  | 
| 83 | 
            -
            const  | 
| 83 | 
            +
            static const uint8_t index_64[128] = {
         | 
| 84 84 | 
             
            	255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
         | 
| 85 85 | 
             
            	255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
         | 
| 86 86 | 
             
            	255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
         | 
| @@ -150,7 +150,7 @@ encode_salt(char *salt, uint8_t *csalt, uint16_t clen, uint8_t logr) | |
| 150 150 | 
             
             */
         | 
| 151 151 |  | 
| 152 152 | 
             
            char   *
         | 
| 153 | 
            -
             | 
| 153 | 
            +
            ruby_bcrypt_gensalt(char *output, uint8_t log_rounds, uint8_t *rseed)
         | 
| 154 154 | 
             
            {
         | 
| 155 155 | 
             
            	if (log_rounds < 4)
         | 
| 156 156 | 
             
            		log_rounds = 4;
         | 
| @@ -164,7 +164,7 @@ bcrypt_gensalt(char *output, uint8_t log_rounds, uint8_t *rseed) | |
| 164 164 | 
             
               i.e. $2$04$iwouldntknowwhattosayetKdJ6iFtacBqJdKe6aW7ou */
         | 
| 165 165 |  | 
| 166 166 | 
             
            char   *
         | 
| 167 | 
            -
             | 
| 167 | 
            +
            ruby_bcrypt(char *output, const char *key, const char *salt)
         | 
| 168 168 | 
             
            {
         | 
| 169 169 | 
             
            	blf_ctx state;
         | 
| 170 170 | 
             
            	uint32_t rounds, i, k;
         | 
    
        data/ext/mri/bcrypt.h
    CHANGED
    
    | @@ -51,7 +51,7 @@ | |
| 51 51 | 
             
             *        cryptographically secure random source.
         | 
| 52 52 | 
             
             * Returns: output
         | 
| 53 53 | 
             
             */
         | 
| 54 | 
            -
            char * | 
| 54 | 
            +
            char *ruby_bcrypt_gensalt(char *output, uint8_t log_rounds, uint8_t *rseed);
         | 
| 55 55 |  | 
| 56 56 | 
             
            /*
         | 
| 57 57 | 
             
             * Given a secret and a salt, generates a salted hash (which you can then store safely).
         | 
| @@ -62,6 +62,6 @@ char *bcrypt_gensalt(char *output, uint8_t log_rounds, uint8_t *rseed); | |
| 62 62 | 
             
             * salt: The salt, as generated by bcrypt_gensalt().
         | 
| 63 63 | 
             
             * Returns: output on success, NULL on error.
         | 
| 64 64 | 
             
             */
         | 
| 65 | 
            -
            char * | 
| 65 | 
            +
            char *ruby_bcrypt(char *output, const char *key, const char *salt);
         | 
| 66 66 |  | 
| 67 67 | 
             
            #endif /* _BCRYPT_H_ */
         | 
    
        data/ext/mri/bcrypt_ext.c
    CHANGED
    
    | @@ -30,7 +30,7 @@ static VALUE cBCryptEngine; | |
| 30 30 |  | 
| 31 31 | 
             
            	static VALUE bcrypt_wrapper(void *_args) {
         | 
| 32 32 | 
             
            		BCryptArguments *args = (BCryptArguments *)_args;
         | 
| 33 | 
            -
            		return (VALUE) | 
| 33 | 
            +
            		return (VALUE)ruby_bcrypt(args->output, args->key, args->salt);
         | 
| 34 34 | 
             
            	}
         | 
| 35 35 |  | 
| 36 36 | 
             
            #endif /* RUBY_1_9 */
         | 
| @@ -41,7 +41,7 @@ static VALUE bc_salt(VALUE self, VALUE cost, VALUE seed) { | |
| 41 41 | 
             
            	int icost = NUM2INT(cost);
         | 
| 42 42 | 
             
            	char salt[BCRYPT_SALT_OUTPUT_SIZE];
         | 
| 43 43 |  | 
| 44 | 
            -
            	 | 
| 44 | 
            +
            	ruby_bcrypt_gensalt(salt, icost, (uint8_t *)RSTRING_PTR(seed));
         | 
| 45 45 | 
             
            	return rb_str_new2(salt);
         | 
| 46 46 | 
             
            }
         | 
| 47 47 |  | 
| @@ -70,7 +70,7 @@ static VALUE bc_crypt(VALUE self, VALUE key, VALUE salt, VALUE cost) { | |
| 70 70 | 
             
            		/* otherwise, fallback to the non-GIL-unlocking code, just like on Ruby 1.8 */
         | 
| 71 71 | 
             
            	#endif
         | 
| 72 72 |  | 
| 73 | 
            -
            	if ( | 
| 73 | 
            +
            	if (ruby_bcrypt(output, safeguarded, (char *)RSTRING_PTR(salt)) != NULL) {
         | 
| 74 74 | 
             
            		return rb_str_new2(output);
         | 
| 75 75 | 
             
            	} else {
         | 
| 76 76 | 
             
            		return Qnil;
         | 
    
        data/lib/bcrypt.rb
    CHANGED
    
    | @@ -2,13 +2,12 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            if RUBY_PLATFORM == "java"
         | 
| 4 4 | 
             
              require 'java'
         | 
| 5 | 
            -
              $CLASSPATH << File.expand_path(File.join(File.dirname(__FILE__), "..", "ext", "jruby"))
         | 
| 6 5 | 
             
            else
         | 
| 7 | 
            -
              $LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(__FILE__), "..", "ext", "mri")))
         | 
| 8 | 
            -
              require "bcrypt_ext"
         | 
| 9 6 | 
             
              require "openssl"
         | 
| 10 7 | 
             
            end
         | 
| 11 8 |  | 
| 9 | 
            +
            require 'bcrypt_ext'
         | 
| 10 | 
            +
             | 
| 12 11 | 
             
            # A Ruby library implementing OpenBSD's bcrypt()/crypt_blowfish algorithm for
         | 
| 13 12 | 
             
            # hashing passwords.
         | 
| 14 13 | 
             
            module BCrypt
         | 
| @@ -18,7 +17,7 @@ module BCrypt | |
| 18 17 | 
             
                class InvalidCost   < StandardError; end  # The cost parameter provided to bcrypt() is invalid.
         | 
| 19 18 | 
             
                class InvalidSecret < StandardError; end  # The secret parameter provided to bcrypt() is invalid.
         | 
| 20 19 | 
             
              end
         | 
| 21 | 
            -
             | 
| 20 | 
            +
             | 
| 22 21 | 
             
              # A Ruby wrapper for the bcrypt() C extension calls and the Java calls.
         | 
| 23 22 | 
             
              class Engine
         | 
| 24 23 | 
             
                # The default computational expense parameter.
         | 
| @@ -27,14 +26,14 @@ module BCrypt | |
| 27 26 | 
             
                MIN_COST        = 4
         | 
| 28 27 | 
             
                # Maximum possible size of bcrypt() salts.
         | 
| 29 28 | 
             
                MAX_SALT_LENGTH = 16
         | 
| 30 | 
            -
             | 
| 29 | 
            +
             | 
| 31 30 | 
             
                if RUBY_PLATFORM != "java"
         | 
| 32 31 | 
             
                  # C-level routines which, if they don't get the right input, will crash the
         | 
| 33 32 | 
             
                  # hell out of the Ruby process.
         | 
| 34 33 | 
             
                  private_class_method :__bc_salt
         | 
| 35 34 | 
             
                  private_class_method :__bc_crypt
         | 
| 36 35 | 
             
                end
         | 
| 37 | 
            -
             | 
| 36 | 
            +
             | 
| 38 37 | 
             
                # Given a secret and a valid salt (see BCrypt::Engine.generate_salt) calculates
         | 
| 39 38 | 
             
                # a bcrypt() password hash.
         | 
| 40 39 | 
             
                def self.hash_secret(secret, salt, cost = nil)
         | 
| @@ -43,7 +42,7 @@ module BCrypt | |
| 43 42 | 
             
                      if cost.nil?
         | 
| 44 43 | 
             
                        cost = autodetect_cost(salt)
         | 
| 45 44 | 
             
                      end
         | 
| 46 | 
            -
             | 
| 45 | 
            +
             | 
| 47 46 | 
             
                      if RUBY_PLATFORM == "java"
         | 
| 48 47 | 
             
                        Java.bcrypt_jruby.BCrypt.hashpw(secret.to_s, salt.to_s)
         | 
| 49 48 | 
             
                      else
         | 
| @@ -56,7 +55,7 @@ module BCrypt | |
| 56 55 | 
             
                    raise Errors::InvalidSecret.new("invalid secret")
         | 
| 57 56 | 
             
                  end
         | 
| 58 57 | 
             
                end
         | 
| 59 | 
            -
             | 
| 58 | 
            +
             | 
| 60 59 | 
             
                # Generates a random salt with a given computational cost.
         | 
| 61 60 | 
             
                def self.generate_salt(cost = DEFAULT_COST)
         | 
| 62 61 | 
             
                  cost = cost.to_i
         | 
| @@ -73,27 +72,27 @@ module BCrypt | |
| 73 72 | 
             
                    raise Errors::InvalidCost.new("cost must be numeric and > 0")
         | 
| 74 73 | 
             
                  end
         | 
| 75 74 | 
             
                end
         | 
| 76 | 
            -
             | 
| 75 | 
            +
             | 
| 77 76 | 
             
                # Returns true if +salt+ is a valid bcrypt() salt, false if not.
         | 
| 78 77 | 
             
                def self.valid_salt?(salt)
         | 
| 79 78 | 
             
                  salt =~ /^\$[0-9a-z]{2,}\$[0-9]{2,}\$[A-Za-z0-9\.\/]{22,}$/
         | 
| 80 79 | 
             
                end
         | 
| 81 | 
            -
             | 
| 80 | 
            +
             | 
| 82 81 | 
             
                # Returns true if +secret+ is a valid bcrypt() secret, false if not.
         | 
| 83 82 | 
             
                def self.valid_secret?(secret)
         | 
| 84 83 | 
             
                  secret.respond_to?(:to_s)
         | 
| 85 84 | 
             
                end
         | 
| 86 | 
            -
             | 
| 85 | 
            +
             | 
| 87 86 | 
             
                # Returns the cost factor which will result in computation times less than +upper_time_limit_in_ms+.
         | 
| 88 | 
            -
                # | 
| 87 | 
            +
                #
         | 
| 89 88 | 
             
                # Example:
         | 
| 90 | 
            -
                # | 
| 89 | 
            +
                #
         | 
| 91 90 | 
             
                #   BCrypt.calibrate(200)  #=> 10
         | 
| 92 91 | 
             
                #   BCrypt.calibrate(1000) #=> 12
         | 
| 93 | 
            -
                # | 
| 92 | 
            +
                #
         | 
| 94 93 | 
             
                #   # should take less than 200ms
         | 
| 95 94 | 
             
                #   BCrypt::Password.create("woo", :cost => 10)
         | 
| 96 | 
            -
                # | 
| 95 | 
            +
                #
         | 
| 97 96 | 
             
                #   # should take less than 1000ms
         | 
| 98 97 | 
             
                #   BCrypt::Password.create("woo", :cost => 12)
         | 
| 99 98 | 
             
                def self.calibrate(upper_time_limit_in_ms)
         | 
| @@ -104,88 +103,88 @@ module BCrypt | |
| 104 103 | 
             
                    return i if end_time * 1_000 > upper_time_limit_in_ms
         | 
| 105 104 | 
             
                  end
         | 
| 106 105 | 
             
                end
         | 
| 107 | 
            -
             | 
| 106 | 
            +
             | 
| 108 107 | 
             
                # Autodetects the cost from the salt string.
         | 
| 109 108 | 
             
                def self.autodetect_cost(salt)
         | 
| 110 109 | 
             
                  salt[4..5].to_i
         | 
| 111 110 | 
             
                end
         | 
| 112 111 | 
             
              end
         | 
| 113 | 
            -
             | 
| 112 | 
            +
             | 
| 114 113 | 
             
              # A password management class which allows you to safely store users' passwords and compare them.
         | 
| 115 | 
            -
              # | 
| 114 | 
            +
              #
         | 
| 116 115 | 
             
              # Example usage:
         | 
| 117 | 
            -
              # | 
| 116 | 
            +
              #
         | 
| 118 117 | 
             
              #   include BCrypt
         | 
| 119 | 
            -
              # | 
| 118 | 
            +
              #
         | 
| 120 119 | 
             
              #   # hash a user's password  
         | 
| 121 120 | 
             
              #   @password = Password.create("my grand secret")
         | 
| 122 121 | 
             
              #   @password #=> "$2a$10$GtKs1Kbsig8ULHZzO1h2TetZfhO4Fmlxphp8bVKnUlZCBYYClPohG"
         | 
| 123 | 
            -
              # | 
| 122 | 
            +
              #
         | 
| 124 123 | 
             
              #   # store it safely
         | 
| 125 124 | 
             
              #   @user.update_attribute(:password, @password)
         | 
| 126 | 
            -
              # | 
| 125 | 
            +
              #
         | 
| 127 126 | 
             
              #   # read it back
         | 
| 128 127 | 
             
              #   @user.reload!
         | 
| 129 128 | 
             
              #   @db_password = Password.new(@user.password)
         | 
| 130 | 
            -
              # | 
| 129 | 
            +
              #
         | 
| 131 130 | 
             
              #   # compare it after retrieval
         | 
| 132 131 | 
             
              #   @db_password == "my grand secret" #=> true
         | 
| 133 132 | 
             
              #   @db_password == "a paltry guess"  #=> false
         | 
| 134 | 
            -
              # | 
| 133 | 
            +
              #
         | 
| 135 134 | 
             
              class Password < String
         | 
| 136 135 | 
             
                # The hash portion of the stored password hash.
         | 
| 137 | 
            -
                attr_reader : | 
| 136 | 
            +
                attr_reader :checksum
         | 
| 138 137 | 
             
                # The salt of the store password hash (including version and cost).
         | 
| 139 138 | 
             
                attr_reader :salt
         | 
| 140 139 | 
             
                # The version of the bcrypt() algorithm used to create the hash.
         | 
| 141 140 | 
             
                attr_reader :version
         | 
| 142 141 | 
             
                # The cost factor used to create the hash.
         | 
| 143 142 | 
             
                attr_reader :cost
         | 
| 144 | 
            -
             | 
| 143 | 
            +
             | 
| 145 144 | 
             
                class << self
         | 
| 146 145 | 
             
                  # Hashes a secret, returning a BCrypt::Password instance. Takes an optional <tt>:cost</tt> option, which is a
         | 
| 147 146 | 
             
                  # logarithmic variable which determines how computational expensive the hash is to calculate (a <tt>:cost</tt> of
         | 
| 148 147 | 
             
                  # 4 is twice as much work as a <tt>:cost</tt> of 3). The higher the <tt>:cost</tt> the harder it becomes for
         | 
| 149 148 | 
             
                  # attackers to try to guess passwords (even if a copy of your database is stolen), but the slower it is to check
         | 
| 150 149 | 
             
                  # users' passwords.
         | 
| 151 | 
            -
                  # | 
| 150 | 
            +
                  #
         | 
| 152 151 | 
             
                  # Example:
         | 
| 153 | 
            -
                  # | 
| 152 | 
            +
                  #
         | 
| 154 153 | 
             
                  #   @password = BCrypt::Password.create("my secret", :cost => 13)
         | 
| 155 154 | 
             
                  def create(secret, options = { :cost => BCrypt::Engine::DEFAULT_COST })
         | 
| 156 155 | 
             
                    Password.new(BCrypt::Engine.hash_secret(secret, BCrypt::Engine.generate_salt(options[:cost]), options[:cost]))
         | 
| 157 156 | 
             
                  end
         | 
| 158 157 | 
             
                end
         | 
| 159 | 
            -
             | 
| 158 | 
            +
             | 
| 160 159 | 
             
                # Initializes a BCrypt::Password instance with the data from a stored hash.
         | 
| 161 160 | 
             
                def initialize(raw_hash)
         | 
| 162 161 | 
             
                  if valid_hash?(raw_hash)
         | 
| 163 162 | 
             
                    self.replace(raw_hash)
         | 
| 164 | 
            -
                    @version, @cost, @salt, @ | 
| 163 | 
            +
                    @version, @cost, @salt, @checksum = split_hash(self)
         | 
| 165 164 | 
             
                  else
         | 
| 166 165 | 
             
                    raise Errors::InvalidHash.new("invalid hash")
         | 
| 167 166 | 
             
                  end
         | 
| 168 167 | 
             
                end
         | 
| 169 | 
            -
             | 
| 168 | 
            +
             | 
| 170 169 | 
             
                # Compares a potential secret against the hash. Returns true if the secret is the original secret, false otherwise.
         | 
| 171 170 | 
             
                def ==(secret)
         | 
| 172 171 | 
             
                  super(BCrypt::Engine.hash_secret(secret, @salt))
         | 
| 173 172 | 
             
                end
         | 
| 174 173 | 
             
                alias_method :is_password?, :==
         | 
| 175 | 
            -
             | 
| 174 | 
            +
             | 
| 176 175 | 
             
              private
         | 
| 177 176 | 
             
                # Returns true if +h+ is a valid hash.
         | 
| 178 177 | 
             
                def valid_hash?(h)
         | 
| 179 178 | 
             
                  h =~ /^\$[0-9a-z]{2}\$[0-9]{2}\$[A-Za-z0-9\.\/]{53}$/
         | 
| 180 179 | 
             
                end
         | 
| 181 | 
            -
             | 
| 180 | 
            +
             | 
| 182 181 | 
             
                # call-seq:
         | 
| 183 182 | 
             
                #   split_hash(raw_hash) -> version, cost, salt, hash
         | 
| 184 | 
            -
                # | 
| 183 | 
            +
                #
         | 
| 185 184 | 
             
                # Splits +h+ into version, cost, salt, and hash and returns them in that order.
         | 
| 186 185 | 
             
                def split_hash(h)
         | 
| 187 186 | 
             
                  b, v, c, mash = h.split('$')
         | 
| 188 | 
            -
                  return v, c.to_i, h[0, 29], mash[-31, 31]
         | 
| 187 | 
            +
                  return v, c.to_i, h[0, 29].to_str, mash[-31, 31].to_str
         | 
| 189 188 | 
             
                end
         | 
| 190 189 | 
             
              end
         | 
| 191 190 | 
             
            end
         | 
| @@ -0,0 +1,175 @@ | |
| 1 | 
            +
            // Copyright (c) 2006 Damien Miller <djm@mindrot.org>
         | 
| 2 | 
            +
            //
         | 
| 3 | 
            +
            // Permission to use, copy, modify, and distribute this software for any
         | 
| 4 | 
            +
            // purpose with or without fee is hereby granted, provided that the above
         | 
| 5 | 
            +
            // copyright notice and this permission notice appear in all copies.
         | 
| 6 | 
            +
            //
         | 
| 7 | 
            +
            // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
         | 
| 8 | 
            +
            // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
         | 
| 9 | 
            +
            // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
         | 
| 10 | 
            +
            // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
         | 
| 11 | 
            +
            // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
         | 
| 12 | 
            +
            // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
         | 
| 13 | 
            +
            // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            import junit.framework.TestCase;
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            /**
         | 
| 18 | 
            +
             * JUnit unit tests for BCrypt routines
         | 
| 19 | 
            +
             * @author Damien Miller
         | 
| 20 | 
            +
             * @version 0.2
         | 
| 21 | 
            +
             */
         | 
| 22 | 
            +
            public class TestBCrypt extends TestCase {
         | 
| 23 | 
            +
            	String test_vectors[][] = {
         | 
| 24 | 
            +
            			{ "", 
         | 
| 25 | 
            +
            			"$2a$06$DCq7YPn5Rq63x1Lad4cll.",
         | 
| 26 | 
            +
            			"$2a$06$DCq7YPn5Rq63x1Lad4cll.TV4S6ytwfsfvkgY8jIucDrjc8deX1s." },
         | 
| 27 | 
            +
            			{ "",
         | 
| 28 | 
            +
            			"$2a$08$HqWuK6/Ng6sg9gQzbLrgb.",
         | 
| 29 | 
            +
            			"$2a$08$HqWuK6/Ng6sg9gQzbLrgb.Tl.ZHfXLhvt/SgVyWhQqgqcZ7ZuUtye" },
         | 
| 30 | 
            +
            			{ "",
         | 
| 31 | 
            +
            			"$2a$10$k1wbIrmNyFAPwPVPSVa/ze",
         | 
| 32 | 
            +
            			"$2a$10$k1wbIrmNyFAPwPVPSVa/zecw2BCEnBwVS2GbrmgzxFUOqW9dk4TCW" },
         | 
| 33 | 
            +
            			{ "",
         | 
| 34 | 
            +
            			"$2a$12$k42ZFHFWqBp3vWli.nIn8u",
         | 
| 35 | 
            +
            			"$2a$12$k42ZFHFWqBp3vWli.nIn8uYyIkbvYRvodzbfbK18SSsY.CsIQPlxO" },
         | 
| 36 | 
            +
            			{ "a",
         | 
| 37 | 
            +
            			"$2a$06$m0CrhHm10qJ3lXRY.5zDGO",
         | 
| 38 | 
            +
            			"$2a$06$m0CrhHm10qJ3lXRY.5zDGO3rS2KdeeWLuGmsfGlMfOxih58VYVfxe" },
         | 
| 39 | 
            +
            			{ "a", 
         | 
| 40 | 
            +
            			"$2a$08$cfcvVd2aQ8CMvoMpP2EBfe",
         | 
| 41 | 
            +
            			"$2a$08$cfcvVd2aQ8CMvoMpP2EBfeodLEkkFJ9umNEfPD18.hUF62qqlC/V." },
         | 
| 42 | 
            +
            			{ "a",
         | 
| 43 | 
            +
            			"$2a$10$k87L/MF28Q673VKh8/cPi.",
         | 
| 44 | 
            +
            			"$2a$10$k87L/MF28Q673VKh8/cPi.SUl7MU/rWuSiIDDFayrKk/1tBsSQu4u" },
         | 
| 45 | 
            +
            			{ "a",
         | 
| 46 | 
            +
            			"$2a$12$8NJH3LsPrANStV6XtBakCe",
         | 
| 47 | 
            +
            			"$2a$12$8NJH3LsPrANStV6XtBakCez0cKHXVxmvxIlcz785vxAIZrihHZpeS" },
         | 
| 48 | 
            +
            			{ "abc",
         | 
| 49 | 
            +
            			"$2a$06$If6bvum7DFjUnE9p2uDeDu",
         | 
| 50 | 
            +
            			"$2a$06$If6bvum7DFjUnE9p2uDeDu0YHzrHM6tf.iqN8.yx.jNN1ILEf7h0i" },
         | 
| 51 | 
            +
            			{ "abc",
         | 
| 52 | 
            +
            			"$2a$08$Ro0CUfOqk6cXEKf3dyaM7O",
         | 
| 53 | 
            +
            			"$2a$08$Ro0CUfOqk6cXEKf3dyaM7OhSCvnwM9s4wIX9JeLapehKK5YdLxKcm" },
         | 
| 54 | 
            +
            			{ "abc",
         | 
| 55 | 
            +
            			"$2a$10$WvvTPHKwdBJ3uk0Z37EMR.",
         | 
| 56 | 
            +
            			"$2a$10$WvvTPHKwdBJ3uk0Z37EMR.hLA2W6N9AEBhEgrAOljy2Ae5MtaSIUi" },
         | 
| 57 | 
            +
            			{ "abc",
         | 
| 58 | 
            +
            			"$2a$12$EXRkfkdmXn2gzds2SSitu.",
         | 
| 59 | 
            +
            			"$2a$12$EXRkfkdmXn2gzds2SSitu.MW9.gAVqa9eLS1//RYtYCmB1eLHg.9q" },
         | 
| 60 | 
            +
            			{ "abcdefghijklmnopqrstuvwxyz",
         | 
| 61 | 
            +
            			"$2a$06$.rCVZVOThsIa97pEDOxvGu",
         | 
| 62 | 
            +
            			"$2a$06$.rCVZVOThsIa97pEDOxvGuRRgzG64bvtJ0938xuqzv18d3ZpQhstC" },
         | 
| 63 | 
            +
            			{ "abcdefghijklmnopqrstuvwxyz",
         | 
| 64 | 
            +
            			"$2a$08$aTsUwsyowQuzRrDqFflhge",
         | 
| 65 | 
            +
            			"$2a$08$aTsUwsyowQuzRrDqFflhgekJ8d9/7Z3GV3UcgvzQW3J5zMyrTvlz." },
         | 
| 66 | 
            +
            			{ "abcdefghijklmnopqrstuvwxyz",
         | 
| 67 | 
            +
            			"$2a$10$fVH8e28OQRj9tqiDXs1e1u",
         | 
| 68 | 
            +
            			"$2a$10$fVH8e28OQRj9tqiDXs1e1uxpsjN0c7II7YPKXua2NAKYvM6iQk7dq" },
         | 
| 69 | 
            +
            			{ "abcdefghijklmnopqrstuvwxyz",
         | 
| 70 | 
            +
            			"$2a$12$D4G5f18o7aMMfwasBL7Gpu",
         | 
| 71 | 
            +
            			"$2a$12$D4G5f18o7aMMfwasBL7GpuQWuP3pkrZrOAnqP.bmezbMng.QwJ/pG" },
         | 
| 72 | 
            +
            			{ "~!@#$%^&*()      ~!@#$%^&*()PNBFRD",
         | 
| 73 | 
            +
            			"$2a$06$fPIsBO8qRqkjj273rfaOI.",
         | 
| 74 | 
            +
            			"$2a$06$fPIsBO8qRqkjj273rfaOI.HtSV9jLDpTbZn782DC6/t7qT67P6FfO" },
         | 
| 75 | 
            +
            			{ "~!@#$%^&*()      ~!@#$%^&*()PNBFRD",
         | 
| 76 | 
            +
            			"$2a$08$Eq2r4G/76Wv39MzSX262hu",
         | 
| 77 | 
            +
            			"$2a$08$Eq2r4G/76Wv39MzSX262huzPz612MZiYHVUJe/OcOql2jo4.9UxTW" },
         | 
| 78 | 
            +
            			{ "~!@#$%^&*()      ~!@#$%^&*()PNBFRD",
         | 
| 79 | 
            +
            			"$2a$10$LgfYWkbzEvQ4JakH7rOvHe",
         | 
| 80 | 
            +
            			"$2a$10$LgfYWkbzEvQ4JakH7rOvHe0y8pHKF9OaFgwUZ2q7W2FFZmZzJYlfS" },
         | 
| 81 | 
            +
            			{ "~!@#$%^&*()      ~!@#$%^&*()PNBFRD",
         | 
| 82 | 
            +
            			"$2a$12$WApznUOJfkEGSmYRfnkrPO",
         | 
| 83 | 
            +
            			"$2a$12$WApznUOJfkEGSmYRfnkrPOr466oFDCaj4b6HY3EXGvfxm43seyhgC" },
         | 
| 84 | 
            +
            		};
         | 
| 85 | 
            +
             | 
| 86 | 
            +
            	/**
         | 
| 87 | 
            +
            	 * Entry point for unit tests
         | 
| 88 | 
            +
            	 * @param args unused
         | 
| 89 | 
            +
            	 */
         | 
| 90 | 
            +
            	public static void main(String[] args) {
         | 
| 91 | 
            +
            		junit.textui.TestRunner.run(TestBCrypt.class);
         | 
| 92 | 
            +
            	}
         | 
| 93 | 
            +
             | 
| 94 | 
            +
            	/**
         | 
| 95 | 
            +
            	 * Test method for 'BCrypt.hashpw(String, String)'
         | 
| 96 | 
            +
            	 */
         | 
| 97 | 
            +
            	public void testHashpw() {
         | 
| 98 | 
            +
            		System.out.print("BCrypt.hashpw(): ");
         | 
| 99 | 
            +
            		for (int i = 0; i < test_vectors.length; i++) {
         | 
| 100 | 
            +
            			String plain = test_vectors[i][0];
         | 
| 101 | 
            +
            			String salt = test_vectors[i][1];
         | 
| 102 | 
            +
            			String expected = test_vectors[i][2];
         | 
| 103 | 
            +
            			String hashed = BCrypt.hashpw(plain, salt);
         | 
| 104 | 
            +
            			assertEquals(hashed, expected);
         | 
| 105 | 
            +
            			System.out.print(".");
         | 
| 106 | 
            +
            		}
         | 
| 107 | 
            +
            		System.out.println("");
         | 
| 108 | 
            +
            	}
         | 
| 109 | 
            +
             | 
| 110 | 
            +
            	/**
         | 
| 111 | 
            +
            	 * Test method for 'BCrypt.gensalt(int)'
         | 
| 112 | 
            +
            	 */
         | 
| 113 | 
            +
            	public void testGensaltInt() {
         | 
| 114 | 
            +
            		System.out.print("BCrypt.gensalt(log_rounds):");
         | 
| 115 | 
            +
            		for (int i = 4; i <= 12; i++) {
         | 
| 116 | 
            +
            			System.out.print(" " + Integer.toString(i) + ":");
         | 
| 117 | 
            +
            			for (int j = 0; j < test_vectors.length; j += 4) {
         | 
| 118 | 
            +
            				String plain = test_vectors[j][0];
         | 
| 119 | 
            +
            				String salt = BCrypt.gensalt(i);
         | 
| 120 | 
            +
            				String hashed1 = BCrypt.hashpw(plain, salt);
         | 
| 121 | 
            +
            				String hashed2 = BCrypt.hashpw(plain, hashed1);
         | 
| 122 | 
            +
            				assertEquals(hashed1, hashed2);
         | 
| 123 | 
            +
            				System.out.print(".");
         | 
| 124 | 
            +
            			}
         | 
| 125 | 
            +
            		}
         | 
| 126 | 
            +
            		System.out.println("");
         | 
| 127 | 
            +
            	}
         | 
| 128 | 
            +
             | 
| 129 | 
            +
            	/**
         | 
| 130 | 
            +
            	 * Test method for 'BCrypt.gensalt()'
         | 
| 131 | 
            +
            	 */
         | 
| 132 | 
            +
            	public void testGensalt() {
         | 
| 133 | 
            +
            		System.out.print("BCrypt.gensalt(): ");
         | 
| 134 | 
            +
            		for (int i = 0; i < test_vectors.length; i += 4) {
         | 
| 135 | 
            +
            			String plain = test_vectors[i][0];
         | 
| 136 | 
            +
            			String salt = BCrypt.gensalt();
         | 
| 137 | 
            +
            			String hashed1 = BCrypt.hashpw(plain, salt);
         | 
| 138 | 
            +
            			String hashed2 = BCrypt.hashpw(plain, hashed1);
         | 
| 139 | 
            +
            			assertEquals(hashed1, hashed2);
         | 
| 140 | 
            +
            			System.out.print(".");
         | 
| 141 | 
            +
            		}
         | 
| 142 | 
            +
            		System.out.println("");
         | 
| 143 | 
            +
            	}
         | 
| 144 | 
            +
             | 
| 145 | 
            +
            	/**
         | 
| 146 | 
            +
            	 * Test method for 'BCrypt.checkpw(String, String)'
         | 
| 147 | 
            +
            	 * expecting success
         | 
| 148 | 
            +
            	 */
         | 
| 149 | 
            +
            	public void testCheckpw_success() {
         | 
| 150 | 
            +
            		System.out.print("BCrypt.checkpw w/ good passwords: ");
         | 
| 151 | 
            +
            		for (int i = 0; i < test_vectors.length; i++) {
         | 
| 152 | 
            +
            			String plain = test_vectors[i][0];
         | 
| 153 | 
            +
            			String expected = test_vectors[i][2];
         | 
| 154 | 
            +
            			assertTrue(BCrypt.checkpw(plain, expected));
         | 
| 155 | 
            +
            			System.out.print(".");
         | 
| 156 | 
            +
            		}
         | 
| 157 | 
            +
            		System.out.println("");
         | 
| 158 | 
            +
            	}
         | 
| 159 | 
            +
             | 
| 160 | 
            +
            	/**
         | 
| 161 | 
            +
            	 * Test method for 'BCrypt.checkpw(String, String)'
         | 
| 162 | 
            +
            	 * expecting failure
         | 
| 163 | 
            +
            	 */
         | 
| 164 | 
            +
            	public void testCheckpw_failure() {
         | 
| 165 | 
            +
            		System.out.print("BCrypt.checkpw w/ bad passwords: ");
         | 
| 166 | 
            +
            		for (int i = 0; i < test_vectors.length; i++) {
         | 
| 167 | 
            +
            			int broken_index = (i + 4) % test_vectors.length;
         | 
| 168 | 
            +
            			String plain = test_vectors[i][0];
         | 
| 169 | 
            +
            			String expected = test_vectors[broken_index][2];
         | 
| 170 | 
            +
            			assertFalse(BCrypt.checkpw(plain, expected));
         | 
| 171 | 
            +
            			System.out.print(".");
         | 
| 172 | 
            +
            		}
         | 
| 173 | 
            +
            		System.out.println("");
         | 
| 174 | 
            +
            	}
         | 
| 175 | 
            +
            }
         | 
    
        data/spec/bcrypt/engine_spec.rb
    CHANGED
    
    | @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper"))
         | 
| 2 2 |  | 
| 3 | 
            -
             | 
| 3 | 
            +
            describe "The BCrypt engine" do
         | 
| 4 4 | 
             
              specify "should calculate the optimal cost factor to fit in a specific time" do
         | 
| 5 5 | 
             
                first = BCrypt::Engine.calibrate(100)
         | 
| 6 6 | 
             
                second = BCrypt::Engine.calibrate(400)
         | 
| @@ -8,64 +8,64 @@ context "The BCrypt engine" do | |
| 8 8 | 
             
              end
         | 
| 9 9 | 
             
            end
         | 
| 10 10 |  | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 11 | 
            +
            describe "Generating BCrypt salts" do
         | 
| 12 | 
            +
             | 
| 13 13 | 
             
              specify "should produce strings" do
         | 
| 14 14 | 
             
                BCrypt::Engine.generate_salt.should be_an_instance_of(String)
         | 
| 15 15 | 
             
              end
         | 
| 16 | 
            -
             | 
| 16 | 
            +
             | 
| 17 17 | 
             
              specify "should produce random data" do
         | 
| 18 18 | 
             
                BCrypt::Engine.generate_salt.should_not equal(BCrypt::Engine.generate_salt)
         | 
| 19 19 | 
             
              end
         | 
| 20 | 
            -
             | 
| 20 | 
            +
             | 
| 21 21 | 
             
              specify "should raise a InvalidCostError if the cost parameter isn't numeric" do
         | 
| 22 22 | 
             
                lambda { BCrypt::Engine.generate_salt('woo') }.should raise_error(BCrypt::Errors::InvalidCost)
         | 
| 23 23 | 
             
              end
         | 
| 24 | 
            -
             | 
| 24 | 
            +
             | 
| 25 25 | 
             
              specify "should raise a InvalidCostError if the cost parameter isn't greater than 0" do
         | 
| 26 26 | 
             
                lambda { BCrypt::Engine.generate_salt(-1) }.should raise_error(BCrypt::Errors::InvalidCost)
         | 
| 27 27 | 
             
              end
         | 
| 28 28 | 
             
            end
         | 
| 29 29 |  | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 30 | 
            +
            describe "Autodetecting of salt cost" do
         | 
| 31 | 
            +
             | 
| 32 32 | 
             
              specify "should work" do
         | 
| 33 33 | 
             
                BCrypt::Engine.autodetect_cost("$2a$08$hRx2IVeHNsTSYYtUWn61Ou").should == 8
         | 
| 34 34 | 
             
                BCrypt::Engine.autodetect_cost("$2a$05$XKd1bMnLgUnc87qvbAaCUu").should == 5
         | 
| 35 35 | 
             
                BCrypt::Engine.autodetect_cost("$2a$13$Lni.CZ6z5A7344POTFBBV.").should == 13
         | 
| 36 36 | 
             
              end
         | 
| 37 | 
            -
             | 
| 37 | 
            +
             | 
| 38 38 | 
             
            end
         | 
| 39 39 |  | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 40 | 
            +
            describe "Generating BCrypt hashes" do
         | 
| 41 | 
            +
             | 
| 42 42 | 
             
              class MyInvalidSecret
         | 
| 43 43 | 
             
                undef to_s
         | 
| 44 44 | 
             
              end
         | 
| 45 | 
            -
             | 
| 45 | 
            +
             | 
| 46 46 | 
             
              before :each do
         | 
| 47 47 | 
             
                @salt = BCrypt::Engine.generate_salt(4)
         | 
| 48 48 | 
             
                @password = "woo"
         | 
| 49 49 | 
             
              end
         | 
| 50 | 
            -
             | 
| 50 | 
            +
             | 
| 51 51 | 
             
              specify "should produce a string" do
         | 
| 52 52 | 
             
                BCrypt::Engine.hash_secret(@password, @salt).should be_an_instance_of(String)
         | 
| 53 53 | 
             
              end
         | 
| 54 | 
            -
             | 
| 54 | 
            +
             | 
| 55 55 | 
             
              specify "should raise an InvalidSalt error if the salt is invalid" do
         | 
| 56 56 | 
             
                lambda { BCrypt::Engine.hash_secret(@password, 'nino') }.should raise_error(BCrypt::Errors::InvalidSalt)
         | 
| 57 57 | 
             
              end
         | 
| 58 | 
            -
             | 
| 58 | 
            +
             | 
| 59 59 | 
             
              specify "should raise an InvalidSecret error if the secret is invalid" do
         | 
| 60 60 | 
             
                lambda { BCrypt::Engine.hash_secret(MyInvalidSecret.new, @salt) }.should raise_error(BCrypt::Errors::InvalidSecret)
         | 
| 61 61 | 
             
                lambda { BCrypt::Engine.hash_secret(nil, @salt) }.should_not raise_error(BCrypt::Errors::InvalidSecret)
         | 
| 62 62 | 
             
                lambda { BCrypt::Engine.hash_secret(false, @salt) }.should_not raise_error(BCrypt::Errors::InvalidSecret)
         | 
| 63 63 | 
             
              end
         | 
| 64 | 
            -
             | 
| 64 | 
            +
             | 
| 65 65 | 
             
              specify "should call #to_s on the secret and use the return value as the actual secret data" do
         | 
| 66 66 | 
             
                BCrypt::Engine.hash_secret(false, @salt).should == BCrypt::Engine.hash_secret("false", @salt)
         | 
| 67 67 | 
             
              end
         | 
| 68 | 
            -
             | 
| 68 | 
            +
             | 
| 69 69 | 
             
              specify "should be interoperable with other implementations" do
         | 
| 70 70 | 
             
                # test vectors from the OpenWall implementation <http://www.openwall.com/crypt/>
         | 
| 71 71 | 
             
                test_vectors = [
         | 
| @@ -1,26 +1,26 @@ | |
| 1 1 | 
             
            require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper"))
         | 
| 2 2 |  | 
| 3 | 
            -
             | 
| 4 | 
            -
             | 
| 3 | 
            +
            describe "Creating a hashed password" do
         | 
| 4 | 
            +
             | 
| 5 5 | 
             
              before :each do
         | 
| 6 6 | 
             
                @secret = "wheedle"
         | 
| 7 7 | 
             
                @password = BCrypt::Password.create(@secret, :cost => 4)
         | 
| 8 8 | 
             
              end
         | 
| 9 | 
            -
             | 
| 9 | 
            +
             | 
| 10 10 | 
             
              specify "should return a BCrypt::Password" do
         | 
| 11 11 | 
             
                @password.should be_an_instance_of(BCrypt::Password)
         | 
| 12 12 | 
             
              end
         | 
| 13 | 
            -
             | 
| 13 | 
            +
             | 
| 14 14 | 
             
              specify "should return a valid bcrypt password" do
         | 
| 15 15 | 
             
                lambda { BCrypt::Password.new(@password) }.should_not raise_error
         | 
| 16 16 | 
             
              end
         | 
| 17 | 
            -
             | 
| 17 | 
            +
             | 
| 18 18 | 
             
              specify "should behave normally if the secret is not a string" do
         | 
| 19 19 | 
             
                lambda { BCrypt::Password.create(nil) }.should_not raise_error(BCrypt::Errors::InvalidSecret)
         | 
| 20 20 | 
             
                lambda { BCrypt::Password.create({:woo => "yeah"}) }.should_not raise_error(BCrypt::Errors::InvalidSecret)
         | 
| 21 21 | 
             
                lambda { BCrypt::Password.create(false) }.should_not raise_error(BCrypt::Errors::InvalidSecret)
         | 
| 22 22 | 
             
              end
         | 
| 23 | 
            -
             | 
| 23 | 
            +
             | 
| 24 24 | 
             
              specify "should tolerate empty string secrets" do
         | 
| 25 25 | 
             
                lambda { BCrypt::Password.create( "\n".chop  ) }.should_not raise_error
         | 
| 26 26 | 
             
                lambda { BCrypt::Password.create( ""         ) }.should_not raise_error
         | 
| @@ -28,37 +28,40 @@ context "Creating a hashed password" do | |
| 28 28 | 
             
              end
         | 
| 29 29 | 
             
            end
         | 
| 30 30 |  | 
| 31 | 
            -
             | 
| 31 | 
            +
            describe "Reading a hashed password" do
         | 
| 32 32 | 
             
              before :each do
         | 
| 33 33 | 
             
                @secret = "U*U"
         | 
| 34 34 | 
             
                @hash = "$2a$05$CCCCCCCCCCCCCCCCCCCCC.E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW"
         | 
| 35 35 | 
             
              end
         | 
| 36 | 
            -
             | 
| 36 | 
            +
             | 
| 37 37 | 
             
              specify "should read the version, cost, salt, and hash" do
         | 
| 38 38 | 
             
                password = BCrypt::Password.new(@hash)
         | 
| 39 39 | 
             
                password.version.should eql("2a")
         | 
| 40 40 | 
             
                password.cost.should equal(5)
         | 
| 41 41 | 
             
                password.salt.should eql("$2a$05$CCCCCCCCCCCCCCCCCCCCC.")
         | 
| 42 | 
            +
                password.salt.class.should == String
         | 
| 43 | 
            +
                password.checksum.should eq("E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW")
         | 
| 44 | 
            +
                password.checksum.class.should == String
         | 
| 42 45 | 
             
                password.to_s.should eql(@hash)
         | 
| 43 46 | 
             
              end
         | 
| 44 | 
            -
             | 
| 47 | 
            +
             | 
| 45 48 | 
             
              specify "should raise an InvalidHashError when given an invalid hash" do
         | 
| 46 49 | 
             
                lambda { BCrypt::Password.new('weedle') }.should raise_error(BCrypt::Errors::InvalidHash)
         | 
| 47 50 | 
             
              end
         | 
| 48 51 | 
             
            end
         | 
| 49 52 |  | 
| 50 | 
            -
             | 
| 53 | 
            +
            describe "Comparing a hashed password with a secret" do
         | 
| 51 54 | 
             
              before :each do
         | 
| 52 55 | 
             
                @secret = "U*U"
         | 
| 53 56 | 
             
                @hash = "$2a$05$CCCCCCCCCCCCCCCCCCCCC.E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW"
         | 
| 54 57 | 
             
                @password = BCrypt::Password.create(@secret)
         | 
| 55 58 | 
             
              end
         | 
| 56 | 
            -
             | 
| 59 | 
            +
             | 
| 57 60 | 
             
              specify "should compare successfully to the original secret" do
         | 
| 58 61 | 
             
                (@password == @secret).should be(true)
         | 
| 59 62 | 
             
              end
         | 
| 60 | 
            -
             | 
| 63 | 
            +
             | 
| 61 64 | 
             
              specify "should compare unsuccessfully to anything besides original secret" do
         | 
| 62 65 | 
             
                (@password == "@secret").should be(false)
         | 
| 63 66 | 
             
              end
         | 
| 64 | 
            -
            end
         | 
| 67 | 
            +
            end
         | 
    
        data/spec/spec_helper.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,12 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification 
         | 
| 2 2 | 
             
            name: bcrypt-ruby
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            -
               | 
| 4 | 
            +
              prerelease: false
         | 
| 5 | 
            +
              segments: 
         | 
| 6 | 
            +
              - 2
         | 
| 7 | 
            +
              - 1
         | 
| 8 | 
            +
              - 3
         | 
| 9 | 
            +
              version: 2.1.3
         | 
| 5 10 | 
             
            platform: ruby
         | 
| 6 11 | 
             
            authors: 
         | 
| 7 12 | 
             
            - Coda Hale
         | 
| @@ -9,10 +14,33 @@ autorequire: | |
| 9 14 | 
             
            bindir: bin
         | 
| 10 15 | 
             
            cert_chain: []
         | 
| 11 16 |  | 
| 12 | 
            -
            date:  | 
| 17 | 
            +
            date: 2010-12-20 00:00:00 -08:00
         | 
| 13 18 | 
             
            default_executable: 
         | 
| 14 | 
            -
            dependencies:  | 
| 15 | 
            -
             | 
| 19 | 
            +
            dependencies: 
         | 
| 20 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 21 | 
            +
              name: rake-compiler
         | 
| 22 | 
            +
              prerelease: false
         | 
| 23 | 
            +
              requirement: &id001 !ruby/object:Gem::Requirement 
         | 
| 24 | 
            +
                requirements: 
         | 
| 25 | 
            +
                - - ">="
         | 
| 26 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 27 | 
            +
                    segments: 
         | 
| 28 | 
            +
                    - 0
         | 
| 29 | 
            +
                    version: "0"
         | 
| 30 | 
            +
              type: :development
         | 
| 31 | 
            +
              version_requirements: *id001
         | 
| 32 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 33 | 
            +
              name: rspec
         | 
| 34 | 
            +
              prerelease: false
         | 
| 35 | 
            +
              requirement: &id002 !ruby/object:Gem::Requirement 
         | 
| 36 | 
            +
                requirements: 
         | 
| 37 | 
            +
                - - ">="
         | 
| 38 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 39 | 
            +
                    segments: 
         | 
| 40 | 
            +
                    - 0
         | 
| 41 | 
            +
                    version: "0"
         | 
| 42 | 
            +
              type: :development
         | 
| 43 | 
            +
              version_requirements: *id002
         | 
| 16 44 | 
             
            description: "    bcrypt() is a sophisticated and secure hash algorithm designed by The OpenBSD project\n    for hashing passwords. bcrypt-ruby provides a simple, humane wrapper for safely handling\n    passwords.\n"
         | 
| 17 45 | 
             
            email: coda.hale@gmail.com
         | 
| 18 46 | 
             
            executables: []
         | 
| @@ -25,22 +53,26 @@ extra_rdoc_files: | |
| 25 53 | 
             
            - CHANGELOG
         | 
| 26 54 | 
             
            - lib/bcrypt.rb
         | 
| 27 55 | 
             
            files: 
         | 
| 56 | 
            +
            - .gitignore
         | 
| 57 | 
            +
            - .rspec
         | 
| 28 58 | 
             
            - CHANGELOG
         | 
| 29 59 | 
             
            - COPYING
         | 
| 30 | 
            -
            -  | 
| 60 | 
            +
            - Gemfile
         | 
| 31 61 | 
             
            - README
         | 
| 32 | 
            -
            -  | 
| 33 | 
            -
            -  | 
| 34 | 
            -
            -  | 
| 35 | 
            -
            - spec/spec_helper.rb
         | 
| 62 | 
            +
            - Rakefile
         | 
| 63 | 
            +
            - bcrypt-ruby.gemspec
         | 
| 64 | 
            +
            - ext/jruby/bcrypt_jruby/BCrypt.java
         | 
| 36 65 | 
             
            - ext/mri/bcrypt.c
         | 
| 37 | 
            -
            - ext/mri/bcrypt_ext.c
         | 
| 38 | 
            -
            - ext/mri/blowfish.c
         | 
| 39 66 | 
             
            - ext/mri/bcrypt.h
         | 
| 67 | 
            +
            - ext/mri/bcrypt_ext.c
         | 
| 40 68 | 
             
            - ext/mri/blf.h
         | 
| 69 | 
            +
            - ext/mri/blowfish.c
         | 
| 41 70 | 
             
            - ext/mri/extconf.rb
         | 
| 42 | 
            -
            -  | 
| 43 | 
            -
            -  | 
| 71 | 
            +
            - lib/bcrypt.rb
         | 
| 72 | 
            +
            - spec/TestBCrypt.java
         | 
| 73 | 
            +
            - spec/bcrypt/engine_spec.rb
         | 
| 74 | 
            +
            - spec/bcrypt/password_spec.rb
         | 
| 75 | 
            +
            - spec/spec_helper.rb
         | 
| 44 76 | 
             
            has_rdoc: true
         | 
| 45 77 | 
             
            homepage: http://bcrypt-ruby.rubyforge.org
         | 
| 46 78 | 
             
            licenses: []
         | 
| @@ -59,18 +91,20 @@ required_ruby_version: !ruby/object:Gem::Requirement | |
| 59 91 | 
             
              requirements: 
         | 
| 60 92 | 
             
              - - ">="
         | 
| 61 93 | 
             
                - !ruby/object:Gem::Version 
         | 
| 94 | 
            +
                  segments: 
         | 
| 95 | 
            +
                  - 0
         | 
| 62 96 | 
             
                  version: "0"
         | 
| 63 | 
            -
              version: 
         | 
| 64 97 | 
             
            required_rubygems_version: !ruby/object:Gem::Requirement 
         | 
| 65 98 | 
             
              requirements: 
         | 
| 66 99 | 
             
              - - ">="
         | 
| 67 100 | 
             
                - !ruby/object:Gem::Version 
         | 
| 101 | 
            +
                  segments: 
         | 
| 102 | 
            +
                  - 0
         | 
| 68 103 | 
             
                  version: "0"
         | 
| 69 | 
            -
              version: 
         | 
| 70 104 | 
             
            requirements: []
         | 
| 71 105 |  | 
| 72 106 | 
             
            rubyforge_project: bcrypt-ruby
         | 
| 73 | 
            -
            rubygems_version: 1.3. | 
| 107 | 
            +
            rubygems_version: 1.3.6
         | 
| 74 108 | 
             
            signing_key: 
         | 
| 75 109 | 
             
            specification_version: 3
         | 
| 76 110 | 
             
            summary: OpenBSD's bcrypt() password hashing algorithm.
         | 
| Binary file |