File Coverage

inc/CryptX_AuthEnc_GCM.xs.inc
Criterion Covered Total %
statement 120 141 85.1
branch 80 220 36.3
condition n/a
subroutine n/a
pod n/a
total 200 361 55.4


line stmt bran cond sub pod time code
1             MODULE = CryptX PACKAGE = Crypt::AuthEnc::GCM
2              
3             PROTOTYPES: DISABLE
4              
5             Crypt::AuthEnc::GCM
6             new(Class, char * cipher_name, SV * key, SV * nonce = NULL)
7             CODE:
8             {
9 16           STRLEN k_len = 0, iv_len = 0;
10 16           unsigned char *k = NULL, *iv = NULL;
11             int id, rv;
12              
13 16 50         if (!SvPOK_spec(key)) croak("FATAL: key must be string/buffer scalar");
    50          
    0          
    0          
    0          
14 16           k = (unsigned char *) SvPVbyte(key, k_len);
15 16 100         if (nonce) {
16 1 50         if (!SvPOK_spec(nonce)) croak("FATAL: nonce must be string/buffer scalar");
    50          
    0          
    0          
    0          
17 1           iv = (unsigned char *)SvPVbyte(nonce, iv_len);
18             }
19              
20 16           id = cryptx_internal_find_cipher(cipher_name);
21 16 50         if (id == -1) croak("FATAL: find_cipher failed for '%s'", cipher_name);
22              
23 16           Newz(0, RETVAL, 1, struct cryptx_authenc_gcm_struct);
24 16 50         if (!RETVAL) croak("FATAL: Newz failed");
25              
26 16           rv = gcm_init(&RETVAL->state, id, k, (unsigned long)k_len);
27 16 50         if (rv != CRYPT_OK) {
28 0           zeromem(RETVAL, sizeof(*RETVAL));
29 0           Safefree(RETVAL);
30 0           croak("FATAL: gcm_init failed: %s", error_to_string(rv));
31             }
32              
33 16 100         if (iv && iv_len > 0) {
    50          
34 1           rv = gcm_add_iv(&RETVAL->state, iv, (unsigned long)iv_len);
35 1 50         if (rv != CRYPT_OK) {
36 0           zeromem(RETVAL, sizeof(*RETVAL));
37 0           Safefree(RETVAL);
38 0           croak("FATAL: gcm_add_iv failed: %s", error_to_string(rv));
39             }
40             }
41             }
42             OUTPUT:
43             RETVAL
44              
45             void
46             DESTROY(Crypt::AuthEnc::GCM self)
47             CODE:
48 17 50         if (self) {
49 17           zeromem(self, sizeof(*self));
50 17           Safefree(self);
51             }
52              
53             Crypt::AuthEnc::GCM
54             clone(Crypt::AuthEnc::GCM self)
55             CODE:
56 1           Newz(0, RETVAL, 1, struct cryptx_authenc_gcm_struct);
57 1 50         if (!RETVAL) croak("FATAL: Newz failed");
58 1           Copy(self, RETVAL, 1, struct cryptx_authenc_gcm_struct);
59             OUTPUT:
60             RETVAL
61              
62             void
63             reset(Crypt::AuthEnc::GCM self)
64             PPCODE:
65             {
66             int rv;
67 1           rv = gcm_reset(&self->state);
68 1 50         if (rv != CRYPT_OK) croak("FATAL: gcm_reset failed: %s", error_to_string(rv));
69 1           self->finalized = 0;
70 1 50         XPUSHs(ST(0)); /* return self */
71             }
72              
73             SV *
74             encrypt_add(Crypt::AuthEnc::GCM self, SV * data)
75             CODE:
76             {
77             int rv;
78             STRLEN in_data_len;
79             unsigned char *in_data, *out_data;
80              
81 11 100         if (self->finalized) croak("FATAL: AEAD object already finalized");
82 10           in_data = (unsigned char *)SvPVbyte(data, in_data_len);
83 10 50         if (in_data_len == 0) {
84 0           RETVAL = newSVpvn("", 0);
85             }
86             else
87             {
88 10           RETVAL = NEWSV(0, in_data_len); /* avoid zero! */
89 10           SvPOK_only(RETVAL);
90 10           SvCUR_set(RETVAL, in_data_len);
91 10           out_data = (unsigned char *)SvPVX(RETVAL);
92 10           rv = gcm_process(&self->state, in_data, (unsigned long)in_data_len, out_data, GCM_ENCRYPT);
93 10 50         if (rv != CRYPT_OK) {
94 0           SvREFCNT_dec(RETVAL);
95 0           croak("FATAL: encrypt_add/gcm_process failed: %s", error_to_string(rv));
96             }
97             }
98             }
99             OUTPUT:
100             RETVAL
101              
102             void
103             iv_add(Crypt::AuthEnc::GCM self, SV * data)
104             PPCODE:
105             {
106             int rv;
107             STRLEN in_data_len;
108             unsigned char *in_data;
109              
110 16 50         if (self->finalized) croak("FATAL: AEAD object already finalized");
111 16           in_data = (unsigned char *)SvPVbyte(data, in_data_len);
112 16           rv = gcm_add_iv(&self->state, in_data, (unsigned long)in_data_len);
113 16 50         if (rv != CRYPT_OK) croak("FATAL: gcm_add_iv failed: %s", error_to_string(rv));
114 16 50         XPUSHs(ST(0)); /* return self */
115             }
116              
117             void
118             adata_add(Crypt::AuthEnc::GCM self, SV * data)
119             PPCODE:
120             {
121             int rv;
122             STRLEN in_data_len;
123             unsigned char *in_data;
124              
125 17 50         if (self->finalized) croak("FATAL: AEAD object already finalized");
126 17           in_data = (unsigned char *)SvPVbyte(data, in_data_len);
127 17           rv = gcm_add_aad(&self->state, in_data, (unsigned long)in_data_len);
128 17 50         if (rv != CRYPT_OK) croak("FATAL: gcm_add_aad failed: %s", error_to_string(rv));
129 17 50         XPUSHs(ST(0)); /* return self */
130             }
131              
132             SV *
133             decrypt_add(Crypt::AuthEnc::GCM self, SV * data)
134             CODE:
135             {
136             int rv;
137             STRLEN in_data_len;
138             unsigned char *in_data, *out_data;
139              
140 27 50         if (self->finalized) croak("FATAL: AEAD object already finalized");
141 27           in_data = (unsigned char *)SvPVbyte(data, in_data_len);
142 27 50         if (in_data_len == 0) {
143 0           RETVAL = newSVpvn("", 0);
144             }
145             else {
146 27           RETVAL = NEWSV(0, in_data_len); /* avoid zero! */
147 27           SvPOK_only(RETVAL);
148 27           SvCUR_set(RETVAL, in_data_len);
149 27           out_data = (unsigned char *)SvPVX(RETVAL);
150 27           rv = gcm_process(&self->state, out_data, (unsigned long)in_data_len, in_data, GCM_DECRYPT);
151 27 50         if (rv != CRYPT_OK) {
152 0           SvREFCNT_dec(RETVAL);
153 0           croak("FATAL: decrypt_add/gcm_process failed: %s", error_to_string(rv));
154             }
155             }
156             }
157             OUTPUT:
158             RETVAL
159              
160              
161             void
162             encrypt_done(Crypt::AuthEnc::GCM self)
163             PPCODE:
164             {
165             int rv;
166             unsigned char tag[MAXBLOCKSIZE];
167 11           unsigned long tag_len = sizeof(tag);
168              
169 11 100         if (self->finalized) croak("FATAL: AEAD object already finalized");
170 10           rv = gcm_done(&self->state, tag, &tag_len);
171 10 50         if (rv != CRYPT_OK) croak("FATAL: gcm_done failed: %s", error_to_string(rv));
172 10           self->finalized = 1;
173 10 50         XPUSHs(sv_2mortal(newSVpvn((char*)tag, tag_len)));
174 10           zeromem(tag, sizeof(tag));
175             }
176              
177             void
178             decrypt_done(Crypt::AuthEnc::GCM self, ...)
179             PPCODE:
180             {
181             int rv;
182             unsigned char tag[MAXBLOCKSIZE];
183 8           unsigned long tag_len = sizeof(tag);
184             STRLEN expected_tag_len;
185             unsigned char *expected_tag;
186              
187 8 50         if (self->finalized) croak("FATAL: AEAD object already finalized");
188 8           rv = gcm_done(&self->state, tag, &tag_len);
189 8 50         if (rv != CRYPT_OK) croak("FATAL: gcm_done failed: %s", error_to_string(rv));
190 8           self->finalized = 1;
191 8 50         if (items == 1) {
192 8 50         XPUSHs(sv_2mortal(newSVpvn((char*)tag, tag_len)));
193 8           zeromem(tag, sizeof(tag));
194             }
195             else {
196 0 0         if (!SvPOK_spec(ST(1))) croak("FATAL: expected_tag must be string/buffer scalar");
    0          
    0          
    0          
    0          
197 0           expected_tag = (unsigned char *) SvPVbyte(ST(1), expected_tag_len);
198 0 0         if (expected_tag_len!=tag_len) {
199 0 0         XPUSHs(sv_2mortal(newSViv(0))); /* false */
200             }
201 0 0         else if (mem_neq(expected_tag, tag, tag_len)) {
202 0 0         XPUSHs(sv_2mortal(newSViv(0))); /* false */
203             }
204             else {
205 0 0         XPUSHs(sv_2mortal(newSViv(1))); /* true */
206             }
207             }
208             }
209              
210             void
211             gcm_encrypt_authenticate(char *cipher_name, SV *key, SV *nonce, SV *header = NULL, SV *plaintext)
212             PPCODE:
213             {
214 10           STRLEN k_len = 0, n_len = 0, h_len = 0, pt_len = 0;
215 10           unsigned char *k = NULL, *n = NULL, *h = NULL, *pt = NULL;
216             int rv, id;
217             unsigned char tag[MAXBLOCKSIZE];
218 10           unsigned long tag_len = sizeof(tag);
219             SV *output;
220              
221 10 50         if (!SvPOK_spec(key)) croak("FATAL: key must be string/buffer scalar");
    100          
    50          
    50          
    50          
222 10           k = (unsigned char *) SvPVbyte(key, k_len);
223 10 50         if (!SvPOK_spec(nonce)) croak("FATAL: nonce must be string/buffer scalar");
    100          
    50          
    50          
    50          
224 10           n = (unsigned char *) SvPVbyte(nonce, n_len);
225 10 50         if (!SvPOK_spec(plaintext)) croak("FATAL: plaintext must be string/buffer scalar");
    50          
    0          
    0          
    0          
226 10           pt = (unsigned char *) SvPVbyte(plaintext, pt_len);
227 10 50         if (header && SvOK(header)) {
    50          
228 10 50         if (!SvPOK_spec(header)) croak("FATAL: header must be string/buffer scalar");
    50          
    0          
    0          
    0          
229 10           h = (unsigned char *) SvPVbyte(header, h_len);
230 10           zeromem(tag, sizeof(tag));
231             }
232              
233 10           id = cryptx_internal_find_cipher(cipher_name);
234 10 50         if(id==-1) croak("FATAL: find_cipher failed for '%s'", cipher_name);
235 10 50         output = NEWSV(0, pt_len > 0 ? pt_len : 1); /* avoid zero! */
236 10           SvPOK_only(output);
237 10           SvCUR_set(output, pt_len);
238              
239 10           rv = gcm_memory(id, k, (unsigned long)k_len, n, (unsigned long)n_len, h, (unsigned long)h_len,
240 10           pt, (unsigned long)pt_len, (unsigned char *)SvPVX(output), tag, &tag_len, GCM_ENCRYPT);
241              
242 10 50         if (rv != CRYPT_OK) {
243 0           SvREFCNT_dec(output);
244 0           croak("FATAL: gcm_memory failed: %s", error_to_string(rv));
245             }
246 10 50         XPUSHs(sv_2mortal(output));
247 10 50         XPUSHs(sv_2mortal(newSVpvn((char*)tag, tag_len)));
248             }
249              
250             void
251             gcm_decrypt_verify(char *cipher_name, SV *key, SV *nonce, SV *header, SV *ciphertext, SV *tagsv)
252             PPCODE:
253             {
254 11           STRLEN k_len = 0, n_len = 0, h_len = 0, ct_len = 0, t_len = 0;
255 11           unsigned char *k = NULL, *n = NULL, *h = NULL, *ct = NULL, *t = NULL;
256             int rv, id;
257             unsigned char tag[MAXBLOCKSIZE];
258             unsigned long tag_len;
259             SV *output;
260              
261 11 50         if (!SvPOK_spec(key)) croak("FATAL: key must be string/buffer scalar");
    50          
    0          
    0          
    0          
262 11           k = (unsigned char *) SvPVbyte(key, k_len);
263 11 50         if (!SvPOK_spec(nonce)) croak("FATAL: nonce must be string/buffer scalar");
    50          
    0          
    0          
    0          
264 11           n = (unsigned char *) SvPVbyte(nonce, n_len);
265 11 50         if (!SvPOK_spec(ciphertext)) croak("FATAL: ciphertext must be string/buffer scalar");
    50          
    0          
    0          
    0          
266 11           ct = (unsigned char *) SvPVbyte(ciphertext, ct_len);
267 11 50         if (!SvPOK_spec(tagsv)) croak("FATAL: tag must be string/buffer scalar");
    50          
    0          
    0          
    0          
268 11           t = (unsigned char *) SvPVbyte(tagsv, t_len);
269 11 50         if (header && SvOK(header)) {
    50          
270 11 50         if (!SvPOK_spec(header)) croak("FATAL: header must be string/buffer scalar");
    50          
    0          
    0          
    0          
271 11           h = (unsigned char *) SvPVbyte(header, h_len);
272 11           zeromem(tag, sizeof(tag));
273             }
274              
275 11           id = cryptx_internal_find_cipher(cipher_name);
276 11 50         if(id==-1) croak("FATAL: find_cipher failed for '%s'", cipher_name);
277 11 50         output = NEWSV(0, ct_len > 0 ? ct_len : 1); /* avoid zero! */
278 11           SvPOK_only(output);
279 11           SvCUR_set(output, ct_len);
280             /* Clamp malformed tags to the stack buffer size before copying. */
281 11           tag_len = (unsigned long)(t_len > sizeof(tag) ? sizeof(tag) : t_len);
282 11 50         if (tag_len > 0) {
283 11           Copy(t, tag, tag_len, unsigned char);
284             }
285              
286 11           rv = gcm_memory(id, k, (unsigned long)k_len, n, (unsigned long)n_len, h, (unsigned long)h_len,
287 11           (unsigned char *)SvPVX(output), (unsigned long)ct_len, ct, tag, &tag_len, GCM_DECRYPT);
288              
289 11 100         if (rv != CRYPT_OK) {
290 3           SvREFCNT_dec(output);
291 3 50         XPUSHs(sv_2mortal(newSVpvn(NULL,0))); /* undef */
292             }
293             else {
294 8 50         XPUSHs(sv_2mortal(output));
295             }
296             }