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