File Coverage

blib/lib/Crypt/KeyDerivation.pm
Criterion Covered Total %
statement 12 12 100.0
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 16 16 100.0


line stmt bran cond sub pod time code
1             package Crypt::KeyDerivation;
2              
3 2     2   78496 use strict;
  2         3  
  2         54  
4 2     2   9 use warnings;
  2         3  
  2         220  
5             our $VERSION = '0.088_004';
6              
7             require Exporter; our @ISA = qw(Exporter); ### use Exporter 5.57 'import';
8             our %EXPORT_TAGS = ( all => [qw(pbkdf1 pbkdf1_openssl pbkdf2 hkdf hkdf_expand hkdf_extract bcrypt_pbkdf scrypt_pbkdf argon2_pbkdf)] );
9             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
10             our @EXPORT = qw();
11              
12 2     2   8 use Carp;
  2         2  
  2         141  
13             $Carp::Internal{(__PACKAGE__)}++;
14 2     2   417 use CryptX;
  2         5  
  2         193  
15              
16             1;
17              
18             =pod
19              
20             =head1 NAME
21              
22             Crypt::KeyDerivation - PBKDF1, PBKDF2, HKDF, Bcrypt, Scrypt, Argon2 key derivation functions
23              
24             =head1 SYNOPSIS
25              
26             use Crypt::KeyDerivation ':all';
27              
28             my $password = 'secret';
29             my $salt = '12345678';
30             my $iteration_count = 5000;
31             my $hash_name = 'SHA256';
32             my $len = 32;
33             my $keying_material = 'input keying material';
34             my $info = 'context';
35             my $rounds = 16;
36             my $N = 1024;
37             my $r = 8;
38             my $p = 1;
39             my $type = 'argon2id';
40             my $t_cost = 3;
41             my $m_factor = 65536;
42             my $parallelism = 1;
43             my $secret = '';
44             my $ad = '';
45              
46             ### PBKDF1/2
47             my $pbkdf1_key = pbkdf1($password, $salt, $iteration_count, $hash_name, $len);
48             my $openssl_pbkdf1_key = pbkdf1_openssl($password, $salt, $iteration_count, $hash_name, $len);
49             my $pbkdf2_key = pbkdf2($password, $salt, $iteration_count, $hash_name, $len);
50              
51             ### HKDF & co.
52             my $hkdf_okm = hkdf($keying_material, $salt, $hash_name, $len, $info);
53             my $prk = hkdf_extract($keying_material, $salt, $hash_name);
54             my $expanded_okm = hkdf_expand($prk, $hash_name, $len, $info);
55              
56             ### bcrypt / scrypt / argon2
57             my $bcrypt_key = bcrypt_pbkdf($password, $salt, $rounds, $hash_name, $len);
58             my $scrypt_key = scrypt_pbkdf($password, $salt, $N, $r, $p, $len);
59             my $argon2_key = argon2_pbkdf($type, $password, $salt, $t_cost, $m_factor, $parallelism, $len, $secret, $ad);
60              
61             =head1 DESCRIPTION
62              
63             Provides an interface to key derivation functions:
64              
65             =over
66              
67             =item * PBKDF1 and PBKDF2 according to PKCS #5 v2.0
68             L
69              
70             =item * HKDF (+ related) according to
71             L
72              
73             =item * Bcrypt-PBKDF as defined by the OpenBSD project
74              
75             =item * Scrypt according to L
76              
77             =item * Argon2 according to L
78              
79             =back
80              
81             While primarily designed for key derivation, the functions PBKDF2, Bcrypt, Scrypt and Argon2
82             are also widely used for password hashing. In that use case the derived key serves as the
83             stored password hash.
84              
85             All functions return raw bytes. Passing an output length of C<0> returns an
86             empty string in this wrapper API. Argument validation still happens first:
87             required password / input-keying-material arguments reject C, invalid
88             hash names and invalid Argon2 type names are still rejected, and malformed
89             optional scalar arguments still return C where applicable.
90              
91             This zero-length behavior is a C wrapper policy. The
92             underlying libtomcrypt functions do not all behave the same way: some accept
93             zero-length outputs, while others reject them with algorithm-specific checks.
94             Code calling libtomcrypt directly should not assume the wrapper behavior.
95              
96             =head1 FUNCTIONS
97              
98             =head2 pbkdf1
99              
100             B if you are not sure, do not use C but rather choose C.
101              
102             my $derived_key = pbkdf1($password, $salt, $iteration_count, $hash_name, $len);
103             #or
104             my $derived_key = pbkdf1($password, $salt, $iteration_count, $hash_name);
105             #or
106             my $derived_key = pbkdf1($password, $salt, $iteration_count);
107             #or
108             my $derived_key = pbkdf1($password, $salt);
109              
110             # $password ......... [binary string] input keying material (password)
111             # $salt ............. [binary string] salt/nonce (expected length: 8 bytes)
112             # $iteration_count .. [integer] optional, DEFAULT: 5000
113             # $hash_name ........ [string] optional, DEFAULT: 'SHA256'
114             # $len .............. [integer] optional, derived key len in bytes, DEFAULT: 32
115              
116             In strict PKCS #5 v1 mode, the derived key length must not exceed the selected
117             hash output size. For example, C allows at most 20 bytes.
118              
119             The underlying algorithm uses only the first 8 bytes of C<$salt>. Shorter salts
120             are rejected; longer salts are accepted but truncated to 8 bytes.
121              
122             =head2 pbkdf1_openssl
123              
124             I
125              
126             OpenSSL-compatible variant of PBKDF1 (implements C). Unlike strict
127             C, the output length is not limited to the hash size -- it can be arbitrarily
128             long by chaining hash blocks.
129              
130             B this function implements the OpenSSL-compatible algorithm, but its
131             default parameters do B match the historical C defaults.
132             OpenSSL traditionally uses C and C, while this wrapper
133             defaults to C and C<5000>. If you need output compatible with the
134             traditional OpenSSL default behavior, pass both values explicitly:
135              
136             my $derived_key = pbkdf1_openssl($password, $salt, 1, 'MD5', $len);
137              
138             my $derived_key = pbkdf1_openssl($password, $salt, $iteration_count, $hash_name, $len);
139             #or
140             my $derived_key = pbkdf1_openssl($password, $salt, $iteration_count, $hash_name);
141             #or
142             my $derived_key = pbkdf1_openssl($password, $salt, $iteration_count);
143             #or
144             my $derived_key = pbkdf1_openssl($password, $salt);
145              
146             # $password ......... [binary string] input keying material (password)
147             # $salt ............. [binary string] salt/nonce (expected length: 8 bytes)
148             # $iteration_count .. [integer] optional, DEFAULT: 5000
149             # $hash_name ........ [string] optional, DEFAULT: 'SHA256'
150             # $len .............. [integer] optional, derived key len in bytes, DEFAULT: 32
151              
152             The underlying algorithm uses only the first 8 bytes of C<$salt>. Shorter salts
153             are rejected; longer salts are accepted but truncated to 8 bytes.
154              
155             =head2 pbkdf2
156              
157             my $derived_key = pbkdf2($password, $salt, $iteration_count, $hash_name, $len);
158             #or
159             my $derived_key = pbkdf2($password, $salt, $iteration_count, $hash_name);
160             #or
161             my $derived_key = pbkdf2($password, $salt, $iteration_count);
162             #or
163             my $derived_key = pbkdf2($password, $salt);
164              
165             # $password ......... [binary string] input keying material (password)
166             # $salt ............. [binary string] salt/nonce (any length; longer is better)
167             # $iteration_count .. [integer] optional, DEFAULT: 5000
168             # $hash_name ........ [string] optional, DEFAULT: 'SHA256'
169             # $len .............. [integer] optional, derived key len in bytes, DEFAULT: 32
170              
171             =head2 hkdf
172              
173             my $okm = hkdf($password, $salt, $hash_name, $len, $info);
174             #or
175             my $okm = hkdf($password, $salt, $hash_name, $len);
176             #or
177             my $okm = hkdf($password, $salt, $hash_name);
178             #or
179             my $okm = hkdf($password, $salt);
180              
181             # $password ... [binary string] input keying material
182             # $salt ....... [binary string | undef] salt; if undef defaults to HashLen zero octets
183             # $hash_name .. [string] optional, DEFAULT: 'SHA256'
184             # $len ........ [integer] optional, derived key len in bytes, DEFAULT: 32
185             # $info ....... [binary string] optional context/application info, DEFAULT: ''
186              
187             Use C for one-shot extract+expand. For multi-step workflows, use
188             C followed by C.
189              
190             The input keying material / pseudokey arguments must be string or
191             stringifiable scalars. Optional C<$salt> and C<$info> may be C.
192              
193             =head2 hkdf_extract
194              
195             my $prk = hkdf_extract($password, $salt, $hash_name);
196             #or
197             my $prk = hkdf_extract($password, $salt);
198              
199             # $password ... [binary string] input keying material
200             # $salt ....... [binary string | undef] salt; if undef defaults to HashLen zero octets
201             # $hash_name .. [string] optional, DEFAULT: 'SHA256'
202              
203             Returns the pseudorandom key (PRK). Its length is the digest size of the
204             selected hash and it is intended to be passed to C.
205              
206              
207             =head2 hkdf_expand
208              
209             my $okm = hkdf_expand($pseudokey, $hash_name, $len, $info);
210             #or
211             my $okm = hkdf_expand($pseudokey, $hash_name, $len);
212             #or
213             my $okm = hkdf_expand($pseudokey, $hash_name);
214             #or
215             my $okm = hkdf_expand($pseudokey);
216              
217             # $pseudokey .. [binary string] input keying material (normally from hkdf_extract)
218             # $hash_name .. [string] optional, DEFAULT: 'SHA256'
219             # $len ........ [integer] optional, derived key len in bytes, DEFAULT: 32
220             # $info ....... [binary string] optional context/application info, DEFAULT: ''
221              
222             C<$pseudokey> is normally the PRK returned by C.
223              
224             =head2 bcrypt_pbkdf
225              
226             bcrypt-based key derivation as defined by the OpenBSD project.
227              
228             I
229              
230              
231             my $derived_key = bcrypt_pbkdf($password, $salt, $rounds, $hash_name, $len);
232             #or
233             my $derived_key = bcrypt_pbkdf($password, $salt, $rounds, $hash_name);
234             #or
235             my $derived_key = bcrypt_pbkdf($password, $salt, $rounds);
236             #or
237             my $derived_key = bcrypt_pbkdf($password, $salt);
238              
239             # $password ... [binary string] input keying material (password)
240             # $salt ....... [binary string] salt/nonce
241             # $rounds ..... [integer] optional, number of rounds, DEFAULT: 16
242             # $hash_name .. [string] optional, DEFAULT: 'SHA512'
243             # $len ........ [integer] optional, derived key len in bytes, DEFAULT: 32
244              
245             Larger C<$rounds> values increase CPU cost linearly.
246              
247             =head2 scrypt_pbkdf
248              
249             scrypt key derivation according to L.
250              
251             I
252              
253              
254             my $derived_key = scrypt_pbkdf($password, $salt, $N, $r, $p, $len);
255             #or
256             my $derived_key = scrypt_pbkdf($password, $salt, $N, $r, $p);
257             #or
258             my $derived_key = scrypt_pbkdf($password, $salt, $N);
259             #or
260             my $derived_key = scrypt_pbkdf($password, $salt);
261              
262             # $password ... [binary string] input keying material (password)
263             # $salt ....... [binary string] salt/nonce
264             # $N .......... [integer] optional, CPU/memory cost (must be power of 2), DEFAULT: 1024
265             # $r .......... [integer] optional, block size, DEFAULT: 8
266             # $p .......... [integer] optional, parallelization parameter, DEFAULT: 1
267             # $len ........ [integer] optional, derived key len in bytes, DEFAULT: 32
268              
269             Use only power-of-two values for C<$N>. Larger C<$N>, C<$r>, and C<$p>
270             increase resource usage substantially; invalid combinations croak.
271              
272             =head2 argon2_pbkdf
273              
274             Argon2 key derivation according to L.
275              
276             I
277              
278              
279             my $derived_key = argon2_pbkdf($type, $password, $salt, $t_cost, $m_factor, $parallelism, $len, $secret, $ad);
280             #or
281             my $derived_key = argon2_pbkdf($type, $password, $salt, $t_cost, $m_factor, $parallelism, $len);
282             #or
283             my $derived_key = argon2_pbkdf($type, $password, $salt, $t_cost, $m_factor, $parallelism);
284             #or
285             my $derived_key = argon2_pbkdf($type, $password, $salt);
286              
287             # $type ... [string] one of 'argon2d', 'argon2i', 'argon2id'
288             # $password ... [binary string] input keying material (password)
289             # $salt ... [binary string] salt/nonce (recommended: at least 16 bytes)
290             # $t_cost ... [integer] optional, time cost (number of iterations), DEFAULT: 3
291             # $m_factor ... [integer] optional, memory cost in kibibytes (1 KiB = 1024 B), DEFAULT: 65536 (= 64 MiB)
292             # $parallelism ... [integer] optional, degree of parallelism, DEFAULT: 1
293             # $len ... [integer] optional, derived key len in bytes, DEFAULT: 32
294             # $secret ... [binary string] optional, secret value, DEFAULT: ''
295             # $ad ... [binary string] optional, associated data, DEFAULT: ''
296              
297             Increasing C<$t_cost>, C<$m_factor>, or C<$parallelism> increases work and
298             memory requirements. Invalid combinations croak. Optional C<$secret> and
299             C<$ad> may be C; otherwise they must be string or stringifiable scalars.
300              
301             =cut