372 lines
7.7 KiB
C
372 lines
7.7 KiB
C
//+-----------------------------------------------------------------------
|
|
//
|
|
// File: passwd.c
|
|
//
|
|
// Contents: Password hashing routine
|
|
//
|
|
//
|
|
// History: 12-20-91, RichardW, created
|
|
//
|
|
//------------------------------------------------------------------------
|
|
|
|
#ifndef WIN32_CHICAGO
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <kerbcomm.h>
|
|
#include <kerbcon.h>
|
|
#include <kerberr.h>
|
|
#else // WIN32_CHICAGO
|
|
#include <kerb.hxx>
|
|
#include <kerbp.h>
|
|
#endif // WIN32_CHICAGO
|
|
#include "wincrypt.h"
|
|
|
|
//
|
|
// Globals used for allowing the replacement of the StringToKey functions
|
|
//
|
|
HCRYPTPROV KerbGlobalStrToKeyProvider = 0;
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: CheckForOutsideStringToKey
|
|
//
|
|
// Synopsis: Call CryptoAPI to query to see if a CSP is registered
|
|
// of the type PROV_REPLACE_OWF.
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: STATUS_SUCCESS if it succeeds, otherwise STATUS_UNSUCCESSFUL
|
|
//
|
|
// Notes:
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
VOID
|
|
CheckForOutsideStringToKey()
|
|
{
|
|
HCRYPTPROV hProv = 0;
|
|
|
|
KerbGlobalStrToKeyProvider = 0;
|
|
|
|
//
|
|
// Try to acquire a context to a CSP which is used for OWF replacement
|
|
//
|
|
if (!CryptAcquireContext(&hProv,
|
|
NULL,
|
|
NULL,
|
|
PROV_REPLACE_OWF,
|
|
CRYPT_VERIFYCONTEXT))
|
|
{
|
|
return;
|
|
}
|
|
|
|
KerbGlobalStrToKeyProvider = hProv;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: UseOutsideStringToKey
|
|
//
|
|
// Synopsis: Calls the CSP to do an outside StringToKey function
|
|
// using the hashing entry points of CryptoAPI.
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
UseOutsideStringToKey(
|
|
IN PUNICODE_STRING pPassword,
|
|
IN ULONG cbKey,
|
|
OUT PUCHAR pbKey
|
|
)
|
|
{
|
|
HCRYPTHASH hHash = 0;
|
|
ULONG cb;
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
|
|
//
|
|
// create the hash
|
|
//
|
|
if (!CryptCreateHash(KerbGlobalStrToKeyProvider,
|
|
CALG_HASH_REPLACE_OWF,
|
|
0,
|
|
0,
|
|
&hHash))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// hash the password
|
|
//
|
|
|
|
if (!CryptHashData(hHash,
|
|
(PUCHAR)pPassword->Buffer,
|
|
pPassword->Length,
|
|
0))
|
|
{
|
|
if (NTE_BAD_DATA == GetLastError())
|
|
{
|
|
Status = NTE_BAD_DATA;
|
|
}
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Get the HP_HASHVAL, this is the key
|
|
//
|
|
cb = cbKey;
|
|
if (!CryptGetHashParam(hHash,
|
|
HP_HASHVAL,
|
|
pbKey,
|
|
&cb,
|
|
0))
|
|
{
|
|
if (NTE_BAD_LEN == GetLastError())
|
|
{
|
|
Status = NTE_BAD_DATA;
|
|
}
|
|
goto Cleanup;
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
Cleanup:
|
|
if (0 != hHash)
|
|
{
|
|
CryptDestroyHash(hHash);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: KerbHashPasswordEx
|
|
//
|
|
// Synopsis: Hashes a password into a kerberos encryption key
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
KERBERR NTAPI
|
|
KerbHashPasswordEx(
|
|
IN PUNICODE_STRING Password,
|
|
IN PUNICODE_STRING PrincipalName,
|
|
IN ULONG EncryptionType,
|
|
OUT PKERB_ENCRYPTION_KEY Key
|
|
)
|
|
{
|
|
PCRYPTO_SYSTEM CryptoSystem;
|
|
NTSTATUS Status;
|
|
KERBERR KerbErr;
|
|
UNICODE_STRING CombinedName;
|
|
ULONG Temp = 0;
|
|
BOOLEAN fUseDefaultStringToKey = TRUE;
|
|
|
|
|
|
RtlInitUnicodeString(
|
|
&CombinedName,
|
|
NULL
|
|
);
|
|
|
|
Key->keyvalue.value = NULL;
|
|
|
|
//
|
|
// Locate the crypto system
|
|
//
|
|
|
|
Status = CDLocateCSystem(
|
|
EncryptionType,
|
|
&CryptoSystem
|
|
);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return(KDC_ERR_ETYPE_NOTSUPP);
|
|
}
|
|
|
|
//
|
|
// Check to see if the principal name must be appended to the password
|
|
//
|
|
|
|
if ((CryptoSystem->Attributes & CSYSTEM_USE_PRINCIPAL_NAME) != 0)
|
|
{
|
|
Temp = (ULONG) Password->Length + (ULONG) PrincipalName->Length;
|
|
|
|
if (Temp > (USHORT) -1)
|
|
{
|
|
KerbErr = KRB_ERR_GENERIC;
|
|
goto Cleanup;
|
|
}
|
|
|
|
CombinedName.Length = (USHORT) Temp;
|
|
CombinedName.MaximumLength = CombinedName.Length;
|
|
CombinedName.Buffer = (LPWSTR) MIDL_user_allocate(CombinedName.Length);
|
|
if (CombinedName.Buffer == NULL)
|
|
{
|
|
KerbErr = KRB_ERR_GENERIC;
|
|
goto Cleanup;
|
|
}
|
|
RtlCopyMemory(
|
|
CombinedName.Buffer,
|
|
Password->Buffer,
|
|
Password->Length
|
|
);
|
|
RtlCopyMemory(
|
|
CombinedName.Buffer + Password->Length/sizeof(WCHAR),
|
|
PrincipalName->Buffer,
|
|
PrincipalName->Length
|
|
);
|
|
}
|
|
else
|
|
{
|
|
CombinedName = *Password;
|
|
}
|
|
|
|
//
|
|
// Get the preferred checksum
|
|
//
|
|
|
|
|
|
|
|
Key->keyvalue.value = (PUCHAR) MIDL_user_allocate(CryptoSystem->KeySize);
|
|
if (Key->keyvalue.value == NULL)
|
|
{
|
|
KerbErr = KRB_ERR_GENERIC;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Check if we need to use an outside supplied string to key
|
|
// calculation
|
|
//
|
|
if (0 != KerbGlobalStrToKeyProvider)
|
|
{
|
|
Status = UseOutsideStringToKey(
|
|
&CombinedName,
|
|
CryptoSystem->KeySize,
|
|
Key->keyvalue.value
|
|
);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
fUseDefaultStringToKey = FALSE;
|
|
}
|
|
//
|
|
// the function will return STATUS_UNSUCCESSFUL indicates not to fall
|
|
// back to the typical string to key function.
|
|
//
|
|
else if (STATUS_UNSUCCESSFUL == Status)
|
|
{
|
|
KerbErr = KRB_ERR_GENERIC;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
if (fUseDefaultStringToKey)
|
|
{
|
|
Status = CryptoSystem->HashString(
|
|
&CombinedName,
|
|
Key->keyvalue.value
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
KerbErr = KRB_ERR_GENERIC;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
Key->keyvalue.length = CryptoSystem->KeySize;
|
|
|
|
Key->keytype = EncryptionType;
|
|
KerbErr = KDC_ERR_NONE;
|
|
|
|
Cleanup:
|
|
|
|
if ((CombinedName.Buffer != Password->Buffer) &&
|
|
(CombinedName.Buffer != NULL))
|
|
{
|
|
MIDL_user_free(CombinedName.Buffer);
|
|
}
|
|
|
|
if (!KERB_SUCCESS(KerbErr) && Key->keyvalue.value != NULL)
|
|
{
|
|
MIDL_user_free(Key->keyvalue.value);
|
|
Key->keyvalue.value = NULL;
|
|
}
|
|
|
|
return(KerbErr);
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: KerbHashPassword
|
|
//
|
|
// Synopsis: Hashes a password into a kerberos encryption key
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
KERBERR NTAPI
|
|
KerbHashPassword(
|
|
IN PUNICODE_STRING Password,
|
|
IN ULONG EncryptionType,
|
|
OUT PKERB_ENCRYPTION_KEY Key
|
|
)
|
|
{
|
|
UNICODE_STRING TempString;
|
|
RtlInitUnicodeString(
|
|
&TempString,
|
|
NULL
|
|
);
|
|
return( KerbHashPasswordEx(
|
|
Password,
|
|
&TempString, // no principal name
|
|
EncryptionType,
|
|
Key
|
|
) );
|
|
}
|
|
|