bcrypt4 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,27 @@
1
+ /*
2
+ * Written by Solar Designer <solar at openwall.com> in 2000-2011.
3
+ * No copyright is claimed, and the software is hereby placed in the public
4
+ * domain. In case this attempt to disclaim copyright and place the software
5
+ * in the public domain is deemed null and void, then the software is
6
+ * Copyright (c) 2000-2011 Solar Designer and it is hereby released to the
7
+ * general public under the following terms:
8
+ *
9
+ * Redistribution and use in source and binary forms, with or without
10
+ * modification, are permitted.
11
+ *
12
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
13
+ *
14
+ * See crypt_blowfish.c for more information.
15
+ */
16
+
17
+ #ifndef _CRYPT_BLOWFISH_H
18
+ #define _CRYPT_BLOWFISH_H
19
+
20
+ extern int _crypt_output_magic(const char *setting, char *output, int size);
21
+ extern char *_crypt_blowfish_rn(const char *key, const char *setting,
22
+ char *output, int size);
23
+ extern char *_crypt_gensalt_blowfish_rn(const char *prefix,
24
+ unsigned long count,
25
+ const char *input, int size, char *output, int output_size);
26
+
27
+ #endif
@@ -0,0 +1,124 @@
1
+ /*
2
+ * Written by Solar Designer <solar at openwall.com> in 2000-2011.
3
+ * No copyright is claimed, and the software is hereby placed in the public
4
+ * domain. In case this attempt to disclaim copyright and place the software
5
+ * in the public domain is deemed null and void, then the software is
6
+ * Copyright (c) 2000-2011 Solar Designer and it is hereby released to the
7
+ * general public under the following terms:
8
+ *
9
+ * Redistribution and use in source and binary forms, with or without
10
+ * modification, are permitted.
11
+ *
12
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
13
+ *
14
+ * See crypt_blowfish.c for more information.
15
+ *
16
+ * This file contains salt generation functions for the traditional and
17
+ * other common crypt(3) algorithms, except for bcrypt which is defined
18
+ * entirely in crypt_blowfish.c.
19
+ */
20
+
21
+ #include <string.h>
22
+
23
+ #include <errno.h>
24
+ #ifndef __set_errno
25
+ #define __set_errno(val) errno = (val)
26
+ #endif
27
+
28
+ /* Just to make sure the prototypes match the actual definitions */
29
+ #include "crypt_gensalt.h"
30
+
31
+ unsigned char _crypt_itoa64[64 + 1] =
32
+ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
33
+
34
+ char *_crypt_gensalt_traditional_rn(const char *prefix, unsigned long count,
35
+ const char *input, int size, char *output, int output_size)
36
+ {
37
+ (void) prefix;
38
+
39
+ if (size < 2 || output_size < 2 + 1 || (count && count != 25)) {
40
+ if (output_size > 0) output[0] = '\0';
41
+ __set_errno((output_size < 2 + 1) ? ERANGE : EINVAL);
42
+ return NULL;
43
+ }
44
+
45
+ output[0] = _crypt_itoa64[(unsigned int)input[0] & 0x3f];
46
+ output[1] = _crypt_itoa64[(unsigned int)input[1] & 0x3f];
47
+ output[2] = '\0';
48
+
49
+ return output;
50
+ }
51
+
52
+ char *_crypt_gensalt_extended_rn(const char *prefix, unsigned long count,
53
+ const char *input, int size, char *output, int output_size)
54
+ {
55
+ unsigned long value;
56
+
57
+ (void) prefix;
58
+
59
+ /* Even iteration counts make it easier to detect weak DES keys from a look
60
+ * at the hash, so they should be avoided */
61
+ if (size < 3 || output_size < 1 + 4 + 4 + 1 ||
62
+ (count && (count > 0xffffff || !(count & 1)))) {
63
+ if (output_size > 0) output[0] = '\0';
64
+ __set_errno((output_size < 1 + 4 + 4 + 1) ? ERANGE : EINVAL);
65
+ return NULL;
66
+ }
67
+
68
+ if (!count) count = 725;
69
+
70
+ output[0] = '_';
71
+ output[1] = _crypt_itoa64[count & 0x3f];
72
+ output[2] = _crypt_itoa64[(count >> 6) & 0x3f];
73
+ output[3] = _crypt_itoa64[(count >> 12) & 0x3f];
74
+ output[4] = _crypt_itoa64[(count >> 18) & 0x3f];
75
+ value = (unsigned long)(unsigned char)input[0] |
76
+ ((unsigned long)(unsigned char)input[1] << 8) |
77
+ ((unsigned long)(unsigned char)input[2] << 16);
78
+ output[5] = _crypt_itoa64[value & 0x3f];
79
+ output[6] = _crypt_itoa64[(value >> 6) & 0x3f];
80
+ output[7] = _crypt_itoa64[(value >> 12) & 0x3f];
81
+ output[8] = _crypt_itoa64[(value >> 18) & 0x3f];
82
+ output[9] = '\0';
83
+
84
+ return output;
85
+ }
86
+
87
+ char *_crypt_gensalt_md5_rn(const char *prefix, unsigned long count,
88
+ const char *input, int size, char *output, int output_size)
89
+ {
90
+ unsigned long value;
91
+
92
+ (void) prefix;
93
+
94
+ if (size < 3 || output_size < 3 + 4 + 1 || (count && count != 1000)) {
95
+ if (output_size > 0) output[0] = '\0';
96
+ __set_errno((output_size < 3 + 4 + 1) ? ERANGE : EINVAL);
97
+ return NULL;
98
+ }
99
+
100
+ output[0] = '$';
101
+ output[1] = '1';
102
+ output[2] = '$';
103
+ value = (unsigned long)(unsigned char)input[0] |
104
+ ((unsigned long)(unsigned char)input[1] << 8) |
105
+ ((unsigned long)(unsigned char)input[2] << 16);
106
+ output[3] = _crypt_itoa64[value & 0x3f];
107
+ output[4] = _crypt_itoa64[(value >> 6) & 0x3f];
108
+ output[5] = _crypt_itoa64[(value >> 12) & 0x3f];
109
+ output[6] = _crypt_itoa64[(value >> 18) & 0x3f];
110
+ output[7] = '\0';
111
+
112
+ if (size >= 6 && output_size >= 3 + 4 + 4 + 1) {
113
+ value = (unsigned long)(unsigned char)input[3] |
114
+ ((unsigned long)(unsigned char)input[4] << 8) |
115
+ ((unsigned long)(unsigned char)input[5] << 16);
116
+ output[7] = _crypt_itoa64[value & 0x3f];
117
+ output[8] = _crypt_itoa64[(value >> 6) & 0x3f];
118
+ output[9] = _crypt_itoa64[(value >> 12) & 0x3f];
119
+ output[10] = _crypt_itoa64[(value >> 18) & 0x3f];
120
+ output[11] = '\0';
121
+ }
122
+
123
+ return output;
124
+ }
@@ -0,0 +1,30 @@
1
+ /*
2
+ * Written by Solar Designer <solar at openwall.com> in 2000-2011.
3
+ * No copyright is claimed, and the software is hereby placed in the public
4
+ * domain. In case this attempt to disclaim copyright and place the software
5
+ * in the public domain is deemed null and void, then the software is
6
+ * Copyright (c) 2000-2011 Solar Designer and it is hereby released to the
7
+ * general public under the following terms:
8
+ *
9
+ * Redistribution and use in source and binary forms, with or without
10
+ * modification, are permitted.
11
+ *
12
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
13
+ *
14
+ * See crypt_blowfish.c for more information.
15
+ */
16
+
17
+ #ifndef _CRYPT_GENSALT_H
18
+ #define _CRYPT_GENSALT_H
19
+
20
+ extern unsigned char _crypt_itoa64[];
21
+ extern char *_crypt_gensalt_traditional_rn(const char *prefix,
22
+ unsigned long count,
23
+ const char *input, int size, char *output, int output_size);
24
+ extern char *_crypt_gensalt_extended_rn(const char *prefix,
25
+ unsigned long count,
26
+ const char *input, int size, char *output, int output_size);
27
+ extern char *_crypt_gensalt_md5_rn(const char *prefix, unsigned long count,
28
+ const char *input, int size, char *output, int output_size);
29
+
30
+ #endif
@@ -0,0 +1,16 @@
1
+ if RUBY_PLATFORM == "java"
2
+ # Don't do anything when run in JRuby; this allows gem installation to pass.
3
+ # We need to write a dummy Makefile so that RubyGems doesn't think compilation
4
+ # failed.
5
+ File.open('Makefile', 'w') do |f|
6
+ f.puts "all:"
7
+ f.puts "\t@true"
8
+ f.puts "install:"
9
+ f.puts "\t@true"
10
+ end
11
+ exit 0
12
+ else
13
+ require "mkmf"
14
+ dir_config("bcrypt_ext")
15
+ create_makefile("bcrypt_ext")
16
+ end
@@ -0,0 +1,43 @@
1
+ /*
2
+ * Written by Solar Designer <solar at openwall.com> in 2000-2011.
3
+ * No copyright is claimed, and the software is hereby placed in the public
4
+ * domain. In case this attempt to disclaim copyright and place the software
5
+ * in the public domain is deemed null and void, then the software is
6
+ * Copyright (c) 2000-2011 Solar Designer and it is hereby released to the
7
+ * general public under the following terms:
8
+ *
9
+ * Redistribution and use in source and binary forms, with or without
10
+ * modification, are permitted.
11
+ *
12
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
13
+ *
14
+ * See crypt_blowfish.c for more information.
15
+ */
16
+
17
+ #ifndef _OW_CRYPT_H
18
+ #define _OW_CRYPT_H
19
+
20
+ #ifndef __GNUC__
21
+ #undef __const
22
+ #define __const const
23
+ #endif
24
+
25
+ #ifndef __SKIP_GNU
26
+ extern char *crypt(__const char *key, __const char *setting);
27
+ extern char *crypt_r(__const char *key, __const char *setting, void *data);
28
+ #endif
29
+
30
+ #ifndef __SKIP_OW
31
+ extern char *crypt_rn(__const char *key, __const char *setting,
32
+ void *data, int size);
33
+ extern char *crypt_ra(__const char *key, __const char *setting,
34
+ void **data, int *size);
35
+ extern char *crypt_gensalt(__const char *prefix, unsigned long count,
36
+ __const char *input, int size);
37
+ extern char *crypt_gensalt_rn(__const char *prefix, unsigned long count,
38
+ __const char *input, int size, char *output, int output_size);
39
+ extern char *crypt_gensalt_ra(__const char *prefix, unsigned long count,
40
+ __const char *input, int size);
41
+ #endif
42
+
43
+ #endif
data/ext/mri/wrapper.c ADDED
@@ -0,0 +1,271 @@
1
+ /*
2
+ * Written by Solar Designer <solar at openwall.com> in 2000-2014.
3
+ * No copyright is claimed, and the software is hereby placed in the public
4
+ * domain. In case this attempt to disclaim copyright and place the software
5
+ * in the public domain is deemed null and void, then the software is
6
+ * Copyright (c) 2000-2014 Solar Designer and it is hereby released to the
7
+ * general public under the following terms:
8
+ *
9
+ * Redistribution and use in source and binary forms, with or without
10
+ * modification, are permitted.
11
+ *
12
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
13
+ *
14
+ * See crypt_blowfish.c for more information.
15
+ */
16
+
17
+ #include <stdlib.h>
18
+ #include <string.h>
19
+
20
+ #include <errno.h>
21
+ #ifndef __set_errno
22
+ #define __set_errno(val) errno = (val)
23
+ #endif
24
+
25
+ #ifdef TEST
26
+ #include <stdio.h>
27
+ #include <unistd.h>
28
+ #include <signal.h>
29
+ #include <time.h>
30
+ #include <sys/time.h>
31
+ #include <sys/times.h>
32
+ #ifdef TEST_THREADS
33
+ #include <pthread.h>
34
+ #endif
35
+ #endif
36
+
37
+ #include <ruby.h>
38
+ #ifdef HAVE_RUBY_UTIL_H
39
+ #include <ruby/util.h>
40
+ #else
41
+ #include <util.h>
42
+ #endif
43
+
44
+ #define CRYPT_OUTPUT_SIZE (7 + 22 + 31 + 1)
45
+ #define CRYPT_GENSALT_OUTPUT_SIZE (7 + 22 + 1)
46
+
47
+ #if defined(__GLIBC__) && defined(_LIBC)
48
+ #define __SKIP_GNU
49
+ #endif
50
+ #include "ow-crypt.h"
51
+
52
+ #include "crypt_blowfish.h"
53
+ #include "crypt_gensalt.h"
54
+
55
+ #if defined(__GLIBC__) && defined(_LIBC)
56
+ /* crypt.h from glibc-crypt-2.1 will define struct crypt_data for us */
57
+ #include "crypt.h"
58
+ extern char *__md5_crypt_r(const char *key, const char *salt,
59
+ char *buffer, int buflen);
60
+ /* crypt-entry.c needs to be patched to define __des_crypt_r rather than
61
+ * __crypt_r, and not define crypt_r and crypt at all */
62
+ extern char *__des_crypt_r(const char *key, const char *salt,
63
+ struct crypt_data *data);
64
+ extern struct crypt_data _ufc_foobar;
65
+ #endif
66
+
67
+ static int _crypt_data_alloc(void **data, int *size, int need)
68
+ {
69
+ void *updated;
70
+
71
+ if (*data && *size >= need) return 0;
72
+
73
+ updated = realloc(*data, need);
74
+
75
+ if (!updated) {
76
+ #ifndef __GLIBC__
77
+ /* realloc(3) on glibc sets errno, so we don't need to bother */
78
+ __set_errno(ENOMEM);
79
+ #endif
80
+ return -1;
81
+ }
82
+
83
+ #if defined(__GLIBC__) && defined(_LIBC)
84
+ if (need >= sizeof(struct crypt_data))
85
+ ((struct crypt_data *)updated)->initialized = 0;
86
+ #endif
87
+
88
+ *data = updated;
89
+ *size = need;
90
+
91
+ return 0;
92
+ }
93
+
94
+ static char *_crypt_retval_magic(char *retval, const char *setting,
95
+ char *output, int size)
96
+ {
97
+ if (retval)
98
+ return retval;
99
+
100
+ if (_crypt_output_magic(setting, output, size))
101
+ return NULL; /* shouldn't happen */
102
+
103
+ return output;
104
+ }
105
+
106
+ #if defined(__GLIBC__) && defined(_LIBC)
107
+ /*
108
+ * Applications may re-use the same instance of struct crypt_data without
109
+ * resetting the initialized field in order to let crypt_r() skip some of
110
+ * its initialization code. Thus, it is important that our multiple hashing
111
+ * algorithms either don't conflict with each other in their use of the
112
+ * data area or reset the initialized field themselves whenever required.
113
+ * Currently, the hashing algorithms simply have no conflicts: the first
114
+ * field of struct crypt_data is the 128-byte large DES key schedule which
115
+ * __des_crypt_r() calculates each time it is called while the two other
116
+ * hashing algorithms use less than 128 bytes of the data area.
117
+ */
118
+
119
+ char *__crypt_rn(__const char *key, __const char *setting,
120
+ void *data, int size)
121
+ {
122
+ if (setting[0] == '$' && setting[1] == '2')
123
+ return _crypt_blowfish_rn(key, setting, (char *)data, size);
124
+ if (setting[0] == '$' && setting[1] == '1')
125
+ return __md5_crypt_r(key, setting, (char *)data, size);
126
+ if (setting[0] == '$' || setting[0] == '_') {
127
+ __set_errno(EINVAL);
128
+ return NULL;
129
+ }
130
+ if (size >= sizeof(struct crypt_data))
131
+ return __des_crypt_r(key, setting, (struct crypt_data *)data);
132
+ __set_errno(ERANGE);
133
+ return NULL;
134
+ }
135
+
136
+ char *__crypt_ra(__const char *key, __const char *setting,
137
+ void **data, int *size)
138
+ {
139
+ if (setting[0] == '$' && setting[1] == '2') {
140
+ if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE))
141
+ return NULL;
142
+ return _crypt_blowfish_rn(key, setting, (char *)*data, *size);
143
+ }
144
+ if (setting[0] == '$' && setting[1] == '1') {
145
+ if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE))
146
+ return NULL;
147
+ return __md5_crypt_r(key, setting, (char *)*data, *size);
148
+ }
149
+ if (setting[0] == '$' || setting[0] == '_') {
150
+ __set_errno(EINVAL);
151
+ return NULL;
152
+ }
153
+ if (_crypt_data_alloc(data, size, sizeof(struct crypt_data)))
154
+ return NULL;
155
+ return __des_crypt_r(key, setting, (struct crypt_data *)*data);
156
+ }
157
+
158
+ char *__crypt_r(__const char *key, __const char *setting,
159
+ struct crypt_data *data)
160
+ {
161
+ return _crypt_retval_magic(
162
+ __crypt_rn(key, setting, data, sizeof(*data)),
163
+ setting, (char *)data, sizeof(*data));
164
+ }
165
+
166
+ char *__crypt(__const char *key, __const char *setting)
167
+ {
168
+ return _crypt_retval_magic(
169
+ __crypt_rn(key, setting, &_ufc_foobar, sizeof(_ufc_foobar)),
170
+ setting, (char *)&_ufc_foobar, sizeof(_ufc_foobar));
171
+ }
172
+ #else
173
+ char *crypt_rn(const char *key, const char *setting, void *data, int size)
174
+ {
175
+ return _crypt_blowfish_rn(key, setting, (char *)data, size);
176
+ }
177
+
178
+ char *crypt_ra(const char *key, const char *setting,
179
+ void **data, int *size)
180
+ {
181
+ if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE))
182
+ return NULL;
183
+ return _crypt_blowfish_rn(key, setting, (char *)*data, *size);
184
+ }
185
+
186
+ char *crypt_r(const char *key, const char *setting, void *data)
187
+ {
188
+ return _crypt_retval_magic(
189
+ crypt_rn(key, setting, data, CRYPT_OUTPUT_SIZE),
190
+ setting, (char *)data, CRYPT_OUTPUT_SIZE);
191
+ }
192
+
193
+ char *crypt(const char *key, const char *setting)
194
+ {
195
+ static char output[CRYPT_OUTPUT_SIZE];
196
+
197
+ return _crypt_retval_magic(
198
+ crypt_rn(key, setting, output, sizeof(output)),
199
+ setting, output, sizeof(output));
200
+ }
201
+
202
+ #define __crypt_gensalt_rn crypt_gensalt_rn
203
+ #define __crypt_gensalt_ra crypt_gensalt_ra
204
+ #define __crypt_gensalt crypt_gensalt
205
+ #endif
206
+
207
+ char *__crypt_gensalt_rn(const char *prefix, unsigned long count,
208
+ const char *input, int size, char *output, int output_size)
209
+ {
210
+ char *(*use)(const char *_prefix, unsigned long _count,
211
+ const char *_input, int _size,
212
+ char *_output, int _output_size);
213
+
214
+ /* This may be supported on some platforms in the future */
215
+ if (!input) {
216
+ __set_errno(EINVAL);
217
+ return NULL;
218
+ }
219
+
220
+ if (!strncmp(prefix, "$2a$", 4) || !strncmp(prefix, "$2b$", 4) ||
221
+ !strncmp(prefix, "$2y$", 4))
222
+ use = _crypt_gensalt_blowfish_rn;
223
+ else
224
+ if (!strncmp(prefix, "$1$", 3))
225
+ use = _crypt_gensalt_md5_rn;
226
+ else
227
+ if (prefix[0] == '_')
228
+ use = _crypt_gensalt_extended_rn;
229
+ else
230
+ if (!prefix[0] ||
231
+ (prefix[0] && prefix[1] &&
232
+ memchr(_crypt_itoa64, prefix[0], 64) &&
233
+ memchr(_crypt_itoa64, prefix[1], 64)))
234
+ use = _crypt_gensalt_traditional_rn;
235
+ else {
236
+ __set_errno(EINVAL);
237
+ return NULL;
238
+ }
239
+
240
+ return use(prefix, count, input, size, output, output_size);
241
+ }
242
+
243
+ char *__crypt_gensalt_ra(const char *prefix, unsigned long count,
244
+ const char *input, int size)
245
+ {
246
+ char output[CRYPT_GENSALT_OUTPUT_SIZE];
247
+ char *retval;
248
+
249
+ retval = __crypt_gensalt_rn(prefix, count,
250
+ input, size, output, sizeof(output));
251
+
252
+ if (retval) {
253
+ retval = ruby_strdup(retval);
254
+ #ifndef __GLIBC__
255
+ /* strdup(3) on glibc sets errno, so we don't need to bother */
256
+ if (!retval)
257
+ __set_errno(ENOMEM);
258
+ #endif
259
+ }
260
+
261
+ return retval;
262
+ }
263
+
264
+ char *__crypt_gensalt(const char *prefix, unsigned long count,
265
+ const char *input, int size)
266
+ {
267
+ static char output[CRYPT_GENSALT_OUTPUT_SIZE];
268
+
269
+ return __crypt_gensalt_rn(prefix, count,
270
+ input, size, output, sizeof(output));
271
+ }
@@ -0,0 +1,116 @@
1
+ module BCrypt
2
+ # A Ruby wrapper for the bcrypt() C extension calls and the Java calls.
3
+ class Engine
4
+ # The default computational expense parameter.
5
+ DEFAULT_COST = 10
6
+ # The minimum cost supported by the algorithm.
7
+ MIN_COST = 4
8
+ # Maximum possible size of bcrypt() salts.
9
+ MAX_SALT_LENGTH = 16
10
+
11
+ if RUBY_PLATFORM != "java"
12
+ # C-level routines which, if they don't get the right input, will crash the
13
+ # hell out of the Ruby process.
14
+ private_class_method :__bc_salt
15
+ private_class_method :__bc_crypt
16
+ end
17
+
18
+ @cost = nil
19
+
20
+ # Returns the cost factor that will be used if one is not specified when
21
+ # creating a password hash. Defaults to DEFAULT_COST if not set.
22
+ def self.cost
23
+ @cost || DEFAULT_COST
24
+ end
25
+
26
+ # Set a default cost factor that will be used if one is not specified when
27
+ # creating a password hash.
28
+ #
29
+ # Example:
30
+ #
31
+ # BCrypt::Engine::DEFAULT_COST #=> 10
32
+ # BCrypt::Password.create('secret').cost #=> 10
33
+ #
34
+ # BCrypt::Engine.cost = 8
35
+ # BCrypt::Password.create('secret').cost #=> 8
36
+ #
37
+ # # cost can still be overridden as needed
38
+ # BCrypt::Password.create('secret', :cost => 6).cost #=> 6
39
+ def self.cost=(cost)
40
+ @cost = cost
41
+ end
42
+
43
+ # Given a secret and a valid salt (see BCrypt::Engine.generate_salt) calculates
44
+ # a bcrypt() password hash.
45
+ def self.hash_secret(secret, salt, _ = nil)
46
+ if valid_secret?(secret)
47
+ if valid_salt?(salt)
48
+ if RUBY_PLATFORM == "java"
49
+ Java.bcrypt_jruby.BCrypt.hashpw(secret.to_s, salt.to_s)
50
+ else
51
+ __bc_crypt(secret.to_s, salt)
52
+ end
53
+ else
54
+ raise Errors::InvalidSalt.new("invalid salt")
55
+ end
56
+ else
57
+ raise Errors::InvalidSecret.new("invalid secret")
58
+ end
59
+ end
60
+
61
+ # Generates a random salt with a given computational cost.
62
+ def self.generate_salt(cost = self.cost)
63
+ cost = cost.to_i
64
+ if cost > 0
65
+ if cost < MIN_COST
66
+ cost = MIN_COST
67
+ end
68
+ if RUBY_PLATFORM == "java"
69
+ Java.bcrypt_jruby.BCrypt.gensalt(cost)
70
+ else
71
+ prefix = "$2a$05$CCCCCCCCCCCCCCCCCCCCC.E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW"
72
+ __bc_salt(prefix, cost, OpenSSL::Random.random_bytes(MAX_SALT_LENGTH))
73
+ end
74
+ else
75
+ raise Errors::InvalidCost.new("cost must be numeric and > 0")
76
+ end
77
+ end
78
+
79
+ # Returns true if +salt+ is a valid bcrypt() salt, false if not.
80
+ def self.valid_salt?(salt)
81
+ !!(salt =~ /^\$[0-9a-z]{2,}\$[0-9]{2,}\$[A-Za-z0-9\.\/]{22,}$/)
82
+ end
83
+
84
+ # Returns true if +secret+ is a valid bcrypt() secret, false if not.
85
+ def self.valid_secret?(secret)
86
+ secret.respond_to?(:to_s)
87
+ end
88
+
89
+ # Returns the cost factor which will result in computation times less than +upper_time_limit_in_ms+.
90
+ #
91
+ # Example:
92
+ #
93
+ # BCrypt::Engine.calibrate(200) #=> 10
94
+ # BCrypt::Engine.calibrate(1000) #=> 12
95
+ #
96
+ # # should take less than 200ms
97
+ # BCrypt::Password.create("woo", :cost => 10)
98
+ #
99
+ # # should take less than 1000ms
100
+ # BCrypt::Password.create("woo", :cost => 12)
101
+ def self.calibrate(upper_time_limit_in_ms)
102
+ 40.times do |i|
103
+ start_time = Time.now
104
+ Password.create("testing testing", :cost => i+1)
105
+ end_time = Time.now - start_time
106
+ return i if end_time * 1_000 > upper_time_limit_in_ms
107
+ end
108
+ end
109
+
110
+ # Autodetects the cost from the salt string.
111
+ def self.autodetect_cost(salt)
112
+ salt[4..5].to_i
113
+ end
114
+ end
115
+
116
+ end
@@ -0,0 +1,22 @@
1
+ module BCrypt
2
+
3
+ class Error < StandardError # :nodoc:
4
+ end
5
+
6
+ module Errors # :nodoc:
7
+
8
+ # The salt parameter provided to bcrypt() is invalid.
9
+ class InvalidSalt < BCrypt::Error; end
10
+
11
+ # The hash parameter provided to bcrypt() is invalid.
12
+ class InvalidHash < BCrypt::Error; end
13
+
14
+ # The cost parameter provided to bcrypt() is invalid.
15
+ class InvalidCost < BCrypt::Error; end
16
+
17
+ # The secret parameter provided to bcrypt() is invalid.
18
+ class InvalidSecret < BCrypt::Error; end
19
+
20
+ end
21
+
22
+ end