bcrypt-ruby 2.1.4 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -5,3 +5,4 @@ ext/mri/Makefile
5
5
  doc
6
6
  pkg
7
7
  *.class
8
+ tmp/
data/CHANGELOG CHANGED
@@ -37,4 +37,8 @@
37
37
  - JVM 1.4/1.5 compatibility [Hongli Lai]
38
38
 
39
39
  2.1.2 Sep 16 2009
40
- - Fixed support for Solaris, OpenSolaris.
40
+ - Fixed support for Solaris, OpenSolaris.
41
+
42
+ 3.0.0 Aug 24, 2011
43
+ - Bcrypt C implementation replaced with a public domain implementation.
44
+ - License changed to MIT
data/COPYING CHANGED
@@ -1,33 +1,28 @@
1
- Copyright 2007-2009 Coda Hale <coda.hale@gmail.com>
1
+ (The MIT License)
2
2
 
3
- Original C implementation of the BCrypt algorithm by Niels Provos.
4
- jBCrypt is Copyright (c) 2006 Damien Miller <djm@mindrot.org>.
3
+ Copyright 2007-2011:
4
+
5
+ * Coda Hale <coda.hale@gmail.com>
5
6
 
6
- All rights reserved.
7
+ C implementation of the BCrypt algorithm by Solar Designer and placed in the
8
+ public domain.
9
+ jBCrypt is Copyright (c) 2006 Damien Miller <djm@mindrot.org>.
7
10
 
8
- Redistribution and use in source and binary forms, with or without
9
- modification, are permitted provided that the following conditions
10
- are met:
11
- 1. Redistributions of source code must retain the above copyright
12
- notice, this list of conditions and the following disclaimer.
13
- 2. Redistributions in binary form must reproduce the above copyright
14
- notice, this list of conditions and the following disclaimer in the
15
- documentation and/or other materials provided with the distribution.
16
- 3. All advertising materials mentioning features or use of this software
17
- must display the following acknowledgement:
11
+ Permission is hereby granted, free of charge, to any person obtaining
12
+ a copy of this software and associated documentation files (the
13
+ 'Software'), to deal in the Software without restriction, including
14
+ without limitation the rights to use, copy, modify, merge, publish,
15
+ distribute, sublicense, and/or sell copies of the Software, and to
16
+ permit persons to whom the Software is furnished to do so, subject to
17
+ the following conditions:
18
18
 
19
- This product includes software developed by Coda Hale.
20
-
21
- 4. The name of the author may not be used to endorse or promote products
22
- derived from this software without specific prior written permission.
19
+ The above copyright notice and this permission notice shall be
20
+ included in all copies or substantial portions of the Software.
23
21
 
