File Coverage

blib/lib/Digest/SHA.pm
Criterion Covered Total %
statement 110 133 82.7
branch 50 82 60.9
condition 9 21 42.8
subroutine 14 17 82.3
pod 7 7 100.0
total 190 260 73.0


line stmt bran cond sub pod time code
1             package Digest::SHA;
2              
3             require 5.003000;
4              
5 24     24   18498 use strict;
  24         142  
  24         553  
6 24     24   95 use warnings;
  24         40  
  24         821  
7 24     24   125 use vars qw($VERSION @ISA @EXPORT_OK $errmsg);
  24         36  
  24         1719  
8 24     24   130 use Fcntl qw(O_RDONLY O_RDWR);
  24         1371  
  24         1174  
9 24     24   10352 use integer;
  24         286  
  24         101  
10              
11             $VERSION = '6.02';
12              
13             require Exporter;
14             @ISA = qw(Exporter);
15             @EXPORT_OK = qw(
16             $errmsg
17             hmac_sha1 hmac_sha1_base64 hmac_sha1_hex
18             hmac_sha224 hmac_sha224_base64 hmac_sha224_hex
19             hmac_sha256 hmac_sha256_base64 hmac_sha256_hex
20             hmac_sha384 hmac_sha384_base64 hmac_sha384_hex
21             hmac_sha512 hmac_sha512_base64 hmac_sha512_hex
22             hmac_sha512224 hmac_sha512224_base64 hmac_sha512224_hex
23             hmac_sha512256 hmac_sha512256_base64 hmac_sha512256_hex
24             sha1 sha1_base64 sha1_hex
25             sha224 sha224_base64 sha224_hex
26             sha256 sha256_base64 sha256_hex
27             sha384 sha384_base64 sha384_hex
28             sha512 sha512_base64 sha512_hex
29             sha512224 sha512224_base64 sha512224_hex
30             sha512256 sha512256_base64 sha512256_hex);
31              
32             # Inherit from Digest::base if possible
33              
34             eval {
35             require Digest::base;
36             push(@ISA, 'Digest::base');
37             };
38              
39             # The following routines aren't time-critical, so they can be left in Perl
40              
41             sub new {
42 27     27 1 62315 my($class, $alg) = @_;
43 27 100       105 $alg =~ s/\D+//g if defined $alg;
44 27 100       80 if (ref($class)) { # instance method
45 9 100 100     71 if (!defined($alg) || ($alg == $class->algorithm)) {
46 7         23 sharewind($class);
47 7         49 return($class);
48             }
49 2 50       12 return shainit($class, $alg) ? $class : undef;
50             }
51 18 100       151 $alg = 1 unless defined $alg;
52 18         170 return $class->newSHA($alg);
53             }
54              
55 24     24   25309 BEGIN { *reset = \&new }
56              
57             sub add_bits {
58 709     709 1 2185 my($self, $data, $nbits) = @_;
59 709 100       970 unless (defined $nbits) {
60 38         43 $nbits = length($data);
61 38         110 $data = pack("B*", $data);
62             }
63 709 50       897 $nbits = length($data) * 8 if $nbits > length($data) * 8;
64 709         3876 shawrite($data, $nbits, $self);
65 709         979 return($self);
66             }
67              
68             sub _bail {
69 0     0   0 my $msg = shift;
70              
71 0         0 $errmsg = $!;
72 0         0 $msg .= ": $!";
73 0         0 require Carp;
74 0         0 Carp::croak($msg);
75             }
76              
77             {
78             my $_can_T_filehandle;
79              
80             sub _istext {
81 1     1   3 local *FH = shift;
82 1         2 my $file = shift;
83              
84 1 50       3 if (! defined $_can_T_filehandle) {
85 1         3 local $^W = 0;
86 1         2 my $istext = eval { -T FH };
  1         15  
87 1 50       3 $_can_T_filehandle = $@ ? 0 : 1;
88 1 50       13 return $_can_T_filehandle ? $istext : -T $file;
89             }
90 0 0       0 return $_can_T_filehandle ? -T FH : -T $file;
91             }
92             }
93              
94             sub _addfile {
95 2     2   5 my ($self, $handle) = @_;
96              
97 2         2 my $n;
98 2         3 my $buf = "";
99              
100 2         38 while (($n = read($handle, $buf, 4096))) {
101 2         12 $self->add($buf);
102             }
103 2 50       8 _bail("Read failed") unless defined $n;
104              
105 2         25 $self;
106             }
107              
108             sub addfile {
109 6     6 1 147 my ($self, $file, $mode) = @_;
110              
111 6 100       21 return(_addfile($self, $file)) unless ref(\$file) eq 'SCALAR';
112              
113 4 50       50 $mode = defined($mode) ? $mode : "";
114             my ($binary, $UNIVERSAL, $BITS) =
115 4         11 map { $_ eq $mode } ("b", "U", "0");
  12         29  
116              
117             ## Always interpret "-" to mean STDIN; otherwise use
118             ## sysopen to handle full range of POSIX file names.
119             ## If $file is a directory, force an EISDIR error
120             ## by attempting to open with mode O_RDWR
121              
122 4         11 local *FH;
123 4 50 33     188 $file eq '-' and open(FH, '< -')
    50 33        
124             or sysopen(FH, $file, -d $file ? O_RDWR : O_RDONLY)
125             or _bail('Open failed');
126              
127 4 100       16 if ($BITS) {
128 2         6 my ($n, $buf) = (0, "");
129 2         33 while (($n = read(FH, $buf, 4096))) {
130 2         7 $buf =~ tr/01//cd;
131 2         7 $self->add_bits($buf);
132             }
133 2 50       7 _bail("Read failed") unless defined $n;
134 2         16 close(FH);
135 2         30 return($self);
136             }
137              
138 2 50 66     10 binmode(FH) if $binary || $UNIVERSAL;
139 2 100 66     6 if ($UNIVERSAL && _istext(*FH, $file)) {
140 1         10 $self->_addfileuniv(*FH);
141             }
142 1         13 else { $self->_addfilebin(*FH) }
143 2         26 close(FH);
144              
145 2         24 $self;
146             }
147              
148             sub getstate {
149 4     4 1 5 my $self = shift;
150              
151 4 50       13 my $alg = $self->algorithm or return;
152 4 50       14 my $state = $self->_getstate or return;
153 4 100       8 my $nD = $alg <= 256 ? 8 : 16;
154 4 100       6 my $nH = $alg <= 256 ? 32 : 64;
155 4 100       13 my $nB = $alg <= 256 ? 64 : 128;
156 4         53 my($H, $block, $blockcnt, $lenhh, $lenhl, $lenlh, $lenll) =
157             $state =~ /^(.{$nH})(.{$nB})(.{4})(.{4})(.{4})(.{4})(.{4})$/s;
158 4         11 for ($alg, $H, $block, $blockcnt, $lenhh, $lenhl, $lenlh, $lenll) {
159 32 50       40 return unless defined $_;
160             }
161              
162 4         11 my @s = ();
163 4         8 push(@s, "alg:" . $alg);
164 4         39 push(@s, "H:" . join(":", unpack("H*", $H) =~ /.{$nD}/g));
165 4         126 push(@s, "block:" . join(":", unpack("H*", $block) =~ /.{2}/g));
166 4         23 push(@s, "blockcnt:" . unpack("N", $blockcnt));
167 4         6 push(@s, "lenhh:" . unpack("N", $lenhh));
168 4         15 push(@s, "lenhl:" . unpack("N", $lenhl));
169 4         6 push(@s, "lenlh:" . unpack("N", $lenlh));
170 4         8 push(@s, "lenll:" . unpack("N", $lenll));
171 4         17 join("\n", @s) . "\n";
172             }
173              
174             sub putstate {
175 11     11 1 1147 my($class, $state) = @_;
176              
177 11         17 my %s = ();
178 11         43 for (split(/\n/, $state)) {
179 96         194 s/^\s+//;
180 96         133 s/\s+$//;
181 96 100       171 next if (/^(#|$)/);
182 88         476 my @f = split(/[:\s]+/);
183 88         118 my $tag = shift(@f);
184 88         262 $s{$tag} = join('', @f);
185             }
186              
187             # H and block may contain arbitrary values, but check everything else
188 11 50       25 grep { $_ == $s{'alg'} } (1,224,256,384,512,512224,512256) or return;
  77         132  
189 11 100       33 length($s{'H'}) == ($s{'alg'} <= 256 ? 64 : 128) or return;
    50          
190 11 100       28 length($s{'block'}) == ($s{'alg'} <= 256 ? 128 : 256) or return;
    50          
191             {
192 24     24   159 no integer;
  24         38  
  24         141  
  11         13  
193 11         17 for (qw(blockcnt lenhh lenhl lenlh lenll)) {
194 55 50       80 0 <= $s{$_} or return;
195 55 50       85 $s{$_} <= 4294967295 or return;
196             }
197 11 100       27 $s{'blockcnt'} < ($s{'alg'} <= 256 ? 512 : 1024) or return;
    50          
198             }
199              
200             my $packed_state = (
201             pack("H*", $s{'H'}) .
202             pack("H*", $s{'block'}) .
203             pack("N", $s{'blockcnt'}) .
204             pack("N", $s{'lenhh'}) .
205             pack("N", $s{'lenhl'}) .
206             pack("N", $s{'lenlh'}) .
207 11         94 pack("N", $s{'lenll'})
208             );
209              
210 11         30 return $class->new($s{'alg'})->_putstate($packed_state);
211             }
212              
213             sub dump {
214 0     0 1   my $self = shift;
215 0           my $file = shift;
216              
217 0 0         my $state = $self->getstate or return;
218 0 0 0       $file = "-" if (!defined($file) || $file eq "");
219              
220 0           local *FH;
221 0 0         open(FH, "> $file") or return;
222 0           print FH $state;
223 0           close(FH);
224              
225 0           return($self);
226             }
227              
228             sub load {
229 0     0 1   my $class = shift;
230 0           my $file = shift;
231              
232 0 0 0       $file = "-" if (!defined($file) || $file eq "");
233              
234 0           local *FH;
235 0 0         open(FH, "< $file") or return;
236 0           my $str = join('', );
237 0           close(FH);
238              
239 0           $class->putstate($str);
240             }
241              
242             eval {
243             require XSLoader;
244             XSLoader::load('Digest::SHA', $VERSION);
245             1;
246             } or do {
247             require DynaLoader;
248             push @ISA, 'DynaLoader';
249             Digest::SHA->bootstrap($VERSION);
250             };
251              
252             1;
253             __END__