File Coverage

blib/lib/Authen/Passphrase/BlowfishCrypt.pm
Criterion Covered Total %
statement 81 83 97.5
branch 40 60 66.6
condition 7 15 46.6
subroutine 19 19 100.0
pod 10 10 100.0
total 157 187 83.9


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Authen::Passphrase::BlowfishCrypt - passphrases using the Blowfish-based
4             Unix crypt()
5              
6             =head1 SYNOPSIS
7              
8             use Authen::Passphrase::BlowfishCrypt;
9              
10             $ppr = Authen::Passphrase::BlowfishCrypt->new(
11             cost => 14,
12             salt => "sodium__chloride",
13             hash_base64 => "BPZijhMHLvPeNMHd6XwZyNamOXVBTPi");
14              
15             $ppr = Authen::Passphrase::BlowfishCrypt->new(
16             cost => 14, salt_random => 1,
17             passphrase => "passphrase");
18              
19             $ppr = Authen::Passphrase::BlowfishCrypt->from_crypt(
20             '$2a$08$a07iYVTrVz7hYEvtakjiXOB'.
21             'PZijhMHLvPeNMHd6XwZyNamOXVBTPi');
22              
23             $ppr = Authen::Passphrase::BlowfishCrypt->from_rfc2307(
24             '{CRYPT}$2a$08$a07iYVTrVz7hYEvtakjiXOB'.
25             'PZijhMHLvPeNMHd6XwZyNamOXVBTPi');
26              
27             $key_nul = $ppr->key_nul;
28             $cost = $ppr->cost;
29             $cost = $ppr->keying_nrounds_log2;
30             $salt = $ppr->salt;
31             $salt_base64 = $ppr->salt_base64;
32             $hash = $ppr->hash;
33             $hash_base64 = $ppr->hash_base64;
34              
35             if($ppr->match($passphrase)) { ...
36              
37             $passwd = $ppr->as_crypt;
38             $userPassword = $ppr->as_rfc2307;
39              
40             =head1 DESCRIPTION
41              
42             An object of this class encapsulates a passphrase hashed using the
43             Blowfish-based Unix crypt() hash function, known as "bcrypt". This is
44             a subclass of L, and this document assumes that the
45             reader is familiar with the documentation for that class.
46              
47             The crypt() function in a modern Unix actually supports several different
48             passphrase schemes. This class is concerned only with one particular
49             scheme, a Blowfish-based algorithm designed by Niels Provos and David
50             Mazieres for OpenBSD. To handle the whole range of passphrase schemes
51             supported by the modern crypt(), see the
52             L constructor and the
53             L method in L.
54              
55             The Blowfish-based crypt() scheme uses a variant of Blowfish called
56             "Eksblowfish", for "expensive key schedule Blowfish". It has the
57             cryptographic strength of Blowfish, and a very slow key setup phase
58             to resist brute-force attacks. There is a "cost" parameter to the
59             scheme: the length of key setup is proportional to 2^cost. There is
60             a 128-bit salt. Up to 72 characters of the passphrase will be used;
61             any more will be ignored.
62              
63             The cost, salt, and passphrase are all used to (very
64             slowly) key Eksblowfish. Once key setup is done, the string
65             "OrpheanBeholderScryDoubt" (three Blowfish blocks long) is encrypted 64
66             times in ECB mode. The final byte of the ciphertext is then dropped,
67             yielding a 23-byte hash.
68              
69             In the crypt() function the salt and hash are represented in ASCII
70             using a base 64 encoding. The base 64 digits are "B<.>", "B",
71             "B" to "B", "B" to "B", "B<0>" to "B<9>" (in that order).
72             The 16-byte salt is represented as 22 base 64 digits, and the 23-byte
73             hash as 31 base 64 digits.
74              
75             This algorithm is intended for situations where the efficiency of
76             a brute force attack is a concern. It is suitable for use in new
77             applications where this requirement exists. If that is not a concern,
78             and it suffices to merely make brute force the most efficient attack, see
79             L for more efficient hash algorithms.
80              
81             Choice of the cost parameter is critical, due to the need to trade off
82             expense of brute-force attack against speed of legitimate passphrase
83             verification. A traditional target is that verification should take
84             about one second on widely-available hardware. (Algorithms that are
85             concerned about brute force speed but lack a cost parameter have often
86             aimed for this, with respect to hardware available at the time of the
87             algorithm's introduction.) As of 2011, this is achieved with a cost
88             parameter around 14.
89              
90             =cut
91              
92             package Authen::Passphrase::BlowfishCrypt;
93              
94 2     2   87022 { use 5.006; }
  2         10  
95 2     2   10 use warnings;
  2         4  
  2         116  
96 2     2   9 use strict;
  2         5  
  2         85  
97              
98 2     2   379 use Authen::Passphrase 0.003;
  2         35  
  2         62  
99 2     2   10 use Carp qw(croak);
  2         4  
  2         186  
100 2     2   1014 use Crypt::Eksblowfish::Bcrypt 0.008 qw(bcrypt_hash en_base64 de_base64);
  2         6790  
  2         160  
101 2     2   325 use Crypt::SysRandom 'random_bytes';
  2         2737  
  2         132  
102              
103             our $VERSION = "0.009";
104              
105 2     2   12 use parent "Authen::Passphrase";
  2         4  
  2         8  
106              
107             =head1 CONSTRUCTORS
108              
109             =over
110              
111             =item Authen::Passphrase::BlowfishCrypt->new(ATTR => VALUE, ...)
112              
113             Generates a new passphrase recogniser object using the Blowfish-based
114             crypt() algorithm. The following attributes may be given:
115              
116             =over
117              
118             =item B
119              
120             Truth value indicating whether to append a NUL to the passphrase before using
121             it as a key. The algorithm as originally devised does not do this,
122             but it was later modified to do it. The version that does append NUL
123             is to be preferred. Default true.
124              
125             =item B
126              
127             Base-two logarithm of the number of keying rounds to perform.
128              
129             =item B
130              
131             Synonym for B.
132              
133             =item B
134              
135             The salt, as a 16-byte string.
136              
137             =item B
138              
139             The salt, as a string of 22 base 64 digits.
140              
141             =item B
142              
143             Causes salt to be generated randomly. The value given for this attribute
144             is ignored.
145              
146             =item B
147              
148             The hash, as a 23-byte string.
149              
150             =item B
151              
152             The hash, as a string of 31 base 64 digits.
153              
154             =item B
155              
156             A passphrase that will be accepted.
157              
158             =back
159              
160             The cost and salt must be given, and either the hash or the passphrase.
161              
162             =cut
163              
164             sub new {
165 11     11 1 180929 my $class = shift;
166 11         25 my $self = bless({}, $class);
167 11         15 my $passphrase;
168 11         28 while(@_) {
169 40         180 my $attr = shift;
170 40         49 my $value = shift;
171 40 100 100     167 if($attr eq "key_nul") {
    100          
    100          
    100          
    100          
    100          
    100          
    50          
172             croak "foldness specified redundantly"
173 7 50       15 if exists $self->{fold};
174 7         16 $self->{key_nul} = !!$value;
175             } elsif($attr eq "cost" || $attr eq "keying_nrounds_log2") {
176             croak "cost specified redundantly"
177 11 50       25 if exists $self->{cost};
178 11 50 33     48 croak "\"$value\" is not a valid cost parameter"
179             unless $value == int($value) && $value >= 0;
180 11         27 $self->{cost} = 0+$value;
181             } elsif($attr eq "salt") {
182             croak "salt specified redundantly"
183 1 50       4 if exists $self->{salt};
184 1 50       5 $value =~ m#\A[\x00-\xff]{16}\z#
185             or croak "\"$value\" is not a valid raw salt";
186 1         3 $self->{salt} = "$value";
187             } elsif($attr eq "salt_base64") {
188             croak "salt specified redundantly"
189 9 50       22 if exists $self->{salt};
190 9 50       16 croak "\"$value\" is not a valid salt"
191             unless length($value) == 22;
192 9         26 $self->{salt} = de_base64($value);
193             } elsif($attr eq "salt_random") {
194             croak "salt specified redundantly"
195 1 50       4 if exists $self->{salt};
196 1         11 $self->{salt} = random_bytes(16);
197             } elsif($attr eq "hash") {
198             croak "hash specified redundantly"
199 1 50 33     5 if exists($self->{hash}) ||
200             defined($passphrase);
201 1 50       3 $value =~ m#\A[\x00-\xff]{23}\z#
202             or croak "not a valid raw hash";
203 1         4 $self->{hash} = "$value";
204             } elsif($attr eq "hash_base64") {
205             croak "hash specified redundantly"
206 8 50 33     23 if exists($self->{hash}) ||
207             defined($passphrase);
208 8 50       16 croak "\"$value\" is not a valid hash"
209             unless length($value) == 31;
210 8         15 $self->{hash} = de_base64($value);
211             } elsif($attr eq "passphrase") {
212             croak "passphrase specified redundantly"
213 2 50 33     9 if exists($self->{hash}) ||
214             defined($passphrase);
215 2         5 $passphrase = $value;
216             } else {
217 0         0 croak "unrecognised attribute `$attr'";
218             }
219             }
220 11 100       87 $self->{key_nul} = !!1 unless exists $self->{key_nul};
221 11 50       21 croak "cost not specified" unless exists $self->{cost};
222 11 50       18 croak "salt not specified" unless exists $self->{salt};
223 11 100       21 $self->{hash} = $self->_hash_of($passphrase) if defined $passphrase;
224 11 50       51710 croak "hash not specified" unless exists $self->{hash};
225 11         38 return $self;
226             }
227              
228             =item Authen::Passphrase::BlowfishCrypt->from_crypt(PASSWD)
229              
230             Generates a new passphrase recogniser object using the Blowfish-based
231             crypt() algorithm, from a crypt string. The crypt string must start with
232             "B<$2$>" for the version that does not append NUL to the key, or "B<$2a$>"
233             for the version that does. The next two characters must be decimal digits
234             giving the cost parameter. This must be followed by "B<$>", 22 base 64
235             digits giving the salt, and finally 31 base 64 digits giving the hash.
236              
237             =cut
238              
239             sub from_crypt {
240 2     2 1 26168 my($class, $passwd) = @_;
241 2 50       14 if($passwd =~ /\A(\$2a?\$)/) {
242 2 50       9 $passwd =~ m#\A\$2(a?)\$([0-9]{2})\$
243             ([./A-Za-z0-9]{22})([./A-Za-z0-9]{31})\z#x
244             or croak "malformed $1 data";
245 2         20 my($kn, $cost, $salt, $hash) = ($1, $2, $3, $4);
246 2         36 return $class->new(key_nul => $kn, cost => $cost,
247             salt_base64 => $salt, hash_base64 => $hash);
248             }
249 0         0 return $class->SUPER::from_crypt($passwd);
250             }
251              
252             =item Authen::Passphrase::BlowfishCrypt->from_rfc2307(USERPASSWORD)
253              
254             Generates a new passphrase recogniser object using the Blowfish-based
255             crypt() algorithm, from an RFC 2307 string. The string must consist of
256             "B<{CRYPT}>" (case insensitive) followed by an acceptable crypt string.
257              
258             =back
259              
260             =head1 METHODS
261              
262             =over
263              
264             =item $ppr->key_nul
265              
266             Returns a truth value indicating whether a NUL will be appended to the
267             passphrase before using it as a key.
268              
269             =cut
270              
271             sub key_nul {
272 21     21 1 2682 my($self) = @_;
273 21         61 return $self->{key_nul};
274             }
275              
276             =item $ppr->cost
277              
278             Returns the base-two logarithm of the number of keying rounds that will
279             be performed.
280              
281             =cut
282              
283             sub cost {
284 23     23 1 41 my($self) = @_;
285 23         75 return $self->{cost};
286             }
287              
288             =item $ppr->keying_nrounds_log2
289              
290             Synonym for L.
291              
292             =cut
293              
294             *keying_nrounds_log2 = \&cost;
295              
296             =item $ppr->salt
297              
298             Returns the salt, as a string of sixteen bytes.
299              
300             =cut
301              
302             sub salt {
303 3     3 1 6 my($self) = @_;
304 3         10 return $self->{salt};
305             }
306              
307             =item $ppr->salt_base64
308              
309             Returns the salt, as a string of 22 base 64 digits.
310              
311             =cut
312              
313             sub salt_base64 {
314 20     20 1 33 my($self) = @_;
315 20         57 return en_base64($self->{salt});
316             }
317              
318             =item $ppr->hash
319              
320             Returns the hash value, as a string of 23 bytes.
321              
322             =cut
323              
324             sub hash {
325 3     3 1 1022 my($self) = @_;
326 3         17 return $self->{hash};
327             }
328              
329             =item $ppr->hash_base64
330              
331             Returns the hash value, as a string of 31 base 64 digits.
332              
333             =cut
334              
335             sub hash_base64 {
336 20     20 1 4256 my($self) = @_;
337 20         45 return en_base64($self->{hash});
338             }
339              
340             =item $ppr->match(PASSPHRASE)
341              
342             =item $ppr->as_crypt
343              
344             =item $ppr->as_rfc2307
345              
346             These methods are part of the standard L interface.
347              
348             =cut
349              
350             sub _hash_of {
351 28     28   51 my($self, $passphrase) = @_;
352             return bcrypt_hash({
353             key_nul => $self->{key_nul},
354             cost => $self->{cost},
355             salt => $self->{salt},
356 28         167 }, $passphrase);
357             }
358              
359             sub match {
360 26     26 1 465621 my($self, $passphrase) = @_;
361 26         77 return $self->_hash_of($passphrase) eq $self->{hash};
362             }
363              
364             sub as_crypt {
365 10     10 1 5080 my($self) = @_;
366             croak "passphrase can't be expressed as a crypt string"
367 10 50       26 if $self->{cost} > 99;
368 10 100       19 return sprintf("\$2%s\$%02d\$%s%s", $self->key_nul ? "a" : "",
369             $self->cost, $self->salt_base64, $self->hash_base64);
370             }
371              
372             =back
373              
374             =head1 SEE ALSO
375              
376             L,
377             L
378              
379             =head1 AUTHOR
380              
381             Andrew Main (Zefram)
382              
383             =head1 COPYRIGHT
384              
385             Copyright (C) 2006, 2007, 2009, 2010, 2012
386             Andrew Main (Zefram)
387              
388             =head1 LICENSE
389              
390             This module is free software; you can redistribute it and/or modify it
391             under the same terms as Perl itself.
392              
393             =cut
394              
395             1;