File Coverage

inc/CryptX_AuthEnc_ChaCha20Poly1305.xs.inc
Criterion Covered Total %
statement 118 142 83.1
branch 91 236 38.5
condition n/a
subroutine n/a
pod n/a
total 209 378 55.2


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