24
- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25
- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26
- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27
- IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28
- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29
- NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33
- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
23
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
26
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
27
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
28
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,29 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ bcrypt-ruby (2.1.4)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+ diff-lcs (1.1.2)
10
+ rake (0.8.7)
11
+ rake-compiler (0.7.5)
12
+ rake
13
+ rspec (2.5.0)
14
+ rspec-core (~> 2.5.0)
15
+ rspec-expectations (~> 2.5.0)
16
+ rspec-mocks (~> 2.5.0)
17
+ rspec-core (2.5.1)
18
+ rspec-expectations (2.5.0)
19
+ diff-lcs (~> 1.1.2)
20
+ rspec-mocks (2.5.0)
21
+
22
+ PLATFORMS
23
+ java
24
+ ruby
25
+
26
+ DEPENDENCIES
27
+ bcrypt-ruby!
28
+ rake-compiler
29
+ rspec
@@ -0,0 +1,184 @@
1
+ # bcrypt-ruby
2
+
3
+ An easy way to keep your users' passwords secure.
4
+
5
+ * http://bcrypt-ruby.rubyforge.org/
6
+ * http://github.com/codahale/bcrypt-ruby/tree/master
7
+
8
+ ## Why you should use `bcrypt()`
9
+
10
+ If you store user passwords in the clear, then an attacker who steals a copy of your database has a giant list of emails
11
+ and passwords. Some of your users will only have one password -- for their email account, for their banking account, for
12
+ your application. A simple hack could escalate into massive identity theft.
13
+
14
+ It's your responsibility as a web developer to make your web application secure -- blaming your users for not being
15
+ security experts is not a professional response to risk.
16
+
17
+ `bcrypt()` allows you to easily harden your application against these kinds of attacks.
18
+
19
+ *Note*: JRuby versions of bcrypt-ruby `<= 2.1.3` had a [security
20
+ vulnerability](http://www.mindrot.org/files/jBCrypt/internat.adv) that
21
+ was fixed in `>= 2.1.4`. If you used a vulnerable version to hash
22
+ passwords with international characters in them, you will need to
23
+ re-hash those passwords. This vulernability only affected the JRuby gem.
24
+
25
+ ## How to install bcrypt
26
+
27
+ sudo gem install bcrypt-ruby
28
+
29
+ The bcrypt-ruby gem is available on the following ruby platforms:
30
+
31
+ * JRuby
32
+ * RubyInstaller 1.8 and 1.9 builds on win32
33
+ * Any 1.8 or 1.9 ruby on a BSD/OSX/Linux system with a compiler
34
+
35
+ ## How to use `bcrypt()` in your Rails application
36
+
37
+ ### The _User_ model
38
+
39
+ require 'bcrypt'
40
+
41
+ class User < ActiveRecord::Base
42
+ # users.password_hash in the database is a :string
43
+ include BCrypt
44
+
45
+ def password
46
+ @password ||= Password.new(password_hash)
47
+ end
48
+
49
+ def password=(new_password)
50
+ @password = Password.create(new_password)
51
+ self.password_hash = @password
52
+ end
53
+ end
54
+
55
+ ### Creating an account
56
+
57
+ def create
58
+ @user = User.new(params[:user])
59
+ @user.password = params[:password]
60
+ @user.save!
61
+ end
62
+
63
+ ### Authenticating a user
64
+
65
+ def login
66
+ @user = User.find_by_email(params[:email])
67
+ if @user.password == params[:password]
68
+ give_token
69
+ else
70
+ redirect_to home_url
71
+ end
72
+ end
73
+
74
+ ### If a user forgets their password?
75
+
76
+ # assign them a random one and mail it to them, asking them to change it
77
+ def forgot_password
78
+ @user = User.find_by_email(params[:email])
79
+ random_password = Array.new(10).map { (65 + rand(58)).chr }.join
80
+ @user.password = random_password
81
+ @user.save!
82
+ Mailer.create_and_deliver_password_change(@user, random_password)
83
+ end
84
+
85
+ ## How to use bcrypt-ruby in general
86
+
87
+ require 'bcrypt'
88
+
89
+ my_password = BCrypt::Password.create("my password")
90
+ #=> "$2a$10$vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa"
91
+
92
+ my_password.version #=> "2a"
93
+ my_password.cost #=> 10
94
+ my_password == "my password" #=> true
95
+ my_password == "not my password" #=> false
96
+
97
+ my_password = BCrypt::Password.new("$2a$10$vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa")
98
+ my_password == "my password" #=> true
99
+ my_password == "not my password" #=> false
100
+
101
+ Check the rdocs for more details -- BCrypt, BCrypt::Password.
102
+
103
+ ## How `bcrypt()` works
104
+
105
+ `bcrypt()` is a hashing algorithm designed by Niels Provos and David Mazières of the OpenBSD Project.
106
+
107
+ ### Background
108
+
109
+ Hash algorithms take a chunk of data (e.g., your user's password) and create a "digital fingerprint," or hash, of it.
110
+ Because this process is not reversible, there's no way to go from the hash back to the password.
111
+
112
+ In other words:
113
+
114
+ hash(p) #=> <unique gibberish>
115
+
116
+ You can store the hash and check it against a hash made of a potentially valid password:
117
+
118
+ <unique gibberish> =? hash(just_entered_password)
119
+
120
+ ### Rainbow Tables
121
+
122
+ But even this has weaknesses -- attackers can just run lists of possible passwords through the same algorithm, store the
123
+ results in a big database, and then look up the passwords by their hash:
124
+
125
+ PrecomputedPassword.find_by_hash(<unique gibberish>).password #=> "secret1"
126
+
127
+ ### Salts
128
+
129
+ The solution to this is to add a small chunk of random data -- called a salt -- to the password before it's hashed:
130
+
131
+ hash(salt + p) #=> <really unique gibberish>
132
+
133
+ The salt is then stored along with the hash in the database, and used to check potentially valid passwords:
134
+
135
+ <really unique gibberish> =? hash(salt + just_entered_password)
136
+
137
+ bcrypt-ruby automatically handles the storage and generation of these salts for you.
138
+
139
+ Adding a salt means that an attacker has to have a gigantic database for each unique salt -- for a salt made of 4
140
+ letters, that's 456,976 different databases. Pretty much no one has that much storage space, so attackers try a
141
+ different, slower method -- throw a list of potential passwords at each individual password:
142
+
143
+ hash(salt + "aadvark") =? <really unique gibberish>
144
+ hash(salt + "abacus") =? <really unique gibberish>
145
+ etc.
146
+
147
+ This is much slower than the big database approach, but most hash algorithms are pretty quick -- and therein lies the
148
+ problem. Hash algorithms aren't usually designed to be slow, they're designed to turn gigabytes of data into secure
149
+ fingerprints as quickly as possible. `bcrypt()`, though, is designed to be computationally expensive:
150
+
151
+ Ten thousand iterations:
152
+ user system total real
153
+ md5 0.070000 0.000000 0.070000 ( 0.070415)
154
+ bcrypt 22.230000 0.080000 22.310000 ( 22.493822)
155
+
156
+ If an attacker was using Ruby to check each password, they could check ~140,000 passwords a second with MD5 but only
157
+ ~450 passwords a second with `bcrypt()`.
158
+
159
+ ### Cost Factors
160
+
161
+ In addition, `bcrypt()` allows you to increase the amount of work required to hash a password as computers get faster. Old
162
+ passwords will still work fine, but new passwords can keep up with the times.
163
+
164
+ The default cost factor used by bcrypt-ruby is 10, which is fine for session-based authentication. If you are using a
165
+ stateless authentication architecture (e.g., HTTP Basic Auth), you will want to lower the cost factor to reduce your
166
+ server load and keep your request times down. This will lower the security provided you, but there are few alternatives.
167
+
168
+ ## More Information
169
+
170
+ `bcrypt()` is currently used as the default password storage hash in OpenBSD, widely regarded as the most secure operating
171
+ system available.
172
+
173
+ For a more technical explanation of the algorithm and its design criteria, please read Niels Provos and David Mazières'
174
+ Usenix99 paper:
175
+ http://www.usenix.org/events/usenix99/provos.html
176
+
177
+ If you'd like more down-to-earth advice regarding cryptography, I suggest reading <i>Practical Cryptography</i> by Niels
178
+ Ferguson and Bruce Schneier:
179
+ http://www.schneier.com/book-practical.html
180
+
181
+ # Etc
182
+
183
+ * Author :: Coda Hale <coda.hale@gmail.com>
184
+ * Website :: http://blog.codahale.com
data/Rakefile CHANGED
@@ -25,6 +25,7 @@ task :default => [:compile, :spec]
25
25
  desc "Run all specs"
26
26
  RSpec::Core::RakeTask.new do |t|
27
27
  t.pattern = 'spec/**/*_spec.rb'
28
+ t.ruby_opts = '-w'
28
29
  end
29
30
 
30
31
  desc "Run all specs, with coverage testing"
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'bcrypt-ruby'
3
- s.version = '2.1.4'
3
+ s.version = '3.0.0'
4
4
 
5
5
  s.summary = "OpenBSD's bcrypt() password hashing algorithm."
6
6
  s.description = <<-EOF
@@ -16,8 +16,8 @@ Gem::Specification.new do |s|
16
16
  s.add_development_dependency 'rspec'
17
17
 
18
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']]
19
+ s.rdoc_options += ['--title', 'bcrypt-ruby', '--line-numbers', '--inline-source', '--main', 'README.md']
20
+ s.extra_rdoc_files += ['README.md', 'COPYING', 'CHANGELOG', *Dir['lib/**/*.rb']]
21
21
 
22
22
  s.extensions = 'ext/mri/extconf.rb'
23
23
 
@@ -1,87 +1,89 @@
1
- #include "ruby.h"
2
- #include "bcrypt.h"
1
+ #include <ruby.h>
2
+ #include <ow-crypt.h>
3
3
 
4
4
  static VALUE mBCrypt;
5
5
  static VALUE cBCryptEngine;
6
6
 
7
- /* Define RSTRING_PTR for Ruby 1.8.5, ruby-core's idea of a point release is
8
- insane. */
9
- #ifndef RSTRING_PTR
10
- # define RSTRING_PTR(s) (RSTRING(s)->ptr)
11
- #endif
12
-
13
7
  #ifdef RUBY_VM
14
8
  # define RUBY_1_9
15
9
  #endif
16
10
 
17
11
  #ifdef RUBY_1_9
18
12
 
19
- /* When on Ruby 1.9+, we will want to unlock the GIL while performing
20
- * expensive calculations, for greater concurrency. Do not do this for
21
- * cheap calculations because locking/unlocking the GIL incurs some overhead as well.
22
- */
23
- #define GIL_UNLOCK_COST_THRESHOLD 9
24
-
25
- typedef struct {
26
- char *output;
27
- const char *key;
28
- const char *salt;
29
- } BCryptArguments;
30
-
31
- static VALUE bcrypt_wrapper(void *_args) {
32
- BCryptArguments *args = (BCryptArguments *)_args;
33
- return (VALUE)ruby_bcrypt(args->output, args->key, args->salt);
34
- }
13
+ /* When on Ruby 1.9+, we will want to unlock the GIL while performing
14
+ * expensive calculations, for greater concurrency. Do not do this for
15
+ * cheap calculations because locking/unlocking the GIL incurs some overhead as well.
16
+ */
17
+ #define GIL_UNLOCK_COST_THRESHOLD 9
18
+
19
+ typedef struct {
20
+ char *output;
21
+ const char *key;
22
+ const char *salt;
23
+ } BCryptArguments;
24
+
25
+ static VALUE bcrypt_wrapper(void *_args) {
26
+ BCryptArguments *args = (BCryptArguments *)_args;
27
+ return (VALUE)ruby_bcrypt(args->output, args->key, args->salt);
28
+ }
35
29
 
36
30
  #endif /* RUBY_1_9 */
37
31
 
38
32
  /* Given a logarithmic cost parameter, generates a salt for use with +bc_crypt+.
39
- */
40
- static VALUE bc_salt(VALUE self, VALUE cost, VALUE seed) {
41
- int icost = NUM2INT(cost);
42
- char salt[BCRYPT_SALT_OUTPUT_SIZE];
43
-
44
- ruby_bcrypt_gensalt(salt, icost, (uint8_t *)RSTRING_PTR(seed));
45
- return rb_str_new2(salt);
33
+ */
34
+ static VALUE bc_salt(VALUE self, VALUE prefix, VALUE count, VALUE input) {
35
+ char * salt;
36
+ VALUE str_salt;
37
+
38
+ salt = crypt_gensalt_ra(
39
+ StringValuePtr(prefix),
40
+ NUM2ULONG(count),
41
+ NIL_P(input) ? NULL : StringValuePtr(input),
42
+ NIL_P(input) ? 0 : RSTRING_LEN(input));
43
+
44
+ if(!salt) return Qnil;
45
+
46
+ str_salt = rb_str_new2(salt);
47
+ free(salt);
48
+
49
+ return str_salt;
46
50
  }
47
51
 
48
52
  /* Given a secret and a salt, generates a salted hash (which you can then store safely).
49
- */
50
- static VALUE bc_crypt(VALUE self, VALUE key, VALUE salt, VALUE cost) {
51
- const char * safeguarded = RSTRING_PTR(key) ? RSTRING_PTR(key) : "";
52
- char output[BCRYPT_OUTPUT_SIZE];
53
-
54
- #ifdef RUBY_1_9
55
- int icost = NUM2INT(cost);
56
- if (icost >= GIL_UNLOCK_COST_THRESHOLD) {
57
- BCryptArguments args;
58
- VALUE ret;
59
-
60
- args.output = output;
61
- args.key = safeguarded;
62
- args.salt = RSTRING_PTR(salt);
63
- ret = rb_thread_blocking_region(bcrypt_wrapper, &args, RUBY_UBF_IO, 0);
64
- if (ret != (VALUE) 0) {
65
- return rb_str_new2(output);
66
- } else {
67
- return Qnil;
68
- }
69
- }
70
- /* otherwise, fallback to the non-GIL-unlocking code, just like on Ruby 1.8 */
71
- #endif
72
-
73
- if (ruby_bcrypt(output, safeguarded, (char *)RSTRING_PTR(salt)) != NULL) {
74
- return rb_str_new2(output);
75
- } else {
76
- return Qnil;
77
- }
53
+ */
54
+ static VALUE bc_crypt(VALUE self, VALUE key, VALUE setting) {
55
+ char * value;
56
+ void * data;
57
+ int size;
58
+ VALUE out;
59
+
60
+ data = NULL;
61
+ size = 0xDEADBEEF;
62
+
63
+ if(NIL_P(key) || NIL_P(setting)) return Qnil;
64
+
65
+ value = crypt_ra(
66
+ NIL_P(key) ? NULL : StringValuePtr(key),
67
+ NIL_P(setting) ? NULL : StringValuePtr(setting),
68
+ &data,
69
+ &size);
70
+
71
+ if(!value) return Qnil;
72
+
73
+ out = rb_str_new(data, size - 1);
74
+
75
+ free(data);
76
+
77
+ return out;
78
78
  }
79
79
 
80
80
  /* Create the BCrypt and BCrypt::Engine modules, and populate them with methods. */
81
81
  void Init_bcrypt_ext(){
82
- mBCrypt = rb_define_module("BCrypt");
83
- cBCryptEngine = rb_define_class_under(mBCrypt, "Engine", rb_cObject);
84
-
85
- rb_define_singleton_method(cBCryptEngine, "__bc_salt", bc_salt, 2);
86
- rb_define_singleton_method(cBCryptEngine, "__bc_crypt", bc_crypt, 3);
82
+ mBCrypt = rb_define_module("BCrypt");
83
+ cBCryptEngine = rb_define_class_under(mBCrypt, "Engine", rb_cObject);
84
+
85
+ rb_define_singleton_method(cBCryptEngine, "__bc_salt", bc_salt, 3);
86
+ rb_define_singleton_method(cBCryptEngine, "__bc_crypt", bc_crypt, 2);
87
87
  }
88
+
89
+ /* vim: set noet sws=4 sw=4: */