File Coverage

blib/lib/Mojolicious/Plugin/Crypto.pm
Criterion Covered Total %
statement 96 108 88.8
branch 19 38 50.0
condition 9 13 69.2
subroutine 18 22 81.8
pod 1 3 33.3
total 143 184 77.7


line stmt bran cond sub pod time code
1             package Mojolicious::Plugin::Crypto;
2             {
3             $Mojolicious::Plugin::Crypto::VERSION = '0.12';
4             }
5 3     3   1226752 use Mojo::Base 'Mojolicious::Plugin';
  3         6  
  3         130  
6 3     3   381 use Mojo::Util;
  3         4  
  3         97  
7 3     3   12 use Mojo::Loader;
  3         7  
  3         15  
8 3     3   1685 use Crypt::CBC;
  3         10600  
  3         104  
9 3     3   1408 use Crypt::PRNG;
  3         7229  
  3         109  
10 3     3   1260 use Crypt::Cipher;
  3         1275  
  3         78  
11 3     3   15 no warnings "experimental";
  3         4  
  3         2956  
12              
13             our %symmetric_algo = (
14             'aes' => 'Crypt::Cipher::AES',
15             'blowfish' => 'Crypt::Cipher::Blowfish',
16             'des' => 'Crypt::Cipher::DES',
17             '3des' => 'Crypt::Cipher::DES_EDE',
18             'triple_des' => 'Crypt::Cipher::DES_EDE',
19             'des_ede' => 'Crypt::Cipher::DES_EDE',
20             'twofish' => 'Crypt::Cipher::Twofish',
21             'xtea' => 'Crypt::Cipher::XTEA',
22             'anubis' => 'Crypt::Cipher::Anubis',
23             'camellia' => 'Crypt::Cipher::Camellia',
24             'kasumi' => 'Crypt::Cipher::KASUMI',
25             'khazad' => 'Crypt::Cipher::Khazad',
26             'multi2' => 'Crypt::Cipher::MULTI2',
27             'noekeon' => 'Crypt::Cipher::Noekeon',
28             'rc2' => 'Crypt::Cipher::RC2',
29             'rc5' => 'Crypt::Cipher::RC5',
30             'rc6' => 'Crypt::Cipher::RC6',
31             );
32              
33             sub register {
34 3     3 1 782 my ( $self, $app, $args ) = @_;
35 3   50     13 $args ||= {};
36              
37 3         13 my $loader = Mojo::Loader->new;
38              
39 3 100 66     28 if ( $args->{symmetric_cipher} || !%{$args} ) {
  3         21  
40 1         3 for my $module ( @{ $loader->search('Crypt::Cipher') } ) {
  1         7  
41 23         2265 my $e = $loader->load($module);
42 23 50 0     20601 warn qq{Loading "$module" failed: $e} and next if ref $e;
43             }
44              
45 1         15 foreach my $method (
46             qw( _crypt_x _decrypt_x crypt_aes decrypt_aes crypt_blowfish decrypt_blowfish crypt_des decrypt_des
47             crypt_3des decrypt_3des crypt_twofish decrypt_twofish crypt_xtea decrypt_xtea crypt_anubis
48             decrypt_anubis crypt_camellia decrypt_camellia crypt_kasumi decrypt_kasumi crypt_khazad
49             decrypt_khazad crypt_noekeon decrypt_noekeon crypt_multi2 decrypt_multi2 crypt_rc2 decrypt_rc2 crypt_rc5
50             decrypt_rc5 crypt_rc6 decrypt_rc6 gen_key gen_iv)
51             )
52             {
53 34         2149 $app->helper( $method => \&{$method} );
  34         191  
54             }
55             }
56              
57 3 100 100     107 if ( $args->{digest} || !%{$args} ) {
  2         10  
58 2         4 for my $module ( @{ $loader->search('Crypt::Digest') } ) {
  2         10  
59 30         3852 my $e = $loader->load($module);
60              
61 30 50       40304 if ( ref $e ) {
62 0 0       0 warn qq{Loading "$module" failed: $e} and next;
63             }
64              
65 224 100       13041 map { $app->helper( $_ => \&{$_} ) } map {
  224         1304  
  390         1714  
66 30         82 $_ ~~ /^sha|md5|md4|md2|ripemd|tiger|whirlpool.*/
67             ? $_
68             : ()
69             } _lm($module);
70              
71             }
72             }
73              
74 3 100 100     202 if ( $args->{mac} || !%{$args} ) {
  2         27  
75 2         5 for my $module ( @{ $loader->search('Crypt::Mac') } ) {
  2         14  
76 12         1755 my $e = $loader->load($module);
77              
78 12 50       19348 if ( ref $e ) {
79 0 0       0 warn qq{Loading "$module" failed: $e} and next;
80             }
81              
82 8 100       575 map { $app->helper( $_ => \&{$_} ) }
  8         76  
  168         691  
83 12         39 map { $_ ~~ /^hmac.*/ ? $_ : () } _lm($module);
84              
85             }
86             }
87              
88             }
89              
90             sub _crypt_x {
91 19     19   1344 my ( $self, $algo, $content, $key ) = @_;
92 19 50       37 $key = $self->gen_key("sha256") unless ($key);
93 19         56 my $keypack = pack( "H16", $key );
94 19         99 my $en = new Crypt::CBC(
95             -key => $keypack,
96             -salt => 1,
97             -cipher => $symmetric_algo{$algo}
98             )->encrypt($content);
99 19         21980 my $enh = unpack( 'H*', $en );
100 19         112 return ( $enh, $key );
101             }
102              
103             sub _decrypt_x {
104 20     20   1450 my ( $self, $algo, $cipher_content, $key ) = @_;
105 20 50       40 return "" unless ($key);
106 20         58 my $keypack = pack( "H16", $key );
107 20         104 my $de = pack( 'H*', $cipher_content );
108 20         103 my $clear = new Crypt::CBC(
109             -key => $keypack,
110             -salt => 1,
111             -cipher => $symmetric_algo{$algo}
112             )->decrypt($de);
113 20         6969 return ( $clear, $key );
114             }
115              
116             sub gen_key {
117 0     0 0 0 my ( $self, $mode ) = @_;
118 0 0       0 ( $mode eq "sha256" ) ? sha256_hex( _prng( 100, "alphanum" ) ) : "NONE";
119             }
120              
121             sub gen_iv {
122 0     0 0 0 my ( $self, $byte, $mode ) = @_;
123 0 0       0 ( $mode eq "prng" ) ? _prng( $byte, "" ) : "";
124             }
125              
126             sub _prng {
127 0     0   0 my ( $byte, $mode ) = @_;
128              
129 0 0       0 Crypt::PRNG->bytes_b64($byte) unless ( $mode ne "base64" );
130 0 0       0 Crypt::PRNG->bytes_hex($byte) unless ( $mode ne "hex" );
131 0 0       0 Crypt::PRNG->string($byte) unless ( $mode ne "alphanum" );
132 0         0 Crypt::PRNG->bytes($byte);
133             }
134              
135             sub _lm {
136 42     42   57 my $module = shift;
137 3     3   17 no strict 'refs';
  3         5  
  3         391  
138 42         48 return grep { defined &{"$module\::$_"} } keys %{"$module\::"};
  822         585  
  822         2012  
  42         344  
139             }
140              
141             sub _d {
142 2     2   3 my ( $called, $data ) = @_;
143 2         6 $called =~ /^([A-Za-z0-9]+)\_.*/;
144 3     3   15 no strict 'refs';
  3         7  
  3         226  
145 2         2 return &{ 'Crypt::Digest::' . uc($1) . '::' . $called }($data);
  2         14  
146             }
147              
148             sub _h {
149 4     4   7 my ( $hash_name, $key, $called, @other ) = @_;
150 3     3   32 no strict 'refs';
  3         4  
  3         187  
151 4         4 return &{ 'Crypt::Mac::HMAC::' . $called }( $hash_name, $key, @other );
  4         20  
152             }
153              
154 3     3   14 use vars qw($AUTOLOAD);
  3         4  
  3         890  
