File Coverage

blib/lib/Crypt/Rhash.pm
Criterion Covered Total %
statement 192 202 95.0
branch 19 40 47.5
condition 11 22 50.0
subroutine 59 60 98.3
pod 14 16 87.5
total 295 340 86.7


line stmt bran cond sub pod time code
1             package Crypt::Rhash;
2              
3 3     3   359436 use 5.006001;
  3         13  
4 3     3   17 use strict;
  3         22  
  3         93  
5 3     3   29 use warnings;
  3         14  
  3         704  
6              
7             require Exporter;
8             our @ISA = (qw(Exporter));
9              
10             # possible tags for export
11             our %EXPORT_TAGS = (
12             Functions => [qw(raw2hex raw2base32 raw2base64)],
13             Constants => [qw(RHASH_CRC32 RHASH_CRC32C RHASH_MD4 RHASH_MD5
14             RHASH_SHA1 RHASH_TIGER RHASH_TTH RHASH_BTIH RHASH_ED2K
15             RHASH_AICH RHASH_WHIRLPOOL RHASH_RIPEMD160 RHASH_GOST94
16             RHASH_GOST94_CRYPTOPRO RHASH_GOST12_256 RHASH_GOST12_512
17             RHASH_SHA224 RHASH_SHA256 RHASH_SHA384 RHASH_SHA512
18             RHASH_SHA3_224 RHASH_SHA3_256 RHASH_SHA3_384 RHASH_SHA3_512
19             RHASH_BLAKE2S RHASH_BLAKE2B RHASH_EDONR256 RHASH_EDONR512
20             RHASH_HAS160 RHASH_SNEFRU128 RHASH_SNEFRU256 RHASH_ALL)]
21             );
22              
23             Exporter::export_tags( );
24             Exporter::export_ok_tags( qw(Functions Constants) );
25              
26             our $VERSION = '1.05';
27              
28             require XSLoader;
29             XSLoader::load('Crypt::Rhash', $VERSION);
30              
31             ##############################################################################
32             # identifiers of hash functions
33 3     3   29 use constant RHASH_CRC32 => 0x01;
  3         27  
  3         458  
34 3     3   23 use constant RHASH_MD4 => 0x02;
  3         6  
  3         209  
35 3     3   18 use constant RHASH_MD5 => 0x04;
  3         15  
  3         179  
36 3     3   18 use constant RHASH_SHA1 => 0x08;
  3         5  
  3         174  
37 3     3   16 use constant RHASH_TIGER => 0x10;
  3         7  
  3         202  
38 3     3   44 use constant RHASH_TTH => 0x20;
  3         4  
  3         136  
39 3     3   14 use constant RHASH_BTIH => 0x40;
  3         6  
  3         163  
40 3     3   16 use constant RHASH_ED2K => 0x80;
  3         3  
  3         126  
41 3     3   15 use constant RHASH_AICH => 0x100;
  3         5  
  3         171  
42 3     3   16 use constant RHASH_WHIRLPOOL => 0x200;
  3         5  
  3         162  
43 3     3   17 use constant RHASH_RIPEMD160 => 0x400;
  3         5  
  3         135  
44 3     3   64 use constant RHASH_GOST94 => 0x800;
  3         19  
  3         149  
45 3     3   32 use constant RHASH_GOST94_CRYPTOPRO => 0x1000;
  3         5  
  3         150  
46 3     3   23 use constant RHASH_HAS160 => 0x2000;
  3         7  
  3         167  
47 3     3   25 use constant RHASH_GOST12_256 => 0x4000;
  3         5  
  3         148  
48 3     3   15 use constant RHASH_GOST12_512 => 0x8000;
  3         4  
  3         169  
49 3     3   16 use constant RHASH_SHA224 => 0x10000;
  3         5  
  3         194  
50 3     3   21 use constant RHASH_SHA256 => 0x20000;
  3         5  
  3         209  
51 3     3   18 use constant RHASH_SHA384 => 0x40000;
  3         5  
  3         179  
52 3     3   16 use constant RHASH_SHA512 => 0x80000;
  3         6  
  3         157  
53 3     3   17 use constant RHASH_EDONR256 => 0x100000;
  3         4  
  3         161  
54 3     3   15 use constant RHASH_EDONR512 => 0x200000;
  3         4  
  3         146  
55 3     3   14 use constant RHASH_SHA3_224 => 0x0400000;
  3         5  
  3         143  
