File Coverage

blib/lib/Authen/Passphrase.pm
Criterion Covered Total %
statement 25 47 53.1
branch 2 24 8.3
condition n/a
subroutine 9 9 100.0
pod 3 3 100.0
total 39 83 46.9


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Authen::Passphrase - hashed passwords/passphrases as objects
4              
5             =head1 SYNOPSIS
6              
7             use Authen::Passphrase;
8              
9             $ppr = Authen::Passphrase->from_crypt($passwd);
10             $ppr = Authen::Passphrase->from_rfc2307($userPassword);
11              
12             if($ppr->match($passphrase)) { ...
13              
14             $passphrase = $ppr->passphrase;
15              
16             $crypt = $ppr->as_crypt;
17             $userPassword = $ppr->as_rfc2307;
18              
19             =head1 DESCRIPTION
20              
21             This is the base class for a system of objects that encapsulate
22             passphrases. An object of this type is a passphrase recogniser: its
23             job is to recognise whether an offered passphrase is the right one.
24             For security, such passphrase recognisers usually do not themselves know
25             the passphrase they are looking for; they can merely recognise it when
26             they see it. There are many schemes in use to achieve this effect,
27             and the intent of this class is to provide a consistent interface to
28             them all, hiding the details.
29              
30             The CPAN package Authen-Passphrase contains implementations of several
31             specific passphrase schemes in addition to the base class. See the
32             specific classes for notes on the security properties of each scheme.
33             In new systems, if there is a choice of which passphrase algorithm to
34             use, it is recommended to use L or
35             L. Most other schemes are too weak
36             for new applications, and should be used only for backward compatibility.
37              
38             =head2 Side-channel cryptanalysis
39              
40             Both the Authen-Passphrase framework and most of the underlying
41             cryptographic algorithm implementations are vulnerable to side-channel
42             cryptanalytic attacks. However, the impact of this is quite limited.
43              
44             Unlike the case of symmetric encryption, where a side-channel attack can
45             extract the plaintext directly, the cryptographic operations involved in
46             passphrase recognition don't directly process the correct passphrase.
47             A sophisticated side-channel attack, applied when offering incorrect
48             passphrases for checking, could potentially extract salt (from the
49             operation of the hashing algorithm) and the target hash value (from
50             the comparison of hash values). This would enable a cryptanalytic or
51             brute-force attack on the passphrase recogniser to be performed offline.
52             This is not a disaster; the very intent of storing only a hash of
53             the correct passphrase is that leakage of these stored values doesn't
54             compromise the passphrase.
55              
56             In a typical usage scenario for this framework, the side-channel attacks
57             that can be mounted are very restricted. If authenticating network
58             users, typically an attacker has no access at all to power consumption,
59             electromagnetic emanation, and other such side channels. The only
60             side channel that is readily available is timing, and the precision of
61             timing measurements is significantly blunted by the normal processes of
62             network communication. For example, it would not normally be feasible
63             to mount a timing attack against hash value comparison (to see how far
64             through the values the first mismatch was).
65              
66             Perl as a whole has not been built as a platform for
67             side-channel-resistant cryptography, so hardening Authen-Passphrase and
68             its underlying algorithms is not feasible. In any serious use of Perl
69             for cryptography, including for authentication using Authen-Passphrase,
70             an analysis should be made of the exposure to side-channel attacks,
71             and if necessary efforts made to further blunt the timing channel.
72              
73             One timing attack that is very obviously feasible over the network is to
74             determine which of several passphrase hashing algorithms is being used.
75             This can potentially distinguish between classes of user accounts,
76             or distinguish between existing and non-existing user accounts when an
77             attacker is guessing usernames. To obscure this information requires
78             an extreme restriction of the timing channel, most likely by explicitly
79             pausing to standardise the amount of time spent on authentication.
80             This defence also rules out essentially all other timing attacks.
81              
82             =head1 PASSPHRASE ENCODINGS
83              
84             Because hashed passphrases frequently need to be stored, various encodings
85             of them have been devised. This class has constructors and methods to
86             support these.
87              
88             =head2 crypt encoding
89              
90             The Unix crypt() function, which performs passphrase hashing, returns
91             hashes in a textual format intended to be stored in a text file.
92             In particular, such hashes are stored in /etc/passwd (and now /etc/shadow)
93             to control access to Unix user accounts. The same textual format has
94             been adopted and extended by other passphrase-handling software such as
95             password crackers.
96              
97             For historical reasons, there are several different syntaxes used in this
98             format. The original DES-based password scheme represents its hashes
99             simply as a string of thirteen base 64 digits. An extended variant of
100             this scheme uses nineteen base 64 digits, preceded by an "B<_>" marker.
101             A more general syntax was developed later, which starts the string with
102             "B<$>", an alphanumeric scheme identifier, and another "B<$>".
103              
104             In addition to actual passphrase hashes, the crypt format can also
105             represent a couple of special cases. The empty string indicates that
106             there is no access control; it is possible to login without giving a
107             passphrase. Finally, any string that is not a possible output of crypt()
108             may be used to prevent login completely; "B<*>" is the usual choice,
109             but other strings are used too.
110              
111             crypt strings are intended to be used in text files that use colon and
112             newline characters as delimiters. This module treats the crypt string
113             syntax as being limited to ASCII graphic characters excluding colon.
114              
115             =head2 RFC 2307 encoding
116              
117             RFC 2307 describes an encoding system for passphrase hashes, to be used
118             in the "B" attribute in LDAP databases. It encodes hashes
119             as ASCII text, and supports several passphrase schemes in an extensible
120             way by starting the encoding with an alphanumeric scheme identifier
121             enclosed in braces. There are several standard scheme identifiers.
122             The "B<{CRYPT}>" scheme allows the use of any crypt encoding.
123              
124             This module treats the RFC 2307 string syntax as being limited to ASCII
125             graphic characters.
126              
127             The RFC 2307 encoding is a good one, and is recommended for storage and
128             exchange of passphrase hashes.
129              
130             =cut
131              
132             package Authen::Passphrase;
133              
134 22     22   408 { use 5.006; }
  22         82  
  22         1541  
135 22     22   150 use warnings;
  22         42  
  22         1694  
136 22     22   120 use strict;
  22         40  
  22         1728  
137              
138 22     22   185 use Carp qw(croak);
  22         47  
  22         2492  
139 22     22   29335 use MIME::Base64 2.21 qw(decode_base64);
  22         38761  
  22         2081  
140 22     22   36356 use Module::Runtime 0.011 qw(use_module);
  22         60681  
  22         429  
141              
142             our $VERSION = "0.008";
143              
144             =head1 CONSTRUCTORS
145              
146             =over
147              
148             =item Authen::Passphrase->from_crypt(PASSWD)
149              
150             Returns a passphrase recogniser object matching the supplied crypt
151             encoding. This constructor may only be called on the base class, not
152             any subclass.
153              
154             The specific passphrase recogniser class is loaded at runtime, so
155             successfully loading C does not guarantee that
156             it will be possible to use a specific type of passphrase recogniser.
157             If necessary, check separately for presence and loadability of the
158             recogniser class.
159              
160             Known scheme identifiers:
161              
162             =over
163              
164             =item B<$1$>
165              
166             A baroque passphrase scheme based on MD5, designed by
167             Poul-Henning Kamp and originally implemented in FreeBSD. See
168             L.
169              
170             =item B<$2$>
171              
172             =item B<$2a$>
173              
174             Two versions of a passphrase scheme based on Blowfish,
175             designed by Niels Provos and David Mazieres for OpenBSD. See
176             L.
177              
178             =item B<$3$>
179              
180             The NT-Hash scheme, which stores the MD4 hash of the passphrase expressed
181             in Unicode. See L.
182              
183             =item B<$IPB2$>
184              
185             Invision Power Board 2.x salted MD5
186              
187             =item B<$K4$>
188              
189             Kerberos AFS DES
190              
191             =item B<$LM$>
192              
193             Half of the Microsoft LAN Manager hash scheme. The two
194             halves of a LAN Manager hash can be separated and manipulated
195             independently; this represents such an isolated half. See
196             L.
197              
198             =item B<$NT$>
199              
200             The NT-Hash scheme, which stores the MD4 hash of the passphrase expressed
201             in Unicode. See L.
202              
203             The B<$3$> identifier refers to the same hash algorithm, but has a
204             slightly different textual format (an extra "B<$>").
205              
206             =item B<$P$>
207              
208             Portable PHP password hash (phpass), based on MD5. See
209             L.
210              
211             =item B<$VMS1$>
212              
213             =item B<$VMS2$>
214              
215             =item B<$VMS3$>
216              
217             Three variants of the Purdy polynomial system used in VMS.
218             See L.
219              
220             =item B<$af$>
221              
222             Kerberos v4 TGT
223              
224             =item B<$apr1$>
225              
226             A variant of the B<$1$> scheme, used by Apache.
227              
228             =item B<$krb5$>
229              
230             Kerberos v5 TGT
231              
232             =back
233              
234             The historical formats supported are:
235              
236             =over
237              
238             =item "I"
239              
240             ("I" represents a base 64 digit.) The original DES-based Unix password
241             hash scheme. See L.
242              
243             =item "B<_>I"
244              
245             ("I" represents a base 64 digit.) Extended DES-based passphrase hash
246             scheme from BSDi. See L.
247              
248             =item ""
249              
250             Accept any passphrase. See L.
251              
252             =item "B<*>"
253              
254             To handle historical practice, anything non-empty but shorter than 13
255             characters and not starting with "B<$>" is treated as deliberately
256             rejecting all passphrases. (See L.)
257             Anything 13 characters or longer, or starting with "B<$>", that is not
258             recognised as a hash is treated as an error.
259              
260             =back
261              
262             There are also two different passphrase schemes that use a crypt string
263             consisting of 24 base 64 digits. One is named "bigcrypt" and appears in
264             HP-UX, Digital Unix, and OSF/1 (see L).
265             The other is named "crypt16" and appears in Ultrix and Tru64 (see
266             L). These schemes conflict. Neither of
267             them is accepted as a crypt string by this constructor; such strings
268             are regarded as invalid encodings.
269              
270             =cut
271              
272             my %crypt_scheme_handler = (
273             "1" => [ "Authen::Passphrase::MD5Crypt", 0.003 ],
274             "2" => [ "Authen::Passphrase::BlowfishCrypt", 0.007 ],
275             "2a" => [ "Authen::Passphrase::BlowfishCrypt", 0.007 ],
276             "3" => [ "Authen::Passphrase::NTHash", 0.003 ],
277             "IPB2" => sub($) { croak '$IPB2$ is unimplemented' },
278             "K4" => sub($) { croak '$K4$ is unimplemented' },
279             "LM" => [ "Authen::Passphrase::LANManagerHalf", 0.003 ],
280             "NT" => [ "Authen::Passphrase::NTHash", 0.003 ],
281             "P" => [ "Authen::Passphrase::PHPass", 0.003 ],
282             "VMS1" => [ "Authen::Passphrase::VMSPurdy", 0.006 ],
283             "VMS2" => [ "Authen::Passphrase::VMSPurdy", 0.006 ],
284             "VMS3" => [ "Authen::Passphrase::VMSPurdy", 0.006 ],
285             "af" => sub($) { croak '$af$ is unimplemented' },
286             "apr1" => sub($) { croak '$apr1$ is unimplemented' },
287             "krb5" => sub($) { croak '$krb5$ is unimplemented' },
288             );
289              
290             sub from_crypt {
291 5     5 1 11 my($class, $passwd) = @_;
292 5 50       1043 croak "crypt string \"$passwd\" not supported for $class"
293             unless $class eq __PACKAGE__;
294 0         0 my $handler;
295 0 0       0 if($passwd =~ /\A\$([0-9A-Za-z]+)\$/) {
    0          
    0          
    0          
296 0         0 my $scheme = $1;
297 0         0 $handler = $crypt_scheme_handler{$scheme};
298 0 0       0 croak "unrecognised crypt scheme \$$scheme\$"
299             unless defined $handler;
300             } elsif($passwd =~ m#\A(?:[^\$].{12}|_.{19})\z#s) {
301 0         0 $handler = [ "Authen::Passphrase::DESCrypt", 0.006 ];
302             } elsif($passwd eq "") {
303 0         0 $handler = [ "Authen::Passphrase::AcceptAll", 0.003 ];
304             } elsif($passwd =~ /\A[^\$].{0,11}\z/s) {
305 0         0 $handler = [ "Authen::Passphrase::RejectAll", 0.003 ];
306             } else {
307 0         0 croak "bad crypt syntax in \"$passwd\"";
308             }
309 0 0       0 if(ref($handler) eq "CODE") {
310 0         0 return $handler->($passwd);
311             } else {
312 0         0 my($modname, $modver) = @$handler;
313 0         0 return use_module($modname, $modver)->from_crypt($passwd);
314             }
315             }
316              
317             =item Authen::Passphrase->from_rfc2307(USERPASSWORD)
318              
319             Returns a passphrase recogniser object matching the supplied RFC 2307
320             encoding. This constructor may only be called on the base class, not
321             any subclass.
322              
323             The specific passphrase recogniser class is loaded at runtime. See the
324             note about this for the L constructor above.
325              
326             Known scheme identifiers:
327              
328             =over
329              
330             =item B<{CLEARTEXT}>
331              
332             Passphrase stored in cleartext. See L.
333              
334             =item B<{CRYPT}>
335              
336             The scheme identifier is followed by a crypt string.
337              
338             =item B<{CRYPT16}>
339              
340             Used ambiguously by Exim, to refer to either crypt16
341             (see L) or bigcrypt (see
342             L) depending on compilation options.
343             This is a bug, resulting from a confusion between the two algorithms.
344             This module does not support any meaning for this scheme identifier.
345              
346             =item B<{K5KEY}>
347              
348             Not a real passphrase scheme, but a placeholder to indicate that a
349             Kerberos key stored separately should be checked against. No data
350             follows the scheme identifier.
351              
352             =item B<{KERBEROS}>
353              
354             Not a real passphrase scheme, but a placeholder to indicate that
355             Kerberos should be invoked to check against a user's passphrase.
356             The scheme identifier is followed by the user's username, in the form
357             "IB<@>I".
358              
359             =item B<{LANM}>
360              
361             Synonym for B<{LANMAN}>, used by CommuniGate Pro.
362              
363             =item B<{LANMAN}>
364              
365             The Microsoft LAN Manager hash scheme. See
366             L.
367              
368             =item B<{MD4}>
369              
370             The MD4 digest of the passphrase is stored. See
371             L.
372              
373             =item B<{MD5}>
374              
375             The MD5 digest of the passphrase is stored. See
376             L.
377              
378             =item B<{MSNT}>
379              
380             The NT-Hash scheme, which stores the MD4 hash of the passphrase expressed
381             in Unicode. See L.
382              
383             =item B<{NS-MTA-MD5}>
384              
385             An MD5-based scheme used by Netscape Mail Server. See
386             L.
387              
388             =item B<{RMD160}>
389              
390             The RIPEMD-160 digest of the passphrase is stored. See
391             L.
392              
393             =item B<{SASL}>
394              
395             Not a real passphrase scheme, but a placeholder to indicate that SASL
396             should be invoked to check against a user's passphrase. The scheme
397             identifier is followed by the user's username.
398              
399             =item B<{SHA}>
400              
401             The SHA-1 digest of the passphrase is stored. See
402             L.
403              
404             =item B<{SMD5}>
405              
406             The MD5 digest of the passphrase plus a salt is stored. See
407             L.
408              
409             =item B<{SSHA}>
410              
411             The SHA-1 digest of the passphrase plus a salt is stored.
412             See L.
413              
414             =item B<{UNIX}>
415              
416             Not a real passphrase scheme, but a placeholder to indicate that Unix
417             mechanisms should be used to check against a Unix user's login passphrase.
418             The scheme identifier is followed by the user's username.
419              
420             =item B<{WM-CRY}>
421              
422             Synonym for B<{CRYPT}>, used by CommuniGate Pro.
423              
424             =back
425              
426             =cut
427              
428             my %rfc2307_scheme_handler = (
429             "CLEARTEXT" => [ "Authen::Passphrase::Clear", 0.003 ],
430             # "CRYPT" is handled specially
431             "CRYPT16" => sub($) { croak "{CRYPT16} is ambiguous" },
432             "K5KEY" => sub($) { croak "{K5KEY} is a placeholder" },
433             "KERBEROS" => sub($) { croak "{KERBEROS} is a placeholder" },
434             "LANM" => [ "Authen::Passphrase::LANManager", 0.003 ],
435             "LANMAN" => [ "Authen::Passphrase::LANManager", 0.003 ],
436             "MD4" => [ "Authen::Passphrase::SaltedDigest", 0.008 ],
437             "MD5" => [ "Authen::Passphrase::SaltedDigest", 0.008 ],
438             "MSNT" => [ "Authen::Passphrase::NTHash", 0.003 ],
439             "NS-MTA-MD5" => [ "Authen::Passphrase::NetscapeMail", 0.003 ],
440             "RMD160" => [ "Authen::Passphrase::SaltedDigest", 0.008 ],
441             "SASL" => sub($) { croak "{SASL} is a placeholder" },
442             "SHA" => [ "Authen::Passphrase::SaltedDigest", 0.008 ],
443             "SMD5" => [ "Authen::Passphrase::SaltedDigest", 0.008 ],
444             "SSHA" => [ "Authen::Passphrase::SaltedDigest", 0.008 ],
445             "UNIX" => sub($) { croak "{UNIX} is a placeholder" },
446             # "WM-CRY" is handled specially
447             );
448              
449             sub from_rfc2307 {
450 11     11 1 2555 my($class, $userpassword) = @_;
451 11 50       186 if($userpassword =~ m#\A\{(?i:crypt|wm-cry)\}(.*)\z#s) {
452 11         34 my $passwd = $1;
453 11         53 return $class->from_crypt($passwd);
454             }
455 0 0       0 croak "RFC 2307 string \"$userpassword\" not supported for $class"
456             unless $class eq __PACKAGE__;
457 0 0       0 $userpassword =~ /\A\{([-0-9a-z]+)\}/i
458             or croak "bad RFC 2307 syntax in \"$userpassword\"";
459 0         0 my $scheme = uc($1);
460 0         0 my $handler = $rfc2307_scheme_handler{$scheme};
461 0 0       0 croak "unrecognised RFC 2307 scheme {$scheme}" unless defined $handler;
462 0 0       0 if(ref($handler) eq "CODE") {
463 0         0 return $handler->($userpassword);
464             } else {
465 0         0 my($modname, $modver) = @$handler;
466 0         0 return use_module($modname, $modver)
467             ->from_rfc2307($userpassword);
468             }
469             }
470              
471             =back
472              
473             =head1 METHODS
474              
475             =over
476              
477             =item $ppr->match(PASSPHRASE)
478              
479             Checks whether the supplied passphrase is correct. Returns a truth value.
480              
481             =item $ppr->passphrase
482              
483             If a matching passphrase can be easily determined by the passphrase
484             recogniser then this method will return it. This is only feasible for
485             very weak passphrase schemes. The method Cs if it is infeasible.
486              
487             =item $ppr->as_crypt
488              
489             Encodes the passphrase recogniser in crypt format and returns the encoded
490             result. Cs if the passphrase recogniser cannot be represented in
491             this form.
492              
493             =item $ppr->as_rfc2307
494              
495             Encodes the passphrase recogniser in RFC 2307 format and returns
496             the encoded result. Cs if the passphrase recogniser cannot be
497             represented in this form.
498              
499             =cut
500              
501 73     73 1 5718 sub as_rfc2307 { "{CRYPT}".$_[0]->as_crypt }
502              
503             =back
504              
505             =head1 SUBCLASSING
506              
507             This class is designed to be subclassed, and cannot be instantiated alone.
508             Any subclass must implement the L method. That is the minimum
509             required.
510              
511             Subclasses should implement the L and L methods
512             and the L and L constructors wherever
513             appropriate, with the following exception. If a passphrase scheme has
514             a crypt encoding but no native RFC 2307 encoding, so it can be RFC 2307
515             encoded only by using the "B<{CRYPT}>" scheme, then L and
516             L should I be implemented by the class. There is a
517             default implementation of the L method that uses "B<{CRYPT}>"
518             and L, and a default implementation of the L
519             method that recognises "B<{CRYPT}>" and passes the embedded crypt string
520             to the L constructor.
521              
522             Implementation of the L method is entirely optional.
523             It should be attempted only for schemes that are so ludicrously weak as
524             to allow passphrases to be cracked reliably in a short time. Dictionary
525             attacks are not appropriate implementations.
526              
527             =head1 SEE ALSO
528              
529             L,
530             L,
531             RFC 2307
532              
533             =head1 AUTHOR
534              
535             Andrew Main (Zefram)
536              
537             =head1 COPYRIGHT
538              
539             Copyright (C) 2006, 2007, 2009, 2010, 2012
540             Andrew Main (Zefram)
541              
542             =head1 LICENSE
543              
544             This module is free software; you can redistribute it and/or modify it
545             under the same terms as Perl itself.
546              
547             =cut
548              
549             1;