File Coverage

blib/lib/Crypt/PBE/PBES2.pm
Criterion Covered Total %
statement 50 51 98.0
branch 4 6 66.6
condition 6 14 42.8
subroutine 12 12 100.0
pod 3 3 100.0
total 75 86 87.2


line stmt bran cond sub pod time code
1             package Crypt::PBE::PBES2;
2              
3 3     3   743 use strict;
  3         14  
  3         88  
4 3     3   15 use warnings;
  3         5  
  3         77  
5              
6 3     3   17 use Carp;
  3         4  
  3         193  
7 3     3   587 use Crypt::CBC;
  3         5190  
  3         76  
8              
9 3     3   1435 use Crypt::PBE::PBKDF2;
  3         9  
  3         208  
10              
11 3     3   21 use Exporter qw(import);
  3         6  
  3         183  
12              
13             our $VERSION = '0.101';
14              
15 3         242 use constant KEY_SIZE => {
16             'aes-128' => 16,
17             'aes-192' => 24,
18             'aes-256' => 32,
19 3     3   19 };
  3         5  
20              
21 3         190 use constant ENCRYPTION => {
22             'aes-128' => 'Crypt::OpenSSL::AES',
23             'aes-192' => 'Crypt::OpenSSL::AES',
24             'aes-256' => 'Crypt::OpenSSL::AES',
25 3     3   22 };
  3         6  
26              
27 3     3   21 use constant HMAC => qw( hmac-sha1 hmac-224 hmac-sha256 hmac-sha384 hmac-sha512 );
  3         6  
  3         1694  
