alexandria-plsql-utils/ora/ntlm_util_pkg.pkb
2015-02-20 19:43:42 +01:00

939 lines
36 KiB
Plaintext
Executable File

create or replace package body ntlm_util_pkg
as
/*
Purpose: Package implements NTLM authentication protocol
Remarks: A PL/SQL port of the Python code at http://code.google.com/p/python-ntlm/
Who Date Description
------ ---------- --------------------------------
FDL 11.05.2011 Created
MBR 11.05.2011 Miscellaneous contributions
*/
m_NTLM_NegotiateUnicode constant raw(4) := utl_raw.cast_from_binary_integer(1); --'00000001';
m_NTLM_NegotiateOEM constant raw(4) := utl_raw.cast_from_binary_integer(2); --'00000002';
m_NTLM_RequestTarget constant raw(4) := utl_raw.cast_from_binary_integer(4); --'00000004';
m_NTLM_Unknown9 constant raw(4) := utl_raw.cast_from_binary_integer(8); -- '00000008';
m_NTLM_NegotiateSign constant raw(4) := utl_raw.cast_from_binary_integer(16); --'00000010';
m_NTLM_NegotiateSeal constant raw(4) := utl_raw.cast_from_binary_integer(32); --'00000020';
m_NTLM_NegotiateDatagram constant raw(4) := utl_raw.cast_from_binary_integer(64); --'00000040';
m_NTLM_NegotiateLanManagerKey constant raw(4) := utl_raw.cast_from_binary_integer(128); --'00000080';
m_NTLM_Unknown8 constant raw(4) := utl_raw.cast_from_binary_integer(256); --'00000100';
m_NTLM_NegotiateNTLM constant raw(4) := utl_raw.cast_from_binary_integer(512); --'00000200';
m_NTLM_NegotiateNTOnly constant raw(4) := utl_raw.cast_from_binary_integer(1024); --'00000400';
m_NTLM_Anonymous constant raw(4) := utl_raw.cast_from_binary_integer(2048); --'00000800';
m_NTLM_NegotiateOemDomainSuppl constant raw(4) := utl_raw.cast_from_binary_integer(4096); --'00001000';
m_NTLM_NegotiateOemWorkstation constant raw(4) := utl_raw.cast_from_binary_integer(8192); --'00002000';
m_NTLM_Unknown6 constant raw(4) := utl_raw.cast_from_binary_integer(16384); --'00004000';
m_NTLM_NegotiateAlwaysSign constant raw(4) := utl_raw.cast_from_binary_integer(32768); --'00008000';
m_NTLM_TargetTypeDomain constant raw(4) := utl_raw.cast_from_binary_integer(65536); --'00010000';
m_NTLM_TargetTypeServer constant raw(4) := utl_raw.cast_from_binary_integer(131072); --'00020000';
m_NTLM_TargetTypeShare constant raw(4) := utl_raw.cast_from_binary_integer(262144); --'00040000';
m_NTLM_NegotiateExtendedSec constant raw(4) := utl_raw.cast_from_binary_integer(524288); --'00080000';
m_NTLM_NegotiateIdentify constant raw(4) := utl_raw.cast_from_binary_integer(1048576); --'00100000';
m_NTLM_Unknown5 constant raw(4) := utl_raw.cast_from_binary_integer(2097152); --'00200000';
m_NTLM_RequestNonNTSessionKey constant raw(4) := utl_raw.cast_from_binary_integer(4194304); --'00400000';
m_NTLM_NegotiateTargetInfo constant raw(4) := utl_raw.cast_from_binary_integer(8388608); --'00800000';
m_NTLM_Unknown4 constant raw(4) := utl_raw.cast_from_binary_integer(16777216); --'01000000';
m_NTLM_NegotiateVersion constant raw(4) := utl_raw.cast_from_binary_integer(33554432); --'02000000';
m_NTLM_Unknown3 constant raw(4) := utl_raw.cast_from_binary_integer(67108864); --'04000000';
m_NTLM_Unknown2 constant raw(4) := utl_raw.cast_from_binary_integer(134217728); --'08000000';
m_NTLM_Unknown1 constant raw(4) := utl_raw.cast_from_binary_integer(268435456); --'10000000';
m_NTLM_Negotiate128 constant raw(4) := utl_raw.cast_from_binary_integer(536870912); --'20000000';
m_NTLM_NegotiateKeyExchange constant raw(4) := utl_raw.cast_from_binary_integer(1073741824); --'40000000';
m_NTLM_Negotiate56 constant raw(4) := utl_raw.cast_from_binary_integer(128, utl_raw.little_endian); -- '80000000'; -- using little endian instead of big beacuse utl_raw.cast_from_binary_integer(2147483648) results in overflow
function bit_or_multi (p_raw1 in raw,
p_raw2 in raw,
p_raw3 in raw := null,
p_raw4 in raw := null,
p_raw5 in raw := null,
p_raw6 in raw := null,
p_raw7 in raw := null,
p_raw8 in raw := null,
p_raw9 in raw := null,
p_raw10 in raw := null,
p_raw11 in raw := null,
p_raw12 in raw := null) return raw
as
l_returnvalue raw(5000);
begin
/*
Purpose: Perform bitwise OR operations on multiple RAWs
Remarks:
Who Date Description
------ ---------- --------------------------------
FDL 12.05.2011 Created
*/
l_returnvalue := utl_raw.bit_or(p_raw1, p_raw2);
if p_raw3 is not null then
l_returnvalue := utl_raw.bit_or(l_returnvalue, p_raw3);
end if;
if p_raw4 is not null then
l_returnvalue := utl_raw.bit_or(l_returnvalue, p_raw4);
end if;
if p_raw5 is not null then
l_returnvalue := utl_raw.bit_or(l_returnvalue, p_raw5);
end if;
if p_raw6 is not null then
l_returnvalue := utl_raw.bit_or(l_returnvalue, p_raw6);
end if;
if p_raw7 is not null then
l_returnvalue := utl_raw.bit_or(l_returnvalue, p_raw7);
end if;
if p_raw8 is not null then
l_returnvalue := utl_raw.bit_or(l_returnvalue, p_raw8);
end if;
if p_raw9 is not null then
l_returnvalue := utl_raw.bit_or(l_returnvalue, p_raw9);
end if;
if p_raw10 is not null then
l_returnvalue := utl_raw.bit_or(l_returnvalue, p_raw10);
end if;
if p_raw11 is not null then
l_returnvalue := utl_raw.bit_or(l_returnvalue, p_raw11);
end if;
if p_raw12 is not null then
l_returnvalue := utl_raw.bit_or(l_returnvalue, p_raw12);
end if;
return l_returnvalue;
end bit_or_multi;
function int_to_raw_little_endian (p_number in number,
p_length in number) return raw
as
l_returnvalue raw(5000);
begin
/*
Purpose: Returning little endian value of integer of specified length
Remarks:
Who Date Description
------ ---------- --------------------------------
FDL 12.05.2011 Created
*/
l_returnvalue := utl_raw.substr(utl_raw.cast_from_binary_integer(p_number, utl_raw.little_endian), 1, p_length);
return l_returnvalue;
end int_to_raw_little_endian;
function get_workstation_name return varchar2
as
l_returnvalue string_util_pkg.t_max_db_varchar2;
begin
/*
Purpose: Get workstation name for executing user
Remarks:
Who Date Description
------ ---------- --------------------------------
FDL 12.05.2011 Created
*/
--l_returnvalue := sys_context('USERENV', 'TERMINAL');
l_returnvalue := upper(sys_context('USERENV', 'server_host'));
return l_returnvalue;
end get_workstation_name;
procedure parse_username (p_username in varchar2,
p_domain out varchar2,
p_user out varchar2)
as
begin
/*
Purpose: Parse username as domain\user
Remarks:
Who Date Description
------ ---------- --------------------------------
FDL 12.05.2011 Created
*/
if instr(p_username, '\') > 0 then
p_domain := upper (substr(p_username, 1, instr(p_username, '\')-1));
p_user := substr(p_username, instr(p_username, '\') + 1, length(p_username) - instr(p_username, '\') + 1);
else
p_domain := null;
p_user := p_username;
end if;
end parse_username;
function get_negotiate_message (p_username in varchar2) return varchar2
as
l_body_length number;
l_payload_start number;
l_domain_str varchar2(500);
l_user_str varchar2(500);
--l_protocol raw(8);
l_protocol raw(16);
l_workstation raw(16);
l_domain raw(16);
l_type raw(4);
l_flags raw(4);
l_workstation_length raw(2);
l_workstation_max_length raw(2);
l_workstation_buffer_offset raw(4);
l_domain_length raw(2);
l_domain_max_length raw(2);
l_domain_buffer_offset raw(4);
l_product_major_version raw(1);
l_product_minor_version raw(1);
l_product_build raw(2);
l_version_reserved1 raw(1);
l_version_reserved2 raw(1);
l_version_reserved3 raw(1);
l_ntlm_revision_current raw(1);
l_return raw(100);
l_returnvalue string_util_pkg.t_max_pl_varchar2;
begin
/*
Purpose: Get negotiate message
Remarks:
Who Date Description
------ ---------- --------------------------------
FDL 12.05.2011 Created
*/
l_body_length := 40;
l_payload_start := l_body_length;
--l_protocol := utl_raw.cast_to_raw('NTLMSSP' || chr(256));
l_protocol := utl_raw.cast_to_raw('NTLMSSP' || chr(0));
l_type := int_to_raw_little_endian(1, 4); --- Type 1
l_flags := bit_or_multi (m_NTLM_NegotiateUnicode,
m_NTLM_NegotiateOEM,
m_NTLM_RequestTarget,
m_NTLM_NegotiateNTLM,
m_NTLM_NegotiateOemDomainSuppl,
m_NTLM_NegotiateOemWorkstation,
m_NTLM_NegotiateAlwaysSign,
m_NTLM_NegotiateExtendedSec,
m_NTLM_NegotiateVersion,
m_NTLM_Negotiate128,
m_NTLM_Negotiate56);
-- need to convert flags to little endian
l_flags := int_to_raw_little_endian (utl_raw.cast_to_binary_integer(l_flags), 4);
l_workstation := utl_raw.cast_to_raw(get_workstation_name);
parse_username (p_username, l_domain_str, l_user_str);
l_domain := utl_raw.cast_to_raw(l_domain_str);
l_workstation_length := int_to_raw_little_endian (utl_raw.length(l_workstation), 2);
l_workstation_max_length := int_to_raw_little_endian (utl_raw.length(l_workstation), 2);
l_workstation_buffer_offset := int_to_raw_little_endian (l_payload_start, 4);
l_payload_start := l_payload_start + utl_raw.length (l_workstation);
l_domain_length := int_to_raw_little_endian (utl_raw.length(l_domain), 2);
l_domain_max_length := int_to_raw_little_endian (utl_raw.length(l_domain), 2);
l_domain_buffer_offset := int_to_raw_little_endian (l_payload_start, 4);
l_payload_start := l_payload_start + utl_raw.length(l_domain);
l_product_major_version := int_to_raw_little_endian (5, 1);
l_product_minor_version := int_to_raw_little_endian (1, 1);
l_product_build := int_to_raw_little_endian (2600, 2);
l_version_reserved1 := int_to_raw_little_endian (0, 1);
l_version_reserved2 := int_to_raw_little_endian (0, 1);
l_version_reserved3 := int_to_raw_little_endian (0, 1);
l_ntlm_revision_current := int_to_raw_little_endian (15, 1);
l_return := utl_raw.concat(l_protocol,
l_type,
l_flags,
l_domain_length,
l_domain_max_length,
l_domain_buffer_offset,
l_workstation_length,
l_workstation_max_length,
l_workstation_buffer_offset,
l_product_major_version,
l_product_minor_version,
l_product_build);
l_return := utl_raw.concat(l_return,
l_version_reserved1,
l_version_reserved2,
l_version_reserved3,
l_ntlm_revision_current);
if utl_raw.length (l_return) <> l_body_length then
raise_application_error(-20000, 'Length of negotiate message is ' || utl_raw.length(l_return) || ' (should be ' || l_body_length ||')');
end if;
l_return := utl_raw.concat (l_return, l_workstation, l_domain);
l_returnvalue := utl_raw.cast_to_varchar2(l_return);
l_returnvalue := encode_util_pkg.str_to_base64(l_returnvalue);
l_returnvalue := replace(l_returnvalue, chr(13) || chr(10), '');
return l_returnvalue;
end get_negotiate_message;
procedure parse_challenge_message (p_message2 in varchar2,
p_server_challenge out raw,
p_negotiate_flags out raw)
as
l_message string_util_pkg.t_max_pl_varchar2;
l_msg raw(4000);
l_signature raw(8);
l_msg_type raw(4);
l_target_name_length raw(2);
l_target_name_maxlength raw(2);
l_target_name_offset raw(4);
l_target_name raw(100);
l_negotiate_flags raw(4);
l_server_challenge raw(8);
l_reserved raw(8);
l_target_info_length raw(2);
l_target_info_maxlength raw(2);
l_target_info_offset raw(4);
l_target_info raw(100);
begin
/*
Purpose: Parse challenge message from server
Remarks:
Who Date Description
------ ---------- --------------------------------
FDL 31.05.2011 Created
*/
l_msg := utl_encode.base64_decode(utl_raw.cast_to_raw(p_message2));
l_signature := utl_raw.substr(l_msg, 1, 8);
l_msg_type := utl_raw.substr(l_msg, 9, 4);
l_target_name_length := utl_raw.substr(l_msg, 13, 2);
l_target_name_maxlength := utl_raw.substr(l_msg, 15, 2);
l_target_name_offset := utl_raw.substr(l_msg, 17, 4);
-- using reverse because the flags are in little endian order?
l_negotiate_flags := utl_raw.reverse(utl_raw.substr(l_msg, 21, 4));
--l_negotiate_flags := utl_raw.substr(l_msg, 21, 4);
l_server_challenge := utl_raw.substr(l_msg, 25, 8);
l_reserved := utl_raw.substr(l_msg, 33, 8);
l_target_info_length := utl_raw.substr(l_msg, 41, 2);
l_target_info_maxlength := utl_raw.substr(l_msg, 43, 2);
l_target_info_offset := utl_raw.substr(l_msg, 45, 4);
debug_pkg.printf('Signature: "%1", Message Type: "%2", Negotiate Flags: "%3", Server Challenge: "%4"', l_signature, l_msg_type, l_negotiate_flags, l_server_challenge);
p_server_challenge := l_server_challenge;
p_negotiate_flags := l_negotiate_flags;
end parse_challenge_message;
function create_des_key (p_bytes in raw) return raw
as
l_byte1 raw(1);
l_byte2 raw(1);
l_byte3 raw(1);
l_byte4 raw(1);
l_byte5 raw(1);
l_byte6 raw(1);
l_byte7 raw(1);
l_byte8 raw(1);
l_returnvalue raw(8);
function raw2num(p_raw in raw) return number
is
begin
return utl_raw.cast_to_binary_integer(p_raw, utl_raw.little_endian);
end;
function get_8bit_mask return raw
as
begin
return utl_raw.cast_from_binary_integer(255, utl_raw.little_endian);
end get_8bit_mask;
begin
/*
Purpose: create an 8-byte DES key from a 7-byte key
Remarks: insert a null bit after every seven bits (so 1010100 becomes 01010100)
Who Date Description
------ ---------- --------------------------------
MBR 03.06.2011 Created
*/
raw_util_pkg.set_endianness (utl_raw.little_endian);
--debug_pkg.printf('input byte 1 = %1', raw2num(utl_raw.substr(p_bytes, 1, 1)));
--debug_pkg.printf('input byte 2 = %1', raw2num(utl_raw.substr(p_bytes, 2, 1)));
--debug_pkg.printf('input byte 3 = %1', raw2num(utl_raw.substr(p_bytes, 3, 1)));
--debug_pkg.printf('input byte 4 = %1', raw2num(utl_raw.substr(p_bytes, 4, 1)));
--debug_pkg.printf('input byte 5 = %1', raw2num(utl_raw.substr(p_bytes, 5, 1)));
--debug_pkg.printf('input byte 6 = %1', raw2num(utl_raw.substr(p_bytes, 6, 1)));
--debug_pkg.printf('input byte 7 = %1', raw2num(utl_raw.substr(p_bytes, 7, 1)));
l_byte1 := utl_raw.substr(p_bytes, 1, 1);
l_byte2 := utl_raw.substr( utl_raw.bit_or(utl_raw.bit_and(raw_util_pkg.bit_shift_left_raw (utl_raw.substr(p_bytes, 1, 1), 7), get_8bit_mask), raw_util_pkg.bit_shift_right_raw (utl_raw.substr(p_bytes, 2, 1), 1)) , 1, 1);
l_byte3 := utl_raw.substr( utl_raw.bit_or(utl_raw.bit_and(raw_util_pkg.bit_shift_left_raw (utl_raw.substr(p_bytes, 2, 1), 6), get_8bit_mask), raw_util_pkg.bit_shift_right_raw (utl_raw.substr(p_bytes, 3, 1), 2)) , 1, 1);
l_byte4 := utl_raw.substr( utl_raw.bit_or(utl_raw.bit_and(raw_util_pkg.bit_shift_left_raw (utl_raw.substr(p_bytes, 3, 1), 5), get_8bit_mask), raw_util_pkg.bit_shift_right_raw (utl_raw.substr(p_bytes, 4, 1), 3)) , 1, 1);
l_byte5 := utl_raw.substr( utl_raw.bit_or(utl_raw.bit_and(raw_util_pkg.bit_shift_left_raw (utl_raw.substr(p_bytes, 4, 1), 4), get_8bit_mask), raw_util_pkg.bit_shift_right_raw (utl_raw.substr(p_bytes, 5, 1), 4)) , 1, 1);
l_byte6 := utl_raw.substr( utl_raw.bit_or(utl_raw.bit_and(raw_util_pkg.bit_shift_left_raw (utl_raw.substr(p_bytes, 5, 1), 3), get_8bit_mask), raw_util_pkg.bit_shift_right_raw (utl_raw.substr(p_bytes, 6, 1), 5)) , 1, 1);
l_byte7 := utl_raw.substr( utl_raw.bit_or(utl_raw.bit_and(raw_util_pkg.bit_shift_left_raw (utl_raw.substr(p_bytes, 6, 1), 2), get_8bit_mask), raw_util_pkg.bit_shift_right_raw (utl_raw.substr(p_bytes, 7, 1), 6)) , 1, 1);
l_byte8 := utl_raw.substr( utl_raw.bit_and (raw_util_pkg.bit_shift_left_raw (utl_raw.substr(p_bytes, 7, 1), 1), get_8bit_mask), 1, 1);
--debug_pkg.printf('output byte 1 = %1', raw2num(l_byte1));
--debug_pkg.printf('output byte 2 = %1', raw2num(l_byte2));
--debug_pkg.printf('output byte 3 = %1', raw2num(l_byte3));
--debug_pkg.printf('output byte 4 = %1', raw2num(l_byte4));
--debug_pkg.printf('output byte 5 = %1', raw2num(l_byte5));
--debug_pkg.printf('output byte 6 = %1', raw2num(l_byte6));
--debug_pkg.printf('output byte 7 = %1', raw2num(l_byte7));
--debug_pkg.printf('output byte 8 = %1', raw2num(l_byte8));
l_returnvalue := utl_raw.concat (l_byte1, l_byte2, l_byte3, l_byte4, l_byte5, l_byte6, l_byte7, l_byte8);
return l_returnvalue;
end create_des_key;
function get_lm_hashed_password_v1 (p_password in raw) return raw
as
-- http://en.wikipedia.org/wiki/LM_hash - "The DES CipherMode should be set to ECB, and PaddingMode should be set to NONE."
l_algorithm constant pls_integer := dbms_crypto.encrypt_des + dbms_crypto.chain_ecb + dbms_crypto.pad_none;
l_user_pw_length pls_integer;
l_lm_password raw(255);
l_magic_str constant raw(20) := utl_raw.cast_to_raw('KGS!@#$%'); -- page 57 in [MS-NLMP]
l_low_key raw(8);
l_high_key raw(8);
l_low_hash raw(255);
l_high_hash raw(255);
l_returnvalue raw(2000);
begin
/*
Purpose: create LanManager (LM) hashed password
Remarks: see http://en.wikipedia.org/wiki/LM_hash#Algorithm
Who Date Description
------ ---------- --------------------------------
MBR 03.06.2011 Created
*/
l_lm_password := p_password;
--debug_pkg.printf('user password byte 1 = %1', utl_raw.cast_to_varchar2(utl_raw.substr(l_lm_password, 1, 1)));
l_user_pw_length := utl_raw.length (l_lm_password);
--debug_pkg.printf('user password byte length = %1', l_user_pw_length);
-- pad the password length to 14 bytes
if l_user_pw_length < 14 then
for i in 1..(14-l_user_pw_length) loop
l_lm_password := utl_raw.concat(l_lm_password, hextoraw('0'));
end loop;
end if;
--debug_pkg.printf('new byte length = %1', utl_raw.length (l_lm_password));
l_lm_password := utl_raw.substr(l_lm_password, 1, 14);
-- do hash
l_low_key := create_des_key (utl_raw.substr(l_lm_password, 1, 7));
l_high_key := create_des_key (utl_raw.substr(l_lm_password, 8, 7));
l_low_hash := dbms_crypto.encrypt (l_magic_str, l_algorithm, l_low_key);
l_high_hash := dbms_crypto.encrypt (l_magic_str, l_algorithm, l_high_key);
l_returnvalue := utl_raw.concat (l_low_hash, l_high_hash);
--debug_pkg.printf('LM hashed password returnvalue (base64 encoded for readability) = %1', utl_raw.cast_to_varchar2(utl_encode.base64_encode(l_returnvalue)));
return l_returnvalue;
end get_lm_hashed_password_v1;
function get_nt_hashed_password_v1 (p_password in varchar2) return raw
as
l_returnvalue raw(4000);
begin
/*
Purpose: Get NT hashed password
Remarks:
Who Date Description
------ ---------- --------------------------------
FDL 01.06.2011 Created
*/
l_returnvalue := dbms_crypto.hash(utl_raw.cast_to_raw(convert (p_password, 'AL16UTF16LE')), dbms_crypto.HASH_MD4);
return l_returnvalue;
end get_nt_hashed_password_v1;
function get_nt_hashed_password_v2 (p_password in varchar2,
p_user in varchar2,
p_domain in varchar2) return raw
as
l_returnvalue raw(4000);
begin
/*
Purpose: Get NT hashed password
Remarks:
Who Date Description
------ ---------- --------------------------------
FDL 01.06.2011 Created
*/
l_returnvalue := get_nt_hashed_password_v1 (p_password);
l_returnvalue := dbms_crypto.mac(utl_raw.cast_to_raw(convert(upper(p_user) || p_domain, 'AL16UTF16LE')), dbms_crypto.HMAC_MD5, l_returnvalue);
return l_returnvalue;
end get_nt_hashed_password_v2;
function get_response (p_password_hash in raw,
p_server_challenge in raw) return raw
as
l_raw raw(21);
l_password_hash_length pls_integer;
l_password_hash raw(21);
l_server_challenge raw(8);
l_hash1 raw(8);
l_hash2 raw(8);
l_hash3 raw(8);
l_algorithm constant pls_integer := dbms_crypto.encrypt_des + dbms_crypto.chain_ecb + dbms_crypto.pad_none;
l_returnvalue raw (24);
begin
/*
Purpose: get LM response
Remarks: generates the LM response given a 16-byte password hash and
the 8 byte server challenge from the Type-2 message
Who Date Description
------ ---------- --------------------------------
FDL 01.06.2011 Created
MBR 16.06.2011 Fixed padding
*/
l_password_hash_length := utl_raw.length (p_password_hash);
--debug_pkg.printf('get_response: password hash length = %1', l_password_hash_length);
if l_password_hash_length < 21 then
l_password_hash := utl_raw.substr(p_password_hash, 1, least(21, l_password_hash_length));
for i in 1..(21-l_password_hash_length) loop
l_password_hash := utl_raw.concat(l_password_hash, hextoraw('0'));
end loop;
end if;
--debug_pkg.printf('new byte length = %1', utl_raw.length (l_password_hash));
l_password_hash := utl_raw.substr(l_password_hash, 1, 21);
l_server_challenge := utl_raw.substr(p_server_challenge, 1, 8);
l_hash1 := dbms_crypto.encrypt(l_server_challenge, l_algorithm, create_des_key(utl_raw.substr(l_password_hash, 1, 7)));
l_hash2 := dbms_crypto.encrypt(l_server_challenge, l_algorithm, create_des_key(utl_raw.substr(l_password_hash, 8, 7)));
l_hash3 := dbms_crypto.encrypt(l_server_challenge, l_algorithm, create_des_key(utl_raw.substr(l_password_hash, 15, 7)));
l_returnvalue := utl_raw.concat(l_hash1, l_hash2, l_hash3);
return l_returnvalue;
end get_response;
procedure calc_response_2sr (p_password_hash in raw,
p_server_challenge in raw,
p_nt_challenge out raw,
p_lm_challenge out raw)
as
l_client_challenge raw(16);
l_sess raw(4000);
begin
/*
Purpose: Calculate response for extended security
Remarks:
Who Date Description
------ ---------- --------------------------------
FDL 06.06.2011 Created
*/
l_client_challenge := hextoraw('AAAAAAAAAAAAAAAA');
--l_client_challenge := hextoraw('39e3f4cd59c5d860');
--l_client_challenge := hextoraw('5487e2f40422146a');
-- generating random client challenge of 16 bytes
--l_client_challenge := utl_raw.concat(utl_raw.cast_from_binary_integer(floor(dbms_random.value(1, 2147483648))), utl_raw.cast_from_binary_integer(floor(dbms_random.value(1, 2147483648))));
p_lm_challenge := utl_raw.concat (l_client_challenge, hextoraw('00000000000000000000000000000000'));
l_sess := dbms_crypto.hash(utl_raw.concat(p_server_challenge, l_client_challenge), dbms_crypto.HASH_MD5);
p_nt_challenge := get_response (p_password_hash, utl_raw.substr(l_sess, 1, 8));
debug_pkg.printf('Challenge: "%3", NT: "%1", LM: ="%2", Sess: "%4", Client Challenge: "%5"', p_nt_challenge, p_lm_challenge, utl_raw.concat(p_server_challenge, p_lm_challenge), l_sess, l_client_challenge);
end calc_response_2sr;
function get_authenticate_message (p_username in varchar2,
p_password in varchar2,
p_server_challenge in raw,
p_negotiate_flags in raw) return varchar2
as
l_returnvalue string_util_pkg.t_max_pl_varchar2;
l_body_length number;
l_payload_start number;
l_is_unicode boolean;
l_negotiate_ext_sec boolean;
l_workstation_str varchar2(500);
l_domain_str varchar2(500);
l_user_str varchar2(500);
--l_protocol raw(8);
l_protocol raw(16);
l_workstation raw(32);
l_domain raw(32);
l_username raw(32); -- was: raw(16)
l_password_hash raw(32);
l_client_challenge raw(8);
l_type raw(4);
l_flags raw(4);
l_workstation_length raw(2);
l_workstation_max_length raw(2);
l_workstation_buffer_offset raw(4);
l_domain_length raw(2);
l_domain_max_length raw(2);
l_domain_buffer_offset raw(4);
l_username_length raw(2);
l_username_max_length raw(2);
l_username_buffer_offset raw(4);
l_lm_challenge_response raw(100);
l_nt_challenge_response raw(100);
l_enc_rand_session_key raw(100);
l_lm_challenge_length raw(2);
l_lm_challenge_max_length raw(2);
l_lm_challenge_buffer_offset raw(4);
l_nt_challenge_length raw(2);
l_nt_challenge_max_length raw(2);
l_nt_challenge_buffer_offset raw(4);
l_encrandsesskey_length raw(2);
l_encrandsesskey_max_length raw(2);
l_encrandsesskey_buffer_offset raw(4);
l_product_major_version raw(1);
l_product_minor_version raw(1);
l_product_build raw(2);
l_version_reserved1 raw(1);
l_version_reserved2 raw(1);
l_version_reserved3 raw(1);
l_ntlm_revision_current raw(1);
l_return raw(2000);
l_lm_hashed_password raw(2000);
begin
/*
Purpose: Get authenticate (type 3) message
Remarks:
Who Date Description
------ ---------- --------------------------------
FDL 01.06.2011 Created
*/
l_body_length := 72;
l_payload_start := l_body_length;
parse_username (p_username, l_domain_str, l_user_str);
l_workstation_str := get_workstation_name;
debug_pkg.printf('username = %1, domain = %2, workstation = %3', l_user_str, l_domain_str, l_workstation_str);
l_flags := bit_or_multi (m_NTLM_NegotiateUnicode,
m_NTLM_RequestTarget,
m_NTLM_NegotiateNTLM,
m_NTLM_NegotiateAlwaysSign,
m_NTLM_NegotiateExtendedSec,
m_NTLM_NegotiateTargetInfo,
m_NTLM_NegotiateVersion,
m_NTLM_Negotiate128,
m_NTLM_Negotiate56);
-- need to convert flags to little endian
l_flags := int_to_raw_little_endian(utl_raw.cast_to_binary_integer(l_flags), 4);
l_lm_challenge_response := get_response (get_lm_hashed_password_v1(utl_raw.cast_to_raw(upper(p_password))), p_server_challenge);
l_nt_challenge_response := get_response (get_nt_hashed_password_v1(p_password), p_server_challenge);
l_enc_rand_session_key := null;
if utl_raw.bit_and (p_negotiate_flags, m_NTLM_NegotiateUnicode) = m_NTLM_NegotiateUnicode then
l_is_unicode := true;
else
l_is_unicode := false;
end if;
if utl_raw.bit_and (p_negotiate_flags, m_NTLM_NegotiateExtendedSec) = m_NTLM_NegotiateExtendedSec then
l_negotiate_ext_sec := true;
else
l_negotiate_ext_sec := false;
end if;
if l_is_unicode then
--debug_pkg.printf('l_is_unicode is TRUE...');
l_workstation_str := convert (l_workstation_str, 'AL16UTF16LE');
l_domain_str := convert (l_domain_str, 'AL16UTF16LE');
l_user_str := convert (l_user_str, 'AL16UTF16LE');
--l_enc_rand_session_key := convert (utl_raw.cast_to_varchar2(l_enc_rand_session_key), 'AL16UTF16LE');
end if;
if l_negotiate_ext_sec then
l_password_hash := get_nt_hashed_password_v1 (p_password);
calc_response_2sr (l_password_hash, p_server_challenge, l_nt_challenge_response, l_lm_challenge_response);
end if;
--l_protocol := utl_raw.cast_to_raw('NTLMSSP' || chr(256));
l_protocol := utl_raw.cast_to_raw('NTLMSSP' || chr(0));
l_type := int_to_raw_little_endian(3, 4); --- Type 3
l_workstation := utl_raw.cast_to_raw(l_workstation_str);
l_domain := utl_raw.cast_to_raw(l_domain_str);
l_username := utl_raw.cast_to_raw(l_user_str);
l_domain_length := int_to_raw_little_endian(utl_raw.length(l_domain), 2);
l_domain_max_length := int_to_raw_little_endian(utl_raw.length(l_domain), 2);
l_domain_buffer_offset := int_to_raw_little_endian(l_payload_start, 4);
l_payload_start := l_payload_start + utl_raw.length(l_domain);
l_username_length := int_to_raw_little_endian(utl_raw.length(l_username), 2);
l_username_max_length := int_to_raw_little_endian(utl_raw.length(l_username), 2);
l_username_buffer_offset := int_to_raw_little_endian(l_payload_start, 4);
l_payload_start := l_payload_start + utl_raw.length(l_username);
l_workstation_length := int_to_raw_little_endian(utl_raw.length(l_workstation), 2);
l_workstation_max_length := int_to_raw_little_endian(utl_raw.length(l_workstation), 2);
l_workstation_buffer_offset := int_to_raw_little_endian(l_payload_start, 4);
l_payload_start := l_payload_start + utl_raw.length(l_workstation);
l_lm_challenge_length := int_to_raw_little_endian(utl_raw.length(l_lm_challenge_response), 2);
l_lm_challenge_max_length := int_to_raw_little_endian(utl_raw.length(l_lm_challenge_response), 2);
l_lm_challenge_buffer_offset := int_to_raw_little_endian(l_payload_start, 4);
l_payload_start := l_payload_start + utl_raw.length(l_lm_challenge_response);
l_nt_challenge_length := int_to_raw_little_endian(utl_raw.length(l_nt_challenge_response), 2);
l_nt_challenge_max_length := int_to_raw_little_endian(utl_raw.length(l_nt_challenge_response), 2);
l_nt_challenge_buffer_offset := int_to_raw_little_endian(l_payload_start, 4);
l_payload_start := l_payload_start + utl_raw.length(l_nt_challenge_response);
--l_encrandsesskey_length := int_to_raw_little_endian(utl_raw.length(l_enc_rand_session_key), 2);
l_encrandsesskey_length := int_to_raw_little_endian(0, 2);
--l_encrandsesskey_max_length := int_to_raw_little_endian(utl_raw.length(l_enc_rand_session_key), 2);
l_encrandsesskey_max_length := int_to_raw_little_endian(0, 2);
l_encrandsesskey_buffer_offset := int_to_raw_little_endian(l_payload_start, 4);
--l_payload_start := l_payload_start + utl_raw.length(l_enc_rand_session_key);
l_payload_start := l_payload_start + 0;
l_product_major_version := int_to_raw_little_endian(5, 1);
l_product_minor_version := int_to_raw_little_endian(1, 1);
l_product_build := int_to_raw_little_endian(2600, 2);
l_version_reserved1 := int_to_raw_little_endian(0, 1);
l_version_reserved2 := int_to_raw_little_endian(0, 1);
l_version_reserved3 := int_to_raw_little_endian(0, 1);
l_ntlm_revision_current := int_to_raw_little_endian(15, 1);
l_return := utl_raw.concat(l_protocol,
l_type,
l_lm_challenge_length,
l_lm_challenge_max_length,
l_lm_challenge_buffer_offset,
l_nt_challenge_length,
l_nt_challenge_max_length,
l_nt_challenge_buffer_offset,
l_domain_length,
l_domain_max_length,
l_domain_buffer_offset);
l_return := utl_raw.concat (l_return,
l_username_length,
l_username_max_length,
l_username_buffer_offset,
l_workstation_length,
l_workstation_max_length,
l_workstation_buffer_offset,
l_encrandsesskey_length,
l_encrandsesskey_max_length,
l_encrandsesskey_buffer_offset);
l_return := utl_raw.concat (l_return,
l_flags,
l_product_major_version,
l_product_minor_version,
l_product_build,
l_version_reserved1,
l_version_reserved2,
l_version_reserved3,
l_ntlm_revision_current);
if utl_raw.length (l_return) <> l_body_length then
raise_application_error (-20000, 'Length of authenticate message is ' || utl_raw.length(l_return) || ' (should be ' || l_body_length ||')');
end if;
--l_return := utl_raw.concat (l_return, l_domain, l_username, l_workstation, l_lm_challenge_response, l_nt_challenge_response, l_enc_rand_session_key);
--l_return := utl_raw.concat (l_return, l_domain, l_username, l_workstation, l_lm_challenge_response, l_nt_challenge_response);
l_return := utl_raw.concat (l_return, l_domain, l_username, l_workstation, l_lm_challenge_response, l_nt_challenge_response);
--l_return := utl_raw.concat (l_domain, l_username, l_workstation, l_lm_challenge_response, l_nt_challenge_response);
l_returnvalue := utl_raw.cast_to_varchar2(l_return);
l_returnvalue := encode_util_pkg.str_to_base64(l_returnvalue);
l_returnvalue := replace(l_returnvalue, chr(13) || chr(10), '');
return l_returnvalue;
end get_authenticate_message;
end ntlm_util_pkg;
/