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 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