/*++

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


