File Coverage

blib/lib/Authen/Passphrase/LANManager.pm
Criterion Covered Total %
statement 62 65 95.3
branch 18 28 64.2
condition 5 12 41.6
subroutine 16 16 100.0
pod 8 8 100.0
total 109 129 84.5


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Authen::Passphrase::LANManager - passphrases using the LAN Manager
4             hash algorithm
5              
6             =head1 SYNOPSIS
7              
8             use Authen::Passphrase::LANManager;
9              
10             $ppr = Authen::Passphrase::LANManager->new(
11             hash_hex => "855c3697d9979e78ac404c4ba2c66533");
12              
13             $ppr = Authen::Passphrase::LANManager->new(
14             passphrase => "passphrase");
15              
16             $ppr = Authen::Passphrase::LANManager->from_rfc2307(
17             "{LANMAN}855c3697d9979e78ac404c4ba2c66533");
18              
19             $hash = $ppr->hash;
20             $hash_hex = $ppr->hash_hex;
21              
22             $ppr0 = $ppr->first_half;
23             $ppr1 = $ppr->second_half;
24              
25             if($ppr->match($passphrase)) { ...
26              
27             $userPassword = $ppr->as_rfc2307;
28              
29             =head1 DESCRIPTION
30              
31             An object of this class encapsulates a passphrase hashed using
32             the Microsoft LAN Manager hash function. 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             The hash algorithm can be used on up to fourteen Latin-1 characters of
37             passphrase. First the passphrase is folded to uppercase, and zero-padded
38             to fourteen bytes. Then it is split into two halves. Each seven-byte
39             half is used as a 56-bit DES key, to encrypt the fixed plaintext block
40             "KGS!@#$%". The eight-byte ciphertexts are concatenated to form the
41             sixteen-byte hash. There is no salt.
42              
43             Because the two halves of the passphrase are hashed separately, it
44             is possible to manipulate (e.g., crack) a half hash in isolation.
45             See L.
46              
47             I Don't even think about using this seriously. It's an
48             exceptionally weak design, flawed in pretty much every respect.
49              
50             =cut
51              
52             package Authen::Passphrase::LANManager;
53              
54 1     1   51514 { use 5.006; }
  1         4  
  1         49  
55 1     1   6 use warnings;
  1         1  
  1         37  
56 1     1   5 use strict;
  1         2  
  1         48  
57              
58 1     1   720 use Authen::Passphrase 0.003;
  1         23  
  1         28  
59 1     1   1433 use Authen::Passphrase::LANManagerHalf;
  1         3  
  1         38  
60 1     1   8 use Carp qw(croak);
  1         2  
  1         74  
61              
62             our $VERSION = "0.008";
63              
64 1     1   7 use parent "Authen::Passphrase";
  1         2  
  1         5  
65              
66             =head1 CONSTRUCTORS
67              
68             =over
69              
70             =item Authen::Passphrase::LANManager->new(ATTR => VALUE, ...)
71              
72             Generates a new passphrase recogniser object using the LAN Manager
73             hash algorithm. The following attributes may be given:
74              
75             =over
76              
77             =item B
78              
79             The hash, as a string of 16 bytes.
80              
81             =item B
82              
83             The hash, as a string of 32 hexadecimal digits.
84              
85             =item B
86              
87             A passphrase that will be accepted.
88              
89             =back
90              
91             Either the hash or the passphrase must be given.
92              
93             =cut
94              
95             sub new {
96 9     9 1 35 my $class = shift;
97 9         33 my $self = bless({}, $class);
98 9         16 my $hash;
99             my $passphrase;
100 9         29 while(@_) {
101 9         17 my $attr = shift;
102 9         16 my $value = shift;
103 9 100       37 if($attr eq "hash") {
    100          
    50          
104 3 50 33     21 croak "hash specified redundantly"
105             if defined($hash) || defined($passphrase);
106 3 50       14 $value =~ m#\A[\x00-\xff]{16}\z#
107             or croak "not a valid LAN Manager hash";
108 3         10 $hash = $value;
109             } elsif($attr eq "hash_hex") {
110 4 50 33     25 croak "hash specified redundantly"
111             if defined($hash) || defined($passphrase);
112 4 50       21 $value =~ m#\A[0-9A-Fa-f]{32}\z#
113             or croak "\"$value\" is not a valid ".
114             "hex LAN Manager hash";
115 4         26 $hash = pack("H*", $value);
116             } elsif($attr eq "passphrase") {
117 2 50 33     17 croak "passphrase specified redundantly"
118             if defined($hash) || defined($passphrase);
119 2 50       9 $self->_passphrase_acceptable($value)
120             or croak "can't accept a passphrase exceeding".
121             " fourteen bytes";
122 2         8 $passphrase = $value;
123             } else {
124 0         0 croak "unrecognised attribute `$attr'";
125             }
126             }
127 9 100       29 if(defined $passphrase) {
    50          
128 2         18 $self->{first_half} =
129             Authen::Passphrase::LANManagerHalf
130             ->new(passphrase => substr($passphrase, 0, 7));
131 2 100       15 $self->{second_half} =
132             Authen::Passphrase::LANManagerHalf
133             ->new(passphrase =>
134             length($passphrase) > 7 ?
135             substr($passphrase, 7, 7) :
136             "");
137             } elsif(defined $hash) {
138 7         44 $self->{first_half} = Authen::Passphrase::LANManagerHalf
139             ->new(hash => substr($hash, 0, 8));
140 7         30 $self->{second_half} = Authen::Passphrase::LANManagerHalf
141             ->new(hash => substr($hash, 8, 8));
142             } else {
143 0         0 croak "hash not specified";
144             }
145 9         29 return $self;
146             }
147              
148             =item Authen::Passphrase::LANManager->from_rfc2307(USERPASSWORD)
149              
150             Generates a LAN Manager passphrase recogniser from the supplied RFC2307
151             encoding. The string must consist of "B<{LANMAN}>" (or its synonym
152             "B<{LANM}>") followed by the hash in hexadecimal; case is ignored.
153              
154             =cut
155              
156             sub from_rfc2307 {
157 2     2 1 4 my($class, $userpassword) = @_;
158 2 50       14 if($userpassword =~ /\A\{(?i:lanm(?:an)?)\}/) {
159 2 50       11 $userpassword =~ /\A\{.*?\}([0-9a-fA-F]{32})\z/
160             or croak "malformed {LANMAN} data";
161 2         6 my $hash = $1;
162 2         7 return $class->new(hash_hex => $hash);
163             }
164 0         0 return $class->SUPER::from_rfc2307($userpassword);
165             }
166              
167             =back
168              
169             =head1 METHODS
170              
171             =over
172              
173             =item $ppr->hash
174              
175             Returns the hash value, as a string of 16 bytes.
176              
177             =cut
178              
179             sub hash {
180 20     20 1 823 my($self) = @_;
181 20         87 return $self->{first_half}->hash.$self->{second_half}->hash;
182             }
183              
184             =item $ppr->hash_hex
185              
186             Returns the hash value, as a string of 32 hexadecimal digits.
187              
188             =cut
189              
190             sub hash_hex {
191 14     14 1 3805 my($self) = @_;
192 14         32 return unpack("H*", $self->hash);
193             }
194              
195             =item $ppr->first_half
196              
197             Returns the hash of the first half of the passphrase, as an
198             L passphrase recogniser.
199              
200             =cut
201              
202             sub first_half {
203 5     5 1 11 my($self) = @_;
204 5         21 return $self->{first_half};
205             }
206              
207             =item $ppr->second_half
208              
209             Returns the hash of the second half of the passphrase, as an
210             L passphrase recogniser.
211              
212             =cut
213              
214             sub second_half {
215 5     5 1 12 my($self) = @_;
216 5         27 return $self->{second_half};
217             }
218              
219             =item $ppr->match(PASSPHRASE)
220              
221             =item $ppr->as_rfc2307
222              
223             These methods are part of the standard L interface.
224              
225             =cut
226              
227             sub _passphrase_acceptable {
228 27     27   49 my($self, $passphrase) = @_;
229 27         232 return $passphrase =~ /\A[\x00-\xff]{0,14}\z/;
230             }
231              
232             sub match {
233 25     25 1 9789 my($self, $passphrase) = @_;
234 25   66     52 return $self->_passphrase_acceptable($passphrase) &&
235             $self->{first_half}->match(substr($passphrase, 0, 7)) &&
236             $self->{second_half}->match(
237             length($passphrase) > 7 ?
238             substr($passphrase, 7, 7) :
239             "");
240             }
241              
242             sub as_rfc2307 {
243 5     5 1 9 my($self) = @_;
244 5         14 return "{LANMAN}".$self->hash_hex;
245             }
246              
247             =back
248              
249             =head1 SEE ALSO
250              
251             L,
252             L,
253             L
254              
255             =head1 AUTHOR
256              
257             Andrew Main (Zefram)
258              
259             =head1 COPYRIGHT
260              
261             Copyright (C) 2006, 2007, 2009, 2010, 2012
262             Andrew Main (Zefram)
263              
264             =head1 LICENSE
265              
266             This module is free software; you can redistribute it and/or modify it
267             under the same terms as Perl itself.
268              
269             =cut
270              
271             1;