bcrypt 3.1.13 → 3.1.22
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.
- checksums.yaml +4 -4
- data/CHANGELOG +100 -67
- data/README.md +4 -6
- data/ext/jruby/bcrypt_jruby/BCrypt.java +4 -3
- data/ext/mri/bcrypt_ext.c +79 -18
- data/ext/mri/crypt_blowfish.c +6 -10
- data/ext/mri/crypt_gensalt.c +1 -1
- data/ext/mri/crypt_gensalt.h +1 -1
- data/ext/mri/wrapper.c +4 -1
- data/ext/mri/x86.S +1 -1
- data/lib/bcrypt/engine.rb +24 -6
- data/lib/bcrypt/password.rb +23 -4
- metadata +43 -31
- data/.gitignore +0 -9
- data/.rspec +0 -3
- data/.travis.yml +0 -17
- data/Gemfile +0 -2
- data/Gemfile.lock +0 -37
- data/Rakefile +0 -70
- data/appveyor.yml +0 -50
- data/bcrypt.gemspec +0 -27
- data/spec/TestBCrypt.java +0 -194
- data/spec/bcrypt/engine_spec.rb +0 -147
- data/spec/bcrypt/error_spec.rb +0 -37
- data/spec/bcrypt/password_spec.rb +0 -124
- data/spec/spec_helper.rb +0 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 521c5039d4a683bdf17faa98c3fddc47318f415597bd7575615c1f309ba65a4d
|
|
4
|
+
data.tar.gz: 9abdb8766bcfdc8cfeacbe41eb66fd0a8436ad5b1e9ff67b18239019387be3a1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6ce98e4f36915b8fb3dc2cc5a0dadb7624914bbfabd8d5e804ac1c945c8fe23794c1a3652841634766c5fe8876cd06ccb04b737c84f54e6b4bca82701d529c07
|
|
7
|
+
data.tar.gz: 9a2eddcb94fa016dfae3e46901df0cd5f9afd30c63789eb4682cf9fc7b55cc3348e1822663a4c4cff9f277d26a6f907ba139d2578fb1510b58559ee76d58d2ce
|
data/CHANGELOG
CHANGED
|
@@ -1,94 +1,127 @@
|
|
|
1
|
-
1.
|
|
2
|
-
-
|
|
1
|
+
3.1.22 Mar 18 2026
|
|
2
|
+
- [CVE-2026-33306] Fix integer overflow in Java extension
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
- Refactored out BCrypt::Internals into more useful BCrypt::Engine.
|
|
8
|
-
- Added validation of secrets -- nil is not healthy.
|
|
4
|
+
3.1.21 Dec 31 2025
|
|
5
|
+
- Use constant time comparisons
|
|
6
|
+
- Mark as Ractor safe
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
- Fixed crashes when hashing weird values (e.g., false, etc.)
|
|
8
|
+
3.1.20 Nov 17 2023
|
|
9
|
+
- Limit packaged files -- decrease gem filesize by ~28% [GH #272 by @pusewicz]
|
|
13
10
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
3.1.19 June 22 2023
|
|
12
|
+
- Deprecate passing the third argument to `BCrypt::Engine.hash_secret` [GH #207 by @sergey-alekseev]
|
|
13
|
+
- Add GC guards so the C compiler won't optimize out references [GH #270]
|
|
17
14
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
sorting issues. [Lee Pope]
|
|
15
|
+
3.1.18 May 16 2022
|
|
16
|
+
- Unlock GVL when calculating hashes and salts [GH #260]
|
|
17
|
+
- Fix compilation warnings in `ext/mri/bcrypt_ext.c` [GH #261]
|
|
22
18
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
3.1.17 Mar 14 2022
|
|
20
|
+
- Fix regex in validators to use \A and \z instead of ^ and $ [GH #121]
|
|
21
|
+
- Truncate secrets greater than 72 bytes in hash_secret [GH #255]
|
|
22
|
+
- Assorted test and doc improvements
|
|
26
23
|
|
|
27
|
-
|
|
28
|
-
-
|
|
24
|
+
3.1.16 Sep 3 2020
|
|
25
|
+
- Fix compilation on FreeBSD. [GH #234]
|
|
29
26
|
|
|
30
|
-
|
|
31
|
-
-
|
|
32
|
-
- Ruby 1.9 compatibility fixes. [Hongli Lai]
|
|
33
|
-
- JRuby support, using Damien Miller's jBCrypt. [Hongli Lai]
|
|
34
|
-
- Ruby 1.9 GIL releasing for high-cost hashes. [Hongli Lai]
|
|
27
|
+
3.1.15 July 21 2020
|
|
28
|
+
- Remove GVL optimization. Apparently it breaks things [GH #230]
|
|
35
29
|
|
|
36
|
-
|
|
37
|
-
-
|
|
30
|
+
3.1.14 July 21 2020
|
|
31
|
+
- Start calibration from the minimum cost supported by the algorithm [GH #206 by @sergey-alekseev]
|
|
38
32
|
|
|
39
|
-
|
|
40
|
-
-
|
|
33
|
+
3.1.13 May 31 2019
|
|
34
|
+
- No longer include compiled binaries for Windows. See GH #173.
|
|
35
|
+
- Update C and Java implementations to latest versions [GH #182 by @fonica]
|
|
36
|
+
- Bump default cost to 12 [GH #181 by @bdewater]
|
|
37
|
+
- Remove explicit support for Rubies 1.8 and 1.9
|
|
38
|
+
- Define SKIP_GNU token when building extension (Fixes FreeBSD >= 12) [GH #189 by @adam12]
|
|
41
39
|
|
|
42
|
-
3.
|
|
43
|
-
-
|
|
44
|
-
-
|
|
40
|
+
3.1.12 May 16 2018
|
|
41
|
+
- Add support for Ruby 2.3, 2.4, and 2.5 in compiled Windows binaries
|
|
42
|
+
- Fix compatibility with libxcrypt - Fixes hash errors in Fedora 28 and Ubuntu 20 [GH #164 by @besser82]
|
|
45
43
|
|
|
46
|
-
3.
|
|
47
|
-
-
|
|
44
|
+
3.1.11 Mar 06 2016
|
|
45
|
+
- Add support for Ruby 2.2 in compiled Windows binaries
|
|
48
46
|
|
|
49
|
-
3.1.
|
|
50
|
-
-
|
|
51
|
-
- BCrypt::Password cost should be set to DEFAULT_COST if nil
|
|
52
|
-
- Add BCrypt::Engine.cost attribute for getting/setting a default cost externally
|
|
47
|
+
3.1.10 Jan 28 2015
|
|
48
|
+
- Fix issue with dumping a BCrypt::Password instance to YAML in Ruby 2.2 [GH #107 by @mattwildig]
|
|
53
49
|
|
|
54
|
-
3.1.
|
|
55
|
-
-
|
|
50
|
+
3.1.9 Oct 23 2014
|
|
51
|
+
- Rebuild corrupt binaries
|
|
56
52
|
|
|
57
|
-
3.1.
|
|
58
|
-
- Add support for Ruby
|
|
59
|
-
- Add support for 64-bit Windows
|
|
53
|
+
3.1.8 Oct 23 2014
|
|
54
|
+
- Add support for Ruby 2.1 in compiled Windows binaries [GH #102]
|
|
60
55
|
|
|
61
|
-
3.1.
|
|
62
|
-
-
|
|
63
|
-
-
|
|
56
|
+
3.1.7 Feb 24 2014
|
|
57
|
+
- Rebuild corrupt Java binary version of gem [GH #90]
|
|
58
|
+
- The 2.1 support for Windows binaries alleged in 3.1.3 was a lie -- documentation removed
|
|
64
59
|
|
|
65
60
|
3.1.6 Feb 21 2014
|
|
66
61
|
- Dummy version of "bcrypt-ruby" needed a couple version bumps to fix some
|
|
67
62
|
bugs. It felt wrong to have that at a higher version than the real gem, so
|
|
68
63
|
the real gem is getting bumped to 3.1.6.
|
|
69
64
|
|
|
70
|
-
3.1.
|
|
71
|
-
-
|
|
72
|
-
-
|
|
65
|
+
3.1.3 Feb 21 2014
|
|
66
|
+
- Add support for Ruby 2.1 in compiled Windows binaries
|
|
67
|
+
- Rename gem from "bcrypt-ruby" to just "bcrypt". [GH #86 by @sferik]
|
|
73
68
|
|
|
74
|
-
3.1.
|
|
75
|
-
- Add support for Ruby 2.1 in compiled Windows binaries
|
|
69
|
+
3.1.2 Aug 26 2013
|
|
70
|
+
- Add support for Ruby 1.8 and 2.0 (in addition to 1.9) in compiled Windows binaries
|
|
71
|
+
- Add support for 64-bit Windows
|
|
76
72
|
|
|
77
|
-
3.1.
|
|
78
|
-
-
|
|
73
|
+
3.1.1 Jul 10 2013
|
|
74
|
+
- Remove support for Ruby 1.8 in compiled win32 binaries
|
|
79
75
|
|
|
80
|
-
3.1.
|
|
81
|
-
-
|
|
76
|
+
3.1.0 May 07 2013
|
|
77
|
+
- Add BCrypt::Password.valid_hash?(str) to check if a string is a valid bcrypt password hash
|
|
78
|
+
- BCrypt::Password cost should be set to DEFAULT_COST if nil
|
|
79
|
+
- Add BCrypt::Engine.cost attribute for getting/setting a default cost externally
|
|
82
80
|
|
|
83
|
-
3.1
|
|
84
|
-
-
|
|
81
|
+
3.0.1 Sep 12 2011
|
|
82
|
+
- create raises an exception if the cost is higher than 31. GH #27
|
|
85
83
|
|
|
86
|
-
3.
|
|
87
|
-
-
|
|
88
|
-
-
|
|
84
|
+
3.0.0 Aug 24 2011
|
|
85
|
+
- Bcrypt C implementation replaced with a public domain implementation.
|
|
86
|
+
- License changed to MIT
|
|
89
87
|
|
|
90
|
-
|
|
91
|
-
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
-
|
|
88
|
+
2.1.2 Sep 16 2009
|
|
89
|
+
- Fixed support for Solaris, OpenSolaris.
|
|
90
|
+
|
|
91
|
+
2.1.1 Aug 14 2009
|
|
92
|
+
- JVM 1.4/1.5 compatibility [Hongli Lai]
|
|
93
|
+
|
|
94
|
+
2.1.0 Aug 12 2009
|
|
95
|
+
- Improved code coverage, unit tests, and build chain. [Hongli Lai]
|
|
96
|
+
- Ruby 1.9 compatibility fixes. [Hongli Lai]
|
|
97
|
+
- JRuby support, using Damien Miller's jBCrypt. [Hongli Lai]
|
|
98
|
+
- Ruby 1.9 GIL releasing for high-cost hashes. [Hongli Lai]
|
|
99
|
+
|
|
100
|
+
2.0.5 Mar 11 2009
|
|
101
|
+
- Fixed Ruby 1.8.5 compatibility. [Mike Pomraning]
|
|
102
|
+
|
|
103
|
+
2.0.4 Mar 09 2009
|
|
104
|
+
- Added Ruby 1.9 compatibility. [Genki Takiuchi]
|
|
105
|
+
- Fixed segfaults on some different types of empty strings. [Mike Pomraning]
|
|
106
|
+
|
|
107
|
+
2.0.3 May 07 2008
|
|
108
|
+
- Made exception classes descend from StandardError, not Exception [Dan42]
|
|
109
|
+
- Changed BCrypt::Engine.hash to BCrypt::Engine.hash_secret to avoid Merb
|
|
110
|
+
sorting issues. [Lee Pope]
|
|
111
|
+
|
|
112
|
+
2.0.2 Jun 06 2007
|
|
113
|
+
- Fixed example code in the README [Winson]
|
|
114
|
+
- Fixed Solaris compatibility [Jeremy LaTrasse, Twitter crew]
|
|
115
|
+
|
|
116
|
+
2.0.1 Mar 09 2007
|
|
117
|
+
- Fixed load path issues
|
|
118
|
+
- Fixed crashes when hashing weird values (e.g., false, etc.)
|
|
119
|
+
|
|
120
|
+
2.0.0 Mar 07 2007
|
|
121
|
+
- Removed BCrypt::Password#exactly_equals -- use BCrypt::Password#eql? instead.
|
|
122
|
+
- Added BCrypt::Password#is_password?.
|
|
123
|
+
- Refactored out BCrypt::Internals into more useful BCrypt::Engine.
|
|
124
|
+
- Added validation of secrets -- nil is not healthy.
|
|
125
|
+
|
|
126
|
+
1.0.0 Feb 27 2007
|
|
127
|
+
- Initial release.
|
data/README.md
CHANGED
|
@@ -2,11 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
An easy way to keep your users' passwords secure.
|
|
4
4
|
|
|
5
|
-
* https://github.com/
|
|
6
|
-
|
|
7
|
-
[](https://travis-ci.org/codahale/bcrypt-ruby)
|
|
8
|
-
[](https://ci.appveyor.com/project/TJSchuck35975/bcrypt-ruby)
|
|
5
|
+
* https://github.com/bcrypt-ruby/bcrypt-ruby/tree/master
|
|
9
6
|
|
|
7
|
+
[](https://github.com/bcrypt-ruby/bcrypt-ruby/actions/workflows/ruby.yml)
|
|
10
8
|
|
|
11
9
|
## Why you should use `bcrypt()`
|
|
12
10
|
|
|
@@ -32,8 +30,8 @@ re-hash those passwords. This vulnerability only affected the JRuby gem.
|
|
|
32
30
|
The bcrypt gem is available on the following Ruby platforms:
|
|
33
31
|
|
|
34
32
|
* JRuby
|
|
35
|
-
* RubyInstaller
|
|
36
|
-
* Any
|
|
33
|
+
* RubyInstaller builds on Windows with the DevKit
|
|
34
|
+
* Any modern Ruby on a BSD/OS X/Linux system with a compiler
|
|
37
35
|
|
|
38
36
|
## How to use `bcrypt()` in your Rails application
|
|
39
37
|
|
|
@@ -688,20 +688,21 @@ public class BCrypt {
|
|
|
688
688
|
*/
|
|
689
689
|
private byte[] crypt_raw(byte password[], byte salt[], int log_rounds,
|
|
690
690
|
boolean sign_ext_bug, int safety) {
|
|
691
|
-
|
|
691
|
+
long rounds;
|
|
692
|
+
int i, j;
|
|
692
693
|
int cdata[] = bf_crypt_ciphertext.clone();
|
|
693
694
|
int clen = cdata.length;
|
|
694
695
|
byte ret[];
|
|
695
696
|
|
|
696
697
|
if (log_rounds < 4 || log_rounds > 31)
|
|
697
698
|
throw new IllegalArgumentException ("Bad number of rounds");
|
|
698
|
-
rounds =
|
|
699
|
+
rounds = roundsForLogRounds(log_rounds);
|
|
699
700
|
if (salt.length != BCRYPT_SALT_LEN)
|
|
700
701
|
throw new IllegalArgumentException ("Bad salt length");
|
|
701
702
|
|
|
702
703
|
init_key();
|
|
703
704
|
ekskey(salt, password, sign_ext_bug, safety);
|
|
704
|
-
for (
|
|
705
|
+
for (long r = 0; r < rounds; r++) {
|
|
705
706
|
key(password, sign_ext_bug, safety);
|
|
706
707
|
key(salt, false, safety);
|
|
707
708
|
}
|
data/ext/mri/bcrypt_ext.c
CHANGED
|
@@ -1,59 +1,120 @@
|
|
|
1
1
|
#include <ruby.h>
|
|
2
2
|
#include <ow-crypt.h>
|
|
3
3
|
|
|
4
|
+
#ifdef HAVE_RUBY_THREAD_H
|
|
5
|
+
#include <ruby/thread.h>
|
|
6
|
+
#endif
|
|
7
|
+
|
|
4
8
|
static VALUE mBCrypt;
|
|
5
9
|
static VALUE cBCryptEngine;
|
|
6
10
|
|
|
11
|
+
struct bc_salt_args {
|
|
12
|
+
const char * prefix;
|
|
13
|
+
unsigned long count;
|
|
14
|
+
const char * input;
|
|
15
|
+
int size;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
static void * bc_salt_nogvl(void * ptr) {
|
|
19
|
+
struct bc_salt_args * args = ptr;
|
|
20
|
+
|
|
21
|
+
return crypt_gensalt_ra(args->prefix, args->count, args->input, args->size);
|
|
22
|
+
}
|
|
23
|
+
|
|
7
24
|
/* Given a logarithmic cost parameter, generates a salt for use with +bc_crypt+.
|
|
8
25
|
*/
|
|
9
26
|
static VALUE bc_salt(VALUE self, VALUE prefix, VALUE count, VALUE input) {
|
|
10
27
|
char * salt;
|
|
11
28
|
VALUE str_salt;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
29
|
+
struct bc_salt_args args;
|
|
30
|
+
|
|
31
|
+
/* duplicate the parameters for thread safety. If another thread has a
|
|
32
|
+
* reference to the parameters and mutates them while we are working,
|
|
33
|
+
* that would be very bad. Duping the strings means that the reference
|
|
34
|
+
* isn't shared. */
|
|
35
|
+
prefix = rb_str_new_frozen(prefix);
|
|
36
|
+
input = rb_str_new_frozen(input);
|
|
37
|
+
|
|
38
|
+
args.prefix = StringValueCStr(prefix);
|
|
39
|
+
args.count = NUM2ULONG(count);
|
|
40
|
+
args.input = NIL_P(input) ? NULL : StringValuePtr(input);
|
|
41
|
+
args.size = NIL_P(input) ? 0 : RSTRING_LEN(input);
|
|
42
|
+
|
|
43
|
+
#ifdef HAVE_RUBY_THREAD_H
|
|
44
|
+
salt = rb_thread_call_without_gvl(bc_salt_nogvl, &args, NULL, NULL);
|
|
45
|
+
#else
|
|
46
|
+
salt = bc_salt_nogvl((void *)&args);
|
|
47
|
+
#endif
|
|
18
48
|
|
|
19
49
|
if(!salt) return Qnil;
|
|
20
50
|
|
|
21
51
|
str_salt = rb_str_new2(salt);
|
|
22
|
-
|
|
52
|
+
|
|
53
|
+
RB_GC_GUARD(prefix);
|
|
54
|
+
RB_GC_GUARD(input);
|
|
55
|
+
free(salt);
|
|
23
56
|
|
|
24
57
|
return str_salt;
|
|
25
58
|
}
|
|
26
59
|
|
|
60
|
+
struct bc_crypt_args {
|
|
61
|
+
const char * key;
|
|
62
|
+
const char * setting;
|
|
63
|
+
void * data;
|
|
64
|
+
int size;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
static void * bc_crypt_nogvl(void * ptr) {
|
|
68
|
+
struct bc_crypt_args * args = ptr;
|
|
69
|
+
|
|
70
|
+
return crypt_ra(args->key, args->setting, &args->data, &args->size);
|
|
71
|
+
}
|
|
72
|
+
|
|
27
73
|
/* Given a secret and a salt, generates a salted hash (which you can then store safely).
|
|
28
74
|
*/
|
|
29
75
|
static VALUE bc_crypt(VALUE self, VALUE key, VALUE setting) {
|
|
30
76
|
char * value;
|
|
31
|
-
void * data;
|
|
32
|
-
int size;
|
|
33
77
|
VALUE out;
|
|
34
78
|
|
|
35
|
-
|
|
36
|
-
size = 0xDEADBEEF;
|
|
79
|
+
struct bc_crypt_args args;
|
|
37
80
|
|
|
38
81
|
if(NIL_P(key) || NIL_P(setting)) return Qnil;
|
|
39
82
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
83
|
+
/* duplicate the parameters for thread safety. If another thread has a
|
|
84
|
+
* reference to the parameters and mutates them while we are working,
|
|
85
|
+
* that would be very bad. Duping the strings means that the reference
|
|
86
|
+
* isn't shared. */
|
|
87
|
+
key = rb_str_new_frozen(key);
|
|
88
|
+
setting = rb_str_new_frozen(setting);
|
|
89
|
+
|
|
90
|
+
args.data = NULL;
|
|
91
|
+
args.size = 0xDEADBEEF;
|
|
92
|
+
args.key = NIL_P(key) ? NULL : StringValueCStr(key);
|
|
93
|
+
args.setting = NIL_P(setting) ? NULL : StringValueCStr(setting);
|
|
94
|
+
|
|
95
|
+
#ifdef HAVE_RUBY_THREAD_H
|
|
96
|
+
value = rb_thread_call_without_gvl(bc_crypt_nogvl, &args, NULL, NULL);
|
|
97
|
+
#else
|
|
98
|
+
value = bc_crypt_nogvl((void *)&args);
|
|
99
|
+
#endif
|
|
45
100
|
|
|
46
|
-
if(!value) return Qnil;
|
|
101
|
+
if(!value || !args.data) return Qnil;
|
|
47
102
|
|
|
48
103
|
out = rb_str_new2(value);
|
|
49
104
|
|
|
50
|
-
|
|
105
|
+
RB_GC_GUARD(key);
|
|
106
|
+
RB_GC_GUARD(setting);
|
|
107
|
+
free(args.data);
|
|
51
108
|
|
|
52
109
|
return out;
|
|
53
110
|
}
|
|
54
111
|
|
|
55
112
|
/* Create the BCrypt and BCrypt::Engine modules, and populate them with methods. */
|
|
56
113
|
void Init_bcrypt_ext(){
|
|
114
|
+
#ifdef HAVE_RB_EXT_RACTOR_SAFE
|
|
115
|
+
rb_ext_ractor_safe(true);
|
|
116
|
+
#endif
|
|
117
|
+
|
|
57
118
|
mBCrypt = rb_define_module("BCrypt");
|
|
58
119
|
cBCryptEngine = rb_define_class_under(mBCrypt, "Engine", rb_cObject);
|
|
59
120
|
|
data/ext/mri/crypt_blowfish.c
CHANGED
|
@@ -361,7 +361,7 @@ static BF_ctx BF_init_state = {
|
|
|
361
361
|
}
|
|
362
362
|
};
|
|
363
363
|
|
|
364
|
-
static unsigned char BF_itoa64[64 + 1] =
|
|
364
|
+
static const unsigned char BF_itoa64[64 + 1] =
|
|
365
365
|
"./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
366
366
|
|
|
367
367
|
static unsigned char BF_atoi64[0x60] = {
|
|
@@ -387,9 +387,8 @@ static int BF_decode(BF_word *dst, const char *src, int size)
|
|
|
387
387
|
unsigned char *dptr = (unsigned char *)dst;
|
|
388
388
|
unsigned char *end = dptr + size;
|
|
389
389
|
const unsigned char *sptr = (const unsigned char *)src;
|
|
390
|
-
unsigned int tmp, c1, c2, c3, c4;
|
|
391
|
-
|
|
392
390
|
do {
|
|
391
|
+
unsigned int tmp, c1, c2, c3, c4;
|
|
393
392
|
BF_safe_atoi64(c1, *sptr++);
|
|
394
393
|
BF_safe_atoi64(c2, *sptr++);
|
|
395
394
|
*dptr++ = (c1 << 2) | ((c2 & 0x30) >> 4);
|
|
@@ -402,7 +401,6 @@ static int BF_decode(BF_word *dst, const char *src, int size)
|
|
|
402
401
|
BF_safe_atoi64(c4, *sptr++);
|
|
403
402
|
*dptr++ = ((c3 & 0x03) << 6) | c4;
|
|
404
403
|
} while (dptr < end);
|
|
405
|
-
|
|
406
404
|
return 0;
|
|
407
405
|
}
|
|
408
406
|
|
|
@@ -411,9 +409,8 @@ static void BF_encode(char *dst, const BF_word *src, int size)
|
|
|
411
409
|
const unsigned char *sptr = (const unsigned char *)src;
|
|
412
410
|
const unsigned char *end = sptr + size;
|
|
413
411
|
unsigned char *dptr = (unsigned char *)dst;
|
|
414
|
-
unsigned int c1, c2;
|
|
415
|
-
|
|
416
412
|
do {
|
|
413
|
+
unsigned int c1, c2;
|
|
417
414
|
c1 = *sptr++;
|
|
418
415
|
*dptr++ = BF_itoa64[c1 >> 2];
|
|
419
416
|
c1 = (c1 & 0x03) << 4;
|
|
@@ -442,10 +439,9 @@ static void BF_swap(BF_word *x, int count)
|
|
|
442
439
|
{
|
|
443
440
|
static int endianness_check = 1;
|
|
444
441
|
char *is_little_endian = (char *)&endianness_check;
|
|
445
|
-
BF_word tmp;
|
|
446
|
-
|
|
447
442
|
if (*is_little_endian)
|
|
448
443
|
do {
|
|
444
|
+
BF_word tmp;
|
|
449
445
|
tmp = *x;
|
|
450
446
|
tmp = (tmp << 16) | (tmp >> 16);
|
|
451
447
|
*x++ = ((tmp & 0x00FF00FF) << 8) | ((tmp >> 8) & 0x00FF00FF);
|
|
@@ -517,7 +513,7 @@ static void BF_swap(BF_word *x, int count)
|
|
|
517
513
|
R = L; \
|
|
518
514
|
L = tmp4 ^ data.ctx.P[BF_N + 1];
|
|
519
515
|
|
|
520
|
-
#if BF_ASM
|
|
516
|
+
#if BF_ASM == 1
|
|
521
517
|
#define BF_body() \
|
|
522
518
|
_BF_body_r(&data.ctx);
|
|
523
519
|
#else
|
|
@@ -650,7 +646,7 @@ static char *BF_crypt(const char *key, const char *setting,
|
|
|
650
646
|
char *output, int size,
|
|
651
647
|
BF_word min)
|
|
652
648
|
{
|
|
653
|
-
#if BF_ASM
|
|
649
|
+
#if BF_ASM == 1
|
|
654
650
|
extern void _BF_body_r(BF_ctx *ctx);
|
|
655
651
|
#endif
|
|
656
652
|
struct {
|
data/ext/mri/crypt_gensalt.c
CHANGED
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
/* Just to make sure the prototypes match the actual definitions */
|
|
29
29
|
#include "crypt_gensalt.h"
|
|
30
30
|
|
|
31
|
-
unsigned char _crypt_itoa64[64 + 1] =
|
|
31
|
+
const unsigned char _crypt_itoa64[64 + 1] =
|
|
32
32
|
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
33
33
|
|
|
34
34
|
char *_crypt_gensalt_traditional_rn(const char *prefix, unsigned long count,
|
data/ext/mri/crypt_gensalt.h
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
#ifndef _CRYPT_GENSALT_H
|
|
18
18
|
#define _CRYPT_GENSALT_H
|
|
19
19
|
|
|
20
|
-
extern unsigned char _crypt_itoa64[];
|
|
20
|
+
extern const unsigned char _crypt_itoa64[];
|
|
21
21
|
extern char *_crypt_gensalt_traditional_rn(const char *prefix,
|
|
22
22
|
unsigned long count,
|
|
23
23
|
const char *input, int size, char *output, int output_size);
|
data/ext/mri/wrapper.c
CHANGED
|
@@ -17,6 +17,9 @@
|
|
|
17
17
|
#include <stdlib.h>
|
|
18
18
|
#include <string.h>
|
|
19
19
|
|
|
20
|
+
/* Redefine strdup to ruby_strdup in case string.h doesn't export it. */
|
|
21
|
+
#include <ruby/util.h>
|
|
22
|
+
|
|
20
23
|
#include <errno.h>
|
|
21
24
|
#ifndef __set_errno
|
|
22
25
|
#define __set_errno(val) errno = (val)
|
|
@@ -176,7 +179,7 @@ char *crypt_ra(const char *key, const char *setting,
|
|
|
176
179
|
return _crypt_blowfish_rn(key, setting, (char *)*data, *size);
|
|
177
180
|
}
|
|
178
181
|
|
|
179
|
-
char *crypt_r(const char *key, const char *setting,
|
|
182
|
+
char *crypt_r(const char *key, const char *setting, struct crypt_data *data)
|
|
180
183
|
{
|
|
181
184
|
return _crypt_retval_magic(
|
|
182
185
|
crypt_rn(key, setting, data, CRYPT_OUTPUT_SIZE),
|
data/ext/mri/x86.S
CHANGED
data/lib/bcrypt/engine.rb
CHANGED
|
@@ -5,6 +5,16 @@ module BCrypt
|
|
|
5
5
|
DEFAULT_COST = 12
|
|
6
6
|
# The minimum cost supported by the algorithm.
|
|
7
7
|
MIN_COST = 4
|
|
8
|
+
# The maximum cost supported by the algorithm.
|
|
9
|
+
MAX_COST = 31
|
|
10
|
+
# Maximum possible size of bcrypt() secrets.
|
|
11
|
+
# Older versions of the bcrypt library would truncate passwords longer
|
|
12
|
+
# than 72 bytes, but newer ones do not. We truncate like the old library for
|
|
13
|
+
# forward compatibility. This way users upgrading from Ubuntu 18.04 to 20.04
|
|
14
|
+
# will not have their user passwords invalidated, for example.
|
|
15
|
+
# A max secret length greater than 255 leads to bcrypt returning nil.
|
|
16
|
+
# https://github.com/bcrypt-ruby/bcrypt-ruby/issues/225#issuecomment-875908425
|
|
17
|
+
MAX_SECRET_BYTESIZE = 72
|
|
8
18
|
# Maximum possible size of bcrypt() salts.
|
|
9
19
|
MAX_SALT_LENGTH = 16
|
|
10
20
|
|
|
@@ -41,14 +51,23 @@ module BCrypt
|
|
|
41
51
|
end
|
|
42
52
|
|
|
43
53
|
# Given a secret and a valid salt (see BCrypt::Engine.generate_salt) calculates
|
|
44
|
-
# a bcrypt() password hash.
|
|
54
|
+
# a bcrypt() password hash. Secrets longer than 72 bytes are truncated.
|
|
45
55
|
def self.hash_secret(secret, salt, _ = nil)
|
|
56
|
+
unless _.nil?
|
|
57
|
+
warn "[DEPRECATION] Passing the third argument to " \
|
|
58
|
+
"`BCrypt::Engine.hash_secret` is deprecated. " \
|
|
59
|
+
"Please do not pass the third argument which " \
|
|
60
|
+
"is currently not used."
|
|
61
|
+
end
|
|
62
|
+
|
|
46
63
|
if valid_secret?(secret)
|
|
47
64
|
if valid_salt?(salt)
|
|
48
65
|
if RUBY_PLATFORM == "java"
|
|
49
66
|
Java.bcrypt_jruby.BCrypt.hashpw(secret.to_s.to_java_bytes, salt.to_s)
|
|
50
67
|
else
|
|
51
|
-
|
|
68
|
+
secret = secret.to_s
|
|
69
|
+
secret = secret.byteslice(0, MAX_SECRET_BYTESIZE) if secret && secret.bytesize > MAX_SECRET_BYTESIZE
|
|
70
|
+
__bc_crypt(secret, salt)
|
|
52
71
|
end
|
|
53
72
|
else
|
|
54
73
|
raise Errors::InvalidSalt.new("invalid salt")
|
|
@@ -68,8 +87,7 @@ module BCrypt
|
|
|
68
87
|
if RUBY_PLATFORM == "java"
|
|
69
88
|
Java.bcrypt_jruby.BCrypt.gensalt(cost)
|
|
70
89
|
else
|
|
71
|
-
|
|
72
|
-
__bc_salt(prefix, cost, OpenSSL::Random.random_bytes(MAX_SALT_LENGTH))
|
|
90
|
+
__bc_salt("$2a$", cost, OpenSSL::Random.random_bytes(MAX_SALT_LENGTH))
|
|
73
91
|
end
|
|
74
92
|
else
|
|
75
93
|
raise Errors::InvalidCost.new("cost must be numeric and > 0")
|
|
@@ -78,7 +96,7 @@ module BCrypt
|
|
|
78
96
|
|
|
79
97
|
# Returns true if +salt+ is a valid bcrypt() salt, false if not.
|
|
80
98
|
def self.valid_salt?(salt)
|
|
81
|
-
!!(salt =~
|
|
99
|
+
!!(salt =~ /\A\$[0-9a-z]{2,}\$[0-9]{2,}\$[A-Za-z0-9\.\/]{22,}\z/)
|
|
82
100
|
end
|
|
83
101
|
|
|
84
102
|
# Returns true if +secret+ is a valid bcrypt() secret, false if not.
|
|
@@ -99,7 +117,7 @@ module BCrypt
|
|
|
99
117
|
# # should take less than 1000ms
|
|
100
118
|
# BCrypt::Password.create("woo", :cost => 12)
|
|
101
119
|
def self.calibrate(upper_time_limit_in_ms)
|
|
102
|
-
|
|
120
|
+
(BCrypt::Engine::MIN_COST..BCrypt::Engine::MAX_COST-1).each do |i|
|
|
103
121
|
start_time = Time.now
|
|
104
122
|
Password.create("testing testing", :cost => i+1)
|
|
105
123
|
end_time = Time.now - start_time
|
data/lib/bcrypt/password.rb
CHANGED
|
@@ -42,12 +42,12 @@ module BCrypt
|
|
|
42
42
|
# @password = BCrypt::Password.create("my secret", :cost => 13)
|
|
43
43
|
def create(secret, options = {})
|
|
44
44
|
cost = options[:cost] || BCrypt::Engine.cost
|
|
45
|
-
raise ArgumentError if cost >
|
|
45
|
+
raise ArgumentError if cost > BCrypt::Engine::MAX_COST
|
|
46
46
|
Password.new(BCrypt::Engine.hash_secret(secret, BCrypt::Engine.generate_salt(cost)))
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
def valid_hash?(h)
|
|
50
|
-
|
|
50
|
+
/\A\$[0-9a-z]{2}\$[0-9]{2}\$[A-Za-z0-9\.\/]{53}\z/ === h
|
|
51
51
|
end
|
|
52
52
|
end
|
|
53
53
|
|
|
@@ -62,8 +62,28 @@ module BCrypt
|
|
|
62
62
|
end
|
|
63
63
|
|
|
64
64
|
# Compares a potential secret against the hash. Returns true if the secret is the original secret, false otherwise.
|
|
65
|
+
#
|
|
66
|
+
# Comparison edge case/gotcha:
|
|
67
|
+
#
|
|
68
|
+
# secret = "my secret"
|
|
69
|
+
# @password = BCrypt::Password.create(secret)
|
|
70
|
+
#
|
|
71
|
+
# @password == secret # => True
|
|
72
|
+
# @password == @password # => False
|
|
73
|
+
# @password == @password.to_s # => False
|
|
74
|
+
# @password.to_s == @password # => True
|
|
75
|
+
# @password.to_s == @password.to_s # => True
|
|
76
|
+
#
|
|
77
|
+
# secret == @password # => probably False, because the secret is not a BCrypt::Password instance.
|
|
65
78
|
def ==(secret)
|
|
66
|
-
|
|
79
|
+
hash = BCrypt::Engine.hash_secret(secret, @salt)
|
|
80
|
+
|
|
81
|
+
return false if hash.strip.empty? || strip.empty? || hash.bytesize != bytesize
|
|
82
|
+
|
|
83
|
+
# Constant time comparison so they can't tell the length.
|
|
84
|
+
res = 0
|
|
85
|
+
bytesize.times { |i| res |= getbyte(i) ^ hash.getbyte(i) }
|
|
86
|
+
res == 0
|
|
67
87
|
end
|
|
68
88
|
alias_method :is_password?, :==
|
|
69
89
|
|
|
@@ -83,5 +103,4 @@ module BCrypt
|
|
|
83
103
|
return v.to_str, c.to_i, h[0, 29].to_str, mash[-31, 31].to_str
|
|
84
104
|
end
|
|
85
105
|
end
|
|
86
|
-
|
|
87
106
|
end
|