File Coverage

blib/lib/Mojolicious/Plugin/Crypto.pm
Criterion Covered Total %
statement 92 104 88.4
branch 19 38 50.0
condition 9 13 69.2
subroutine 18 22 81.8
pod 1 3 33.3
total 139 180 77.2


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