155              
156             sub AUTOLOAD {
157 45     45   20947 my ( $self, $c, $k, @other ) = @_;
158 45         185 my $called = $AUTOLOAD =~ s/.*:://r;
159 45 100       201 return _d( $called, $c )
160             unless ( $called !~ /^sha|md5|md4|md2|ripemd|tiger|whirlpool.*/ );
161 43 100       86 return _h( $c, $k, $called, @other ) unless ( $called !~ /^hmac.*/ );
162 39         82 $called =~ m/(.*)_(.*)/;
163 39         92 my $func = "_" . lc($1) . "_x";
164 39         227 return $self->$func( lc($2), $c, $k );
165             }
166 0     0     sub DESTROY { }
167              
168             #################### main pod documentation begin ###################
169              
170             =head1 NAME
171              
172             Mojolicious::Plugin::Crypto - Provide interface to some cryptographic stuff.
173              
174             =head1 SYNOPSIS
175              
176             use Mojolicious::Plugin::Crypto;
177            
178             my $fix_key = 'secretpassphrase';
179             my $plain = "NemuxMojoCrypt";
180              
181             #### Symmetric Functions
182             # You can leave key value empty and it will generate a new key for you
183              
184             my ($crypted, $key) = $t->app->crypt_aes($plain, $fix_key);
185            
186             #... [ store this crypted data where do you want ... ]
187            
188             # and decrypt it
189             my $clean = $t->app->decrypt_aes($crypted, $key);
190            
191             ### Hash
192              
193             ### From string/buffer
194             my $digest_hex = $t->app->sha256_hex("Take this content");
195             ### From filehandle
196             my $digest_raw = $t->app->sha256_file(*FILEHANDLE);
197             ### From File
198             $digest_hex = $t->app->sha256_file_hex('filename.txt');
199              
200             ### base64
201             my $digest_b64 = $t->app->sha256_b64('data string');
202             my $digest_b64u = $t->app->sha256_b64u('data string');
203              
204             =head1 DESCRIPTION
205              
206             =over
207              
208             =item *
209              
210             Symmetric cipher algorithms using cipher-block chaining. AES, Blowfish, DES, 3DES and more, see below.
211              
212             =item *
213              
214             Hash/Digest Functions - SHA*, MD*, Whirlpool, CHAES, RIPEMD*, Tiger192.
215              
216             =item *
217              
218             HMAC message authentication code (MAC) algorithm.
219              
220             =back
221              
222             =head2 Symmetric algorithms supported
223              
224             You can use this plugin in order to encrypt and decrypt using one of these algorithms:
225              
226             =over
227              
228             =item *
229              
230             B
231              
232             =item *
233              
234             B
235              
236             =item *
237              
238             B
239              
240             =item *
241              
242             B
243              
244             =item *
245              
246             B
247              
248             =item *
249              
250             B
251              
252             =item *
253              
254             B
255              
256             =item *
257              
258             B
259              
260             =item *
261              
262             B
263              
264             =item *
265              
266             B
267              
268             =item *
269              
270             B
271              
272             =item *
273              
274             B
275              
276             =item *
277              
278             B
279              
280             =item *
281              
282             B
283              
284             =item *
285              
286             B
287              
288             =back
289              
290              
291             =head1 Symmetric Algorithms USAGE
292              
293             =head2 crypt_[ALGO_NAME]()
294            
295             call function crypt_ followed by the lowercase algorithms name. For example crypt_aes("My Plain Test", "ThisIsMySecretKey")
296             an array will be the return value with ('securedata', 'keyused').
297              
298             =head2 decrypt_[ALGO_NAME]()
299            
300             The same thing for decryption decrypt_ followed by the algorithms name in lowercase
301             Ex.: decrypt_aes("MyCryptedValue","ThisIsMySecretKey") it will return an array with two values:
302             the first one is the clear text decrypted and the last one the key used. That's all.
303              
304             =head2 methods list
305              
306             crypt_aes()
307             crypt_blowfish()
308             crypt_des()
309             crypt_3des() [|| crypt_des_ede() || crypt_triple_des()]
310             crypt_twofish()
311             crypt_xtea();
312             crypt_anubis();
313             crypt_camellia();
314             crypt_kasumi();
315             crypt_khazad();
316             crypt_noekeon();
317             crypt_multi2();
318             crypt_rc2();
319             crypt_rc5();
320             crypt_rc6();
321              
322             and the same for decrypt functions (please make the effort to put "de" in front of "crypt_[name]")
323              
324             =head2 3DES: Multiple names, same result
325              
326             =over 4
327              
328             =item 1
329              
330             B
331              
332             =item 2
333              
334             B
335              
336             =item 3
337              
338             B
339              
340             =back
341              
342             =head2 nested calls
343              
344             =over 4
345              
346             =item *
347              
348             B
349              
350             =back
351              
352             ($crypted, $key) = app->crypt_xtea(app->crypt_twofish(app->crypt_3des(app->crypt_blowfish(app->crypt_aes($super_plain,$super_secret)))));
353              
354             =over 4
355              
356             =item *
357              
358             B
359              
360             =back
361              
362             ($plain, $key) = app->decrypt_aes(app->decrypt_blowfish(app->decrypt_3des(app->decrypt_twofish(app->decrypt_xtea($crypted,$super_secret)))));
363              
364             =head1 Hash/Digest Functions
365              
366             Use this plugin in order to calculate digest through this algorithms:
367              
368             =over
369              
370             =item *
371              
372             B
373              
374             =item *
375              
376             B
377              
378             =item *
379              
380             B
381              
382             =item *
383              
384             B
385              
386             =item *
387              
388             B
389              
390             =item *
391              
392             B
393              
394             =item *
395              
396             B
397              
398             =item *
399              
400             B
401              
402             =item *
403              
404             B
405              
406             =item *
407              
408             B
409              
410             =item *
411              
412             B
413              
414             =item *
415              
416             B
417              
418             =item *
419              
420             B
421              
422             =item *
423            
424             B
425              
426             =item *
427            
428             B
429              
430             =back
431              
432             =head1 Hash/Digest Functions USAGE
433              
434             =head2 [ALGO_NAME]()
435              
436             Example: app->sha256();
437              
438             =head2 [ALGO_NAME]_hex()
439              
440             Example: app->sha256_hex();
441              
442             =head2 [ALGO_NAME]_b64()
443              
444             Example: app->sha256_b64();
445              
446             =head2 [ALGO_NAME]_b64u()
447              
448             Example: app->sha256_b64u();
449              
450             =head2 [ALGO_NAME]_file([FILENAME|FILEHANDLE])
451              
452             Example: app->sha256_file();
453              
454             =head2 [ALGO_NAME]_file_hex([FILENAME|FILEHANDLE])
455              
456             Example: app->sha256_file_hex();
457              
458             =head2 [ALGO_NAME]_file_b64([FILENAME|FILEHANDLE])
459              
460             Example: app->sha256_file_b64();
461              
462             =head2 [ALGO_NAME]_file_b64u([FILENAME|FILEHANDLE])
463              
464             Example: app->sha256_file_b64u();
465              
466             =head1 HMAC - Message authentication code HMAC
467              
468             Use this plugin in order to calculate HMAC:
469              
470             =head2 hmac([HASHNAME], [KEY], 'data buffer');
471              
472             Example: app->hmac('SHA256', $key, 'data buffer');
473              
474             =head2 hmac_hex([HASHNAME], [KEY], 'data buffer');
475              
476             Example: app->hmac_hex('SHA256', $key, 'data buffer');
477              
478             =head2 hmac_b64([HASHNAME], [KEY], 'data buffer');
479              
480             Example: app->hmac_b64('SHA256', $key, 'data buffer');
481              
482             =head2 hmac_b64u([HASHNAME], [KEY], 'data buffer');
483              
484             Example: app->hmac_b64u('SHA256', $key, 'data buffer');
485              
486             =head1 Dummy example using Mojolicious::Lite
487              
488             You can test in this way
489            
490             perl mymojoapp.pl /aes/enc?data=nemux
491             perl mymojoapp.pl /aes/dec?data=53616c7465645f5f6355829a809369eee5dfb9489eaee7e190b67d15d2e35ce8
492              
493             perl mymojoapp.pl /blowfish/enc?data=nemux
494             perl mymojoapp.pl /blowfish/dec?data=53616c7465645f5f16d8c8aa479121d039b04703083a9391
495              
496             #!/usr/bin/env perl
497              
498             use Mojolicious::Lite;
499            
500             plugin 'Crypto', {
501             symmetric_cipher => 1, # 0|1 -> enable or disable features avoiding to load unuseful modules
502             digest => 1, # With no arguments it will load all features automatically
503             mac => 1
504             };
505              
506             my $bigsecret = "MyNameisMarcoRomano";
507              
508             get '/digest/sha256' => sub {
509             my $self = shift;
510             my $data = $self->param('data');
511             my $hex_digest = $self->sha256_hex($data);
512             $self->render(text => $hex_digest);
513             };
514              
515             get '/digest/md5' => sub {
516             my $self = shift;
517             my $data = $self->param('data');
518             my ($hex_digest) = $self->md5_hex($data);
519             $self->render(text => $hex_digest);
520             };
521              
522             get '/aes/enc' => sub {
523             my $self = shift;
524             my $data = $self->param('data');
525             my ($securedata) = $self->crypt_aes($data, $bigsecret);
526             $self->render(text => $securedata);
527             };
528              
529             get '/aes/dec' => sub {
530             my $self = shift;
531             my $data = $self->param('data');
532             my ($plaintext) = $self->decrypt_aes($data, $bigsecret);
533             $self->render(text => $plaintext);
534             };
535              
536             get '/blowfish/enc' => sub {
537             my $self = shift;
538             my $data = $self->param('data');
539             my ($securedata) = $self->crypt_blowfish($data, $bigsecret);
540             $self->render(text => $securedata);
541             };
542              
543             get '/blowfish/dec' => sub {
544             my $self = shift;
545             my $data = $self->param('data');
546             my ($plaintext) = $self->decrypt_blowfish($data, $bigsecret);
547             $self->render(text => $plaintext);
548             };
549              
550             app->start;
551              
552             =head1 BUGS
553              
554             =head1 TODO
555              
556             =over
557              
558             =item *
559              
560             Random numbers generator
561              
562             =item *
563              
564             Asymmetric algorithms
565              
566             =back
567              
568             =head1 SUPPORT
569              
570             Write me if you need some help and feel free to improve it.
571             Github: http://git.io/lQl5cA
572              
573             @nemux_
574              
575             =head1 AUTHOR
576              
577             Marco Romano
578             CPAN ID: NEMUX
579             Mojolicious CryptO Plugin
580            
581             nemux@cpan.org - @nemux_
582              
583             http://search.cpan.org/~nemux/
584              
585             =head1 COPYRIGHT
586              
587             This program is free software; you can redistribute
588             it and/or modify it under the same terms as Perl itself.
589              
590             The full text of the license can be found in the
591             LICENSE file included with this module.
592              
593              
594             =head1 SEE ALSO
595              
596             perl(1). L
597              
598             =cut
599              
600             #################### main pod documentation end ###################
601              
602             1;