File Coverage

blib/lib/Authen/Passphrase/BlowfishCrypt.pm
Criterion Covered Total %
statement 82 84 97.6
branch 40 60 66.6
condition 7 15 46.6
subroutine 19 19 100.0
pod 10 10 100.0
total 158 188 84.0


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 => 8,
12             salt => "sodium__chloride",
13             hash_base64 => "BPZijhMHLvPeNMHd6XwZyNamOXVBTPi");
14              
15             $ppr = Authen::Passphrase::BlowfishCrypt->new(
16             cost => 8, 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 1     1   23959 { use 5.006; }
  1         4  
  1         57  
95 1     1   6 use warnings;
  1         1  
  1         37  
96 1     1   6 use strict;
  1         2  
  1         44  
97              
98 1     1   618 use Authen::Passphrase 0.003;
  1         23  
  1         34  
99 1     1   10 use Carp qw(croak);
  1         2  
  1         75  
100 1     1   131854 use Crypt::Eksblowfish::Bcrypt 0.008 qw(bcrypt_hash en_base64 de_base64);
  1         344907  
  1         289  
101 1     1   2279 use Data::Entropy::Algorithms 0.000 qw(rand_bits);
  1         25276  
  1         135  
102              
103             our $VERSION = "0.008";
104              
105 1     1   10 use parent "Authen::Passphrase";
  1         1  
  1         6  
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. The source of randomness may be controlled by the facility
145             described in L.
146              
147             =item B
148              
149             The hash, as a 23-byte string.
150              
151             =item B
152              
153             The hash, as a string of 31 base 64 digits.
154              
155             =item B
156              
157             A passphrase that will be accepted.
158              
159             =back
160              
161             The cost and salt must be given, and either the hash or the passphrase.
162              
163             =cut
164              
165             sub new {
166 11     11 1 4695 my $class = shift;
167 11         52 my $self = bless({}, $class);
168 11         23 my $passphrase;
169 11         51 while(@_) {
170 40         9038 my $attr = shift;
171 40         59 my $value = shift;
172 40 100 100     281 if($attr eq "key_nul") {
    100          
    100          
    100          
    100          
    100          
    100          
    50          
173 7 50       25 croak "foldness specified redundantly"
174             if exists $self->{fold};
175 7         30 $self->{key_nul} = !!$value;
176             } elsif($attr eq "cost" || $attr eq "keying_nrounds_log2") {
177 11 50       80 croak "cost specified redundantly"
178             if exists $self->{cost};
179 11 50 33     85 croak "\"$value\" is not a valid cost parameter"
180             unless $value == int($value) && $value >= 0;
181 11         42 $self->{cost} = 0+$value;
182             } elsif($attr eq "salt") {
183 1 50       3 croak "salt specified redundantly"
184             if exists $self->{salt};
185 1 50       10 $value =~ m#\A[\x00-\xff]{16}\z#
186             or croak "\"$value\" is not a valid raw salt";
187 1         4 $self->{salt} = "$value";
188             } elsif($attr eq "salt_base64") {
189 9 50       29 croak "salt specified redundantly"
190             if exists $self->{salt};
191 9 50       25 croak "\"$value\" is not a valid salt"
192             unless length($value) == 22;
193 9         34 $self->{salt} = de_base64($value);
194             } elsif($attr eq "salt_random") {
195 1 50       4 croak "salt specified redundantly"
196             if exists $self->{salt};
197 1         7 $self->{salt} = rand_bits(128);
198             } elsif($attr eq "hash") {
199 1 50 33     8 croak "hash specified redundantly"
200             if exists($self->{hash}) ||
201             defined($passphrase);
202 1 50       6 $value =~ m#\A[\x00-\xff]{23}\z#
203             or croak "not a valid raw hash";
204 1         6 $self->{hash} = "$value";
205             } elsif($attr eq "hash_base64") {
206 8 50 33     44 croak "hash specified redundantly"
207             if exists($self->{hash}) ||
208             defined($passphrase);
209 8 50       22 croak "\"$value\" is not a valid hash"
210             unless length($value) == 31;
211 8         19 $self->{hash} = de_base64($value);
212             } elsif($attr eq "passphrase") {
213 2 50 33     16 croak "passphrase specified redundantly"
214             if exists($self->{hash}) ||
215             defined($passphrase);
216 2         8 $passphrase = $value;
217             } else {
218 0         0 croak "unrecognised attribute `$attr'";
219             }
220             }
221 11 100       133 $self->{key_nul} = !!1 unless exists $self->{key_nul};
222 11 50       27 croak "cost not specified" unless exists $self->{cost};
223 11 50       28 croak "salt not specified" unless exists $self->{salt};
224 11 100       31 $self->{hash} = $self->_hash_of($passphrase) if defined $passphrase;
225 11 50       65177 croak "hash not specified" unless exists $self->{hash};
226 11         42 return $self;
227             }
228              
229             =item Authen::Passphrase::BlowfishCrypt->from_crypt(PASSWD)
230              
231             Generates a new passphrase recogniser object using the Blowfish-based
232             crypt() algorithm, from a crypt string. The crypt string must start with
233             "B<$2$>" for the version that does not append NUL to the key, or "B<$2a$>"
234             for the version that does. The next two characters must be decimal digits
235             giving the cost parameter. This must be followed by "B<$>", 22 base 64
236             digits giving the salt, and finally 31 base 64 digits giving the hash.
237              
238             =cut
239              
240             sub from_crypt {
241 2     2 1 38364 my($class, $passwd) = @_;
242 2 50       16 if($passwd =~ /\A(\$2a?\$)/) {
243 2 50       13 $passwd =~ m#\A\$2(a?)\$([0-9]{2})\$
244             ([./A-Za-z0-9]{22})([./A-Za-z0-9]{31})\z#x
245             or croak "malformed $1 data";
246 2         14 my($kn, $cost, $salt, $hash) = ($1, $2, $3, $4);
247 2         11 return $class->new(key_nul => $kn, cost => $cost,
248             salt_base64 => $salt, hash_base64 => $hash);
249             }
250 0         0 return $class->SUPER::from_crypt($passwd);
251             }
252              
253             =item Authen::Passphrase::BlowfishCrypt->from_rfc2307(USERPASSWORD)
254              
255             Generates a new passphrase recogniser object using the Blowfish-based
256             crypt() algorithm, from an RFC 2307 string. The string must consist of
257             "B<{CRYPT}>" (case insensitive) followed by an acceptable crypt string.
258              
259             =back
260              
261             =head1 METHODS
262              
263             =over
264              
265             =item $ppr->key_nul
266              
267             Returns a truth value indicating whether a NUL will be appended to the
268             passphrase before using it as a key.
269              
270             =cut
271              
272             sub key_nul {
273 21     21 1 4938 my($self) = @_;
274 21         158 return $self->{key_nul};
275             }
276              
277             =item $ppr->cost
278              
279             Returns the base-two logarithm of the number of keying rounds that will
280             be performed.
281              
282             =cut
283              
284             sub cost {
285 23     23 1 41 my($self) = @_;
286 23         94 return $self->{cost};
287             }
288              
289             =item $ppr->keying_nrounds_log2
290              
291             Synonym for L.
292              
293             =cut
294              
295             *keying_nrounds_log2 = \&cost;
296              
297             =item $ppr->salt
298              
299             Returns the salt, as a string of sixteen bytes.
300              
301             =cut
302              
303             sub salt {
304 3     3 1 9 my($self) = @_;
305 3         17 return $self->{salt};
306             }
307              
308             =item $ppr->salt_base64
309              
310             Returns the salt, as a string of 22 base 64 digits.
311              
312             =cut
313              
314             sub salt_base64 {
315 20     20 1 31 my($self) = @_;
316 20         75 return en_base64($self->{salt});
317             }
318              
319             =item $ppr->hash
320              
321             Returns the hash value, as a string of 23 bytes.
322              
323             =cut
324              
325             sub hash {
326 3     3 1 4000 my($self) = @_;
327 3         22 return $self->{hash};
328             }
329              
330             =item $ppr->hash_base64
331              
332             Returns the hash value, as a string of 31 base 64 digits.
333              
334             =cut
335              
336             sub hash_base64 {
337 20     20 1 3438 my($self) = @_;
338 20         67 return en_base64($self->{hash});
339             }
340              
341             =item $ppr->match(PASSPHRASE)
342              
343             =item $ppr->as_crypt
344              
345             =item $ppr->as_rfc2307
346              
347             These methods are part of the standard L interface.
348              
349             =cut
350              
351             sub _hash_of {
352 28     28   48 my($self, $passphrase) = @_;
353 28         239 return bcrypt_hash({
354             key_nul => $self->{key_nul},
355             cost => $self->{cost},
356             salt => $self->{salt},
357             }, $passphrase);
358             }
359              
360             sub match {
361 26     26 1 618553 my($self, $passphrase) = @_;
362 26         85 return $self->_hash_of($passphrase) eq $self->{hash};
363             }
364              
365             sub as_crypt {
366 10     10 1 3590 my($self) = @_;
367 10 50       33 croak "passphrase can't be expressed as a crypt string"
368             if $self->{cost} > 99;
369 10 100       27 return sprintf("\$2%s\$%02d\$%s%s", $self->key_nul ? "a" : "",
370             $self->cost, $self->salt_base64, $self->hash_base64);
371             }
372              
373             =back
374              
375             =head1 SEE ALSO
376              
377             L,
378             L
379              
380             =head1 AUTHOR
381              
382             Andrew Main (Zefram)
383              
384             =head1 COPYRIGHT
385              
386             Copyright (C) 2006, 2007, 2009, 2010, 2012
387             Andrew Main (Zefram)
388              
389             =head1 LICENSE
390              
391             This module is free software; you can redistribute it and/or modify it
392             under the same terms as Perl itself.
393              
394             =cut
395              
396             1;