File Coverage

blib/lib/HTTP/CryptoCookie.pm
Criterion Covered Total %
statement 51 90 56.6
branch 3 26 11.5
condition 3 20 15.0
subroutine 13 15 86.6
pod 4 4 100.0
total 74 155 47.7


line stmt bran cond sub pod time code
1             package HTTP::CryptoCookie;
2              
3 2     2   64235 use 5.006001;
  2         8  
  2         79  
4 2     2   11 use strict;
  2         4  
  2         70  
5             # use warnings;
6              
7 2     2   28453 use CGI qw(:standard); # for now, move to Apache (mod_perl) later
  2         73915  
  2         16  
8 2     2   11336 use CGI::Cookie;
  2         11025  
  2         71  
9 2     2   2398 use Crypt::CBC;
  2         16180  
  2         87  
10 2     2   1849 use Digest::SHA2;
  2         2291  
  2         84  
11 2     2   1982 use Convert::ASCII::Armour;
  2         411573  
  2         78  
12 2     2   23 use Compress::Zlib qw(compress uncompress);
  2         5  
  2         194  
13 2     2   2378 use FreezeThaw qw(freeze thaw);
  2         10529  
  2         163  
14 2     2   53006 use Data::Dumper;
  2         22520  
  2         1894  
15              
16             # first, some notes about compression and cryptography.
17             #
18             # never, ever compress an encrypted string. this can potentially
19             # give a cryptanalysist clues about the encryption algorithm,
20             # the key, and the plaintext. so remember... compress, then encrypt.
21              
22             require Exporter;
23              
24             our @ISA = qw(Exporter);
25              
26             our $VERSION = '1.14';
27              
28             my $aa = new Convert::ASCII::Armour;
29              
30             sub _roll_dough {
31 1001     1001   2017 my ($self,$struct) = @_;
32              
33 1001         5008 my $step_one = compress(freeze($struct));
34 1001         878346 my $step_two = $self->{cipher}->encrypt($step_one);
35              
36 1001         1571991 my $cooked = $aa->armour(
37             Object => 'HCC',
38             Headers => {},
39             Content => {data=>$step_two},
40             Compress => 1);
41              
42 1001         564138 return $cooked;
43             }
44              
45             sub new {
46 3     3 1 812 my($class,$key) = @_;
47 3 50       15 die "argument of key required" unless $key;
48              
49 3         53 my $digest = new Digest::SHA2(256);
50 3         26 $digest->add(($key));
51 3         21 my $digest_key = $digest->digest();
52              
53 3         98 my $self = bless {
54             cipher => Crypt::CBC->new(
55             -key => $digest_key,
56             -cipher => 'Rijndael',
57             -regenerate_key => 0,
58             -salt => 1,
59             -header => 'salt'),
60             }, $class;
61              
62             # redefine the value of $key in memory, then undef it
63 3         21741 $key = join '', map { chr(int(rand(255))) } (0..(100+length $key));
  399         4033  
64 3         53 undef $key;
65 3         38 return $self;
66             }
67              
68             sub get_cookie {
69 0     0 1 0 my($self, %args) = @_;
70              
71 0 0       0 ref $args{cookie_name} && return undef;
72              
73 0 0       0 my %cookies = (! exists $self->{debug}) ? CGI::Cookie->fetch() : $args{force_cookie};
74 0 0       0 if(my $cookie = $cookies{$args{cookie_name}}) {
75             # first step, unarmour
76 0         0 my $dough = $aa->unarmour($cookie->value);
77 0         0 my $xcval = $self->{cipher}->decrypt($dough->{Content}{data});
78             # next step, uncompress
79 0 0       0 if(length($xcval) > 0) {
80 0         0 my $rv = (thaw(uncompress($xcval)))[0];
81 0         0 return $rv;
82             } else {
83 0         0 return undef;
84             }
85             }
86 0         0 return undef;
87             }
88              
89             sub set_cookie {
90 1001     1001 1 16715 my($self, %args) = @_;
91             # a basic cookie...
92              
93              
94 1001 50 33     11383 if(exists $args{cookie} && exists $args{cookie_name}) {
  0 0          
95             # bake the cookie
96              
97 1001   50     6951 my $cookie = CGI::Cookie->new(
      50        
98             -name => $args{cookie_name},
99             -value => $self->_roll_dough($args{cookie}),
100             -path => $args{path} || '/',
101             -expires => $args{exp},
102             -secure => $args{secure} || 0,
103             -domain => $args{domain},
104             );
105              
106              
107             # toss the cookie at the browser
108 1001 50       189737 if(exists $args{r}) {
109 0         0 $args{r}->headers_out->set('Set-Cookie' => $cookie);
110             } else {
111 1001         45324 print header(-cookie =>[$cookie]);
112             }
113 1001         1252474 return 1;
114             } elsif (scalar(@{$args{cookies}}) > 0) {
115 0           my $jar = [];
116              
117 0           foreach my $cookie (@{$args{cookies}}) {
  0            
118 0   0       my $oreo = CGI::Cookie->new(
      0        
      0        
      0        
      0        
119             -name => $cookie->{name} || $cookie->{cookie_name},
120             -value => $self->_roll_dough($cookie->{cookie}),
121             -path => $cookie->{path} || $args{path} || '/',
122             -expires => $cookie->{exp} || $args{exp},
123             -secure => $cookie->{secure} || $args{secure} || 0,
124             -domain => $cookie->{domain} || $args{domain},
125             );
126              
127 0           push(@{$jar}, $oreo);
  0            
128 0 0         if(exists $args{r}) {
129 0           $args{r}->headers_out->set('Set-Cookie' => $oreo);
130             }
131             }
132              
133 0 0         print header(-cookie => $jar) unless (exists $args{r});
134 0           return scalar(@{$jar});
  0            
135             }
136 0           return undef;
137             }
138              
139             sub del_cookie {
140 0     0 1   my($self,%args) = @_;
141              
142 0           my $jar = [];
143              
144 0 0         unless(ref($args{cookie_name}) eq 'ARRAY') {
145 0           $args{cookie_name} = [ $args{cookie_name} ];
146             }
147              
148 0           foreach my $cookie_name (@{$args{cookie_name}}) {
  0            
149 0           my $donut_hole = CGI::Cookie->new(
150             -name => $cookie_name,
151             -expires => '-1M',
152             );
153              
154 0           push(@{$jar}, $donut_hole);
  0            
155 0 0         if(exists $args{r}) {
156 0           $args{r}->headers_out->set('Set-Cookie' => $donut_hole);
157             }
158 0 0         print header(-cookie => $jar) unless (exists $args{r});
159             }
160            
161 0           return scalar(@{$jar});
  0            
162             }
163              
164             1;
165             __END__