File Coverage

blib/lib/Authen/Passphrase/Crypt16.pm
Criterion Covered Total %
statement 72 75 96.0
branch 28 42 66.6
condition 7 18 38.8
subroutine 17 17 100.0
pod 8 8 100.0
total 132 160 82.5


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Authen::Passphrase::Crypt16 - passphrases using Ultrix crypt16 algorithm
4              
5             =head1 SYNOPSIS
6              
7             use Authen::Passphrase::Crypt16;
8              
9             $ppr = Authen::Passphrase::Crypt16->new(
10             salt_base64 => "qi",
11             hash_base64 => "8H8R7OM4xMUNMPuRAZxlY.");
12              
13             $ppr = Authen::Passphrase::Crypt16->new(
14             salt_random => 12,
15             passphrase => "passphrase");
16              
17             $salt = $ppr->salt;
18             $salt_base64 = $ppr->salt_base64_2;
19             $hash = $ppr->hash;
20             $hash_base64 = $ppr->hash_base64;
21              
22             $ppr0 = $ppr->first_half;
23             $ppr1 = $ppr->second_half;
24              
25             if($ppr->match($passphrase)) { ...
26              
27             =head1 DESCRIPTION
28              
29             An object of this class encapsulates a passphrase hashed using the
30             "crypt16" hash function found in Ultrix and Tru64. Do not confuse
31             this with the "bigcrypt" found on HP-UX, Digital Unix, and OSF/1 (for
32             which see L). This is a subclass of
33             L, and this document assumes that the reader is
34             familiar with the documentation for that class.
35              
36             This is a derivation of the original DES-based crypt function found on all
37             Unices (see L). The first eight bytes of
38             the passphrase are used as a DES key to encrypt the all-bits-zero block
39             through 20 rounds of (12-bit) salted DES. (The standard crypt function
40             does this, but with 25 encryption rounds instead of 20.) Then the
41             next eight bytes, or the null string if the passphrase is eight bytes
42             or shorter, are used as a DES key to encrypt the all-bits-zero block
43             through 5 rounds of salted DES with the same salt. The two eight-byte
44             ciphertexts are concatenated to form the sixteen-byte hash.
45              
46             A password hash of this scheme is conventionally represented in ASCII as
47             a 24-character string using a base 64 encoding. The first two characters
48             give the salt, the next eleven give the hash of the first half, and the
49             last eleven give the hash of the second half. A hash thus encoded is
50             used as a crypt string, on those systems where the crypt16 algorithm
51             is part of crypt(), but the syntax clashes with that of bigcrypt.
52             This module does not treat it as a crypt string syntax.
53              
54             Because the two halves of the passphrase are hashed separately, it
55             is possible to manipulate (e.g., crack) a half hash in isolation.
56             See L for handling of a single half.
57              
58             I This is a fatally flawed design, often providing I
59             security than the plain DES scheme alone. Do not use seriously.
60              
61             =cut
62              
63             package Authen::Passphrase::Crypt16;
64              
65 1     1   2410240 { use 5.006; }
  1         5  
  1         74  
66 1     1   7 use warnings;
  1         2  
  1         47  
67 1     1   7 use strict;
  1         2  
  1         53  
68              
69 1     1   813 use Authen::Passphrase 0.003;
  1         20  
  1         29  
70 1     1   668 use Authen::Passphrase::DESCrypt;
  1         3  
  1         210  
71 1     1   12 use Carp qw(croak);
  1         2  
  1         89  
72 1     1   6 use Crypt::UnixCrypt_XS 0.08 qw(base64_to_block base64_to_int12);
  1         35  
  1         61  
73 1     1   5 use Data::Entropy::Algorithms 0.000 qw(rand_int);
  1         19  
  1         74  
74              
75             our $VERSION = "0.008";
76              
77 1     1   5 use parent "Authen::Passphrase";
  1         2  
  1         5  
78              
79             =head1 CONSTRUCTOR
80              
81             =over
82              
83             =item Authen::Passphrase::Crypt16->new(ATTR => VALUE, ...)
84              
85             Generates a new passphrase recogniser object using the crypt16 hash
86             algorithm. The following attributes may be given:
87              
88             =over
89              
90             =item B
91              
92             The salt, as an integer in the range [0, 4096).
93              
94             =item B
95              
96             The salt, as a string of two base 64 digits.
97              
98             =item B
99              
100             Causes salt to be generated randomly. The value given for this
101             attribute must be 12, indicating generation of 12 bits of salt.
102             The source of randomness may be controlled by the facility described
103             in L.
104              
105             =item B
106              
107             The hash, as a string of 16 bytes.
108              
109             =item B
110              
111             The hash, as a string of 22 base 64 digits.
112              
113             =item B
114              
115             A passphrase that will be accepted.
116              
117             =back
118              
119             The salt must be given, and either the hash or the passphrase.
120              
121             =cut
122              
123             sub new {
124 9     9 1 2602 my $class = shift;
125 9         32 my $self = bless({}, $class);
126 9         18 my $salt;
127             my $hash;
128 0         0 my $passphrase;
129 9         33 while(@_) {
130 18         11181 my $attr = shift;
131 18         26 my $value = shift;
132 18 100       105 if($attr eq "salt") {
    100          
    100          
    100          
    100          
    50          
133 3 50       12 croak "salt specified redundantly"
134             if defined $salt;
135 3 50 33     37 croak "\"$value\" is not a valid salt"
      33        
136             unless $value == int($value) &&
137             $value >= 0 && $value < 4096;
138 3         9 $salt = $value;
139             } elsif($attr eq "salt_base64") {
140 5 50       14 croak "salt specified redundantly"
141             if defined $salt;
142 5 50       23 $value =~ m#\A[./0-9A-Za-z]{2}\z#
143             or croak "\"$value\" is not a valid salt";
144 5         25 $salt = base64_to_int12($value);
145             } elsif($attr eq "salt_random") {
146 1 50       4 croak "salt specified redundantly"
147             if defined $salt;
148 1 50       4 croak "\"$value\" is not a valid salt size"
149             unless $value == 12;
150 1         8 $salt = rand_int(1 << $value);
151             } elsif($attr eq "hash") {
152 1 50 33     8 croak "hash specified redundantly"
153             if defined($hash) || defined($passphrase);
154 1 50       11 $value =~ m#\A[\x00-\xff]{16}\z#
155             or croak "not a valid crypt16 hash";
156 1         5 $hash = $value;
157             } elsif($attr eq "hash_base64") {
158 5 50 33     31 croak "hash specified redundantly"
159             if defined($hash) || defined($passphrase);
160 5 50       25 $value =~ m#\A(?:[./0-9A-Za-z]{10}[.26AEIMQUYcgkosw])
161             {2}\z#x
162             or croak "\"$value\" is not a valid ".
163             "encoded hash";
164 5         88 $hash = base64_to_block(substr($value, 0, 11)).
165             base64_to_block(substr($value, 11));
166             } elsif($attr eq "passphrase") {
167 3 50 33     21 croak "passphrase specified redundantly"
168             if defined($hash) || defined($passphrase);
169 3         10 $passphrase = $value;
170             } else {
171 0         0 croak "unrecognised attribute `$attr'";
172             }
173             }
174 9 50       26 croak "salt not specified" unless defined $salt;
175 9 100       33 if(defined $passphrase) {
    50          
176 3         34 $self->{first_half} =
177             Authen::Passphrase::DESCrypt
178             ->new(nrounds => 20, salt => $salt,
179             passphrase => substr($passphrase, 0, 8));
180 3 100       49 $self->{second_half} =
181             Authen::Passphrase::DESCrypt
182             ->new(nrounds => 5, salt => $salt,
183             passphrase =>
184             length($passphrase) > 8 ?
185             substr($passphrase, 8) : "");
186             } elsif(defined $hash) {
187 6         81 $self->{first_half} = Authen::Passphrase::DESCrypt
188             ->new(nrounds => 20, salt => $salt,
189             hash => substr($hash, 0, 8));
190 6         33 $self->{second_half} = Authen::Passphrase::DESCrypt
191             ->new(nrounds => 5, salt => $salt,
192             hash => substr($hash, 8, 8));
193             } else {
194 0         0 croak "hash not specified";
195             }
196 9         32 return $self;
197             }
198              
199             =back
200              
201             =head1 METHODS
202              
203             =over
204              
205             =item $ppr->salt
206              
207             Returns the salt, as a Perl integer.
208              
209             =cut
210              
211             sub salt {
212 3     3 1 1623 my($self) = @_;
213 3         15 return $self->{first_half}->salt;
214             }
215              
216             =item $ppr->salt_base64_2
217              
218             Returns the salt, as a string of two base 64 digits.
219              
220             =cut
221              
222             sub salt_base64_2 {
223 7     7 1 3057 my($self) = @_;
224 7         36 return $self->{first_half}->salt_base64_2;
225             }
226              
227             =item $ppr->hash
228              
229             Returns the hash value, as a string of 16 bytes.
230              
231             =cut
232              
233             sub hash {
234 2     2 1 8 my($self) = @_;
235 2         14 return $self->{first_half}->hash.$self->{second_half}->hash;
236             }
237              
238             =item $ppr->hash_base64
239              
240             Returns the hash value, as a string of 22 base 64 digits. This is the
241             concatenation of the base 64 encodings of the two hashes, rather than
242             a base64 encoding of the combined hash.
243              
244             =cut
245              
246             sub hash_base64 {
247 8     8 1 16 my($self) = @_;
248 8         38 return $self->{first_half}->hash_base64.
249             $self->{second_half}->hash_base64;
250             }
251              
252             =item $ppr->first_half
253              
254             Returns the hash of the first half of the passphrase, as an
255             L passphrase recogniser.
256              
257             =cut
258              
259             sub first_half {
260 1     1 1 2 my($self) = @_;
261 1         3 return $self->{first_half};
262             }
263              
264             =item $ppr->second_half
265              
266             Returns the hash of the second half of the passphrase, as an
267             L passphrase recogniser.
268              
269             =cut
270              
271             sub second_half {
272 1     1 1 3 my($self) = @_;
273 1         5 return $self->{second_half};
274             }
275              
276             =item $ppr->match(PASSPHRASE)
277              
278             This method is part of the standard L interface.
279              
280             =cut
281              
282             sub match {
283 26     26 1 10994 my($self, $passphrase) = @_;
284 26   66     125 return $self->{first_half}->match(substr($passphrase, 0, 8)) &&
285             $self->{second_half}->match(
286             length($passphrase) > 8 ? substr($passphrase, 8) : "");
287             }
288              
289             =back
290              
291             =head1 SEE ALSO
292              
293             L,
294             L
295              
296             =head1 AUTHOR
297              
298             Andrew Main (Zefram)
299              
300             =head1 COPYRIGHT
301              
302             Copyright (C) 2006, 2007, 2009, 2010, 2012
303             Andrew Main (Zefram)
304              
305             =head1 LICENSE
306              
307             This module is free software; you can redistribute it and/or modify it
308             under the same terms as Perl itself.
309              
310             =cut
311              
312             1;