File: bcrypt_ext.c

package info (click to toggle)
ruby-bcrypt 3.1.20-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 340 kB
  • sloc: ansic: 1,390; java: 764; ruby: 438; asm: 157; makefile: 12
file content (121 lines) | stat: -rw-r--r-- 3,279 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#include <ruby.h>
#include <ow-crypt.h>

#ifdef HAVE_RUBY_THREAD_H
#include <ruby/thread.h>
#endif

static VALUE mBCrypt;
static VALUE cBCryptEngine;

struct bc_salt_args {
    const char * prefix;
    unsigned long count;
    const char * input;
    int size;
};

static void * bc_salt_nogvl(void * ptr) {
    struct bc_salt_args * args = ptr;

    return crypt_gensalt_ra(args->prefix, args->count, args->input, args->size);
}

/* Given a logarithmic cost parameter, generates a salt for use with +bc_crypt+.
*/
static VALUE bc_salt(VALUE self, VALUE prefix, VALUE count, VALUE input) {
    char * salt;
    VALUE str_salt;
    struct bc_salt_args args;

    /* duplicate the parameters for thread safety.  If another thread has a
     * reference to the parameters and mutates them while we are working,
     * that would be very bad.  Duping the strings means that the reference
     * isn't shared. */
    prefix = rb_str_new_frozen(prefix);
    input  = rb_str_new_frozen(input);

    args.prefix = StringValueCStr(prefix);
    args.count  = NUM2ULONG(count);
    args.input  = NIL_P(input) ? NULL : StringValuePtr(input);
    args.size   = NIL_P(input) ? 0 : RSTRING_LEN(input);

#ifdef HAVE_RUBY_THREAD_H
    salt = rb_thread_call_without_gvl(bc_salt_nogvl, &args, NULL, NULL);
#else
    salt = bc_salt_nogvl((void *)&args);
#endif

    if(!salt) return Qnil;

    str_salt = rb_str_new2(salt);

    RB_GC_GUARD(prefix);
    RB_GC_GUARD(input);
    free(salt);

    return str_salt;
}

struct bc_crypt_args {
    const char * key;
    const char * setting;
    void * data;
    int size;
};

static void * bc_crypt_nogvl(void * ptr) {
    struct bc_crypt_args * args = ptr;

    return crypt_ra(args->key, args->setting, &args->data, &args->size);
}

/* Given a secret and a salt, generates a salted hash (which you can then store safely).
*/
static VALUE bc_crypt(VALUE self, VALUE key, VALUE setting) {
    char * value;
    VALUE out;

    struct bc_crypt_args args;

    if(NIL_P(key) || NIL_P(setting)) return Qnil;

    /* duplicate the parameters for thread safety.  If another thread has a
     * reference to the parameters and mutates them while we are working,
     * that would be very bad.  Duping the strings means that the reference
     * isn't shared. */
    key     = rb_str_new_frozen(key);
    setting = rb_str_new_frozen(setting);

    args.data    = NULL;
    args.size    = 0xDEADBEEF;
    args.key     = NIL_P(key)     ? NULL : StringValueCStr(key);
    args.setting = NIL_P(setting) ? NULL : StringValueCStr(setting);

#ifdef HAVE_RUBY_THREAD_H
    value = rb_thread_call_without_gvl(bc_crypt_nogvl, &args, NULL, NULL);
#else
    value = bc_crypt_nogvl((void *)&args);
#endif

    if(!value || !args.data) return Qnil;

    out = rb_str_new2(value);

    RB_GC_GUARD(key);
    RB_GC_GUARD(setting);
    free(args.data);

    return out;
}

/* Create the BCrypt and BCrypt::Engine modules, and populate them with methods. */
void Init_bcrypt_ext(){
    mBCrypt = rb_define_module("BCrypt");
    cBCryptEngine = rb_define_class_under(mBCrypt, "Engine", rb_cObject);

    rb_define_singleton_method(cBCryptEngine, "__bc_salt", bc_salt, 3);
    rb_define_singleton_method(cBCryptEngine, "__bc_crypt", bc_crypt, 2);
}

/* vim: set noet sws=4 sw=4: */