File Coverage

blib/lib/Crypt/PBE/PBKDF1.pm
Criterion Covered Total %
statement 78 85 91.7
branch 7 12 58.3
condition 22 44 50.0
subroutine 20 24 83.3
pod 9 10 90.0
total 136 175 77.7


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