267 lines
5.8 KiB
C
267 lines
5.8 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1989 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
response.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
Contains functions that calculate the correct response to return
|
|||
|
to the server when logging on.
|
|||
|
|
|||
|
CalculateLmResponse
|
|||
|
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
David Chalmers (Davidc) 10-21-91
|
|||
|
David Arnold (DavidAr) 12-15-93 (Adapted for RPC SSP)
|
|||
|
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#ifdef BLDR_KERNEL_RUNTIME
|
|||
|
#include <bootdefs.h>
|
|||
|
#endif
|
|||
|
#include <ntlmsspi.h>
|
|||
|
#include <descrypt.h>
|
|||
|
#include <crypt.h>
|
|||
|
#include <string.h>
|
|||
|
|
|||
|
//
|
|||
|
// Define the user session key that represents an error.
|
|||
|
// This value will be generated by other parts of the system on failure.
|
|||
|
// We will check for it in our query code and return an error if it's found.
|
|||
|
//
|
|||
|
|
|||
|
USER_SESSION_KEY ErrorSessionKey = { 0, 0, 0, 0, 0, 0, 0, 0,
|
|||
|
0, 0, 0, 0, 0, 0, 0, 0
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
CalculateLmResponse(
|
|||
|
IN PLM_CHALLENGE LmChallenge,
|
|||
|
IN PLM_OWF_PASSWORD LmOwfPassword,
|
|||
|
OUT PLM_RESPONSE LmResponse
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Takes the challenge sent by the server and the OwfPassword generated
|
|||
|
from the password the user entered and calculates the response to
|
|||
|
return to the server.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
LmChallenge - The challenge sent by the server
|
|||
|
|
|||
|
LmOwfPassword - The hashed password.
|
|||
|
|
|||
|
LmResponse - The response is returned here.
|
|||
|
|
|||
|
|
|||
|
Return Values:
|
|||
|
|
|||
|
TRUE - The function completed successfully. The response
|
|||
|
is in LmResponse.
|
|||
|
|
|||
|
FALSE - Something failed. The LmResponse is undefined.
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
BLOCK_KEY Key;
|
|||
|
PCHAR pKey, pData;
|
|||
|
|
|||
|
// The first 2 keys we can get at by type-casting
|
|||
|
|
|||
|
if (DES_ECB_LM(ENCR_KEY,
|
|||
|
(unsigned char *)&(((PBLOCK_KEY)(LmOwfPassword->data))[0]),
|
|||
|
(unsigned char *)LmChallenge,
|
|||
|
(unsigned char *)&(LmResponse->data[0])
|
|||
|
) != CRYPT_OK) {
|
|||
|
return (FALSE);
|
|||
|
}
|
|||
|
|
|||
|
if (DES_ECB_LM(ENCR_KEY,
|
|||
|
(unsigned char *)&(((PBLOCK_KEY)(LmOwfPassword->data))[1]),
|
|||
|
(unsigned char *)LmChallenge,
|
|||
|
(unsigned char *)&(LmResponse->data[1])
|
|||
|
) != CRYPT_OK) {
|
|||
|
return (FALSE);
|
|||
|
}
|
|||
|
|
|||
|
// To get the last key we must copy the remainder of the OwfPassword
|
|||
|
// and fill the rest of the key with 0s
|
|||
|
|
|||
|
pKey = &(Key.data[0]);
|
|||
|
pData = (PCHAR)&(((PBLOCK_KEY)(LmOwfPassword->data))[2]);
|
|||
|
|
|||
|
while (pData < (PCHAR)&(LmOwfPassword->data[2])) {
|
|||
|
*pKey++ = *pData++;
|
|||
|
}
|
|||
|
|
|||
|
// Zero extend
|
|||
|
|
|||
|
while (pKey < (PCHAR)&((&Key)[1])) {
|
|||
|
*pKey++ = 0;
|
|||
|
}
|
|||
|
|
|||
|
// Use the 3rd key
|
|||
|
|
|||
|
if (DES_ECB_LM(ENCR_KEY,
|
|||
|
(const char *)&Key,
|
|||
|
(unsigned char *)LmChallenge,
|
|||
|
(unsigned char *)&(LmResponse->data[2])
|
|||
|
) != CRYPT_OK) {
|
|||
|
return (FALSE);
|
|||
|
}
|
|||
|
|
|||
|
return(TRUE);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
CalculateNtResponse(
|
|||
|
IN PNT_CHALLENGE NtChallenge,
|
|||
|
IN PNT_OWF_PASSWORD NtOwfPassword,
|
|||
|
OUT PNT_RESPONSE NtResponse
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Calculates the NT challenge response. Currently just calls the
|
|||
|
LM function.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
return CalculateLmResponse(
|
|||
|
(PLM_CHALLENGE)NtChallenge,
|
|||
|
(PLM_OWF_PASSWORD)NtOwfPassword,
|
|||
|
(PLM_RESPONSE)NtResponse);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
CalculateUserSessionKeyLm(
|
|||
|
IN PLM_RESPONSE LmResponse,
|
|||
|
IN PLM_OWF_PASSWORD LmOwfPassword,
|
|||
|
OUT PUSER_SESSION_KEY UserSessionKey)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Takes the passed Response and OwfPassword and generates a UserSessionKey.
|
|||
|
|
|||
|
The current implementation takes the one-way-function of the OwfPassword
|
|||
|
and returns this as the key.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
LmResponse - The response sent during session setup.
|
|||
|
|
|||
|
LmOwfPassword - The hashed version of the user's password.
|
|||
|
|
|||
|
Return Values:
|
|||
|
|
|||
|
STATUS_SUCCESS - The function was completed successfully.
|
|||
|
The UserSessionKey is in UserSessionKey.
|
|||
|
|
|||
|
STATUS_UNSUCCESSFUL - Something failed. The UserSessionKey is undefined.
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
BOOL Status;
|
|||
|
NT_PASSWORD NtPassword;
|
|||
|
|
|||
|
//
|
|||
|
// Make the Owf password look like an NT password
|
|||
|
//
|
|||
|
|
|||
|
NtPassword.Buffer = (PWSTR)LmOwfPassword; // We can do this cast because we
|
|||
|
// know the OWF routine treats this
|
|||
|
// pointer as a byte pointer.
|
|||
|
NtPassword.Length = sizeof(*LmOwfPassword);
|
|||
|
NtPassword.MaximumLength = sizeof(*LmOwfPassword);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Calculate the OWF of the OwfPassword
|
|||
|
//
|
|||
|
|
|||
|
Status = CalculateNtOwfPassword( &NtPassword,
|
|||
|
(PNT_OWF_PASSWORD)UserSessionKey
|
|||
|
);
|
|||
|
if (!Status) {
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check if we've generated the error session key
|
|||
|
//
|
|||
|
|
|||
|
if (!_fmemcmp(UserSessionKey, &ErrorSessionKey, sizeof(*UserSessionKey))) {
|
|||
|
|
|||
|
//
|
|||
|
// Move away from the error session key
|
|||
|
//
|
|||
|
|
|||
|
UserSessionKey->data[0].data[0] ++;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return(TRUE);
|
|||
|
|
|||
|
UNREFERENCED_PARAMETER(LmResponse);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
CalculateUserSessionKeyNt(
|
|||
|
IN PNT_RESPONSE NtResponse,
|
|||
|
IN PNT_OWF_PASSWORD NtOwfPassword,
|
|||
|
OUT PUSER_SESSION_KEY UserSessionKey)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Takes the passed Response and OwfPassword and generates a UserSessionKey.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
NtResponse - The response sent during session setup.
|
|||
|
|
|||
|
NtOwfPassword - The hashed version of the user's password.
|
|||
|
|
|||
|
Return Values:
|
|||
|
|
|||
|
STATUS_SUCCESS - The function was completed successfully.
|
|||
|
The UserSessionKey is in UserSessionKey.
|
|||
|
|
|||
|
STATUS_UNSUCCESSFUL - Something failed. The UserSessionKey is undefined.
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
// Just call the LM version
|
|||
|
|
|||
|
return(CalculateUserSessionKeyLm((PLM_RESPONSE)NtResponse,
|
|||
|
(PLM_OWF_PASSWORD)NtOwfPassword,
|
|||
|
UserSessionKey));
|
|||
|
}
|
|||
|
|
|||
|
|