windows-nt/Source/XPSP1/NT/base/ntsetup/encrypt/encrypt.c
2020-09-26 16:20:57 +08:00

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;
}