28              
29             sub new {
30              
31 16     16 1 684 my ( $class, %params ) = @_;
32              
33             my $self = {
34             password => $params{password} || croak('Specify password'),
35             hmac => $params{hmac} || croak('Specify HMAC digest algorithm'),
36             encryption => $params{encryption} || croak('Specify encryption method'),
37 16   33     94 count => $params{count} || 1_000,
      33        
      33        
      50        
38             dk_len => 0,
39             };
40              
41 16         28 my $dk_len = KEY_SIZE->{ $params{encryption} };
42              
43 16 50       28 if ( !$dk_len ) {
44 0         0 croak('Unknown encryption method');
45             }
46              
47 16         21 $self->{dk_len} = $dk_len;
48              
49 16         38 return bless $self, $class;
50              
51             }
52              
53             sub encrypt {
54              
55 16     16 1 10545 my ( $self, $data ) = @_;
56              
57 16         62 my $salt = Crypt::CBC->random_bytes(16);
58 16         11853 my $iv = Crypt::CBC->random_bytes(16);
59              
60             my $key = pbkdf2(
61             prf => $self->{hmac},
62             password => $self->{password},
63             salt => $salt,
64             dk_len => $self->{dk_len},
65             count => $self->{count}
66 16         11337 );
67              
68             my $cipher = Crypt::CBC->new(
69             -key => $key,
70             -keysize => length($key),
71             -iv => $iv,
72             -header => 'none',
73             -literal_key => 1,
74             -cipher => ENCRYPTION->{ $self->{encryption} }
75 16         165 );
76              
77 16         6075 my $encrypted = $cipher->encrypt($data);
78              
79 16         1802 my @result = ( $salt, $iv, $encrypted );
80              
81 16 100       173 return wantarray ? @result : join( '', @result );
82              
83             }
84              
85             sub decrypt {
86              
87 16     16 1 43 my ( $self, $salt, $iv, $encrypted ) = @_;
88              
89 16 50 66     54 if ( !$iv && !$encrypted ) {
90              
91 1         2 my $data = $salt;
92              
93 1         4 $salt = substr( $data, 0, 16 );
94 1         2 $iv = substr( $data, 16, 16 );
95 1         2 $encrypted = substr( $data, 32 );
96              
97             }
98              
99             my $key = pbkdf2(
100             prf => $self->{hmac},
101             password => $self->{password},
102             salt => $salt,
103             dk_len => $self->{dk_len},
104             count => $self->{count}
105 16         58 );
106              
107             my $cipher = Crypt::CBC->new(
108             -key => $key,
109             -keysize => length($key),
110             -iv => $iv,
111             -header => 'none',
112             -literal_key => 1,
113             -cipher => ENCRYPTION->{ $self->{encryption} }
114 16         151 );
115              
116 16         2270 return $cipher->decrypt($encrypted);
117              
118             }
119              
120             1;
121              
122             =head1 NAME
123              
124             Crypt::PBE::PBES2 - Perl extension for PKCS #5 Password-Based Encryption Schema 2 (PBES2)
125              
126             =head1 SYNOPSIS
127              
128             use Crypt::PBE::PBES2;
129              
130             my $pbes2 = Crypt::PBE::PBES2->new(
131             'hmac' => 'hmac-sha256',
132             'encryption' => 'aes-128',
133             'password' => 'mypassword'
134             );
135              
136             my $encrypted = $pbes2->encrypt('secret');
137             say $pbes2->decrypt($encrypted); # secret
138              
139              
140             =head1 DESCRIPTION
141              
142             PBES2 combines a password-based key derivation function, which shall be PBKDF2
143             with an underlying encryption scheme. The key length and any other parameters
144             for the underlying encryption scheme depend on the scheme.
145              
146             PBES2 is recommended for new applications.
147              
148              
149             =head1 CONSTRUCTOR
150              
151             =head2 Crypt::PBE::PBES2->new ( %params )
152              
153             Params:
154              
155             =over 4
156              
157             =item * C : The password to use for the derivation
158              
159             =item * C : HMAC digest algorithm ("hmac-sha1", "hmac-sha224", "hmac-sha256", "hmac-sha384" or "hmac-512")
160              
161             =item * C : Encryption method ("aes-128", "aes-192" or "aes-256")
162              
163             =item * C : The number of internal iteractions to perform for the derivation key (default "1_000")
164              
165             =back
166              
167              
168             =head1 METHODS
169              
170             =head2 $pbes2->encrypt( $message )
171              
172             Perform the encryption and return the encrypted message in binary format.
173              
174             You can encode the encrypted message in Base64 using L:
175              
176             $b64_encrypted = encode_base64 $pbes2->encrypt('secret');
177              
178              
179             =head2 $pbes2->decrypt( $data )
180              
181             Perform the decryption and return the original message.
182              
183             $decrypted = $pbes2->decrypt($encrypted);
184              
185             You can decode the Base64 encrypted message using L:
186              
187             $decrypted = $pbes2->decrypt(decode_base64 $b64_encrypted);
188              
189              
190             =head1 SUPPORT
191              
192             =head2 Bugs / Feature Requests
193              
194             Please report any bugs or feature requests through the issue tracker
195             at L.
196             You will be notified automatically of any progress on your issue.
197              
198             =head2 Source Code
199              
200             This is open source software. The code repository is available for
201             public review and contribution under the terms of the license.
202              
203             L
204              
205             git clone https://github.com/giterlizzi/perl-Crypt-PBE.git
206              
207              
208             =head1 AUTHOR
209              
210             =over 4
211              
212             =item * Giuseppe Di Terlizzi
213              
214             =back
215              
216              
217             =head1 SEE ALSO
218              
219             =over 4
220              
221             =item L
222              
223             =item L
224              
225             =item [RFC2898] PKCS #5: Password-Based Cryptography Specification Version 2.0 (L)
226              
227             =item [RFC8018] PKCS #5: Password-Based Cryptography Specification Version 2.1 (L)
228              
229             =back
230              
231              
232             =head1 LICENSE AND COPYRIGHT
233              
234             This software is copyright (c) 2020 by Giuseppe Di Terlizzi.
235              
236             This is free software; you can redistribute it and/or modify it under
237             the same terms as the Perl 5 programming language system itself.
238              
239             =cut