File Coverage

blib/lib/Crypt/PBE/PBKDF1.pm
Criterion Covered Total %
statement 67 85 78.8
branch 7 12 58.3
condition 22 44 50.0
subroutine 17 23 73.9
pod 9 10 90.0
total 122 174 70.1


line stmt bran cond sub pod time code
1             package Crypt::PBE::PBKDF1;
2              
3 4     4   796 use strict;
  4         9  
  4         126  
4 4     4   18 use warnings;
  4         9  
  4         101  
5              
6 4     4   20 use Carp;
  4         7  
  4         266  
7              
8 4     4   1037 use MIME::Base64;
  4         1332  
  4         251  
9              
10 4     4   1868 use Digest::MD2 qw(md2);
  4         2275  
  4         251  
11 4     4   28 use Digest::MD5 qw(md5);
  4         8  
  4         159  
12 4     4   2226 use Digest::SHA qw(sha1);
  4         12549  
  4         357  
13              
14 4     4   33 use Exporter qw(import);
  4         7  
  4         2701  
15              
16             our $VERSION = '0.101';
17              
18             our @EXPORT = qw(
19             pbkdf1
20             pbkdf1_base64
21             pbkdf1_hex
22             );
23              
24             our @EXPORT_OK = qw(
25             pbkdf1_md2
26             pbkdf1_md2_base64
27             pbkdf1_md2_hex
28              
29             pbkdf1_md5
30             pbkdf1_md5_base64
31             pbkdf1_md5_hex
32              
33             pbkdf1_sha1
34             pbkdf1_sha1_base64
35             pbkdf1_sha1_hex
36             );
37              
38             sub new {
39              
40 1     1 1 605 my ( $class, %params ) = @_;
41              
42 1   33     5 my $password = delete $params{password} || croak 'Specify password';
43 1   33     3 my $salt = delete $params{salt} || croak 'Specify salt';
44 1   50     6 my $count = delete $params{count} || 1_000;
45 1   50     4 my $hash = delete $params{hash} || 'sha1';
46 1         2 my $dk_len = 20;
47              
48 1 50 33     6 $dk_len = 16 if ( $hash eq 'md5' || $hash eq 'md2' );
49              
50 1         3 my $self = {
51             password => $password,
52             salt => $salt,
53             count => $count,
54             hash => $hash,
55             dk_len => $dk_len
56             };
57              
58 1         2 bless $self, $class;
59              
60 1         3 return $self;
61              
62             }
63              
64             sub hash_algorithm {
65 0     0 0 0 my ($self) = @_;
66 0         0 return $self->{hash};
67             }
68              
69             sub count {
70 0     0 1 0 my ($self) = @_;
71 0         0 return $self->{count};
72             }
73              
74             sub derived_key_length {
75 0     0 1 0 my ($self) = @_;
76 0         0 return $self->{dk_len};
77             }
78              
79             sub derived_key {
80 0     0 1 0 my ($self) = @_;
81             return pbkdf1(
82             password => $self->{password},
83             salt => $self->{salt},
84             count => $self->{count},
85             hash => $self->{hash},
86             dk_len => $self->{dk_len}
87 0         0 );
88             }
89              
90             sub derived_key_base64 {
91 1     1 1 399 my ($self) = @_;
92             return pbkdf1_base64(
93             password => $self->{password},
94             salt => $self->{salt},
95             count => $self->{count},
96             hash => $self->{hash},
97             dk_len => $self->{dk_len}
98 1         6 );
99             }
100              
101             sub derived_key_hex {
102 1     1 1 2 my ($self) = @_;
103             return pbkdf1_hex(
104             password => $self->{password},
105             salt => $self->{salt},
106             count => $self->{count},
107             hash => $self->{hash},
108             dk_len => $self->{dk_len}
109 1         4 );
110             }
111              
112             # PBKDF1 (P, S, c, dkLen)
113             #
114             # Options: Hash underlying hash function
115             #
116             # Input: P password, an octet string
117             # S salt, an octet string
118             # c iteration count, a positive integer
119             # dkLen intended length in octets of derived key,
120             # a positive integer, at most 16 for MD2 or
121             # MD5 and 20 for SHA-1
122             # Output: DK derived key, a dkLen-octet string
123              
124             sub pbkdf1 {
125              
126 9     9 1 35 my (%params) = @_;
127              
128 9   50     47 my $hash = delete( $params{hash} ) || 'sha1';
129 9   33     34 my $P = delete( $params{password} ) || croak('Specify password');
130 9   33     24 my $S = delete( $params{salt} ) || croak('Specify salt');
131 9   50     20 my $c = delete( $params{count} ) || 1_000;
132 9         16 my $dkLen = delete( $params{dk_len} );
133              
134 9 50 100     48 if ( $hash ne 'md2' && $hash ne 'md5' && $hash ne 'sha1' ) {
      66        
135 0         0 croak 'unknown hash function';
136             }
137              
138 9 100       19 if ( !$dkLen ) {
139 4 50       26 $dkLen = 16 if ( $hash =~ /md(2|5)/ );
140 4 50       15 $dkLen = 20 if ( $hash eq 'sha1' );
141             }
142              
143 9 50 66     78 if ( ( $hash eq 'md5' && $dkLen > 16 ) || ( $hash eq 'md2' && $dkLen > 16 ) || ( $hash eq 'sha1' && $dkLen > 20 ) )
      66        
      33        
      66        
      33        
144             {
145 0         0 croak 'derived key too long';
146             }
147              
148 9         19 my $T = $P . $S;
149              
150 4     4   68 no strict 'refs'; ## no critic
  4         11  
  4         899  
151              
152 9         26 for ( 1 .. $c ) {
153 9000         11280 $T = &{$hash}($T);
  9000         32619  
154             }
155              
156 9         23 my $DK = substr( $T, 0, $dkLen );
157              
158 9         72 return $DK;
159              
160             }
161              
162             sub pbkdf1_hex {
163 1     1 1 2 return join '', unpack '(H2)*', pbkdf1(@_);
164             }
165              
166             sub pbkdf1_base64 {
167 1     1 1 3 return encode_base64 pbkdf1(@_), '';
168             }
169              
170             for my $digest (qw/md2 md5 sha1/) {
171              
172             my $dk_len = 16;
173             $dk_len = 20 if ( $digest eq 'sha1' );
174              
175             my $sub_name = 'pbkdf1_' . $digest;
176              
177 4     4   32 no strict 'refs'; ## no critic
  4         9  
  4         1052  
178              
179             *{$sub_name} = sub {
180 0     0   0 my (%params) = @_;
181 0         0 $params{hash} = $digest;
182 0         0 $params{dk_len} = $dk_len;
183 0         0 return pbkdf1(%params);
184             };
185              
186             *{ $sub_name . '_base64' } = sub {
187 3     3   11 my (%params) = @_;
188 3         6 $params{hash} = $digest;
189 3         6 $params{dk_len} = $dk_len;
190 3         9 return encode_base64 pbkdf1(%params), '';
191             };
192              
193             *{ $sub_name . '_hex' } = sub {
194 0     0     my (%params) = @_;
195 0           $params{hash} = $digest;
196 0           $params{dk_len} = $dk_len;
197 0           return join '', unpack '(H2)*', pbkdf1(%params);
198             };
199              
200             }
201              
202             1;
203             __END__