56 3     3   20 use constant RHASH_SHA3_256 => 0x0800000;
  3         6  
  3         180  
57 3     3   16 use constant RHASH_SHA3_384 => 0x1000000;
  3         4  
  3         170  
58 3     3   15 use constant RHASH_SHA3_512 => 0x2000000;
  3         25  
  3         190  
59 3     3   19 use constant RHASH_CRC32C => 0x4000000;
  3         5  
  3         171  
60 3     3   35 use constant RHASH_SNEFRU128 => 0x8000000;
  3         4  
  3         164  
61 3     3   16 use constant RHASH_SNEFRU256 => 0x10000000;
  3         6  
  3         145  
62 3     3   15 use constant RHASH_BLAKE2S => 0x20000000;
  3         6  
  3         155  
63 3     3   16 use constant RHASH_BLAKE2B => 0x40000000;
  3         5  
  3         176  
64 3     3   16 use constant RHASH_ALL => 0x7FFFFFFF;
  3         5  
  3         2959  
65              
66             ##############################################################################
67             # Rhash class methods
68              
69             # Rhash object constructor
70             sub new($$@)
71             {
72 5     5 0 380057 my ($class, @hash_ids) = @_;
73              
74             # validate @hash_ids to be an array of hash identifiers
75 5 50       21 scalar(@_) > 0 or die "hash_id not specified\n";
76 5         15 for my $id (@hash_ids) {
77 7 50 33     55 if (ref($id) || !scalar($id) || (scalar($id) & RHASH_ALL) != $id) {
      33        
78 0         0 die "bad hash_id = " . scalar($id) . " " . ref($id) . "\n";
79             }
80             }
81             # handle legacy initialization by a single bitmask
82 5 100 100     30 if (scalar(@hash_ids) == 1 && ($hash_ids[0] & ($hash_ids[0] - 1)) != 0) {
83             # Split the bit mask into the array of single bits
84 2         10 for (my $mask = shift(@hash_ids); $mask; $mask = $mask & ($mask - 1)) {
85 62         138 push(@hash_ids, $mask & -$mask);
86             }
87             }
88 5 50       179 my $context = rhash_init_multi_wrapper(\@hash_ids) or return undef;
89 5         22 my $self = {
90             context => $context,
91             };
92 5         32 return bless $self, $class;
93             }
94              
95             # destructor
96             sub DESTROY($)
97             {
98 3     3   7 my $self = shift;
99             # the 'if' added as workaround for perl 'global destruction' bug
100             # ($self->{context} can disappear on global destruction)
101 3 50       34 rhash_free($self->{context}) if $self->{context};
102             }
103              
104             sub update($$)
105             {
106 4     4 1 20 my $self = shift;
107 4         9 my $message = shift;
108 4         64 rhash_update($self->{context}, $message);
109 4         22 return $self;
110             }
111              
112             sub update_fd($$;$$)
113             {
114 3     3 1 10 my ($self, $fd, $start, $size) = @_;
115 3         5 my $res = 0;
116 3         6 my $num = 0;
117              
118 3         7 binmode($fd);
119 3 100       11 if(defined($start)) {
120 1 50       12 seek($fd, scalar($start), 0) or return undef;
121             }
122              
123 3         6 my $data;
124 3 100       9 if(defined($size)) {
125 1         4 for(my $left = scalar($size); $left > 0; $left -= 8192) {
126 1 50       48 ($res = read($fd, $data,
    50          
127             ($left < 8192 ? $left : 8192))) || last;
128 1         9 rhash_update($self->{context}, $data);
129 1         5 $num += $res;
130             }
131             } else {
132 2         97 while( ($res = read($fd, $data, 8192)) ) {
133 2         24 rhash_update($self->{context}, $data);
134 2         8 $num += $res;
135             }
136             }
137              
138 3 50       34 return (defined($res) ? $num : undef); # return undef on read error
139             }
140              
141             sub update_file($$;$$)
142             {
143 2     2 1 10 my ($self, $file, $start, $size) = @_;
144 2 50       146 open(my $fd, "<", $file) or return undef;
145 2         12 my $res = $self->update_fd($fd, $start, $size);
146 2         48 close($fd);
147 2         20 return $res;
148             }
149              
150             sub final($)
151             {
152 3     3 1 6 my $self = shift;
153 3         527 rhash_final($self->{context});
154 3         11 return $self;
155             }
156              
157             sub reset($)
158             {
159 3     3 1 25 my $self = shift;
160 3         23 rhash_reset($self->{context});
161 3         11 return $self;
162             }
163              
164             sub hashed_length($)
165             {
166 2     2 1 5 my $self = shift;
167 2         20 return rhash_get_hashed_length($self->{context});
168             }
169              
170             sub hash_id($)
171             {
172 1     1 1 3 my $self = shift;
173 1         10 return rhash_get_hash_id($self->{context});
174             }
175              
176             ##############################################################################
177             # Message digest formatting functions
178              
179             # printing constants
180 3     3   26 use constant RHPR_DEFAULT => 0x0;
  3         4  
  3         177  
