line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Apache::CryptHash; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
#require 5.005_62; |
4
|
1
|
|
|
1
|
|
622
|
use strict; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
39
|
|
5
|
|
|
|
|
|
|
#use warnings; |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
BEGIN { |
8
|
|
|
|
|
|
|
# use Apache; |
9
|
1
|
|
|
1
|
|
670
|
use MIME::Base64; |
|
1
|
|
|
|
|
711
|
|
|
1
|
|
|
|
|
56
|
|
10
|
1
|
|
|
1
|
|
1279
|
use Crypt::CapnMidNite; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
use vars qw($VERSION); |
12
|
|
|
|
|
|
|
$VERSION = do { my @r = (q$Revision: 3.03 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r }; |
13
|
|
|
|
|
|
|
} |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
sub init() { |
17
|
|
|
|
|
|
|
my ($proto, $crypt) = @_; |
18
|
|
|
|
|
|
|
my $class = ref($proto) || $proto; |
19
|
|
|
|
|
|
|
my $self = {}; |
20
|
|
|
|
|
|
|
$self->{NAME} = 'Secret'; # default header name |
21
|
|
|
|
|
|
|
$self->{CRYPT} = $crypt || do { # default password is hostname |
22
|
|
|
|
|
|
|
require Sys::Hostname; # 'no, NO' turns encryption off |
23
|
|
|
|
|
|
|
&Sys::Hostname::hostname; |
24
|
|
|
|
|
|
|
}; |
25
|
|
|
|
|
|
|
bless ($self, $class); |
26
|
|
|
|
|
|
|
return $self; |
27
|
|
|
|
|
|
|
} |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
sub name { |
30
|
|
|
|
|
|
|
&_readNset(\shift->{NAME},@_); |
31
|
|
|
|
|
|
|
} |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
sub passcode { |
34
|
|
|
|
|
|
|
&_readNset(\shift->{CRYPT},@_); |
35
|
|
|
|
|
|
|
} |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
sub _readNset { |
38
|
|
|
|
|
|
|
my($var,$new) = @_; |
39
|
|
|
|
|
|
|
my $rv = $$var; |
40
|
|
|
|
|
|
|
$$var = $new if defined $new; |
41
|
|
|
|
|
|
|
return $rv; |
42
|
|
|
|
|
|
|
} |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
##################################################### |
45
|
|
|
|
|
|
|
# md5_hex |
46
|
|
|
|
|
|
|
# |
47
|
|
|
|
|
|
|
# input: string |
48
|
|
|
|
|
|
|
# returns: md5 hex hash of string |
49
|
|
|
|
|
|
|
# |
50
|
|
|
|
|
|
|
sub md5_hex($$) { |
51
|
|
|
|
|
|
|
my ($self, $string) = @_; |
52
|
|
|
|
|
|
|
return Crypt::CapnMidNite->new->md5_hex($string); |
53
|
|
|
|
|
|
|
} |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
##################################################### |
56
|
|
|
|
|
|
|
# md5_b64 |
57
|
|
|
|
|
|
|
# |
58
|
|
|
|
|
|
|
# input: string |
59
|
|
|
|
|
|
|
# returns: md5 base 64 of string |
60
|
|
|
|
|
|
|
# |
61
|
|
|
|
|
|
|
sub md5_b64($$) { |
62
|
|
|
|
|
|
|
my ($self, $string) = @_; |
63
|
|
|
|
|
|
|
return Crypt::CapnMidNite->new->md5_base64($string); |
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
##################################################### |
67
|
|
|
|
|
|
|
# encode |
68
|
|
|
|
|
|
|
# create an encrypted cookie from data values passed in hash |
69
|
|
|
|
|
|
|
# input: pointer to hash, # \%p |
70
|
|
|
|
|
|
|
# (optional) pointer to keys # \@k |
71
|
|
|
|
|
|
|
# (array) of values to include in MAC |
72
|
|
|
|
|
|
|
# these must be invarient and will |
73
|
|
|
|
|
|
|
# fail to decrypt otherwise |
74
|
|
|
|
|
|
|
# |
75
|
|
|
|
|
|
|
sub encode($$$) { |
76
|
|
|
|
|
|
|
my ( $self, $state, $k ) = @_; # get my self |
77
|
|
|
|
|
|
|
&_MAC($self, $state, $k, 'generate'); # add MAC to state |
78
|
|
|
|
|
|
|
my $cipher = Crypt::CapnMidNite->new_md5_rc4($self->{CRYPT}); |
79
|
|
|
|
|
|
|
my %s = %$state; |
80
|
|
|
|
|
|
|
foreach (keys %s) { |
81
|
|
|
|
|
|
|
$s{$_} =~ s/:/%58/g; |
82
|
|
|
|
|
|
|
} |
83
|
|
|
|
|
|
|
my $cook = $self->{NAME}; |
84
|
|
|
|
|
|
|
if ( $self->{CRYPT} =~ /^no$/i ) { |
85
|
|
|
|
|
|
|
$cook .= '.Debug:' . join ':', %s; |
86
|
|
|
|
|
|
|
} else { |
87
|
|
|
|
|
|
|
$cook .= ':' . MIME::Base64::encode($cipher->encrypt(join ':', %s),""); |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
$cook =~ tr/=/$/; |
90
|
|
|
|
|
|
|
return $cook; |
91
|
|
|
|
|
|
|
} |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
##################################### |
94
|
|
|
|
|
|
|
# |
95
|
|
|
|
|
|
|
# input: pointer to cookie value # \$string |
96
|
|
|
|
|
|
|
# pointer to state hash # \%state to fill |
97
|
|
|
|
|
|
|
# pointer key arrau in MAC # \@keys |
98
|
|
|
|
|
|
|
# return: true or undef, fill hash with state values if true |
99
|
|
|
|
|
|
|
# |
100
|
|
|
|
|
|
|
sub decode ($$$) { |
101
|
|
|
|
|
|
|
my ($self, $cook, $state, $ck) = @_; |
102
|
|
|
|
|
|
|
my %s; |
103
|
|
|
|
|
|
|
$$cook =~ tr/$/=/; |
104
|
|
|
|
|
|
|
my $rv = &_decrypt($self, $cook, \%s, $ck); |
105
|
|
|
|
|
|
|
return undef unless $rv; |
106
|
|
|
|
|
|
|
%$state = %s; |
107
|
|
|
|
|
|
|
$rv; |
108
|
|
|
|
|
|
|
} |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
sub _decrypt { |
111
|
|
|
|
|
|
|
my ($self, $cook, $state, $ck) = @_; |
112
|
|
|
|
|
|
|
my $cipher = Crypt::CapnMidNite->new_md5_rc4($self->{CRYPT}); |
113
|
|
|
|
|
|
|
my ($flag, $realcook) = split(':', $$cook, 2); |
114
|
|
|
|
|
|
|
$realcook =~ tr/$/=/; |
115
|
|
|
|
|
|
|
if ( $flag =~ /.Debug$/ ) { |
116
|
|
|
|
|
|
|
%$state = &_evensplit(':', $realcook); |
117
|
|
|
|
|
|
|
} else { |
118
|
|
|
|
|
|
|
%$state = &_evensplit(':',$cipher->decrypt(MIME::Base64::decode($realcook))); |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
return undef unless exists ${$state}{MAC}; # punt if decode failure |
121
|
|
|
|
|
|
|
foreach (keys %$state) { |
122
|
|
|
|
|
|
|
${$state}{$_} =~ s/%58/:/g; |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
# invalid if the cookie was tampered with |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
return undef unless &_MAC($self, $state, $ck, 'check'); |
127
|
|
|
|
|
|
|
foreach ( @$ck ) { |
128
|
|
|
|
|
|
|
return undef unless exists ${$state}{$_}; |
129
|
|
|
|
|
|
|
} |
130
|
|
|
|
|
|
|
$flag; # return true |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
sub checkMAC { |
134
|
|
|
|
|
|
|
my ( $self, $s, $k ) = @_; |
135
|
|
|
|
|
|
|
return _MAC($self, $s, $k, 'check'); |
136
|
|
|
|
|
|
|
} |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
sub _MAC { |
139
|
|
|
|
|
|
|
my ( $self, $s, $k, $action ) = @_; |
140
|
|
|
|
|
|
|
@_ = ($k) ? sort @$k : (); |
141
|
|
|
|
|
|
|
my @fields = @{$s}{@_}; |
142
|
|
|
|
|
|
|
my $md5 = Crypt::CapnMidNite->new_md5; |
143
|
|
|
|
|
|
|
my $newmac = $md5->md5_base64($self->{CRYPT} . |
144
|
|
|
|
|
|
|
$md5->md5_base64(join '', $self->{CRYPT}, @fields)); |
145
|
|
|
|
|
|
|
return $s->{MAC} = $newmac if $action eq 'generate'; |
146
|
|
|
|
|
|
|
return 1 if ($newmac eq $s->{MAC} && $action eq 'check'); |
147
|
|
|
|
|
|
|
return undef; |
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
# split to an even number of fields |
151
|
|
|
|
|
|
|
# this will split to a hash when the trailing value is null |
152
|
|
|
|
|
|
|
# |
153
|
|
|
|
|
|
|
sub _evensplit { |
154
|
|
|
|
|
|
|
my ( $m, $s ) = @_; |
155
|
|
|
|
|
|
|
@_ = split(/$m/, $s, -1); |
156
|
|
|
|
|
|
|
push ( @_, '') if @_ % 2; |
157
|
|
|
|
|
|
|
@_; |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
1; |
161
|
|
|
|
|
|
|
__END__ |