git ssb

0+

dangerousbeans / %aPBe2k3ugtjBr4rrsU1…



Commit 03c07302c3f65146490bf60e9a39bd16fe1dcf67

Got rid of BCrypt::Internals in favor of an Engine singleton class with accurate method names.

git-svn-id: http://bcrypt-ruby.rubyforge.org/svn/trunk@8 b1e0f299-433e-4bb3-9895-84128a6cfb6a
codahale committed on 2/28/2007, 2:43:14 AM
Parent: e61acd33cc691daece9560ddd9e2367cfc31fab9

Files changed

ext/bcrypt_ext.cchanged
lib/bcrypt.rbchanged
spec/bcrypt/internals_spec.rbdeleted
spec/bcrypt/engine_spec.rbadded
ext/bcrypt_ext.cView
@@ -3,9 +3,9 @@
33 char *bcrypt_gensalt(u_int8_t, u_int8_t *);
44 char *bcrypt(const char *, const char *);
55
66 VALUE mBCrypt;
7-VALUE mBCryptInternals;
7 +VALUE cBCryptEngine;
88
99 /* Given a logarithmic cost parameter, generates a salt for use with +bc_crypt+.
1010 */
1111 static VALUE bc_salt(VALUE self, VALUE cost, VALUE seed) {
@@ -20,9 +20,9 @@
2020
2121 /* Create the BCrypt and BCrypt::Internals modules, and populate them with methods. */
2222 void Init_bcrypt_ext(){
2323 mBCrypt = rb_define_module("BCrypt");
24- mBCryptInternals = rb_define_module_under(mBCrypt, "Internals");
24 + cBCryptEngine = rb_define_class_under(mBCrypt, "Engine", rb_cObject);
2525
26- rb_define_method(mBCryptInternals, "__bc_salt", bc_salt, 2);
27- rb_define_method(mBCryptInternals, "__bc_crypt", bc_crypt, 2);
26 + rb_define_singleton_method(cBCryptEngine, "__bc_salt", bc_salt, 2);
27 + rb_define_singleton_method(cBCryptEngine, "__bc_crypt", bc_crypt, 2);
2828 }
lib/bcrypt.rbView
@@ -15,36 +15,40 @@
1515 # The cost parameter provided to bcrypt() is invalid.
1616 class InvalidCost < Exception; end
1717 end
1818
19- # The default computational expense parameter.
20- DEFAULT_COST = 10
21-
22- module Internals # :nodoc:
23- # contains the C-level methods and other internally bits
19 + # A Ruby wrapper for the bcrypt() extension calls.
20 + class Engine
21 + DEFAULT_COST = 10 # The default computational expense parameter.
22 + MAX_SALT_LENGTH = 16 # Maximum possible size of bcrypt() salts.
2423
25- # Maximum length of salts.
26- MAX_SALT_LENGTH = 16
24 + # C-level routines which, if they don't get the right input, will crash the
25 + # hell out of the Ruby process.
26 + private_class_method :__bc_salt
27 + private_class_method :__bc_crypt
2728
28- # Wrap this in some error checking otherwise it'll explode.
29- def _bc_crypt(key, salt)
29 + # Given a secret and a valid salt (see BCrypt::Engine.generate_salt) calculates
30 + # a bcrypt() password hash.
31 + def self.hash(secret, salt)
3032 if valid_salt?(salt)
31- __bc_crypt(key, salt)
33 + __bc_crypt(secret, salt)
3234 else
3335 raise Errors::InvalidSalt.new("invalid salt")
3436 end
3537 end
3638
37- def _bc_salt(cost = DEFAULT_COST)
39 + # Generates a random salt with a given computational cost.
40 + def self.generate_salt(cost = DEFAULT_COST)
3841 if cost.to_i > 0
3942 __bc_salt(cost, OpenSSL::Random.random_bytes(MAX_SALT_LENGTH))
4043 else
4144 raise Errors::InvalidCost.new("cost must be numeric and > 0")
4245 end
4346 end
4447
45- def valid_salt?(s)
46- s =~ /^\$[0-9a-z]{2,}\$[0-9]{2,}\$[A-Za-z0-9\.\/]{22,}$/
48 + # Returns true if +salt+ is a valid bcrypt() salt, false if not.
49 + def self.valid_salt?(salt)
50 + salt =~ /^\$[0-9a-z]{2,}\$[0-9]{2,}\$[A-Za-z0-9\.\/]{22,}$/
4751 end
4852 end
4953
5054 # Returns the cost factor which will result in computation times less than +upper_time_limit_in_ms+.
@@ -108,13 +112,11 @@
108112 #
109113 # Example:
110114 #
111115 # @password = BCrypt::Password.create("my secret", :cost => 13)
112- def create(secret, options = { :cost => DEFAULT_COST })
113- Password.new(_bc_crypt(secret, _bc_salt(options[:cost])))
116 + def create(secret, options = { :cost => BCrypt::Engine::DEFAULT_COST })
117 + Password.new(BCrypt::Engine.hash(secret, BCrypt::Engine.generate_salt(options[:cost])))
114118 end
115- private
116- include Internals
117119 end
118120
119121 # Initializes a BCrypt::Password instance with the data from a stored hash.
120122 def initialize(raw_hash)
@@ -129,9 +131,9 @@
129131 alias_method :exactly_equals, :==
130132
131133 # Compares a potential secret against the hash. Returns true if the secret is the original secret, false otherwise.
132134 def ==(secret)
133- self.exactly_equals(self.class._bc_crypt(secret, @salt))
135 + self.exactly_equals(BCrypt::Engine.hash(secret, @salt))
134136 end
135137
136138 private
137139 # Returns true if +h+ is a valid hash.
spec/bcrypt/internals_spec.rbView
@@ -1,48 +1,0 @@
1-require File.join(File.dirname(__FILE__), "..", "spec_helper")
2-
3-context "Generating BCrypt salts" do
4- include BCrypt::Internals
5-
6- specify "should produce strings" do
7- _bc_salt.should be_an_instance_of(String)
8- end
9-
10- specify "should produce random data" do
11- _bc_salt.should_not equal(_bc_salt)
12- end
13-
14- specify "should raise a InvalidCostError if the cost parameter isn't numeric" do
15- lambda { _bc_salt('woo') }.should raise_error(BCrypt::Errors::InvalidCost)
16- end
17-end
18-
19-context "Generating BCrypt hashes" do
20- include BCrypt::Internals
21-
22- setup do
23- @salt = _bc_salt
24- @password = "woo"
25- end
26-
27- specify "should produce a string" do
28- _bc_crypt(@password, @salt).should be_an_instance_of(String)
29- end
30-
31- specify "should raise an InvalidSaltError if the salt is invalid" do
32- lambda { _bc_crypt(@password, 'nino') }.should raise_error(BCrypt::Errors::InvalidSalt)
33- end
34-
35- specify "should be interoperable with other implementations" do
36- # test vectors from the OpenWall implementation <http://www.openwall.com/crypt/>
37- test_vectors = [
38- ["U*U", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW"],
39- ["U*U*", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.VGOzA784oUp/Z0DY336zx7pLYAy0lwK"],
40- ["U*U*U", "$2a$05$XXXXXXXXXXXXXXXXXXXXXO", "$2a$05$XXXXXXXXXXXXXXXXXXXXXOAcXxm9kjPGEMsLznoKqmqw7tc8WCx4a"],
41- ["", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.7uG0VCzI2bS7j6ymqJi9CdcdxiRTWNy"],
42- ["0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", "$2a$05$abcdefghijklmnopqrstuu", "$2a$05$abcdefghijklmnopqrstuu5s2v8.iXieOjg/.AySBTTZIIVFJeBui"]
43- ]
44- for secret, salt, test_vector in test_vectors
45- _bc_crypt(secret, salt).should eql(test_vector)
46- end
47- end
48-end
spec/bcrypt/engine_spec.rbView
@@ -1,0 +1,46 @@
1 +require File.join(File.dirname(__FILE__), "..", "spec_helper")
2 +
3 +context "Generating BCrypt salts" do
4 +
5 + specify "should produce strings" do
6 + BCrypt::Engine.generate_salt.should be_an_instance_of(String)
7 + end
8 +
9 + specify "should produce random data" do
10 + BCrypt::Engine.generate_salt.should_not equal(BCrypt::Engine.generate_salt)
11 + end
12 +
13 + specify "should raise a InvalidCostError if the cost parameter isn't numeric" do
14 + lambda { BCrypt::Engine.generate_salt('woo') }.should raise_error(BCrypt::Errors::InvalidCost)
15 + end
16 +end
17 +
18 +context "Generating BCrypt hashes" do
19 +
20 + setup do
21 + @salt = BCrypt::Engine.generate_salt(5)
22 + @password = "woo"
23 + end
24 +
25 + specify "should produce a string" do
26 + BCrypt::Engine.hash(@password, @salt).should be_an_instance_of(String)
27 + end
28 +
29 + specify "should raise an InvalidSaltError if the salt is invalid" do
30 + lambda { BCrypt::Engine.hash(@password, 'nino') }.should raise_error(BCrypt::Errors::InvalidSalt)
31 + end
32 +
33 + specify "should be interoperable with other implementations" do
34 + # test vectors from the OpenWall implementation <http://www.openwall.com/crypt/>
35 + test_vectors = [
36 + ["U*U", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW"],
37 + ["U*U*", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.VGOzA784oUp/Z0DY336zx7pLYAy0lwK"],
38 + ["U*U*U", "$2a$05$XXXXXXXXXXXXXXXXXXXXXO", "$2a$05$XXXXXXXXXXXXXXXXXXXXXOAcXxm9kjPGEMsLznoKqmqw7tc8WCx4a"],
39 + ["", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.7uG0VCzI2bS7j6ymqJi9CdcdxiRTWNy"],
40 + ["0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", "$2a$05$abcdefghijklmnopqrstuu", "$2a$05$abcdefghijklmnopqrstuu5s2v8.iXieOjg/.AySBTTZIIVFJeBui"]
41 + ]
42 + for secret, salt, test_vector in test_vectors
43 + BCrypt::Engine.hash(secret, salt).should eql(test_vector)
44 + end
45 + end
46 +end

Built with git-ssb-web