|
|
/*++
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; the buffer MUST be at least STRING_ENCODED_PASSWORD_SIZE chars (including nul) 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; }
|