File Coverage

blib/lib/Digest/SHA.pm
Criterion Covered Total %
statement 114 140 81.4
branch 51 90 56.6
condition 7 15 46.6
subroutine 15 18 83.3
pod 7 7 100.0
total 194 270 71.8


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