868 lines
18 KiB
C
868 lines
18 KiB
C
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
encrypt.c
|
|
|
|
Abstract:
|
|
|
|
Provides a set of functions dealing with OWF hash values of passwords.
|
|
|
|
Author:
|
|
|
|
Ovidiu Temereanca (ovidiut) 14-Mar-2000
|
|
|
|
Revision History:
|
|
|
|
<alias> <date> <comments>
|
|
|
|
--*/
|
|
|
|
//
|
|
// Includes
|
|
//
|
|
|
|
#include <windows.h>
|
|
|
|
#include "encrypt.h"
|
|
|
|
//
|
|
// Strings
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Constants
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Macros
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Types
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Globals
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Macro expansion list
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Private function prototypes
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Macro expansion definition
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Code
|
|
//
|
|
|
|
PSTR
|
|
ConvertW2A (
|
|
IN PCWSTR Unicode,
|
|
IN UINT CodePage
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Converts an UNICODE string to it's ANSI equivalent, using the given codepage.
|
|
|
|
Arguments:
|
|
|
|
Unicode - Specifies the string to be converted
|
|
CodePage - Specifies the code page used for conversion
|
|
|
|
Return value:
|
|
|
|
A pointer to the ANSI string if successful, or NULL on error. Call GetLastError()
|
|
to determine the cause of failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
PSTR ansi = NULL;
|
|
DWORD rc;
|
|
|
|
rc = WideCharToMultiByte (
|
|
CodePage,
|
|
WC_NO_BEST_FIT_CHARS,
|
|
Unicode,
|
|
-1,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if (rc || *Unicode == L'\0') {
|
|
|
|
ansi = (PSTR)HeapAlloc (GetProcessHeap (), 0, (rc + 1) * sizeof (CHAR));
|
|
if (ansi) {
|
|
rc = WideCharToMultiByte (
|
|
CodePage,
|
|
WC_NO_BEST_FIT_CHARS,
|
|
Unicode,
|
|
-1,
|
|
ansi,
|
|
rc + 1,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if (!(rc || *Unicode == L'\0')) {
|
|
rc = GetLastError ();
|
|
HeapFree (GetProcessHeap (), 0, (PVOID)ansi);
|
|
ansi = NULL;
|
|
SetLastError (rc);
|
|
}
|
|
}
|
|
}
|
|
|
|
return ansi;
|
|
}
|
|
|
|
|
|
PWSTR
|
|
ConvertA2W (
|
|
IN PCSTR Ansi,
|
|
IN UINT CodePage
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Converts an ANSI string to it's UNICODE equivalent, using the given codepage.
|
|
|
|
Arguments:
|
|
|
|
Ansi - Specifies the string to be converted
|
|
CodePage - Specifies the code page used for conversion
|
|
|
|
Return value:
|
|
|
|
A pointer to the UNICODE string if successful, or NULL on error. Call GetLastError()
|
|
to determine the cause of failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
PWSTR unicode = NULL;
|
|
DWORD rc;
|
|
|
|
rc = MultiByteToWideChar (
|
|
CodePage,
|
|
MB_ERR_INVALID_CHARS,
|
|
Ansi,
|
|
-1,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
if (rc || *Ansi == '\0') {
|
|
|
|
unicode = (PWSTR) HeapAlloc (GetProcessHeap (), 0, (rc + 1) * sizeof (WCHAR));
|
|
if (unicode) {
|
|
rc = MultiByteToWideChar (
|
|
CodePage,
|
|
MB_ERR_INVALID_CHARS,
|
|
Ansi,
|
|
-1,
|
|
unicode,
|
|
rc + 1
|
|
);
|
|
|
|
if (!(rc || *Ansi == '\0')) {
|
|
rc = GetLastError ();
|
|
HeapFree (GetProcessHeap (), 0, (PVOID)unicode);
|
|
unicode = NULL;
|
|
SetLastError (rc);
|
|
}
|
|
}
|
|
}
|
|
|
|
return unicode;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
EncodeLmOwfPassword converts a password to the LM OWF format.
|
|
|
|
Arguments:
|
|
|
|
Password - Specifies the password to be hashed
|
|
OwfPassword - Receives the hash form
|
|
ComplexNtPassword - Receives TRUE if the password is complex (longer than 14 chars);
|
|
optional
|
|
|
|
Return value:
|
|
|
|
TRUE on successful hashing
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
EncodeLmOwfPasswordA (
|
|
IN PCSTR AnsiPassword,
|
|
OUT PLM_OWF_PASSWORD OwfPassword,
|
|
OUT PBOOL ComplexNtPassword OPTIONAL
|
|
)
|
|
{
|
|
CHAR oemPassword[LM_PASSWORD_SIZE_MAX];
|
|
CHAR password[LM_PASSWORD_SIZE_MAX];
|
|
BOOL complex;
|
|
|
|
if (!AnsiPassword) {
|
|
AnsiPassword = "";
|
|
}
|
|
|
|
complex = lstrlenA (AnsiPassword) > LM20_PWLEN;
|
|
if (ComplexNtPassword) {
|
|
*ComplexNtPassword = complex;
|
|
}
|
|
|
|
if (complex) {
|
|
password[0] = 0;
|
|
} else {
|
|
lstrcpyA (oemPassword, AnsiPassword);
|
|
CharUpperA (oemPassword);
|
|
CharToOemA (oemPassword, password);
|
|
}
|
|
|
|
return CalculateLmOwfPassword (password, OwfPassword);
|
|
}
|
|
|
|
BOOL
|
|
EncodeLmOwfPasswordW (
|
|
IN PCWSTR Password,
|
|
OUT PLM_OWF_PASSWORD OwfPassword,
|
|
OUT PBOOL ComplexNtPassword OPTIONAL
|
|
)
|
|
{
|
|
PSTR ansi;
|
|
BOOL b = FALSE;
|
|
|
|
if (!Password) {
|
|
Password = L"";
|
|
}
|
|
|
|
ansi = ConvertW2A (Password, CP_ACP);
|
|
if (ansi) {
|
|
b = EncodeLmOwfPasswordA (ansi, OwfPassword, ComplexNtPassword);
|
|
HeapFree (GetProcessHeap (), 0, (PVOID)ansi);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
StringEncodeLmOwfPassword converts a password to the LM OWF format, expressed as
|
|
a string of characters (each byte converted to 2 hex digits).
|
|
|
|
Arguments:
|
|
|
|
Password - Specifies the password to be hashed
|
|
EncodedPassword - Receives the hash form, as a string of hex digits
|
|
ComplexNtPassword - Receives TRUE if the password is complex (longer than 14 chars);
|
|
optional
|
|
|
|
Return value:
|
|
|
|
TRUE on successful hashing
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
StringEncodeLmOwfPasswordA (
|
|
IN PCSTR Password,
|
|
OUT PSTR EncodedPassword,
|
|
OUT PBOOL ComplexNtPassword OPTIONAL
|
|
)
|
|
{
|
|
LM_OWF_PASSWORD owfPassword;
|
|
PBYTE start;
|
|
PBYTE end;
|
|
PSTR dest;
|
|
|
|
if (!EncodeLmOwfPasswordA (Password, &owfPassword, ComplexNtPassword)) {
|
|
return FALSE;
|
|
}
|
|
//
|
|
// each byte will be represented as 2 chars, so it will be twice as long
|
|
//
|
|
start = (PBYTE)&owfPassword;
|
|
end = start + sizeof (LM_OWF_PASSWORD);
|
|
dest = EncodedPassword;
|
|
while (start < end) {
|
|
dest += wsprintfA (dest, "%02x", (UINT)(*start));
|
|
start++;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
StringEncodeLmOwfPasswordW (
|
|
IN PCWSTR Password,
|
|
OUT PWSTR EncodedPassword,
|
|
OUT PBOOL ComplexNtPassword OPTIONAL
|
|
)
|
|
{
|
|
LM_OWF_PASSWORD owfPassword;
|
|
PBYTE start;
|
|
PBYTE end;
|
|
PWSTR dest;
|
|
|
|
if (!EncodeLmOwfPasswordW (Password, &owfPassword, ComplexNtPassword)) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// each byte will be represented as 2 chars, so it will be twice as long
|
|
//
|
|
start = (PBYTE)&owfPassword;
|
|
end = start + sizeof (LM_OWF_PASSWORD);
|
|
dest = EncodedPassword;
|
|
while (start < end) {
|
|
dest += wsprintfW (dest, L"%02x", (UINT)(*start));
|
|
start++;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
EncodeNtOwfPassword converts a password to the NT OWF format.
|
|
|
|
Arguments:
|
|
|
|
Password - Specifies the password to be hashed
|
|
OwfPassword - Receives the hash form
|
|
|
|
Return value:
|
|
|
|
TRUE on successful hashing
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
EncodeNtOwfPasswordA (
|
|
IN PCSTR Password,
|
|
OUT PNT_OWF_PASSWORD OwfPassword
|
|
)
|
|
{
|
|
PWSTR unicode;
|
|
BOOL b = FALSE;
|
|
|
|
unicode = ConvertA2W (Password, CP_ACP);
|
|
if (unicode) {
|
|
b = EncodeNtOwfPasswordW (unicode, OwfPassword);
|
|
HeapFree (GetProcessHeap (), 0, unicode);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
BOOL
|
|
EncodeNtOwfPasswordW (
|
|
IN PCWSTR Password,
|
|
OUT PNT_OWF_PASSWORD OwfPassword
|
|
)
|
|
{
|
|
NT_PASSWORD pwd;
|
|
|
|
if (Password) {
|
|
pwd.Buffer = (PWSTR)Password;
|
|
pwd.Length = (USHORT)lstrlenW (Password) * (USHORT)sizeof (WCHAR);
|
|
pwd.MaximumLength = pwd.Length + (USHORT) sizeof (WCHAR);
|
|
} else {
|
|
ZeroMemory (&pwd, sizeof (pwd));
|
|
}
|
|
|
|
return CalculateNtOwfPassword (&pwd, OwfPassword);
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
StringEncodeNtOwfPassword converts a password to the NT OWF format, expressed as
|
|
a string of characters (each byte converted to 2 hex digits).
|
|
|
|
Arguments:
|
|
|
|
Password - Specifies the password to be hashed
|
|
EncodedPassword - Receives the hash form, as a string of hex digits
|
|
|
|
Return value:
|
|
|
|
TRUE on successful hashing
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
StringEncodeNtOwfPasswordA (
|
|
IN PCSTR Password,
|
|
OUT PSTR EncodedPassword
|
|
)
|
|
{
|
|
NT_OWF_PASSWORD owfPassword;
|
|
PBYTE start;
|
|
PBYTE end;
|
|
PSTR dest;
|
|
|
|
if (!EncodeNtOwfPasswordA (Password, &owfPassword)) {
|
|
return FALSE;
|
|
}
|
|
//
|
|
// each byte will be represented as 2 chars, so it will be twice as long
|
|
//
|
|
start = (PBYTE)&owfPassword;
|
|
end = start + sizeof (NT_OWF_PASSWORD);
|
|
dest = EncodedPassword;
|
|
while (start < end) {
|
|
dest += wsprintfA (dest, "%02x", (UINT)(*start));
|
|
start++;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
StringEncodeNtOwfPasswordW (
|
|
IN PCWSTR Password,
|
|
OUT PWSTR EncodedPassword
|
|
)
|
|
{
|
|
NT_OWF_PASSWORD owfPassword;
|
|
PBYTE start;
|
|
PBYTE end;
|
|
PWSTR dest;
|
|
|
|
if (!EncodeNtOwfPasswordW (Password, &owfPassword)) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// each byte will be represented as 2 chars, so it will be twice as long
|
|
//
|
|
start = (PBYTE)&owfPassword;
|
|
end = start + sizeof (NT_OWF_PASSWORD);
|
|
dest = EncodedPassword;
|
|
while (start < end) {
|
|
dest += wsprintfW (dest, L"%02x", (UINT)(*start));
|
|
start++;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
StringDecodeLmOwfPassword converts a hashed password to the LM OWF format
|
|
|
|
Arguments:
|
|
|
|
EncodedOwfPassword - Specifies the password to be hashed
|
|
OwfPassword - Receives the hash form
|
|
|
|
Return value:
|
|
|
|
TRUE on successful decoding of the string
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
StringDecodeLmOwfPasswordA (
|
|
IN PCSTR EncodedOwfPassword,
|
|
OUT PLM_OWF_PASSWORD OwfPassword
|
|
)
|
|
{
|
|
DWORD nible;
|
|
PCSTR p;
|
|
PBYTE dest;
|
|
CHAR ch;
|
|
|
|
if (lstrlenA (EncodedOwfPassword) != sizeof (LM_OWF_PASSWORD) * 2) {
|
|
return FALSE;
|
|
}
|
|
|
|
nible = 0;
|
|
p = EncodedOwfPassword;
|
|
dest = (PBYTE)OwfPassword;
|
|
ch = 0;
|
|
while (*p) {
|
|
if (!((*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'f') || (*p >= 'A' && *p <= 'F'))) {
|
|
return FALSE;
|
|
}
|
|
if (*p <= '9') {
|
|
ch |= *p - '0';
|
|
} else if (*p <= 'F') {
|
|
ch |= *p - 'A' + 10;
|
|
} else {
|
|
ch |= *p - 'a' + 10;
|
|
}
|
|
p++;
|
|
nible++;
|
|
if ((nible & 1) == 0) {
|
|
*dest++ = ch;
|
|
ch = 0;
|
|
} else {
|
|
ch <<= 4;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
StringDecodeLmOwfPasswordW (
|
|
IN PCWSTR EncodedOwfPassword,
|
|
OUT PLM_OWF_PASSWORD OwfPassword
|
|
)
|
|
{
|
|
DWORD nible;
|
|
PCWSTR p;
|
|
PBYTE dest;
|
|
WCHAR ch;
|
|
|
|
if (lstrlenW (EncodedOwfPassword) != sizeof (LM_OWF_PASSWORD) * 2) {
|
|
return FALSE;
|
|
}
|
|
|
|
nible = 0;
|
|
p = EncodedOwfPassword;
|
|
dest = (PBYTE)OwfPassword;
|
|
ch = 0;
|
|
while (*p) {
|
|
if (!((*p >= L'0' && *p <= L'9') || (*p >= L'a' && *p <= L'f') || (*p >= L'A' && *p <= L'F'))) {
|
|
return FALSE;
|
|
}
|
|
if (*p <= L'9') {
|
|
ch |= *p - L'0';
|
|
} else if (*p <= L'F') {
|
|
ch |= *p - L'A' + 10;
|
|
} else {
|
|
ch |= *p - L'a' + 10;
|
|
}
|
|
p++;
|
|
nible++;
|
|
if ((nible & 1) == 0) {
|
|
*dest++ = (BYTE)ch;
|
|
ch = 0;
|
|
} else {
|
|
ch <<= 4;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
StringDecodeNtOwfPassword converts a hashed password to the NT OWF format
|
|
|
|
Arguments:
|
|
|
|
EncodedOwfPassword - Specifies the password to be hashed
|
|
OwfPassword - Receives the hash form
|
|
|
|
Return value:
|
|
|
|
TRUE on successful decoding of the string
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
StringDecodeNtOwfPasswordA (
|
|
IN PCSTR EncodedOwfPassword,
|
|
OUT PNT_OWF_PASSWORD OwfPassword
|
|
)
|
|
{
|
|
DWORD nible;
|
|
PCSTR p;
|
|
PBYTE dest;
|
|
CHAR ch;
|
|
|
|
if (lstrlenA (EncodedOwfPassword) != sizeof (NT_OWF_PASSWORD) * 2) {
|
|
return FALSE;
|
|
}
|
|
|
|
nible = 0;
|
|
p = EncodedOwfPassword;
|
|
dest = (PBYTE)OwfPassword;
|
|
ch = 0;
|
|
while (*p) {
|
|
if (!((*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'f') || (*p >= 'A' && *p <= 'F'))) {
|
|
return FALSE;
|
|
}
|
|
if (*p <= '9') {
|
|
ch |= *p - '0';
|
|
} else if (*p <= 'F') {
|
|
ch |= *p - 'A' + 10;
|
|
} else {
|
|
ch |= *p - 'a' + 10;
|
|
}
|
|
p++;
|
|
nible++;
|
|
if ((nible & 1) == 0) {
|
|
*dest++ = ch;
|
|
ch = 0;
|
|
} else {
|
|
ch <<= 4;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
StringDecodeNtOwfPasswordW (
|
|
IN PCWSTR EncodedOwfPassword,
|
|
OUT PNT_OWF_PASSWORD OwfPassword
|
|
)
|
|
{
|
|
DWORD nible;
|
|
PCWSTR p;
|
|
PBYTE dest;
|
|
WCHAR ch;
|
|
|
|
if (lstrlenW (EncodedOwfPassword) != sizeof (NT_OWF_PASSWORD) * 2) {
|
|
return FALSE;
|
|
}
|
|
|
|
nible = 0;
|
|
p = EncodedOwfPassword;
|
|
dest = (PBYTE)OwfPassword;
|
|
ch = 0;
|
|
while (*p) {
|
|
if (!((*p >= L'0' && *p <= L'9') || (*p >= L'a' && *p <= L'f') || (*p >= L'A' && *p <= L'F'))) {
|
|
return FALSE;
|
|
}
|
|
if (*p <= L'9') {
|
|
ch |= *p - L'0';
|
|
} else if (*p <= L'F') {
|
|
ch |= *p - L'A' + 10;
|
|
} else {
|
|
ch |= *p - L'a' + 10;
|
|
}
|
|
p++;
|
|
nible++;
|
|
if ((nible & 1) == 0) {
|
|
*dest++ = (BYTE)ch;
|
|
ch = 0;
|
|
} else {
|
|
ch <<= 4;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
StringEncodeOwfPassword converts a password to its hashed format, expressed as
|
|
a string of characters (each byte converted to 2 hex digits). The result is
|
|
obtained joining the 2 substrings, one representing LM OWF and the other NT OWF
|
|
|
|
Arguments:
|
|
|
|
Password - Specifies the password to be hashed
|
|
EncodedPassword - Receives the hash form, as a string of hex digits
|
|
ComplexNtPassword - Receives TRUE if the password is complex (longer than 14 chars);
|
|
optional
|
|
|
|
Return value:
|
|
|
|
TRUE on successful hashing
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
StringEncodeOwfPasswordA (
|
|
IN PCSTR Password,
|
|
OUT PSTR EncodedPassword,
|
|
OUT PBOOL ComplexNtPassword OPTIONAL
|
|
)
|
|
{
|
|
return StringEncodeLmOwfPasswordA (Password, EncodedPassword, ComplexNtPassword) &&
|
|
StringEncodeNtOwfPasswordA (Password, EncodedPassword + STRING_ENCODED_LM_OWF_PWD_LENGTH);
|
|
}
|
|
|
|
BOOL
|
|
StringEncodeOwfPasswordW (
|
|
IN PCWSTR Password,
|
|
OUT PWSTR EncodedPassword,
|
|
OUT PBOOL ComplexNtPassword OPTIONAL
|
|
)
|
|
{
|
|
return StringEncodeLmOwfPasswordW (Password, EncodedPassword, ComplexNtPassword) &&
|
|
StringEncodeNtOwfPasswordW (Password, EncodedPassword + STRING_ENCODED_LM_OWF_PWD_LENGTH);
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
StringDecodeOwfPassword decodes a password's LM OWF and NT OWF forms from its hashed format,
|
|
expressed as a string of hex digits.
|
|
|
|
Arguments:
|
|
|
|
EncodedOwfPassword - Specifies the password to be hashed
|
|
LmOwfPassword - Receives the LM OWF hash form
|
|
NtOwfPassword - Receives the NT OWF hash form
|
|
ComplexNtPassword - Receives TRUE if the password is complex (longer than 14 chars);
|
|
optional
|
|
|
|
Return value:
|
|
|
|
TRUE on successful hashing
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
StringDecodeOwfPasswordA (
|
|
IN PCSTR EncodedOwfPassword,
|
|
OUT PLM_OWF_PASSWORD LmOwfPassword,
|
|
OUT PNT_OWF_PASSWORD NtOwfPassword,
|
|
OUT PBOOL ComplexNtPassword OPTIONAL
|
|
)
|
|
{
|
|
PSTR p;
|
|
CHAR ch;
|
|
BOOL b;
|
|
CHAR buffer[sizeof (LM_OWF_PASSWORD) * 2 + sizeof (NT_OWF_PASSWORD) * 2 + 2];
|
|
LM_OWF_PASSWORD lmNull;
|
|
NT_OWF_PASSWORD ntNull;
|
|
|
|
if (lstrlenA (EncodedOwfPassword) != sizeof (LM_OWF_PASSWORD) * 2 + sizeof (NT_OWF_PASSWORD) * 2) {
|
|
return FALSE;
|
|
}
|
|
|
|
lstrcpyA (buffer, EncodedOwfPassword);
|
|
//
|
|
// split the string in two
|
|
//
|
|
p = buffer + (sizeof (LM_OWF_PASSWORD) * 2);
|
|
|
|
ch = *p;
|
|
*p = 0;
|
|
b = StringDecodeLmOwfPasswordA (EncodedOwfPassword, LmOwfPassword);
|
|
*p = ch;
|
|
|
|
if (b) {
|
|
b = StringDecodeNtOwfPasswordA (p, NtOwfPassword);
|
|
}
|
|
|
|
if (b && ComplexNtPassword) {
|
|
b = EncodeLmOwfPasswordA ("", &lmNull, NULL) && EncodeNtOwfPasswordA ("", &ntNull);
|
|
if (b) {
|
|
//
|
|
// it's a complex password if the LM hash is for NULL pwd
|
|
// but NT hash it's not
|
|
//
|
|
*ComplexNtPassword = CompareLmPasswords (LmOwfPassword, &lmNull) == 0 &&
|
|
CompareNtPasswords (NtOwfPassword, &ntNull) != 0;
|
|
}
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
BOOL
|
|
StringDecodeOwfPasswordW (
|
|
IN PCWSTR EncodedOwfPassword,
|
|
OUT PLM_OWF_PASSWORD LmOwfPassword,
|
|
OUT PNT_OWF_PASSWORD NtOwfPassword,
|
|
OUT PBOOL ComplexNtPassword OPTIONAL
|
|
)
|
|
{
|
|
PWSTR p;
|
|
WCHAR ch;
|
|
BOOL b;
|
|
WCHAR buffer[sizeof (LM_OWF_PASSWORD) * 2 + sizeof (NT_OWF_PASSWORD) * 2 + 2];
|
|
LM_OWF_PASSWORD lmNull;
|
|
NT_OWF_PASSWORD ntNull;
|
|
|
|
if (lstrlenW (EncodedOwfPassword) != sizeof (LM_OWF_PASSWORD) * 2 + sizeof (NT_OWF_PASSWORD) * 2) {
|
|
return FALSE;
|
|
}
|
|
|
|
lstrcpyW (buffer, EncodedOwfPassword);
|
|
//
|
|
// split the string in two
|
|
//
|
|
p = buffer + (sizeof (LM_OWF_PASSWORD) * 2);
|
|
|
|
ch = *p;
|
|
*p = 0;
|
|
b = StringDecodeLmOwfPasswordW (buffer, LmOwfPassword);
|
|
*p = ch;
|
|
|
|
if (b) {
|
|
b = StringDecodeNtOwfPasswordW (p, NtOwfPassword);
|
|
}
|
|
|
|
if (b && ComplexNtPassword) {
|
|
b = EncodeLmOwfPasswordW (L"", &lmNull, NULL) && EncodeNtOwfPasswordW (L"", &ntNull);
|
|
if (b) {
|
|
//
|
|
// it's a complex password if the LM hash is for NULL pwd
|
|
// but NT hash it's not
|
|
//
|
|
*ComplexNtPassword = CompareLmPasswords (LmOwfPassword, &lmNull) == 0 &&
|
|
CompareNtPasswords (NtOwfPassword, &ntNull) != 0;
|
|
}
|
|
}
|
|
|
|
return b;
|
|
}
|