181 3     3   18 use constant RHPR_RAW => 0x1;
  3         4  
  3         197  
182 3     3   18 use constant RHPR_HEX => 0x2;
  3         6  
  3         149  
183 3     3   17 use constant RHPR_BASE32 => 0x3;
  3         5  
  3         168  
184 3     3   15 use constant RHPR_BASE64 => 0x4;
  3         5  
  3         200  
185 3     3   18 use constant RHPR_UPPERCASE => 0x8;
  3         18  
  3         179  
186 3     3   15 use constant RHPR_REVERSE => 0x10;
  3         6  
  3         2643  
187              
188             sub hash($;$$)
189             {
190 43     43 1 79 my $self = shift;
191 43   100     136 my $hash_id = scalar(shift) || 0;
192 43   100     127 my $print_flags = scalar(shift) || RHPR_DEFAULT;
193 43         438 return rhash_print_wrapper($self->{context}, $hash_id, $print_flags);
194             }
195              
196             sub hash_base32($;$)
197             {
198 1     1 1 6 hash($_[0], $_[1], RHPR_BASE32);
199             }
200              
201             sub hash_base64($;$)
202             {
203 1     1 1 5 hash($_[0], $_[1], RHPR_BASE64);
204             }
205              
206             sub hash_hex($;$)
207             {
208 2     2 1 10 hash($_[0], $_[1], RHPR_HEX);
209             }
210              
211             sub hash_rhex($;$)
212             {
213 1     1 1 5 hash($_[0], $_[1], RHPR_HEX | RHPR_REVERSE);
214             }
215              
216             sub hash_raw($;$)
217             {
218 1     1 0 5 hash($_[0], $_[1], RHPR_RAW);
219             }
220              
221             sub magnet_link($;$@)
222             {
223 4     4 1 14 my ($self, $filename, @hash_ids) = @_;
224 4         8 my $hash_mask = 0;
225 4 100       11 if (scalar(@hash_ids)) {
226 2         5 for my $id (@hash_ids) {
227 5 50 33     35 if (ref($id) || !scalar($id) || (scalar($id) & RHASH_ALL) != $id) {
      33        
228 0         0 die "bad hash_id = " . scalar($id) . " " . ref($id) . "\n";
229             }
230 5         11 $hash_mask = $hash_mask | scalar($id);
231             }
232             } else {
233 2         5 $hash_mask = undef;
234             }
235 4         59 return rhash_print_magnet_wrapper($self->{context}, $filename, $hash_mask);
236             }
237              
238             our $AUTOLOAD;
239              
240             # report error if a script called unexisting method/field
241             sub AUTOLOAD
242             {
243 0     0   0 my ($self, $field, $type, $pkg) = ($_[0], $AUTOLOAD, undef, __PACKAGE__);
244 0         0 $field =~ s/.*://;
245 0 0       0 die "function $field does not exist\n" if $field =~ /^(rhash_|raw2)/;
246 0 0       0 die "no arguments specified to $field()\n" if !@_;
247 0 0       0 die "the $field() argument is undefined\n" if !defined $self;
248              
249 0 0 0     0 ($type = ref($self)) && $type eq $pkg || die "the $field() argument is not a $pkg reference\n";
250 0 0       0 my $text = (exists $self->{$field} ? "is not accessible" : "does not exist");
251 0         0 die "the method $field() $text in the class $pkg\n";
252             }
253              
254             # static functions
255              
256             sub msg($$)
257             {
258 1     1 1 251436 my ($hash_id, $msg) = @_;
259 1         14 my $raw = rhash_msg_wrapper($hash_id, $msg); # get a binary message digest
260 1 50       18 return (is_base32($hash_id) ? raw2base32($raw) : raw2hex($raw));
261             }
262              
263             1;
264             __END__