File Coverage

lib/Crypt/Argon2.xs
Criterion Covered Total %
statement 46 57 80.7
branch 18 40 45.0
condition n/a
subroutine n/a
pod n/a
total 64 97 65.9


line stmt bran cond sub pod time code
1             #define PERL_NO_GET_CONTEXT
2              
3             #include
4             #include
5             #include
6              
7             #include
8              
9 19           static size_t S_parse_size(pTHX_ SV* value, int type) {
10             STRLEN len;
11 19 50         const char* string = SvPVbyte(value, len);
12 19           char* end = NULL;
13 19           int base = strtoul(string, &end, 0);
14 19 50         if (end == string)
15 0           Perl_croak(aTHX_ "Couldn't compute %s tag: memory cost doesn't contain anything numeric", argon2_type2string(type, 0));
16 19           switch(*end) {
17             case '\0':
18 0 0         if (base > 1024)
19 0           return base / 1024;
20             else
21 0           Perl_croak(aTHX_ "Couldn't compute %s tag: Memory size much be at least a kilobyte", argon2_type2string(type, 0));
22             case 'k':
23 4           return base;
24             case 'M':
25 13           return base * 1024;
26             case 'G':
27 2           return base * 1024 * 1024;
28             default:
29 0           Perl_croak(aTHX_ "Couldn't compute %s tag: Can't parse '%c' as an order of magnitude", argon2_type2string(type, 0), *end);
30             }
31             }
32             #define parse_size(value, type) S_parse_size(aTHX_ value, type)
33              
34 10           static enum Argon2_type S_find_argon2_type(pTHX_ const char* name, size_t name_len) {
35 10 100         if (name_len == 8 && strnEQ(name, "argon2id", 8))
    50          
36             return Argon2_id;
37 9 50         else if (name_len == 7 && strnEQ(name, "argon2i", 7))
    50          
38             return Argon2_i;
39 0 0         else if (name_len == 7 && strnEQ(name, "argon2d", 7))
    0          
40             return Argon2_d;
41 0           Perl_croak(aTHX_ "No such argon2 type %s", name);
42             }
43             #define find_argon2_type(name, len) S_find_argon2_type(aTHX_ name, len)
44              
45 1           static enum Argon2_type S_get_argon2_type(pTHX_ SV* name_sv) {
46             STRLEN name_len;
47 1 50         const char* name = SvPV(name_sv, name_len);
48 1           return find_argon2_type(name, name_len);
49             }
50             #define get_argon2_type(name) S_get_argon2_type(aTHX_ name)
51              
52 10           static SV* S_argon2_pass(pTHX_ enum Argon2_type type, SV* password, SV* salt, int t_cost, SV* m_factor, int parallelism, size_t output_length) {
53 10           int m_cost = parse_size(m_factor, type);
54             STRLEN password_len, salt_len;
55 10 50         const char* password_raw = SvPVbyte(password, password_len);
56 10 50         const char* salt_raw = SvPVbyte(salt, salt_len);
57 10           size_t encoded_length = argon2_encodedlen(t_cost, m_cost, parallelism, salt_len, output_length, type);
58 10           SV* result = newSV(encoded_length - 1);
59 10           SvPOK_only(result);
60 10           int rc = argon2_hash(t_cost, m_cost, parallelism,
61             password_raw, password_len,
62             salt_raw, salt_len,
63             NULL, output_length,
64             SvPVX(result), encoded_length,
65             type, ARGON2_VERSION_NUMBER
66             );
67 10 50         if (rc != ARGON2_OK) {
68             SvREFCNT_dec(result);
69 0           Perl_croak(aTHX_ "Couldn't compute %s tag: %s", argon2_type2string(type, FALSE), argon2_error_message(rc));
70             }
71 10           SvCUR(result) = encoded_length - 1;
72 10           return result;
73             }
74             #define argon2_pass(type, password, salt, t_cost, m_factor, parallelism, output_length) S_argon2_pass(aTHX_ type, password, salt, t_cost, m_factor, parallelism, output_length)
75              
76 9           static SV* S_argon2_raw(pTHX_ enum Argon2_type type, SV* password, SV* salt, int t_cost, SV* m_factor, int parallelism, size_t output_length) {
77 9           int m_cost = parse_size(m_factor, type);
78             STRLEN password_len, salt_len;
79 9 50         const char* password_raw = SvPVbyte(password, password_len);
80 9 50         const char* salt_raw = SvPVbyte(salt, salt_len);
81 9           SV* result = newSV(output_length);
82 9           SvPOK_only(result);
83 9           int rc = argon2_hash(t_cost, m_cost, parallelism,
84             password_raw, password_len,
85             salt_raw, salt_len,
86 9           SvPVX(result), output_length,
87             NULL, 0,
88             type, ARGON2_VERSION_NUMBER
89             );
90 9 50         if (rc != ARGON2_OK) {
91             SvREFCNT_dec(result);
92 0           Perl_croak(aTHX_ "Couldn't compute %s tag: %s", argon2_type2string(type, FALSE), argon2_error_message(rc));
93             }
94 9           SvCUR(result) = output_length;
95 9           return result;
96             }
97             #define argon2_raw(type, password, salt, t_cost, m_factor, parallelism, output_length) S_argon2_raw(aTHX_ type, password, salt, t_cost, m_factor, parallelism, output_length)
98              
99             MODULE = Crypt::Argon2 PACKAGE = Crypt::Argon2
100              
101             SV* argon2_pass(enum Argon2_type type, SV* password, SV* salt, int t_cost, SV* m_factor, int parallelism, size_t output_length)
102              
103             SV* argon2id_pass(SV* password, SV* salt, int t_cost, SV* m_factor, int parallelism, size_t output_length)
104             ALIAS:
105             argon2d_pass = Argon2_d
106             argon2i_pass = Argon2_i
107             argon2id_pass = Argon2_id
108             CODE:
109 9           RETVAL = argon2_pass(ix, password, salt, t_cost, m_factor, parallelism, output_length);
110             OUTPUT:
111             RETVAL
112              
113              
114             SV* argon2_raw(enum Argon2_type type, SV* password, SV* salt, int t_cost, SV* m_factor, int parallelism, size_t output_length)
115              
116             SV* argon2id_raw(SV* password, SV* salt, int t_cost, SV* m_factor, int parallelism, size_t output_length)
117             ALIAS:
118             argon2d_raw = Argon2_d
119             argon2i_raw = Argon2_i
120             argon2id_raw = Argon2_id
121             CODE:
122 9           RETVAL = argon2_raw(ix, password, salt, t_cost, m_factor, parallelism, output_length);
123             OUTPUT:
124             RETVAL
125              
126             bool argon2d_verify(SV* encoded, SV* password)
127             ALIAS:
128             argon2d_verify = Argon2_d
129             argon2i_verify = Argon2_i
130             argon2id_verify = Argon2_id
131             argon2_verify = 4
132             PREINIT:
133             const char* password_raw, *encoded_raw;
134             STRLEN password_len, encoded_len;
135             int status;
136             CODE:
137 9 50         encoded_raw = SvPVbyte(encoded, encoded_len);
138 9 50         if (ix == 4) {
139 9           const char* second_dollar = memchr(encoded_raw + 1, '$', encoded_len - 1);
140 9           ix = find_argon2_type(encoded_raw + 1, second_dollar - encoded_raw - 1);
141             }
142 9 50         password_raw = SvPVbyte(password, password_len);
143 9 50         status = argon2_verify(SvPVbyte_nolen(encoded), password_raw, password_len, ix);
144 9           switch(status) {
145             case ARGON2_OK:
146             RETVAL = TRUE;
147             break;
148             case ARGON2_VERIFY_MISMATCH:
149             RETVAL = FALSE;
150 0           break;
151             default:
152 0           Perl_croak(aTHX_ "Could not verify %s tag: %s", argon2_type2string(ix, FALSE), argon2_error_message(status));
153             }
154             OUTPUT:
155             RETVAL