File Coverage

lib/Digest/Perl/MD5.pm
Criterion Covered Total %
statement 176 179 98.3
branch 14 18 77.7
condition 3 9 33.3
subroutine 22 23 95.6
pod 0 17 0.0
total 215 246 87.4


line stmt bran cond sub pod time code
1             package Digest::Perl::MD5;
2 1     1   16970 use strict;
  1         2  
  1         41  
3 1     1   742 use integer;
  1         18  
  1         7  
4 1     1   40 use Exporter;
  1         2  
  1         65  
5 1     1   6 use vars qw($VERSION @ISA @EXPORTER @EXPORT_OK);
  1         4  
  1         2417  
6              
7             @EXPORT_OK = qw(md5 md5_hex md5_base64);
8              
9             @ISA = 'Exporter';
10             $VERSION = '1.91';
11              
12             # I-Vektor
13             sub A() { 0x67_45_23_01 }
14             sub B() { 0xef_cd_ab_89 }
15             sub C() { 0x98_ba_dc_fe }
16             sub D() { 0x10_32_54_76 }
17              
18             # for internal use
19             sub MAX() { 0xFFFFFFFF }
20              
21             # pad a message to a multiple of 64
22             sub padding {
23 50276     50276 0 93959 my $l = length( my $msg = shift() . chr(128) );
24 50276 100       134915 $msg .= "\0" x ( ( $l % 64 <= 56 ? 56 : 120 ) - $l % 64 );
25 50276         68036 $l = ( $l - 1 ) * 8;
26 50276         147867 $msg .= pack 'VV', $l & MAX, ( $l >> 16 >> 16 );
27             }
28              
29             sub rotate_left($$) {
30              
31             #$_[0] << $_[1] | $_[0] >> (32 - $_[1]);
32             #my $right = $_[0] >> (32 - $_[1]);
33             #my $rmask = (1 << $_[1]) - 1;
34 0     0 0 0 ( $_[0] << $_[1] ) |
35             ( ( $_[0] >> ( 32 - $_[1] ) ) & ( ( 1 << $_[1] ) - 1 ) );
36              
37             #$_[0] << $_[1] | (($_[0]>> (32 - $_[1])) & (1 << (32 - $_[1])) - 1);
38             }
39              
40             sub gen_code {
41              
42             # Discard upper 32 bits on 64 bit archs.
43 1     1 0 3 my $MSK = ( ( 1 << 16 ) << 16 ) ? ' & ' . MAX : '';
44              
45             # FF => "X0=rotate_left(((X1&X2)|(~X1&X3))+X0+X4+X6$MSK,X5)+X1$MSK;",
46             # GG => "X0=rotate_left(((X1&X3)|(X2&(~X3)))+X0+X4+X6$MSK,X5)+X1$MSK;",
47             # Only mask before rotate, not after; final mask in round() return
48 1         7 my %f = (
49             FF => "X0=rotate_left((X3^(X1&(X2^X3)))+X0+X4+X6$MSK,X5)+X1;",
50             GG => "X0=rotate_left((X2^(X3&(X1^X2)))+X0+X4+X6$MSK,X5)+X1;",
51             HH => "X0=rotate_left((X1^X2^X3)+X0+X4+X6$MSK,X5)+X1;",
52             II => "X0=rotate_left((X2^(X1|(~X3)))+X0+X4+X6$MSK,X5)+X1;",
53             );
54              
55             #unless ( (1 << 16) << 16) { %f = %{$CODES{'32bit'}} }
56             #else { %f = %{$CODES{'64bit'}} }
57              
58 1         13 my %s = ( # shift lengths
59             S11 => 7,
60             S12 => 12,
61             S13 => 17,
62             S14 => 22,
63             S21 => 5,
64             S22 => 9,
65             S23 => 14,
66             S24 => 20,
67             S31 => 4,
68             S32 => 11,
69             S33 => 16,
70             S34 => 23,
71             S41 => 6,
72             S42 => 10,
73             S43 => 15,
74             S44 => 21
75             );
76              
77 1         2 my $insert = "\n";
78 1         6 while ( defined( my $data = ) ) {
79 64         89 chomp $data;
80 64 50       155 next unless $data =~ /^[FGHI]/;
81 64         246 my ( $func, @x ) = split /,/, $data;
82 64         102 my $c = $f{$func};
83 64         894 $c =~ s/X(\d)/$x[$1]/g;
84 64         110 $c =~ s/(S\d{2})/$s{$1}/;
85 64         257 $c =~ s/^(.*)=rotate_left\((.*),(.*)\)\+(.*)$//;
86              
87 64         123 my $su = 32 - $3;
88 64         99 my $sh = ( 1 << $3 ) - 1;
89              
90 64         263 $c = "$1=(((\$r=$2)<<$3)|((\$r>>$su)&$sh))+$4";
91              
92             #my $rotate = "(($2 << $3) || (($2 >> (32 - $3)) & (1 << $2) - 1)))";
93             # $c = "\$r = $2;
94             # $1 = ((\$r << $3) | ((\$r >> (32 - $3)) & ((1 << $3) - 1))) + $4";
95 64         331 $insert .= "\t$c\n";
96             }
97 1         14 close DATA;
98              
99 1         5 my $dump = '
100             sub round {
101             my ($a,$b,$c,$d) = @_[0 .. 3];
102             my $r;' . $insert . '
103             ($_[0]+$a)'
104             . $MSK
105             . ', ($_[1]+$b)'
106             . $MSK
107             . ', ($_[2]+$c)'
108             . $MSK
109             . ', ($_[3]+$d)'
110             . $MSK . ';
111             }';
112 1     52281 0 1787 eval $dump;
  52281         157483  
  52281         70594  
  52281         120031  
  52281         95602  
  52281         99091  
  52281         103573  
  52281         97690  
  52281         95656  
  52281         94206  
  52281         93426  
  52281         96966  
  52281         106494  
  52281         104062  
  52281         98025  
  52281         98191  
  52281         97683  
  52281         94732  
  52281         92103  
  52281         94987  
  52281         95065  
  52281         95751  
  52281         102059  
  52281         94022  
  52281         91270  
  52281         93983  
  52281         97347  
  52281         96388  
  52281         99592  
  52281         94376  
  52281         99760  
  52281         93209  
  52281         92726  
  52281         91968  
  52281         91095  
  52281         90753  
  52281         91738  
  52281         95025  
  52281         92612  
  52281         87238  
  52281         89082  
  52281         98129  
  52281         87977  
  52281         87119  
  52281         86823  
  52281         89351  
  52281         89259  
  52281         91532  
  52281         85311  
  52281         102605  
  52281         90803  
  52281         96119  
  52281         92015  
  52281         90790  
  52281         93109  
  52281         91649  
  52281         90265  
  52281         90245  
  52281         87954  
  52281         86418  
  52281         92612  
  52281         92997  
  52281         88825  
  52281         90374  
  52281         94141  
  52281         91905  
  52281         90713  
  52281         268872  
113              
114             # print "$dump\n";
115             # exit 0;
116             }
117              
118             gen_code();
119              
120             #########################################
121             # Private output converter functions:
122 274     274   1204 sub _encode_hex { unpack 'H*', $_[0] }
123              
124             sub _encode_base64 {
125 8     8   10 my $res;
126 8         54 while ( $_[0] =~ /(.{1,45})/gs ) {
127 8         49 $res .= substr pack( 'u', $1 ), 1;
128 8         27 chop $res;
129             }
130 8         16 $res =~ tr|` -_|AA-Za-z0-9+/|; #`
131 8         16 chop $res;
132 8         11 chop $res;
133 8         72 $res;
134             }
135              
136             #########################################
137             # OOP interface:
138             sub new {
139 6     6 0 609 my $proto = shift;
140 6   33     39 my $class = ref $proto || $proto;
141 6         13 my $self = {};
142 6         13 bless $self, $class;
143 6         20 $self->reset();
144 6         26 $self;
145             }
146              
147             sub reset {
148 17     17 0 27 my $self = shift;
149 17         44 delete $self->{_data};
150 17         57 $self->{_state} = [ A, B, C, D ];
151 17         27 $self->{_length} = 0;
152 17         30 $self;
153             }
154              
155             sub add {
156 281     281 0 547 my $self = shift;
157 281 100       803 $self->{_data} .= join '', @_ if @_;
158 281         380 my ( $i, $c );
159 281         576 for $i ( 0 .. ( length $self->{_data} ) / 64 - 1 ) {
160 993         4134 my @X = unpack 'V16', substr $self->{_data}, $i * 64, 64;
161 993         1507 @{ $self->{_state} } = round( @{ $self->{_state} }, @X );
  993         2589  
  993         21245  
162 993         2656 ++$c;
163             }
164 281 100       494 if ($c) {
165 25         71 substr( $self->{_data}, 0, $c * 64 ) = '';
166 25         47 $self->{_length} += $c * 64;
167             }
168 281         639 $self;
169             }
170              
171             sub finalize {
172 10     10 0 15 my $self = shift;
173 10         20 $self->{_data} .= chr(128);
174 10         19 my $l = $self->{_length} + length $self->{_data};
175 10 50       70 $self->{_data} .= "\0" x ( ( $l % 64 <= 56 ? 56 : 120 ) - $l % 64 );
176 10         22 $l = ( $l - 1 ) * 8;
177 10         51 $self->{_data} .= pack 'VV', $l & MAX, ( $l >> 16 >> 16 );
178 10         24 $self->add();
179 10         17 $self;
180             }
181              
182             sub addfile {
183 1     1 0 70 my ( $self, $fh ) = @_;
184 1 50 33     32 if ( !ref($fh) && ref( \$fh ) ne "GLOB" ) {
185 0         0 require Symbol;
186 0         0 $fh = Symbol::qualify( $fh, scalar caller );
187             }
188              
189             # $self->{_data} .= do{local$/;<$fh>};
190 1         3 my $read = 0;
191 1         3 my $buffer = '';
192 1         88 $self->add($buffer) while $read = read $fh, $buffer, 8192;
193 1 50       8 die __PACKAGE__, " read failed: $!" unless defined $read;
194 1         9 $self;
195             }
196              
197             sub add_bits {
198 3     3 0 17 my $self = shift;
199 3 100       16 return $self->add( pack 'B*', shift ) if @_ == 1;
200 2         7 my ( $b, $n ) = @_;
201 2 100       15 die __PACKAGE__, " Invalid number of bits\n" if $n % 8;
202 1         6 $self->add( substr $b, 0, $n / 8 );
203             }
204              
205             sub digest {
206 10     10 0 16 my $self = shift;
207 10         29 $self->finalize();
208 10         15 my $res = pack 'V4', @{ $self->{_state} };
  10         39  
209 10         35 $self->reset();
210 10         35 $res;
211             }
212              
213             sub hexdigest {
214 4     4 0 18 _encode_hex( $_[0]->digest );
215             }
216              
217             sub b64digest {
218 4     4 0 24 _encode_base64( $_[0]->digest );
219             }
220              
221             sub clone {
222 1     1 0 6 my $self = shift;
223             my $clone = {
224 1         6 _state => [ @{ $self->{_state} } ],
225             _length => $self->{_length},
226             _data => $self->{_data}
227 1         2 };
228 1   33     8 bless $clone, ref $self || $self;
229             }
230              
231             #########################################
232             # Procedural interface:
233             sub md5 {
234 50276     50276 0 247753 my $message = padding( join '', @_ );
235 50276         104919 my ( $a, $b, $c, $d ) = ( A, B, C, D );
236 50276         59689 my $i;
237 50276         122637 for $i ( 0 .. ( length $message ) / 64 - 1 ) {
238 51288         170334 my @X = unpack 'V16', substr $message, $i * 64, 64;
239 51288         1018414 ( $a, $b, $c, $d ) = round( $a, $b, $c, $d, @X );
240             }
241 50276         163690 pack 'V4', $a, $b, $c, $d;
242             }
243 270     270 0 204329 sub md5_hex { _encode_hex &md5 }
244 4     4 0 123 sub md5_base64 { _encode_base64 &md5 }
245              
246             1;
247              
248             =head1 NAME
249              
250             Digest::MD5::Perl - Perl implementation of Ron Rivest's MD5 Algorithm
251              
252             =head1 DISCLAIMER
253              
254             This is B an interface (like C) but a Perl implementation of MD5.
255             It is written in perl only and because of this it is slow but it works without C-Code.
256             You should use C instead of this module if it is available.
257             This module is only useful for
258              
259             =over 4
260              
261             =item
262              
263             computers where you cannot install C (e.g. lack of a C-Compiler)
264              
265             =item
266              
267             hashing only small amounts of data (less than one million bytes). I use it to
268             hash passwords.
269              
270             =item
271              
272             educational purposes
273              
274             =back
275              
276             =head1 SYNOPSIS
277              
278             # Functional style
279             use Digest::MD5 qw(md5 md5_hex md5_base64);
280              
281             $hash = md5 $data;
282             $hash = md5_hex $data;
283             $hash = md5_base64 $data;
284            
285              
286             # OO style
287             use Digest::MD5;
288              
289             $ctx = Digest::MD5->new;
290              
291             $ctx->add($data);
292             $ctx->addfile(*FILE);
293              
294             $digest = $ctx->digest;
295             $digest = $ctx->hexdigest;
296             $digest = $ctx->b64digest;
297              
298             =head1 DESCRIPTION
299              
300             This module has the same interface as the much faster C. So you can
301             easily exchange them, e.g.
302              
303             BEGIN {
304             eval {
305             require Digest::MD5;
306             import Digest::MD5 'md5_hex'
307             };
308             if ($@) { # oops, no Digest::MD5
309             require Digest::Perl::MD5;
310             import Digest::Perl::MD5 'md5_hex'
311             }
312             }
313              
314             If the C module is available it is used and if not you take
315             C.
316              
317             You can also install the Perl part of Digest::MD5 together with Digest::Perl::MD5
318             and use Digest::MD5 as normal, it falls back to Digest::Perl::MD5 if it
319             cannot load its object files.
320              
321             For detailed documentation see the C module.
322              
323             =head1 EXAMPLES
324              
325             The simplest way to use this library is to import the md5_hex()
326             function (or one of its cousins):
327              
328             use Digest::Perl::MD5 'md5_hex';
329             print 'Digest is ', md5_hex('foobarbaz'), "\n";
330              
331             The above example would print out the message
332              
333             Digest is 6df23dc03f9b54cc38a0fc1483df6e21
334              
335             provided that the implementation is working correctly. The same
336             checksum can also be calculated in OO style:
337              
338             use Digest::MD5;
339            
340             $md5 = Digest::MD5->new;
341             $md5->add('foo', 'bar');
342             $md5->add('baz');
343             $digest = $md5->hexdigest;
344            
345             print "Digest is $digest\n";
346              
347             The digest methods are destructive. That means you can only call them
348             once and the $md5 object is reset after use. You can make a copy with clone:
349              
350             $md5->clone->hexdigest
351              
352             =head1 LIMITATIONS
353              
354             This implementation of the MD5 algorithm has some limitations:
355              
356             =over 4
357              
358             =item
359              
360             It's slow, very slow. I've done my very best but Digest::MD5 is still about 100 times faster.
361             You can only hash data up to one million bytes in an acceptable time. But it's very useful
362             for hashing small amounts of data like passwords.
363              
364             =item
365              
366             You can only hash up to 2^32 bits = 512 MB on 32-bit archs. But you should
367             use C for those amounts of data anyway.
368              
369             =back
370              
371             =head1 SEE ALSO
372              
373             L
374              
375             L
376              
377             RFC 1321
378              
379             tools/md5: a small BSD compatible md5 tool written in pure perl.
380              
381             =head1 COPYRIGHT
382              
383             This library is free software; you can redistribute it and/or
384             modify it under the same terms as Perl itself.
385              
386             Copyright 2000 Christian Lackas, Imperia Software Solutions
387             Copyright 1998-1999 Gisle Aas.
388             Copyright 1995-1996 Neil Winton.
389             Copyright 1991-1992 RSA Data Security, Inc.
390              
391             The MD5 algorithm is defined in RFC 1321. The basic C code
392             implementing the algorithm is derived from that in the RFC and is
393             covered by the following copyright:
394              
395             =over 4
396              
397             =item
398              
399             Copyright (C) 1991-1992, RSA Data Security, Inc. Created 1991. All
400             rights reserved.
401              
402             License to copy and use this software is granted provided that it
403             is identified as the "RSA Data Security, Inc. MD5 Message-Digest
404             Algorithm" in all material mentioning or referencing this software
405             or this function.
406              
407             License is also granted to make and use derivative works provided
408             that such works are identified as "derived from the RSA Data
409             Security, Inc. MD5 Message-Digest Algorithm" in all material
410             mentioning or referencing the derived work.
411              
412             RSA Data Security, Inc. makes no representations concerning either
413             the merchantability of this software or the suitability of this
414             software for any particular purpose. It is provided "as is"
415             without express or implied warranty of any kind.
416              
417             These notices must be retained in any copies of any part of this
418             documentation and/or software.
419              
420             =back
421              
422             This copyright does not prohibit distribution of any version of Perl
423             containing this extension under the terms of the GNU or Artistic
424             licenses.
425              
426             =head1 AUTHORS
427              
428             The original MD5 interface was written by Neil Winton
429             ().
430              
431             C was made by Gisle Aas (I took his Interface
432             and part of the documentation).
433              
434             Thanks to Guido Flohr for his 'use integer'-hint.
435              
436             This release was made by Christian Lackas .
437              
438             =cut
439              
440             __DATA__