view release on metacpan or search on metacpan
lib/Authen/NTLM/HTTP.pm view on Meta::CPAN
138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
'cChallenge'
=> 0
# a counter to stir the seed to generate random
},
$package
;
# number for the nonce
}
####################################################################
# http_negotiate creates a NTLM-over-HTTP tag line for NTLM #
# negotiate packet given the domain (from Win32::DomainName()) and #
# the workstation name (from $ENV{'COMPUTERNAME'} or #
# Win32::NodeName()) and the negotiation flags. #
####################################################################
sub
http_negotiate($$)
{
my
$self
=
shift
;
my
$flags
=
shift
;
my
$str
= encode_base64(
$self
->SUPER::negotiate_msg(
$flags
));
$str
=~ s/\s//g;
return
"Authorization: NTLM "
.
$str
;
}
###########################################################################
# http_parse_negotiate parses the NTLM-over-HTTP negotiate tag line and #
# return a list of NTLM Negotiation Flags, Server Network Domain and #
# Machine name of the client. #
###########################################################################
sub
http_parse_negotiate($$)
{
my
(
$self
,
$pkt
) =
@_
;
$pkt
=~ s/Authorization: NTLM //;
my
$str
= decode_base64(
$pkt
);
return
$self
->SUPER::parse_negotiate(
$str
);
}
####################################################################
# http_challenge composes the NTLM-over-HTTP challenge tag line. It#
# takes NTLM Negotiation Flags as an argument. #
####################################################################
sub
http_challenge($$)
{
my
$self
=
$_
[0];
my
$flags
=
$_
[1];
my
$nonce
=
undef
;
my
$str
;
$nonce
=
$_
[2]
if
@_
== 3;
if
(
defined
$nonce
) {
$str
= encode_base64(
$self
->SUPER::challenge_msg(
$flags
,
$nonce
));
}
else
{
lib/Authen/NTLM/HTTP.pm view on Meta::CPAN
202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
return
$self
->SUPER::parse_challenge(
$str
);
}
###########################################################################
# http_auth creates the NTLM-over-HTTP response to an NTLM challenge from #
# the server. It takes 2 arguments: $nonce obtained from parse_challenge #
# and NTLM Negotiation Flags. This function ASSUMEs the input of user #
# domain, user name and workstation name are in ASCII format and not in #
# UNICODE format. #
###########################################################################
sub
http_auth($$$)
{
my
$self
=
shift
;
my
$nonce
=
shift
;
my
$flags
=
shift
;
my
$str
= encode_base64(
$self
->SUPER::auth_msg(
$nonce
,
$flags
));
$str
=~ s/\s//g;;
if
(
$self
->{
'type'
} eq NTLMSSP_HTTP_PROXY) {
return
"Proxy-Authorization: NTLM "
.
$str
;
}
else
{
return
"Authorization: NTLM "
.
$str
;
}
}
###########################################################################
# http_parse_auth parses the NTLM-over-HTTP authentication tag line and #
# return a list of NTLM Negotiation Flags, LM response, NT response, User #
# Domain, User Name, User Machine Name and Session Key. #
###########################################################################
sub
http_parse_auth($$)
{
my
(
$self
,
$pkt
) =
@_
;
if
(
$self
->{
'type'
} eq NTLMSSP_HTTP_PROXY) {
$pkt
=~ s/Proxy-Authorization: NTLM //;
}
else
{
$pkt
=~ s/Authorization: NTLM //;
}
my
$str
= decode_base64(
$pkt
);
return
$self
->SUPER::parse_auth(
$str
);
lib/Authen/NTLM/HTTP/Base.pm view on Meta::CPAN
105106107108109110111112113114115116117118119120121122123124125126127# get back session key, LUID
# request non-ntsession key
sub
lm_hash($);
sub
nt_hash($);
sub
calc_resp($$);
#########################################################################
# Constructor to initialize authentication related information. In this #
# version, we assume NTLM as the authentication scheme of choice. #
# The constructor takes the class name, LM hash of the client password #
# and the LM hash of the client password as arguments. #
#########################################################################
sub
new_client {
usage(
"new_client Authen::NTLM(\$lm_hpw, \$nt_hpw\) or\nnew_client Authen::NTLM\(\$lm_hpw, \$nt_hpw, \$user, \$user_domain, \$domain, \$machine\)"
)
unless
@_
== 3 or
@_
== 7;
my
(
$package
,
$lm_hpw
,
$nt_hpw
,
$user
,
$user_domain
,
$domain
,
$machine
) =
@_
;
lib/Authen/NTLM/HTTP/Base.pm view on Meta::CPAN
160161162163164165166167168169170171172173174175176177178179180
bless
{
'domain'
=>
$domain
,
'cChallenge'
=> 0
# a counter to stir the seed to generate random
},
$package
;
# number for the nonce
}
##########################################################################
# lm_hash calculates the LM hash to be used to calculate the LM response #
# It takes a password and return the 21 bytes LM password hash. #
##########################################################################
sub
lm_hash($)
{
my
(
$passwd
) =
@_
;
my
$cipher1
;
my
$cipher2
;
my
$magic
=
pack
(
"H16"
,
"4B47532140232425"
);
# magical string to be encrypted for the LM password hash
while
(
length
(
$passwd
) < 14) {
$passwd
.=
chr
(0);
}
my
$lm_pw
=
substr
(
$passwd
, 0, 14);
$lm_pw
=
uc
(
$lm_pw
);
# change the password to upper case
lib/Authen/NTLM/HTTP/Base.pm view on Meta::CPAN
187188189190191192193194195196197198199200201202203204205206207
$cipher1
= Crypt::DES->new(
substr
(
$key
, 0, 8));
$cipher2
= Crypt::DES->new(
substr
(
$key
, 8, 8));
}
return
$cipher1
->encrypt(
$magic
) .
$cipher2
->encrypt(
$magic
) .
pack
(
"H10"
,
"0000000000"
);
}
##########################################################################
# nt_hash calculates the NT hash to be used to calculate the NT response #
# It takes a password and return the 21 bytes NT password hash. #
##########################################################################
sub
nt_hash($)
{
my
(
$passwd
) =
@_
;
my
$nt_pw
= unicodify(
$passwd
);
my
$nt_hpw
;
if
(
$Authen::NTLM::HTTP::Base::PurePerl
== 1) {
$nt_hpw
= md4(
$nt_pw
) .
pack
(
"H10"
,
"0000000000"
);
}
else
{
my
$md4
= new Digest::MD4;
$md4
->add(
$nt_pw
);
lib/Authen/NTLM/HTTP/Base.pm view on Meta::CPAN
209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
}
return
$nt_hpw
;
}
####################################################################
# negotiate_msg creates the NTLM negotiate packet given the domain #
# (from Win32::DomainName()) and the workstation name (from #
# $ENV{'COMPUTERNAME'} or Win32::NodeName()) and the negotiation #
# flags. #
####################################################################
sub
negotiate_msg($$)
{
my
$self
=
$_
[0];
my
$flags
=
pack
(
"V"
,
$_
[1]);
my
$domain
=
$self
->{
'domain'
};
my
$machine
=
$self
->{
'machine'
};
my
$msg
= NTLMSSP_SIGNATURE .
chr
(0);
$msg
.=
pack
(
"V"
, NTLMSSP_NEGOTIATE);
$msg
.=
$flags
;
my
$offset
=
length
(
$msg
) + 8*2;
$msg
.=
pack
(
"v"
,
length
(
$domain
)) .
pack
(
"v"
,
length
(
$domain
)) .
pack
(
"V"
,
$offset
+
length
(
$machine
));
$msg
.=
pack
(
"v"
,
length
(
$machine
)) .
pack
(
"v"
,
length
(
$machine
)) .
pack
(
"V"
,
$offset
);
$msg
.=
$machine
.
$domain
;
return
$msg
;
}
###########################################################################
# parse_negotiate parses the NTLM negotiate and return a list of NTLM #
# Negotiation Flags, Server Network Domain and Machine name of the client.#
###########################################################################
sub
parse_negotiate($$)
{
my
(
$self
,
$pkt
) =
@_
;
substr
(
$pkt
, 0, 8) eq (NTLMSSP_SIGNATURE .
chr
(0)) or usage
"NTLM Negotiate doesn't contain NTLMSSP_SIGNATURE!\n"
;
my
$type
= GetInt32(
substr
(
$pkt
, 8));
$type
== NTLMSSP_NEGOTIATE or usage
"Not an NTLM Negotiate Message!\n"
;
my
$flags
= GetInt32(
substr
(
$pkt
, 12));
my
$domain
= GetString(
$pkt
, 16);
my
$machine
= GetString(
$pkt
, 24);
return
(
$flags
,
$domain
,
$machine
);
}
####################################################################
# challenge_msg composes the NTLM challenge message. It takes NTLM #
# Negotiation Flags as an argument. #
####################################################################
sub
challenge_msg($$)
{
my
$self
=
$_
[0];
my
$flags
=
pack
(
"V"
,
$_
[1]);
my
$nonce
=
undef
;
$nonce
=
$_
[2]
if
@_
== 3;
my
$domain
=
$self
->{
'domain'
};
my
$msg
= NTLMSSP_SIGNATURE .
chr
(0);
$self
->{
'cChallenge'
} += 0x100;
$msg
.=
pack
(
"V"
, NTLMSSP_CHALLENGE);
if
(
$_
[1] & NTLMSSP_TARGET_TYPE_DOMAIN) {
lib/Authen/NTLM/HTTP/Base.pm view on Meta::CPAN
345346347348349350351352353354355356357358359360361362363364365
return
unpack
(
"v"
,
substr
(
$str
, 0, 2));
}
###########################################################################
# auth_msg creates the NTLM response to an NTLM challenge from the #
# server. It takes 2 arguments: $nonce obtained from parse_challenge and #
# NTLM Negotiation Flags. #
# This function ASSUMEs the input of user domain, user name and #
# workstation name are in ASCII format and not in UNICODE format. #
###########################################################################
sub
auth_msg($$$)
{
my
(
$self
,
$nonce
) =
@_
;
my
$session_key
= session_key();
my
$user_domain
=
$self
->{
'user_domain'
};
my
$username
=
$self
->{
'user'
};
my
$machine
=
$self
->{
'machine'
};
my
$lm_resp
= calc_resp(
$self
->{
'lm_hpw'
},
$nonce
);
my
$nt_resp
= calc_resp(
$self
->{
'nt_hpw'
},
$nonce
);
my
$flags
=
pack
(
"V"
,
$_
[2]);
my
$msg
= NTLMSSP_SIGNATURE .
chr
(0);
lib/Authen/NTLM/HTTP/Base.pm view on Meta::CPAN
384385386387388389390391392393394395396397398399400401402403404
$msg
.=
$flags
.
$user_domain
.
$username
.
$machine
.
$lm_resp
.
$nt_resp
.
$session_key
;
}
return
$msg
;
}
###########################################################################
# parse_auth parses the NTLM authentication and return a list of NTLM #
# Negotiation Flags, LM response, NT response, User Domain, User Name, #
# User Machine Name and Session Key. #
###########################################################################
sub
parse_auth($$)
{
my
(
$self
,
$pkt
) =
@_
;
substr
(
$pkt
, 0, 8) eq (NTLMSSP_SIGNATURE .
chr
(0)) or usage
"NTLM Authentication doesn't contain NTLMSSP_SIGNATURE!\n"
;
my
$type
= GetInt32(
substr
(
$pkt
, 8));
$type
== NTLMSSP_AUTH or usage
"Not an NTLM Authetication Message!\n"
;
my
$lm_resp
= GetString(
$pkt
, 12);
my
$nt_resp
= GetString(
$pkt
, 20);
my
$flags
= GetInt32(
substr
(
$pkt
, 60));
my
$user_domain
= GetString(
$pkt
, 28);
$user_domain
= un_unicodify(
$user_domain
)
if
$flags
& NTLMSSP_NEGOTIATE_UNICODE;
lib/Authen/NTLM/HTTP/Base.pm view on Meta::CPAN
416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457#####################################################################
sub
session_key
{
return
""
;
}
#######################################################################
# compute_nonce computes the 8-bytes nonce to be included in server's
# NTLM challenge packet.
#######################################################################
sub
compute_nonce($)
{
my
(
$cChallenge
) =
@_
;
my
@SysTime
= UNIXTimeToFILETIME(
$cChallenge
,
time
);
my
$Seed
= ((
$SysTime
[1] + 1) << 0) |
((
$SysTime
[2] + 0) << 8) |
((
$SysTime
[3] - 1) << 16) |
((
$SysTime
[4] + 0) << 24);
srand
$Seed
;
my
$ulChallenge0
=
rand
(2**16)+
rand
(2**32);
my
$ulChallenge1
=
rand
(2**16)+
rand
(2**32);
my
$ulNegate
=
rand
(2**16)+
rand
(2**32);
if
(
$ulNegate
& 0x1) {
$ulChallenge0
|= 0x80000000;}
if
(
$ulNegate
& 0x2) {
$ulChallenge1
|= 0x80000000;}
return
pack
(
"V"
,
$ulChallenge0
) .
pack
(
"V"
,
$ulChallenge1
);
}
#########################################################################
# convert_key converts a 7-bytes key to an 8-bytes key based on an
# algorithm.
#########################################################################
sub
convert_key($) {
my
(
$in_key
) =
@_
;
my
@byte
;
my
$result
=
""
;
usage(
"exactly 7-bytes key"
)
unless
length
(
$in_key
) == 7;
$byte
[0] =
substr
(
$in_key
, 0, 1);
$byte
[1] =
chr
(((
ord
(
substr
(
$in_key
, 0, 1)) << 7) & 0xFF) | (
ord
(
substr
(
$in_key
, 1, 1)) >> 1));
$byte
[2] =
chr
(((
ord
(
substr
(
$in_key
, 1, 1)) << 6) & 0xFF) | (
ord
(
substr
(
$in_key
, 2, 1)) >> 2));
$byte
[3] =
chr
(((
ord
(
substr
(
$in_key
, 2, 1)) << 5) & 0xFF) | (
ord
(
substr
(
$in_key
, 3, 1)) >> 3));
$byte
[4] =
chr
(((
ord
(
substr
(
$in_key
, 3, 1)) << 4) & 0xFF) | (
ord
(
substr
(
$in_key
, 4, 1)) >> 4));
$byte
[5] =
chr
(((
ord
(
substr
(
$in_key
, 4, 1)) << 3) & 0xFF) | (
ord
(
substr
(
$in_key
, 5, 1)) >> 5));
lib/Authen/NTLM/HTTP/Base.pm view on Meta::CPAN
461462463464465466467468469470471472473474475476477478479480481
$byte
[
$i
] = set_odd_parity(
$byte
[
$i
]);
$result
.=
$byte
[
$i
];
}
return
$result
;
}
##########################################################################
# set_odd_parity turns one-byte into odd parity. Odd parity means that
# a number in binary has odd number of 1's.
##########################################################################
sub
set_odd_parity($)
{
my
(
$byte
) =
@_
;
my
$parity
= 0;
my
$ordbyte
;
usage(
"single byte input only"
)
unless
length
(
$byte
) == 1;
$ordbyte
=
ord
(
$byte
);
for
(
my
$i
= 0;
$i
< 8; ++
$i
) {
if
(
$ordbyte
& 0x01) {++
$parity
;}
$ordbyte
>>= 1;
}
lib/Authen/NTLM/HTTP/Base.pm view on Meta::CPAN
488489490491492493494495496497498499500501502503504505506507508
$ordbyte
|= 0x01;
}
}
return
chr
(
$ordbyte
);
}
###########################################################################
# calc_resp computes the 24-bytes NTLM response based on the password hash
# and the nonce.
###########################################################################
sub
calc_resp($$)
{
my
(
$key
,
$nonce
) =
@_
;
my
$cipher1
;
my
$cipher2
;
my
$cipher3
;
usage(
"key must be 21-bytes long"
)
unless
length
(
$key
) == 21;
usage(
"nonce must be 8-bytes long"
)
unless
length
(
$nonce
) == 8;
if
(
$Authen::NTLM::HTTP::Base::PurePerl
) {
$cipher1
= Crypt::DES_PP->new(convert_key(
substr
(
$key
, 0, 7)));
$cipher2
= Crypt::DES_PP->new(convert_key(
substr
(
$key
, 7, 7)));
lib/Authen/NTLM/HTTP/Base.pm view on Meta::CPAN
531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
for
(
$i
= 0;
$i
<
length
(
$str
) / 2; ++
$i
) {
$newstr
.=
substr
(
$str
, 2
*$i
, 1);
}
return
$newstr
;
}
#########################################################################
# unicodify takes an ASCII string and turns it into a unicode string.
#########################################################################
sub
unicodify($)
{
my
(
$str
) =
@_
;
my
$newstr
=
""
;
my
$i
;
for
(
$i
= 0;
$i
<
length
(
$str
); ++
$i
) {
$newstr
.=
substr
(
$str
,
$i
, 1) .
chr
(0);
}
return
$newstr
;
}
##########################################################################
# UNIXTimeToFILETIME converts UNIX time_t to 64-bit FILETIME format used
# in win32 platforms. It returns two 32-bit integer. The first one is
# the upper 32-bit and the second one is the lower 32-bit. The result is
# adjusted by cChallenge as in NTLM spec. For those of you who want to
# use this function for actual use, please remove the cChallenge variable.
##########################################################################
sub
UNIXTimeToFILETIME($$)
{
my
(
$cChallenge
,
$time
) =
@_
;
$time
=
$time
* 10000000 + 11644473600000000 +
$cChallenge
;
my
$uppertime
=
$time
/ (2**32);
my
$lowertime
=
$time
- floor(
$uppertime
) * 2**32;
return
(
$lowertime
& 0x000000ff,
$lowertime
& 0x0000ff00,
$lowertime
& 0x00ff0000,
$lowertime
& 0xff000000,
$uppertime
& 0x000000ff,