File Coverage

lib/Tie/EncryptedHash.pm
Criterion Covered Total %
statement 129 144 89.5
branch 74 86 86.0
condition 37 55 67.2
subroutine 19 25 76.0
pod 0 9 0.0
total 259 319 81.1


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -s
2             ##
3             ## Tie::EncryptedHash - A tied hash with encrypted fields.
4             ##
5             ## Copyright (c) 2000, Vipul Ved Prakash. All rights reserved.
6             ## This code is based on Damian Conway's Tie::SecureHash.
7             ##
8             ## $Id: EncryptedHash.pm,v 1.8 2000/09/02 19:23:00 vipul Exp vipul $
9             ## vi:expandtab=1;ts=4;
10              
11             package Tie::EncryptedHash;
12            
13 7     7   21047 use strict;
  7         17  
  7         274  
14 7     7   41 use vars qw($VERSION $strict);
  7         11  
  7         465  
15 7     7   38 use Digest::MD5 qw(md5_base64);
  7         15  
  7         495  
16 7     7   7722 use Crypt::CBC;
  7         52820  
  7         264  
17 7     7   8292 use Data::Dumper;
  7         92519  
  7         606  
18 7     7   67 use Carp;
  7         21  
  7         27497  
19              
20             ( $VERSION ) = '$Revision: 1.8 $' =~ /\s(\d+\.\d+)\s/;
21              
22             my $DEBUG = 0;
23              
24             sub debug {
25 0 0   0 0 0 return undef unless $DEBUG;
26 0         0 my ($caller, undef) = caller;
27 0         0 my (undef,undef,$line,$sub) = caller(1); $sub =~ s/.*://;
  0         0  
28 0         0 $sub = sprintf "%10s()%4d",$sub,$line;
29 0         0 print "$sub " . (shift) . "\n";
30             }
31              
32             # sub new {
33             # my ($class,%args) = @_;
34             # my %self = (); tie %self, $class;
35             # my $self = bless \%self, $class;
36             # $self->{__password} = $args{__password} if $args{__password};
37             # $self->{__cipher} = $args{__cipher} || qq{Blowfish};
38             # return $self;
39             # }
40              
41             sub new {
42 3     3 0 114 my ($class,%args) = @_;
43 3         10 my $self = {}; tie %$self, $class;
  3         22  
44 3         11 bless $self, $class;
45 3 100       15 $self->{__password} = $args{__password} if $args{__password};
46 3   100     38 $self->{__cipher} = $args{__cipher} || qq{Blowfish};
47 3         14 return $self;
48             }
49              
50              
51             sub _access {
52              
53 659     659   1275 my ($self, $key, $caller, $file, $value, $delete) = @_;
54 659   33     1651 my $class = ref $self || $self;
55             # SPECIAL ATTRIBUTE
56 659 100 66     4582 if ( $key =~ /(__password|__hide|__scaffolding|__cipher)$/ ) {
    100 33        
    50          
57 104         217 my $key = $1;
58 104 50 100     371 unless($value||$delete) {return undef unless $caller eq $class}
  26 100       130  
59 78 100 100     224 if ($delete && ($key =~ /__password/)) {
60 4         8 for (keys %{$$self{__scaffolding}}) {
  4         36  
61 1 50       6 if ( ref $self->{$_} ) {
62 1         12 $self->{$_} = encrypt($self->{$_}, $self->{__scaffolding}{$_}, $self->{__cipher});
63 1         1364 delete $self->{__scaffolding}{$_};
64             }
65             }
66             }
67 78 100       163 delete $$self{$key} if $delete;
68 78 100       347 return $self->{$key} = $value if $value;
69 5         27 return $self->{$key};
70             # SECRET FIELD
71             } elsif ( $key =~ m/^(_{1}[^_][^:]*)$/ ||$key =~ m/.*?::(_{1}[^_][^:]*)/ ) {
72 491         1060 my $ctext = $self->{$1};
73 491 100 66     1512 if ( ref $ctext && !($value)) { # ENCRYPT REF AT FETCH
74 144   33     504 my $pass = $self->{__scaffolding}{$1} || $self->{__password};
75 144 50       273 return undef unless $pass;
76 144         360 $self->{$1} = encrypt($ctext, $pass, $self->{__cipher});
77 144         207406 return $self->FETCH ($1);
78             }
79 347         427 my $ptext = qq{}; my $isnot = !( exists $self->{$1} );
  347         677  
80 347         661 my $auth = verify($self,$1);
81 347 50 66     1245 return undef if !($auth) && ref $self->{$1};
82 347 100 100     999 return undef if !($auth) && $self->{__hide};
83 341 100 100     1484 if ($auth && $auth ne "1") { $ptext = $auth }
  161         252  
84 341 100 66     2900 if ($value && $auth) { # STORE
    100 100        
    100 66        
    100 66        
    50 33        
85 62 100       132 if ( ref $value ) {
86 39         777 $self->{__scaffolding}{$1} = $self->{__password}; $ctext = $value;
  39         68  
87             } else {
88 23         49 my $key = $1;
89 23 100       74 unless ($self->{__password}) {
90 1 50       22 if ($value =~ m:^\S+\s\S{22}\s:) {
91 1         5 return $self->{$key} = $value;
92 0         0 } else { return undef }
93             }
94 22         221 $ctext = encrypt($value, $self->{__password}, $self->{__cipher});
95             }
96 61         59665 $self->{$1} = $ctext;
97 61         215 return $value;
98             } elsif ($auth && $delete) { # DELETE
99 4         16 delete $$self{$1}
100             } elsif ($isnot && (!($value))) { # DOESN'T EXIST
101 43         135 return;
102             } elsif ((!($auth)) && $ctext) {
103 83         348 return $ctext; # FETCH return ciphertext
104             } elsif ($auth && !($isnot)) { # FETCH return plaintext
105 149 100       954 if (ref $ptext) {
106 132         304 $self->{$1} = $ptext;
107 132         354 $self->{__scaffolding}{$1} = $self->{__password}; # Ref counting mechanism
108 132         650 return $self->{$1};
109             }
110             }
111 21 50       46 return undef unless $auth;
112 21         132 return $ptext;
113             # PUBLIC FIELD
114             } elsif ( $key =~ m/([^:]*)$/ || $key =~ m/.*?::([^:]*)/ ) {
115 64 100       163 $self->{$1} = $value if $value;
116 64 100       125 delete $$self{$1} if $delete;
117 64 100       388 return $self->{$1} if $self->{$1};
118 16         83 return undef;
119             }
120              
121             }
122              
123             sub encrypt { # ($plaintext, $password, $cipher)
124 167 100   167 0 959 $_[0] = qq{REF }. Data::Dumper->new([$_[0]])->Indent(0)->Terse(0)->Purity(1)->Dumpxs if ref $_[0];
125 167         15311 return qq{$_[2] } . md5_base64($_[0]) .qq{ } .
126             Crypt::CBC->new($_[1],$_[2])->encrypt_hex($_[0])
127             }
128              
129             sub decrypt { # ($cipher $md5sum $ciphertext, $password)
130 258 100   258 0 551 return undef unless $_[1];
131 251         1479 my ($m, $d, $c) = split /\s/,$_[0];
132 251         1033 my $ptext = Crypt::CBC->new($_[1],$m)->decrypt_hex($c);
133 251         86333 my $check = md5_base64($ptext);
134 251 100       983 if ( $d eq $check ) {
135 165 100       640 if ($ptext =~ /^REF (.*)/is) {
136 132         164 my ($VAR1,$VAR2,$VAR3,$VAR4,$VAR5,$VAR6,$VAR7,$VAR8);
137 132         8269 return eval qq{$1};
138             }
139 33         75 return $ptext;
140             }
141             }
142              
143             sub verify { # ($self, $key)
144 371     371 0 956 my ($self, $key) = splice @_,0,2;
145             # debug ("$self->{__scaffolding}{$key}, $self->{__password}, $self->{$key}");
146 371 100       1210 return 1 unless $key =~ m:^_:;
147 355 100       838 return 1 unless exists $self->{$key};
148 258 50 33     700 return undef if ref $self->{$key} && ($self->{__scaffolding}{$key} ne
149             $self->{__password});
150 258         695 my $ptext = decrypt($self->{$key}, $self->{__password});
151 258 100       1140 return $ptext if $ptext;
152             }
153            
154 0     0 0 0 sub each { CORE::each %{$_[0]} }
  0         0  
