bcrypt-ruby 2.1.2 → 2.1.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of bcrypt-ruby might be problematic. Click here for more details.

data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ *.o
2
+ *.bundle
3
+ *.so
4
+ ext/mri/Makefile
5
+ doc
6
+ pkg
7
+ *.class
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --backtrace
3
+ --format documentation
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source :rubygems
2
+ gemspec
data/Rakefile CHANGED
@@ -1,24 +1,12 @@
1
- gem "rspec"
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 "benchmark"
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
- Spec::Rake::SpecTask.new do |t|
38
- t.spec_files = FileList['spec/**/*_spec.rb']
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
- Spec::Rake::SpecTask.new(:rcov) do |t|
44
- t.spec_files = FileList['spec/**/*_spec.rb']
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.rcov_dir = 'doc/coverage'
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 << '--title' << 'bcrypt-ruby' << '--line-numbers' << '--inline-source' << '--main' << 'README'
41
+ rdoc.options += GEMSPEC.rdoc_options
55
42
  rdoc.template = ENV['TEMPLATE'] if ENV['TEMPLATE']
56
- rdoc.rdoc_files.include('README', 'COPYING', 'CHANGELOG', 'lib/**/*.rb')
43
+ rdoc.rdoc_files.include(*GEMSPEC.extra_rdoc_files)
57
44
  end
58
45
 
59
- spec = Gem::Specification.new do |s|
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
- desc "Clean, then compile the extension that's native to the current Ruby compiler."
94
- if RUBY_PLATFORM == "java"
95
- task :compile => 'compile:jruby'
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
- task :compile => 'compile:mri'
98
- end
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
- namespace :compile do
101
- desc "CLean, then compile all extensions"
102
- task :all => [:mri, :jruby]
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
- desc "Clean, then compile the JRuby extension"
113
- task :jruby => :clean do
114
- Dir.chdir('ext/jruby/bcrypt_jruby') do
115
- sh "javac -source 1.4 -target 1.4 BCrypt.java"
116
- end
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."
@@ -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 static uint8_t Base64Code[] =
80
+ static const uint8_t Base64Code[] =
81
81
  "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
82
82
 
83
- const static uint8_t index_64[128] = {
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
- bcrypt_gensalt(char *output, uint8_t log_rounds, uint8_t *rseed)
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
- bcrypt(char *output, const char *key, const char *salt)
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 *bcrypt_gensalt(char *output, uint8_t log_rounds, uint8_t *rseed);
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 *bcrypt(char *output, const char *key, const char *salt);
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)bcrypt(args->output, args->key, args->salt);
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
- bcrypt_gensalt(salt, icost, (uint8_t *)RSTRING_PTR(seed));
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 (bcrypt(output, safeguarded, (char *)RSTRING_PTR(salt)) != NULL) {
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 :hash
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, @hash = split_hash(self)
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
+ }
@@ -1,6 +1,6 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper"))
2
2
 
3
- context "The BCrypt engine" do
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
- context "Generating BCrypt salts" do
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
- context "Autodetecting of salt cost" do
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
- context "Generating BCrypt hashes" do
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
- context "Creating a hashed password" do
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
- context "Reading a hashed password" do
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
- context "Comparing a hashed password with a secret" do
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
@@ -1,4 +1,2 @@
1
- $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib'))
2
- require "rubygems"
3
- require "spec"
4
- require "bcrypt"
1
+ $:.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'bcrypt'
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
- version: 2.1.2
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: 2009-09-16 00:00:00 -07:00
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
- - Rakefile
60
+ - Gemfile
31
61
  - README
32
- - lib/bcrypt.rb
33
- - spec/bcrypt/engine_spec.rb
34
- - spec/bcrypt/password_spec.rb
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
- - ext/jruby/bcrypt_jruby/BCrypt.java
43
- - ext/jruby/bcrypt_jruby/BCrypt.class
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.5
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