Authen-Perl-NTLM
view release on metacpan or search on metacpan
lib/Authen/Perl/NTLM.pm view on Meta::CPAN
use constant NTLMSSP_REQUEST_INIT_RESPONSE => 0x00100000;
# get back session key, LUID
use constant NTLMSSP_REQUEST_ACCEPT_RESPONSE => 0x00200000;
# request non-ntsession key
use constant NTLMSSP_REQUEST_NON_NT_SESSION_KEY => 0x00400000;
use constant NTLMSSP_NEGOTIATE_TARGET_INFO => 0x00800000;
use constant NTLMSSP_NEGOTIATE_128 => 0x20000000;
use constant NTLMSSP_NEGOTIATE_KEY_EXCH => 0x40000000;
use constant NTLMSSP_NEGOTIATE_80000000 => 0x80000000;
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::Perl::NTLM(\$lm_hpw, \$nt_hpw\) or\nnew_client Authen::Perl::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/Perl/NTLM.pm view on Meta::CPAN
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/Perl/NTLM.pm view on Meta::CPAN
$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::Perl::NTLM::PurePerl == 1) {
$nt_hpw = md4($nt_pw) . pack("H10", "0000000000");
}
else {
my $md4 = new Digest::MD4;
$md4->add($nt_pw);
lib/Authen/Perl/NTLM.pm view on Meta::CPAN
}
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;
}
####################################################################
# challenge_msg composes the NTLM challenge message. It takes NTLM #
# Negotiation Flags as an argument. #
####################################################################
sub challenge_msg($)
{
my ($self) = @_;
my $flags = pack("V", $_[1]);
my $domain = $self->{'domain'};
my $msg = NTLMSSP_SIGNATURE . chr(0);
$self->{'cChallenge'} += 0x100;
$msg .= pack("V", NTLMSSP_CHALLENGE);
$msg .= pack("v", length($domain)) . pack("v", length($domain)) . pack("V", 48);
$msg .= $flags;
$msg .= compute_nonce($self->{'cChallenge'});
lib/Authen/Perl/NTLM.pm view on Meta::CPAN
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/Perl/NTLM.pm view on Meta::CPAN
#####################################################################
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/Perl/NTLM.pm view on Meta::CPAN
$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/Perl/NTLM.pm view on Meta::CPAN
$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::Perl::NTLM::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/Perl/NTLM.pm view on Meta::CPAN
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,
( run in 0.285 second using v1.01-cache-2.11-cpan-65fba6d93b7 )