File Coverage

blib/lib/Crypt/PBE/PBES2.pm
Criterion Covered Total %
statement 53 54 98.1
branch 4 6 66.6
condition 6 14 42.8
subroutine 13 13 100.0
pod 3 3 100.0
total 79 90 87.7


line stmt bran cond sub pod time code
1             package Crypt::PBE::PBES2;
2              
3 4     4   776 use strict;
  4         10  
  4         125  
4 4     4   23 use warnings;
  4         8  
  4         125  
5 4     4   610 use utf8;
  4         21  
  4         22  
6              
7 4     4   97 use Carp;
  4         8  
  4         231  
8 4     4   634 use Crypt::CBC;
  4         8078  
  4         135  
9 4     4   25 use Exporter qw(import);
  4         7  
  4         125  
10              
11 4     4   1913 use Crypt::PBE::PBKDF2;
  4         13  
  4         471  
12              
13             our $VERSION = '0.102';
14              
15 4         433 use constant KEY_SIZE => {
16             'aes-128' => 16,
17             'aes-192' => 24,
18             'aes-256' => 32,
19 4     4   59 };
  4         8  
20              
21 4         266 use constant ENCRYPTION => {
22             'aes-128' => 'Crypt::OpenSSL::AES',
23             'aes-192' => 'Crypt::OpenSSL::AES',
24             'aes-256' => 'Crypt::OpenSSL::AES',
25 4     4   37 };
  4         9  
26              
27 4     4   26 use constant HMAC => qw( hmac-sha1 hmac-224 hmac-sha256 hmac-sha384 hmac-sha512 );
  4         20  
  4         2584  
28              
29             sub new {
30              
31 24     24 1 747 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 24   33     175 count => $params{count} || 1_000,
      33        
      33        
      50        
38             dk_len => 0,
39             };
40              
41 24         59 my $dk_len = KEY_SIZE->{ $params{encryption} };
42              
43 24 50       51 if ( !$dk_len ) {
44 0         0 croak('Unknown encryption method');
45             }
46              
47 24         41 $self->{dk_len} = $dk_len;
48              
49 24         71 return bless $self, $class;
50              
51             }
52              
53             sub encrypt {
54              
55 20     20 1 28525 my ( $self, $data ) = @_;
56              
57 20         137 my $salt = Crypt::CBC->random_bytes(16);
58 20         15027 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 20         14841 );
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 20         344 );
76              
77 20         13456 my $encrypted = $cipher->encrypt($data);
78              
79 20         20142 my @result = ( $salt, $iv, $encrypted );
80              
81 20 100       403 return wantarray ? @result : join( '', @result );
82              
83             }
84              
85             sub decrypt {
86              
87 20     20 1 79 my ( $self, $salt, $iv, $encrypted ) = @_;
88              
89 20 50 66     84 if ( !$iv && !$encrypted ) {
90              
91 5         13 my $data = $salt;
92              
93 5         17 $salt = substr( $data, 0, 16 );
94 5         16 $iv = substr( $data, 16, 16 );
95 5         11 $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 20         129 );
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 20         407 );
115              
116 20         6585 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-2021 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