Files: ba77ac1e2d88b72126fa0495b28fecd821ca118c / ext / mri / bcrypt_ext.c
2425 bytesRaw
1 | |
2 | |
3 | |
4 | static VALUE mBCrypt; |
5 | static VALUE cBCryptEngine; |
6 | |
7 | /* Define RSTRING_PTR for Ruby 1.8.5, ruby-core's idea of a point release is |
8 | insane. */ |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
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 | |
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)bcrypt(args->output, args->key, args->salt); |
34 | } |
35 | |
36 | |
37 | |
38 | /* 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 | bcrypt_gensalt(salt, icost, (uint8_t *)RSTRING_PTR(seed)); |
45 | return rb_str_new2(salt); |
46 | } |
47 | |
48 | /* 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 | |
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 | |
72 | |
73 | if (bcrypt(output, safeguarded, (char *)RSTRING_PTR(salt)) != NULL) { |
74 | return rb_str_new2(output); |
75 | } else { |
76 | return Qnil; |
77 | } |
78 | } |
79 | |
80 | /* Create the BCrypt and BCrypt::Engine modules, and populate them with methods. */ |
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); |
87 | } |
88 |
Built with git-ssb-web