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