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   8703 use strict;
  1         2  
  1         31  
3 1     1   943 use integer;
  1         10  
  1         6  
4 1     1   26 use Exporter;
  1         5  
  1         35  
5 1     1   4 use vars qw($VERSION @ISA @EXPORTER @EXPORT_OK);
  1         1  
  1         1884  
6              
7             @EXPORT_OK = qw(md5 md5_hex md5_base64);
8              
9             @ISA = 'Exporter';
10             $VERSION = '1.9';
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 82762 my $l = length (my $msg = shift() . chr(128));
24 50276 100       118213 $msg .= "\0" x (($l%64<=56?56:120)-$l%64);
25 50276         58474 $l = ($l-1)*8;
26 50276         152002 $msg .= pack 'VV', $l & MAX , ($l >> 16 >> 16);
27             }
28              
29              
30             sub rotate_left($$) {
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]) | (( $_[0] >> (32 - $_[1]) ) & ((1 << $_[1]) - 1));
35             #$_[0] << $_[1] | (($_[0]>> (32 - $_[1])) & (1 << (32 - $_[1])) - 1);
36             }
37              
38             sub gen_code {
39             # Discard upper 32 bits on 64 bit archs.
40 1     1 0 3 my $MSK = ((1 << 16) << 16) ? ' & ' . MAX : '';
41             # FF => "X0=rotate_left(((X1&X2)|(~X1&X3))+X0+X4+X6$MSK,X5)+X1$MSK;",
42             # GG => "X0=rotate_left(((X1&X3)|(X2&(~X3)))+X0+X4+X6$MSK,X5)+X1$MSK;",
43 1         8 my %f = (
44             FF => "X0=rotate_left((X3^(X1&(X2^X3)))+X0+X4+X6$MSK,X5)+X1$MSK;",
45             GG => "X0=rotate_left((X2^(X3&(X1^X2)))+X0+X4+X6$MSK,X5)+X1$MSK;",
46             HH => "X0=rotate_left((X1^X2^X3)+X0+X4+X6$MSK,X5)+X1$MSK;",
47             II => "X0=rotate_left((X2^(X1|(~X3)))+X0+X4+X6$MSK,X5)+X1$MSK;",
48             );
49             #unless ( (1 << 16) << 16) { %f = %{$CODES{'32bit'}} }
50             #else { %f = %{$CODES{'64bit'}} }
51              
52 1         13 my %s = ( # shift lengths
53             S11 => 7, S12 => 12, S13 => 17, S14 => 22, S21 => 5, S22 => 9, S23 => 14,
54             S24 => 20, S31 => 4, S32 => 11, S33 => 16, S34 => 23, S41 => 6, S42 => 10,
55             S43 => 15, S44 => 21
56             );
57              
58 1         1 my $insert = "\n";
59 1         6 while(defined( my $data = )) {
60 64         66 chomp $data;
61 64 50       159 next unless $data =~ /^[FGHI]/;
62 64         261 my ($func,@x) = split /,/, $data;
63 64         107 my $c = $f{$func};
64 64         789 $c =~ s/X(\d)/$x[$1]/g;
65 64         84 $c =~ s/(S\d{2})/$s{$1}/;
66 64         339 $c =~ s/^(.*)=rotate_left\((.*),(.*)\)\+(.*)$//;
67              
68 64         109 my $su = 32 - $3;
69 64         99 my $sh = (1 << $3) - 1;
70              
71 64         216 $c = "$1=(((\$r=$2)<<$3)|((\$r>>$su)&$sh))+$4";
72              
73             #my $rotate = "(($2 << $3) || (($2 >> (32 - $3)) & (1 << $2) - 1)))";
74             # $c = "\$r = $2;
75             # $1 = ((\$r << $3) | ((\$r >> (32 - $3)) & ((1 << $3) - 1))) + $4";
76 64         314 $insert .= "\t$c\n";
77             }
78 1         13 close DATA;
79            
80 1         19 my $dump = '
81             sub round {
82             my ($a,$b,$c,$d) = @_[0 .. 3];
83             my $r;' . $insert . '
84             $_[0]+$a' . $MSK . ', $_[1]+$b ' . $MSK .
85             ', $_[2]+$c' . $MSK . ', $_[3]+$d' . $MSK . ';
86             }';
87 1     52281 0 1571 eval $dump;
  52281         96786  
  52281         54822  
  52281         113446  
  52281         91506  
  52281         91876  
  52281         90499  
  52281         91407  
  52281         99824  
  52281         91105  
  52281         83828  
  52281         92419  
  52281         84586  
  52281         87081  
  52281         85101  
  52281         82395  
  52281         87495  
  52281         85140  
  52281         91133  
  52281         83340  
  52281         88736  
  52281         83025  
  52281         88470  
  52281         85455  
  52281         90763  
  52281         92514  
  52281         85663  
  52281         90074  
  52281         86721  
  52281         91063  
  52281         81046  
  52281         84502  
  52281         85436  
  52281         84474  
  52281         82628  
  52281         87995  
  52281         86670  
  52281         81607  
  52281         83123  
  52281         92131  
  52281         85184  
  52281         79473  
  52281         88782  
  52281         91091  
  52281         87094  
  52281         80598  
  52281         84468  
  52281         98246  
  52281         87526  
  52281         87707  
  52281         89486  
  52281         89237  
  52281         83949  
  52281         86307  
  52281         90174  
  52281         85209  
  52281         78185  
  52281         80975  
  52281         85326  
  52281         81515  
  52281         81048  
  52281         91981  
  52281         80259  
  52281         81016  
  52281         84243  
  52281         87295  
  52281         86513  
  52281         282234  
88             # print "$dump\n";
89             # exit 0;
90             }
91              
92             gen_code();
93              
94             #########################################
95             # Private output converter functions:
96 274     274   915 sub _encode_hex { unpack 'H*', $_[0] }
97             sub _encode_base64 {
98 8     8   8 my $res;
99 8         43 while ($_[0] =~ /(.{1,45})/gs) {
100 8         35 $res .= substr pack('u', $1), 1;
101 8         23 chop $res;
102             }
103 8         10 $res =~ tr|` -_|AA-Za-z0-9+/|;#`
104 8         11 chop $res; chop $res;
  8         8  
105 8         43 $res
106             }
107              
108             #########################################
109             # OOP interface:
110             sub new {
111 6     6 0 658 my $proto = shift;
112 6   33     36 my $class = ref $proto || $proto;
113 6         11 my $self = {};
114 6         22 bless $self, $class;
115 6         17 $self->reset();
116 6         14 $self
117             }
118              
119             sub reset {
120 17     17 0 21 my $self = shift;
121 17         49 delete $self->{_data};
122 17         43 $self->{_state} = [A,B,C,D];
123 17         33 $self->{_length} = 0;
124 17         21 $self
125             }
126              
127             sub add {
128 281     281 0 659 my $self = shift;
129 281 100       794 $self->{_data} .= join '', @_ if @_;
130 281         245 my ($i,$c);
131 281         496 for $i (0 .. (length $self->{_data})/64-1) {
132 993         4091 my @X = unpack 'V16', substr $self->{_data}, $i*64, 64;
133 993         1430 @{$self->{_state}} = round(@{$self->{_state}},@X);
  993         2719  
  993         17208  
134 993         2562 ++$c;
135             }
136 281 100       460 if ($c) {
137 25         50 substr ($self->{_data}, 0, $c*64) = '';
138 25         36 $self->{_length} += $c*64;
139             }
140             $self
141 281         528 }
142              
143             sub finalize {
144 10     10 0 9 my $self = shift;
145 10         12 $self->{_data} .= chr(128);
146 10         18 my $l = $self->{_length} + length $self->{_data};
147 10 50       37 $self->{_data} .= "\0" x (($l%64<=56?56:120)-$l%64);
148 10         11 $l = ($l-1)*8;
149 10         31 $self->{_data} .= pack 'VV', $l & MAX , ($l >> 16 >> 16);
150 10         22 $self->add();
151 10         10 $self
152             }
153              
154             sub addfile {
155 1     1 0 79 my ($self,$fh) = @_;
156 1 50 33     17 if (!ref($fh) && ref(\$fh) ne "GLOB") {
157 0         0 require Symbol;
158 0         0 $fh = Symbol::qualify($fh, scalar caller);
159             }
160             # $self->{_data} .= do{local$/;<$fh>};
161 1         3 my $read = 0;
162 1         3 my $buffer = '';
163 1         45 $self->add($buffer) while $read = read $fh, $buffer, 8192;
164 1 50       6 die __PACKAGE__, " read failed: $!" unless defined $read;
165 1         6 $self
166             }
167              
168             sub add_bits {
169 3     3 0 13 my $self = shift;
170 3 100       12 return $self->add( pack 'B*', shift ) if @_ == 1;
171 2         4 my ($b,$n) = @_;
172 2 100       12 die __PACKAGE__, " Invalid number of bits\n" if $n%8;
173 1         5 $self->add( substr $b, 0, $n/8 )
174             }
175              
176             sub digest {
177 10     10 0 9 my $self = shift;
178 10         24 $self->finalize();
179 10         9 my $res = pack 'V4', @{$self->{_state}};
  10         28  
180 10         28 $self->reset();
181 10         29 $res
182             }
183              
184             sub hexdigest {
185 4     4 0 21 _encode_hex($_[0]->digest)
186             }
187              
188             sub b64digest {
189 4     4 0 40 _encode_base64($_[0]->digest)
190             }
191              
192             sub clone {
193 1     1 0 5 my $self = shift;
194 1         5 my $clone = {
195 1         3 _state => [@{$self->{_state}}],
196             _length => $self->{_length},
197             _data => $self->{_data}
198             };
199 1   33     7 bless $clone, ref $self || $self;
200             }
201              
202             #########################################
203             # Procedural interface:
204             sub md5 {
205 50276     50276 0 221886 my $message = padding(join'',@_);
206 50276         78445 my ($a,$b,$c,$d) = (A,B,C,D);
207 50276         45437 my $i;
208 50276         84836 for $i (0 .. (length $message)/64-1) {
209 51288         207176 my @X = unpack 'V16', substr $message,$i*64,64;
210 51288         916032 ($a,$b,$c,$d) = round($a,$b,$c,$d,@X);
211             }
212 50276         144754 pack 'V4',$a,$b,$c,$d;
213             }
214 270     270 0 2438 sub md5_hex { _encode_hex &md5 }
215 4     4 0 119 sub md5_base64 { _encode_base64 &md5 }
216              
217              
218             1;
219              
220             =head1 NAME
221              
222             Digest::MD5::Perl - Perl implementation of Ron Rivests MD5 Algorithm
223              
224             =head1 DISCLAIMER
225              
226             This is B an interface (like C) but a Perl implementation of MD5.
227             It is written in perl only and because of this it is slow but it works without C-Code.
228             You should use C instead of this module if it is available.
229             This module is only useful for
230              
231             =over 4
232              
233             =item
234              
235             computers where you cannot install C (e.g. lack of a C-Compiler)
236              
237             =item
238              
239             encrypting only small amounts of data (less than one million bytes). I use it to
240             hash passwords.
241              
242             =item
243              
244             educational purposes
245              
246             =back
247              
248             =head1 SYNOPSIS
249              
250             # Functional style
251             use Digest::MD5 qw(md5 md5_hex md5_base64);
252              
253             $hash = md5 $data;
254             $hash = md5_hex $data;
255             $hash = md5_base64 $data;
256            
257              
258             # OO style
259             use Digest::MD5;
260              
261             $ctx = Digest::MD5->new;
262              
263             $ctx->add($data);
264             $ctx->addfile(*FILE);
265              
266             $digest = $ctx->digest;
267             $digest = $ctx->hexdigest;
268             $digest = $ctx->b64digest;
269              
270             =head1 DESCRIPTION
271              
272             This modules has the same interface as the much faster C. So you can
273             easily exchange them, e.g.
274              
275             BEGIN {
276             eval {
277             require Digest::MD5;
278             import Digest::MD5 'md5_hex'
279             };
280             if ($@) { # ups, no Digest::MD5
281             require Digest::Perl::MD5;
282             import Digest::Perl::MD5 'md5_hex'
283             }
284             }
285              
286             If the C module is available it is used and if not you take
287             C.
288              
289             You can also install the Perl part of Digest::MD5 together with Digest::Perl::MD5
290             and use Digest::MD5 as normal, it falls back to Digest::Perl::MD5 if it
291             cannot load its object files.
292              
293             For a detailed Documentation see the C module.
294              
295             =head1 EXAMPLES
296              
297             The simplest way to use this library is to import the md5_hex()
298             function (or one of its cousins):
299              
300             use Digest::Perl::MD5 'md5_hex';
301             print 'Digest is ', md5_hex('foobarbaz'), "\n";
302              
303             The above example would print out the message
304              
305             Digest is 6df23dc03f9b54cc38a0fc1483df6e21
306              
307             provided that the implementation is working correctly. The same
308             checksum can also be calculated in OO style:
309              
310             use Digest::MD5;
311            
312             $md5 = Digest::MD5->new;
313             $md5->add('foo', 'bar');
314             $md5->add('baz');
315             $digest = $md5->hexdigest;
316            
317             print "Digest is $digest\n";
318              
319             The digest methods are destructive. That means you can only call them
320             once and the $md5 objects is reset after use. You can make a copy with clone:
321              
322             $md5->clone->hexdigest
323              
324             =head1 LIMITATIONS
325              
326             This implementation of the MD5 algorithm has some limitations:
327              
328             =over 4
329              
330             =item
331              
332             It's slow, very slow. I've done my very best but Digest::MD5 is still about 100 times faster.
333             You can only encrypt Data up to one million bytes in an acceptable time. But it's very useful
334             for encrypting small amounts of data like passwords.
335              
336             =item
337              
338             You can only encrypt up to 2^32 bits = 512 MB on 32bit archs. But You should
339             use C for those amounts of data anyway.
340              
341             =back
342              
343             =head1 SEE ALSO
344              
345             L
346              
347             L
348              
349             RFC 1321
350              
351             tools/md5: a small BSD compatible md5 tool written in pure perl.
352              
353             =head1 COPYRIGHT
354              
355             This library is free software; you can redistribute it and/or
356             modify it under the same terms as Perl itself.
357              
358             Copyright 2000 Christian Lackas, Imperia Software Solutions
359             Copyright 1998-1999 Gisle Aas.
360             Copyright 1995-1996 Neil Winton.
361             Copyright 1991-1992 RSA Data Security, Inc.
362              
363             The MD5 algorithm is defined in RFC 1321. The basic C code
364             implementing the algorithm is derived from that in the RFC and is
365             covered by the following copyright:
366              
367             =over 4
368              
369             =item
370              
371             Copyright (C) 1991-1992, RSA Data Security, Inc. Created 1991. All
372             rights reserved.
373              
374             License to copy and use this software is granted provided that it
375             is identified as the "RSA Data Security, Inc. MD5 Message-Digest
376             Algorithm" in all material mentioning or referencing this software
377             or this function.
378              
379             License is also granted to make and use derivative works provided
380             that such works are identified as "derived from the RSA Data
381             Security, Inc. MD5 Message-Digest Algorithm" in all material
382             mentioning or referencing the derived work.
383              
384             RSA Data Security, Inc. makes no representations concerning either
385             the merchantability of this software or the suitability of this
386             software for any particular purpose. It is provided "as is"
387             without express or implied warranty of any kind.
388              
389             These notices must be retained in any copies of any part of this
390             documentation and/or software.
391              
392             =back
393              
394             This copyright does not prohibit distribution of any version of Perl
395             containing this extension under the terms of the GNU or Artistic
396             licenses.
397              
398             =head1 AUTHORS
399              
400             The original MD5 interface was written by Neil Winton
401             ().
402              
403             C was made by Gisle Aas (I took his Interface
404             and part of the documentation).
405              
406             Thanks to Guido Flohr for his 'use integer'-hint.
407              
408             This release was made by Christian Lackas .
409              
410             =cut
411              
412             __DATA__