File Coverage

Blowfish.xs
Criterion Covered Total %
statement 124 147 84.3
branch 47 82 57.3
condition n/a
subroutine n/a
pod n/a
total 171 229 74.6


line stmt bran cond sub pod time code
1             #define PERL_NO_GET_CONTEXT
2             #include "EXTERN.h"
3             #include "perl.h"
4             #include "XSUB.h"
5             #define NEED_mg_findext
6             #include "ppport.h"
7              
8             #include
9             #if OPENSSL_VERSION_NUMBER >= 0x30000000L
10             #include
11             #include
12             #endif
13              
14             /*==========================================================*/
15             /* */
16             /* hexdump.xs: */
17             /* https://gist.github.com/mcnewton/14322391d50240ec9ebf */
18             /* */
19             /* Matthew Newton @mcnewton */
20             /* See hexdump.xs for LICENSE information */
21             /*==========================================================*/
22              
23             #ifdef INCLUDE_HEXDUMP
24             #include "hexdump.xs"
25             #endif
26              
27             /*==================================================*/
28             /* */
29             /* Macro to swap from little endian to big endian */
30             /* */
31             /*==================================================*/
32             # undef n2l
33             # define n2l(c,l) (l =((unsigned long)(*((c)++)))<<24L, \
34             l|=((unsigned long)(*((c)++)))<<16L, \
35             l|=((unsigned long)(*((c)++)))<< 8L, \
36             l|=((unsigned long)(*((c)++))))
37              
38             /*==================================================*/
39             /* */
40             /* Macro to swap from big endian to little endian */
41             /* */
42             /*==================================================*/
43             # undef l2n
44             # define l2n(l,c) (*((c)++)=(unsigned char)(((l)>>24L)&0xff), \
45             *((c)++)=(unsigned char)(((l)>>16L)&0xff), \
46             *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \
47             *((c)++)=(unsigned char)(((l) )&0xff))
48              
49             /*============================================*/
50             /* */
51             /* ensure_hv(SV *sv, const char *identifier) */
52             /* */
53             /* Helper function Taken from p5-Git-Raw */
54             /* to ensure that a value is a hash. It is */
55             /* used to verify that the 'options' passed */
56             /* in the constructor is valid */
57             /* */
58             /*============================================*/
59 5           STATIC HV *ensure_hv(pTHX_ SV *sv, const char *identifier) {
60 5 50         if (!SvROK(sv) || SvTYPE(SvRV(sv)) != SVt_PVHV)
    50          
61 0           croak("Invalid type for '%s', expected a hash", identifier);
62              
63 5           return (HV *) SvRV(sv);
64             }
65              
66             /*======================================================================*/
67             /* */
68             /* big_endian(const unsigned char *in, unsigned char *out) */
69             /* */
70             /* Swap the endianness of the block of data 'in'. This is only */
71             /* required for compatability with the original version of */
72             /* Crypt::OpenSSL::Blowfish. Which calls BF_encrypt and BF_decrypt */
73             /* without switching to big endian first. This function is called if */
74             /* Crypt::OpenSSL::Blowfish is created without any options (other than */
75             /* the key). */
76             /* */
77             /*======================================================================*/
78 9           void big_endian(const unsigned char *in, unsigned char *out)
79             {
80             BF_LONG l;
81             BF_LONG d[2];
82              
83 9           n2l(in, l);
84 9           d[0] = l;
85 9           n2l(in, l);
86 9           d[1] = l;
87 9           Copy(d, out, 2, BF_LONG);
88 9           l = d[0] = d[1] = 0;
89 9           }
90              
91             /*======================================================================*/
92             /* */
93             /* return_big_endian(const unsigned char *in) */
94             /* */
95             /* Swap the endianness of the block of data 'in'. This is only */
96             /* required for compatability with the original version of */
97             /* Crypt::OpenSSL::Blowfish. Which calls BF_encrypt and BF_decrypt */
98             /* without switching to big endian first. This function is called if */
99             /* Crypt::OpenSSL::Blowfish is created without any options (other than */
100             /* the key) or if the Modules get_big_endian is called. */
101             /* */
102             /*======================================================================*/
103 9           unsigned char * return_big_endian(pTHX_ const unsigned char *in)
104             {
105             unsigned char * out;
106 9           Newx(out, BF_BLOCK, unsigned char); //Bunsigned char, unsigned char);
107 9           big_endian(in, out);
108 9           return out;
109             }
110              
111             /*======================================================================*/
112             /* */
113             /* little_endian(const BF_LONG *d, unsigned char *out) */
114             /* */
115             /* Swap the endianness of the block of data 'in'. This is only */
116             /* required for compatability with the original version of */
117             /* Crypt::OpenSSL::Blowfish. Which calls BF_encrypt and BF_decrypt */
118             /* without switching to big endian first. This function is called if */
119             /* Crypt::OpenSSL::Blowfish is created without any options (other than */
120             /* the key). */
121             /* */
122             /*======================================================================*/
123 9           void little_endian(const BF_LONG *in, unsigned char *out)
124             {
125             BF_LONG l;
126              
127 9           l = in[0];
128 9           l2n(l, out);
129 9           l = in[1];
130 9           l2n(l, out);
131 9           }
132              
133             /*======================================================================*/
134             /* */
135             /* return_little_endian(const unsigned char *in) */
136             /* */
137             /* Swap the endianness of the block of data 'in'. This is only */
138             /* required for compatability with the original version of */
139             /* Crypt::OpenSSL::Blowfish. Which calls BF_encrypt and BF_decrypt */
140             /* without switching to big endian first. This function is called if */
141             /* Crypt::OpenSSL::Blowfish is created without any options (other than */
142             /* the key) or if the Modules get_big_endian is called. */
143             /* */
144             /*======================================================================*/
145 9           unsigned char * return_little_endian(pTHX_ unsigned char *in)
146             {
147             unsigned char *out;
148             BF_LONG d[2];
149              
150 9           Newx(out, BF_BLOCK, unsigned char);
151 9           Copy(in, d, BF_BLOCK, unsigned char);
152              
153 9           little_endian(d, out);
154              
155 9           return out;
156             }
157              
158 50           void print_pointers(pTHX_ char * name, void * pointer) {
159             #ifdef PRINT_POINTERS
160             printf("Crypt pointer - %s: %p\n", name, pointer);
161             printf("Crypt INT of pointer - %s: %lu\n", name, (unsigned long) PTR2IV(pointer));
162             #endif
163 50           }
164              
165             static const MGVTBL ks_magic = { NULL, NULL, NULL, NULL, NULL };
166              
167             MODULE = Crypt::OpenSSL::Blowfish PACKAGE = Crypt::OpenSSL::Blowfish PREFIX = blowfish_
168             PROTOTYPES: DISABLE
169              
170             #=============================================
171             #
172             # blowfish_new(class, key_sv, ...)
173             #
174             # Instantiate the BF_KEY and add it to the
175             # object
176             #
177             #=============================================
178             SV *
179             blowfish_new(class, key_sv, ...)
180             const char * class
181             SV * key_sv
182             PREINIT:
183 8           SV *ks = newSV(0);
184 8           IV mod = 1;
185             STRLEN keysize;
186             unsigned char * key;
187             #if OPENSSL_VERSION_NUMBER >= 0x30000000L
188 8           EVP_CIPHER_CTX *ctx = NULL;
189             OSSL_PROVIDER *legacy;
190             OSSL_PROVIDER *deflt;
191             #else
192             BF_KEY *bf_ks;
193             #endif
194 8           HV * options = NULL;
195             HV * attributes;
196 8           SV *modern = newSV(0);
197             CODE:
198             {
199             PERL_UNUSED_ARG(options);
200 8           options = newHV();
201 8 100         if (items > 2)
202 5           options = ensure_hv(aTHX_ ST(2), "options");
203              
204 8 50         if (!SvPOK (key_sv))
205 0           croak("Key must be a scalar");
206              
207 8           key = (unsigned char *) SvPVbyte(key_sv, keysize);
208              
209             /* FIXME: openssl seems to use 16-byte keys only */
210 8 100         if (keysize != 8 && keysize !=16 && keysize != 24 && keysize != 32)
    50          
    0          
    0          
211 0           croak ("The key must be 64, 128, 192 or 256 bits long");
212             #if OPENSSL_VERSION_NUMBER >= 0x30000000L
213 8           legacy = OSSL_PROVIDER_load(NULL, "legacy");
214 8 50         if (legacy == NULL) {
215 0           croak("Failed to load Legacy provider\n");
216             }
217              
218 8           deflt = OSSL_PROVIDER_load(NULL, "default");
219 8 50         if (deflt == NULL) {
220 0           OSSL_PROVIDER_unload(legacy);
221 0           croak("Failed to load Default provider\n");
222             }
223              
224             /* Create the EVP_CIPHER_CTX object */
225 8 50         if(!(ctx = EVP_CIPHER_CTX_new()))
226 0           croak ("Failed to create the EVP_CIPHER_CTX object\n");
227              
228 8 50         if(0 == EVP_CipherInit_ex2(ctx, EVP_bf_ecb(), NULL, NULL, 0, NULL))
229 0           croak ("EVP_CipherInit_ex2 failed\n");
230              
231 8           EVP_CIPHER_CTX_set_key_length(ctx, keysize);
232             /*hexdump(stdout, (unsigned char *) ctx, sizeof(ctx), 16, 8); */
233 8 50         OPENSSL_assert(EVP_CIPHER_CTX_key_length(ctx) == keysize);
234 8 50         OPENSSL_assert(EVP_CIPHER_CTX_iv_length(ctx) == 0); /*FIXME */
235              
236 8 50         if (0 == EVP_CipherInit_ex2(ctx, NULL, key, NULL, 0, NULL))
237 0           croak ("EVP_CipherInit_ex2 failed\n");
238              
239             /*hexdump(stdout, (unsigned char *) ctx, sizeof(ctx), 16, 8); */
240 8           print_pointers(aTHX_ "ctx", ctx);
241             #else
242             /* Allocate memory to hold the Blowfish BF_KEY object */
243             Newx(bf_ks, 1, BF_KEY);
244              
245             BF_set_key(bf_ks, keysize, key);
246              
247             print_pointers(aTHX_ "bf_ks", bf_ks);
248             #endif
249 8           attributes = newHV();
250 8           SV *const self = newRV_inc( (SV *)attributes );
251             #if OPENSSL_VERSION_NUMBER >= 0x30000000L
252 8           sv_magicext(ks, NULL, PERL_MAGIC_ext,
253             &ks_magic, (const char *) ctx, 0);
254             #else
255             sv_magicext(ks, NULL, PERL_MAGIC_ext,
256             &ks_magic, (const char *) bf_ks, 0);
257             #endif
258 8 50         if((hv_store(attributes, "ks", 2, ks, 0)) == NULL)
259 0           croak("unable to store the BF_KEY");
260              
261 8 100         if (items > 2) {
262 5           sv_magicext(modern, NULL, PERL_MAGIC_ext,
263             &ks_magic, (const char *) mod, 0);
264              
265 5 50         if((hv_store(attributes, "modern", 6, modern, 0)) == NULL)
266 0           croak("unable to store the modern");
267             }
268              
269 8           print_pointers(aTHX_ "modern", modern);
270 8           RETVAL = sv_bless( self, gv_stashpv( class, 0 ) );
271             }
272             OUTPUT:
273             RETVAL
274              
275             #=============================================
276             #
277             # blowfish_crypt(self, data_sv, encrypt)
278             #
279             # Crypt/Decrypt the data depending on the encrypt
280             #
281             #=============================================
282             SV * blowfish_crypt(self, data_sv, encrypt)
283             HV * self
284             SV * data_sv
285             int encrypt
286             PREINIT:
287             STRLEN data_len;
288             unsigned char * in;
289             MAGIC* mg;
290             SV **svp;
291 15           int *modern = 0;
292             unsigned char *out;
293             #if OPENSSL_VERSION_NUMBER >= 0x30000000L
294             EVP_CIPHER_CTX *ctx;
295 15           int out_len = 0;
296 15           int ciphertext_len = 0;
297 15 50         int plaintext_len = 0;
298             #else
299             BF_KEY *bf_ks = NULL;
300             #endif
301             CODE:
302             {
303 15 100         if (hv_exists(self, "modern", strlen("modern"))) {
304 10           svp = hv_fetch(self, "modern", strlen("modern"), 0);
305 10 50         if (!SvMAGICAL(*svp) || (mg = mg_findext(*svp, PERL_MAGIC_ext, &ks_magic)) == NULL)
    50          
306 0           croak("Accessing the modern value from magic failed");
307 10           modern = (int *) mg->mg_ptr;
308             }
309              
310 15           in = (unsigned char *) SvPVbyte(data_sv, data_len);
311              
312             /*hexdump(stdout, data, data_len, 16, 8); */
313              
314 15           Newx(out, BF_BLOCK, unsigned char);
315 15 100         if (! modern) {
316 5           Copy(in, out, BF_BLOCK, unsigned char);
317 5           in = return_big_endian(aTHX_ out);
318             }
319              
320             /*hexdump(stdout, data, data_len, 16, 8); */
321 15 50         if (!hv_exists(self, "ks", strlen("ks")))
322 0           croak("ks not found in self!\n");
323              
324 15           svp = hv_fetch(self, "ks", strlen("ks"), 0);
325              
326 15 50         if (!SvMAGICAL(*svp) || (mg = mg_findext(*svp, PERL_MAGIC_ext, &ks_magic)) == NULL)
    50          
327 0           croak("Accessing the key from magic failed");
328             #if OPENSSL_VERSION_NUMBER >= 0x30000000L
329 15           ctx = (EVP_CIPHER_CTX *) mg->mg_ptr;
330 15           print_pointers(aTHX_ "ctx", ctx);
331              
332 15 100         if ( encrypt == 1) {
333 9           EVP_CIPHER_CTX_set_padding(ctx, 0);
334 9 50         if (0 == EVP_CipherInit_ex2(ctx, NULL, NULL, NULL, encrypt, NULL))
335 0           croak("EVP_CipherInit_ex2 failed");
336              
337 9 50         if (0 == EVP_CipherUpdate(ctx, out, &out_len, in, data_len))
338 0           croak ("EVP_CipherUpdate failed in Encrypt\n");
339              
340 9           ciphertext_len += out_len;
341              
342 9 50         if (0 == EVP_CipherFinal_ex(ctx, out + out_len, &out_len))
343 0           croak ("EVP_CipherFinal_ex failed in Encrypt\n");
344              
345 9           ciphertext_len += out_len;
346              
347             /*hexdump(stdout, (unsigned char *) out, sizeof(out), 16, 8); */
348             } else {
349 6           print_pointers(aTHX_ "ctx", ctx);
350             /*hexdump(stdout, (unsigned char *) data, sizeof(data), 16, 8); */
351 6           EVP_CIPHER_CTX_set_padding(ctx, 0);
352 6 50         if (0 == EVP_CipherInit_ex2(ctx, NULL, NULL, NULL, encrypt, NULL))
353 0           croak(">>>EVP_CipherInit_ex2 failed");
354              
355             /*hexdump(stdout, (unsigned char *) ctx, sizeof(ctx), 16, 8); */
356 6 50         if (0 == EVP_CipherUpdate(ctx, out, &out_len, in, data_len))
357 0           croak ("EVP_CipherUpdate failed in Decrypt\n");
358              
359             /*hexdump(stdout, (unsigned char *) ciphertext, sizeof(plaintext), 16, 8); */
360 6           plaintext_len += out_len;
361              
362 6 50         if (0 == EVP_CipherFinal_ex(ctx, out + out_len, &out_len))
363 0           croak ("EVP_CipherFinal_ex failed in Decrypt\n");
364              
365 6           plaintext_len += out_len;
366             /*hexdump(stdout, (unsigned char *) plaintext, sizeof(plaintext), 16, 8); */
367             }
368             #else
369             bf_ks = (BF_KEY *) mg->mg_ptr;
370             print_pointers(aTHX_ "bf_ks", bf_ks);
371              
372             /*hexdump(stdout, bf_ks, sizeof(BF_KEY), 16, 8); */
373             if (data_len != BF_BLOCK) {
374             croak("data must be 8 bytes long");
375             }
376              
377             BF_ecb_encrypt(in, out, bf_ks, encrypt);
378             #endif
379             /*hexdump(stdout, out, sizeof(char)*8, 16, 8); */
380              
381 15 100         if (! modern) {
382 5           Copy(out, in, BF_BLOCK, unsigned char );
383 5           out = return_little_endian(aTHX_ in);
384             }
385              
386             /*hexdump(stdout, out, sizeof(char)*8, 16, 8); */
387              
388 15           RETVAL = newSV (data_len);
389 15           SvPOK_only (RETVAL);
390 15           SvCUR_set (RETVAL, data_len);
391 15           sv_setpvn(RETVAL, (char *) out, data_len);
392              
393             }
394             OUTPUT:
395             RETVAL
396              
397             #=============================================
398             #
399             # blowfish_get_big_endian(self, data_sv)
400             #
401             # Convert the data_sv to big-endian
402             #
403             #=============================================
404             SV *
405             blowfish_get_big_endian(self, data_sv)
406             HV * self
407             SV * data_sv
408             PREINIT:
409             unsigned char * in;
410             unsigned char * out;
411             STRLEN data_len;
412             CODE:
413             PERL_UNUSED_ARG(self);
414 4           in = (unsigned char *) SvPVbyte(data_sv, data_len);
415 4           out = return_big_endian(aTHX_ in);
416              
417 4           RETVAL = newSV (data_len);
418 4           SvPOK_only (RETVAL);
419 4           SvCUR_set (RETVAL, data_len);
420 4           sv_setpvn(RETVAL, (char *) out, data_len);
421             OUTPUT:
422             RETVAL
423              
424             #=============================================
425             #
426             # blowfish_get_little_endian(self, data_sv)
427             #
428             # Convert the data_sv to little-endian
429             #
430             #=============================================
431             SV *
432             blowfish_get_little_endian(self, data_sv)
433             HV * self
434             SV * data_sv
435             PREINIT:
436             unsigned char *in;
437             unsigned char *out;
438             STRLEN data_len;
439             CODE:
440             PERL_UNUSED_ARG(self);
441 4           in = (unsigned char *) SvPVbyte(data_sv, data_len);
442 4           out = return_little_endian(aTHX_ in);
443              
444 4           RETVAL = newSV (data_len);
445 4           SvPOK_only (RETVAL);
446 4           SvCUR_set (RETVAL, data_len);
447 4           sv_setpvn(RETVAL, (char *) out, data_len);
448             OUTPUT:
449             RETVAL
450              
451             #===========================================
452             #
453             # blowfish_DESTROY(self)
454             #
455             # Free the BF_KEY as the module is unloaded
456             #
457             #===========================================
458             void
459             blowfish_DESTROY(self)
460             HV *self
461             PREINIT:
462             SV **svp;
463             #if OPENSSL_VERSION_NUMBER >= 0x30000000L
464 8           EVP_CIPHER_CTX *ctx = NULL;
465             #else
466             BF_KEY *bf_ks = NULL;
467             #endif
468             MAGIC* mg;
469             MAGIC* mg_mod;
470 8 50         int * modern = NULL;
471             CODE:
472 8 50         if (!hv_exists(self, "ks", strlen("ks")))
473 0           croak("ks not found in self!\n");
474              
475 8           svp = hv_fetch(self, "ks", strlen("ks"), 0);
476              
477 8 50         if (!SvMAGICAL(*svp) || (mg = mg_findext(*svp, PERL_MAGIC_ext, &ks_magic)) == NULL)
    50          
478 0           croak("STORE is invalid");
479             #if OPENSSL_VERSION_NUMBER >= 0x30000000L
480 8           ctx = (EVP_CIPHER_CTX *) mg->mg_ptr;
481 8           print_pointers(aTHX_ "ctx", ctx);
482              
483 8 100         if (!hv_exists(self, "modern", strlen("modern")))
484 3           croak("modern not found in self!\n");
485              
486 5           svp = hv_fetch(self, "modern", strlen("modern"), 0);
487              
488 5 50         if (!SvMAGICAL(*svp) || (mg_mod = mg_findext(*svp, PERL_MAGIC_ext, &ks_magic)) == NULL)
    50          
489 0           modern = (int *) mg_mod->mg_ptr;
490 5           print_pointers(aTHX_ "modern", modern);
491             /* Clean up */
492 5           EVP_CIPHER_CTX_free(ctx);
493 5           Safefree(modern);
494             #else
495             bf_ks = (BF_KEY *) mg->mg_ptr;
496             print_pointers(aTHX_ "bf_ks", bf_ks);
497             Safefree(bf_ks);
498             #endif