155 0     0 0 0 sub keys { CORE::keys %{$_[0]} }
  0         0  
156 0     0 0 0 sub values { CORE::values %{$_[0]} }
  0         0  
157 0     0 0 0 sub exists { CORE::exists $_[0]->{$_[1]} }
158              
159             sub TIEHASH # ($class, @args)
160             {
161 12   33 12   74840 my $class = ref($_[0]) || $_[0];
162 12         45 my $self = bless {}, $class;
163 12 100       90 $self->{__password} = $_[1] if $_[1];
164 12   100     103 $self->{__cipher} = $_[2] || qq{Blowfish};
165 12         57 return $self;
166             }
167              
168             sub FETCH # ($self, $key)
169             {
170 361     361   2243 my ($self, $key) = @_;
171 361         1419 my $entry = _access($self,$key,(caller)[0..1]);
172 361 100       3062 return $entry if $entry;
173             }
174              
175             sub STORE # ($self, $key, $value)
176             {
177 155     155   1955 my ($self, $key, $value) = @_;
178 155         596 my $entry = _access($self,$key,(caller)[0..1],$value);
179 155 50       777 return $entry if $entry;
180             }
181              
182             sub DELETE # ($self, $key)
183             {
184 13     13   111 my ($self, $key) = @_;
185 13         55 return _access($self,$key,(caller)[0..1],'',1);
186             }
187              
188             sub CLEAR # ($self)
189             {
190 8     8   65 my ($self) = @_;
191 24         64 return undef if grep { ! $self->verify($_) }
  48         109  
192 8 100       12 grep { ! /__/ } CORE::keys %{$self};
  8         33  
193 4         12 %{$self} = ();
  4         25  
194             }
195              
196             sub EXISTS # ($self, $key)
197             {
198 40     40   348 my ($self, $key) = @_;
199 40         134 my @context = (caller)[0..1];
200 40 100       94 return _access($self,$key,@context) ? 1 : '';
201             }
202              
203             sub FIRSTKEY # ($self)
204             {
205 10     10   522 my ($self) = @_;
206 10         15 CORE::keys %{$self};
  10         22  
207 10         50 goto &NEXTKEY;
208             }
209              
210             sub NEXTKEY # ($self)
211             {
212 74     74   115 my $self = $_[0]; my $key;
  74         753  
213 74         277 my @context = (caller)[0..1];
214 74         105 while (defined($key = CORE::each %{$self})) {
  100         305  
215 90 100       141 last if eval { _access($self,$key,@context) }
  90         173  
216             }
217 74         1568 return $key;
218             }
219              
220             sub DESTROY # ($self)
221 0     0     {
222             }
223              
224             1;
225             __END__