File Coverage

inc/CryptX_AuthEnc_CCM.xs.inc
Criterion Covered Total %
statement 114 138 82.6
branch 68 220 30.9
condition n/a
subroutine n/a
pod n/a
total 182 358 50.8


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