mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
788 lines
19 KiB
788 lines
19 KiB
/*++
|
|
|
|
Copyright (c) 1987-1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ssiauth.c
|
|
|
|
Abstract:
|
|
|
|
Authentication related functions
|
|
|
|
Author:
|
|
|
|
Ported from Lan Man 2.0
|
|
|
|
Environment:
|
|
|
|
User mode only.
|
|
Contains NT-specific code.
|
|
Requires ANSI C extensions: slash-slash comments, long external names.
|
|
|
|
Revision History:
|
|
|
|
12-Jul-1991 (cliffv)
|
|
Ported to NT. Converted to NT style.
|
|
|
|
--*/
|
|
|
|
//
|
|
// Common include files.
|
|
//
|
|
|
|
#include <logonsrv.h> // Include files common to entire service
|
|
|
|
//
|
|
// Include files specific to this .c file
|
|
//
|
|
|
|
#include <lmerr.h> // NERR_*
|
|
|
|
|
|
LONG NlGlobalSessionCounter = 0;
|
|
|
|
|
|
VOID
|
|
NlMakeSessionKey(
|
|
IN PNT_OWF_PASSWORD CryptKey,
|
|
IN PNETLOGON_CREDENTIAL ClientChallenge,
|
|
IN PNETLOGON_CREDENTIAL ServerChallenge,
|
|
OUT PNETLOGON_SESSION_KEY SessionKey
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Build an encryption key for use in authentication for
|
|
this RequestorName.
|
|
|
|
Arguments:
|
|
|
|
CryptKey -- The OWF password of the user account being used.
|
|
|
|
ClientChallenge -- 8 byte (64 bit) number generated by caller
|
|
|
|
ServerChallenge -- 8 byte (64 bit) number generated by primary
|
|
|
|
SessionKey -- 8 byte (64 bit) number generated at both ends
|
|
|
|
Return Value:
|
|
|
|
TRUE: Success
|
|
FALSE: Failure
|
|
|
|
NT status code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
BLOCK_KEY BlockKey;
|
|
NETLOGON_SESSION_KEY TempSessionKey;
|
|
|
|
//
|
|
// we will have a 112 bit key (64 bit encrypted rest padded with 0s)
|
|
//
|
|
|
|
RtlZeroMemory(SessionKey, sizeof(NETLOGON_SESSION_KEY));
|
|
|
|
//
|
|
// SessionKey = C + P (arithmetic sum ignore carry)
|
|
//
|
|
|
|
*((unsigned long * ) SessionKey) =
|
|
*((unsigned long * ) ClientChallenge) +
|
|
*((unsigned long * ) ServerChallenge);
|
|
|
|
*((unsigned long * )((LPBYTE)SessionKey + 4)) =
|
|
*((unsigned long * )((LPBYTE)ClientChallenge + 4)) +
|
|
*((unsigned long * )((LPBYTE)ServerChallenge + 4));
|
|
|
|
|
|
//
|
|
// CryptKey is our 16 byte key to be used as described in codespec
|
|
// use first 7 bytes of CryptKey for first encryption
|
|
//
|
|
|
|
RtlCopyMemory( &BlockKey, CryptKey, BLOCK_KEY_LENGTH );
|
|
|
|
Status = RtlEncryptBlock(
|
|
(PCLEAR_BLOCK) SessionKey, // Clear text
|
|
&BlockKey, // Key
|
|
(PCYPHER_BLOCK) &TempSessionKey); // Cypher Block
|
|
|
|
NlAssert( NT_SUCCESS( Status ) );
|
|
|
|
|
|
//
|
|
// Further encrypt the encrypted "SessionKey" using upper 7 bytes
|
|
//
|
|
|
|
NlAssert( LM_OWF_PASSWORD_LENGTH == 2*BLOCK_KEY_LENGTH+2 );
|
|
|
|
RtlCopyMemory( &BlockKey,
|
|
((PUCHAR)CryptKey) + 2 + BLOCK_KEY_LENGTH,
|
|
BLOCK_KEY_LENGTH );
|
|
|
|
Status = RtlEncryptBlock(
|
|
(PCLEAR_BLOCK) &TempSessionKey, // Clear text
|
|
&BlockKey, // Key
|
|
(PCYPHER_BLOCK) SessionKey); // Cypher Block
|
|
|
|
NlAssert( NT_SUCCESS( Status ) );
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NlCheckAuthenticator(
|
|
IN OUT PSERVER_SESSION ServerSession,
|
|
IN PNETLOGON_AUTHENTICATOR Authenticator,
|
|
OUT PNETLOGON_AUTHENTICATOR ReturnAuthenticator
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Verify that supplied Authenticator is valid.
|
|
It is intended for use by the server side after initial authentication
|
|
has succeeded. This routine will modify the seed by
|
|
first adding the time-of-day received from the Authenticator
|
|
and then by incrementing it.
|
|
|
|
A ReturnAuthenticator is built based on the final seed.
|
|
|
|
Arguments:
|
|
|
|
ServerSession - Pointer to the ServerSession structure. The following
|
|
fields are used:
|
|
|
|
SsAuthenticationSeed - Supplies the seed used for authentication and
|
|
returns the updated seed.
|
|
|
|
SsSessionKey - The session key used for encryption.
|
|
|
|
SsCheck - Is zeroed to indicate successful communication with the client.
|
|
|
|
Authenticator - The authenticator passed by the caller.
|
|
|
|
ReturnAuthenticator - The authenticator we'll return to the caller.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS;
|
|
STATUS_ACCESS_DENIED;
|
|
STATUS_TIME_DIFFERENCE_AT_DC;
|
|
|
|
--*/
|
|
{
|
|
|
|
NETLOGON_CREDENTIAL TargetCredential;
|
|
|
|
|
|
#ifdef notdef // Doesn't work if caller in different time zone
|
|
|
|
LARGE_INTEGER TimeNow;
|
|
long timeofday;
|
|
long timediff;
|
|
|
|
//
|
|
// First check if time-of-day is rational.
|
|
//
|
|
|
|
NtQuerySystemTime( &TimeNow );
|
|
RtlTimeToSecondsSince1970( &TimeNow, &timeofday );
|
|
|
|
timediff = timeofday - Authenticator->timestamp;
|
|
if (timediff < 0) {
|
|
timediff = Authenticator->timestamp - timeofday;
|
|
}
|
|
|
|
if (timediff > RATIONAL_TIME) {
|
|
return STATUS_TIME_DIFFERENCE_AT_DC;
|
|
}
|
|
#endif // notdef
|
|
|
|
|
|
#ifdef BAD_ALIGNMENT
|
|
NlPrint((NL_CHALLENGE_RES,"NlCheckAuthenticator: Seed = %lx %lx\n",
|
|
((DWORD *) (&ServerSession->SsAuthenticationSeed))[0],
|
|
((DWORD *) (&ServerSession->SsAuthenticationSeed))[1]));
|
|
|
|
|
|
NlPrint((NL_CHALLENGE_RES,
|
|
"NlCheckAuthenticator: SessionKey = %lx %lx %lx %lx\n",
|
|
((DWORD *) (&ServerSession->SsSessionKey))[0],
|
|
((DWORD *) (&ServerSession->SsSessionKey))[1],
|
|
((DWORD *) (&ServerSession->SsSessionKey))[2],
|
|
((DWORD *) (&ServerSession->SsSessionKey))[3]));
|
|
|
|
NlPrint((NL_CHALLENGE_RES,
|
|
"NlCheckAuthenticator: Client Authenticator GOT = %lx %lx\n",
|
|
((DWORD *) (&Authenticator->Credential))[0],
|
|
((DWORD *) (&Authenticator->Credential))[1]));
|
|
|
|
NlPrint((NL_CHALLENGE_RES,
|
|
"NlCheckAuthenticator: Time = %lx\n",
|
|
((DWORD *) (&Authenticator->timestamp))[0] ));
|
|
#endif // BAD_ALIGNMENT
|
|
|
|
|
|
|
|
//
|
|
// modify the seed before computing auth_credential for verification
|
|
// Two long words are added and overflow carry (if any) ignored
|
|
// This will leave upper 4 bytes unchanged
|
|
//
|
|
|
|
*((unsigned long * ) &ServerSession->SsAuthenticationSeed) += Authenticator->timestamp;
|
|
|
|
|
|
#ifdef BAD_ALIGNMENT
|
|
NlPrint((NL_CHALLENGE_RES,
|
|
"NlCheckAuthenticator: Seed + TIME = %lx %lx\n",
|
|
((DWORD *) (&ServerSession->SsAuthenticationSeed))[0],
|
|
((DWORD *) (&ServerSession->SsAuthenticationSeed))[1]));
|
|
#endif // BAD_ALIGNMENT
|
|
|
|
|
|
//
|
|
// Compute TargetCredential to verify the one supplied in the Authenticator
|
|
//
|
|
|
|
NlComputeCredentials( &ServerSession->SsAuthenticationSeed,
|
|
&TargetCredential,
|
|
&ServerSession->SsSessionKey );
|
|
|
|
|
|
#ifdef BAD_ALIGNMENT
|
|
NlPrint((NL_CHALLENGE_RES,
|
|
"NlCheckAuthenticator: Client Authenticator MADE = %lx %lx\n",
|
|
((DWORD *) (&TargetCredential))[0],
|
|
((DWORD *) (&TargetCredential))[1]));
|
|
#endif // BAD_ALIGNMENT
|
|
|
|
//
|
|
// verify the computed credentials with those supplied
|
|
// Authenticator must have used seed + time_of_day as seed
|
|
//
|
|
|
|
if (RtlCompareMemory( &Authenticator->Credential,
|
|
&TargetCredential,
|
|
sizeof(TargetCredential)) !=
|
|
sizeof(TargetCredential)) {
|
|
return STATUS_ACCESS_DENIED;
|
|
}
|
|
|
|
//
|
|
// modify our seed before computing the ReturnAuthenticator.
|
|
// The requestor will increment his seed if he matches this credentials.
|
|
//
|
|
|
|
(*((unsigned long * ) &ServerSession->SsAuthenticationSeed))++;
|
|
|
|
//
|
|
// compute ClientCredential to send back to requestor
|
|
//
|
|
|
|
NlComputeCredentials( &ServerSession->SsAuthenticationSeed,
|
|
&ReturnAuthenticator->Credential,
|
|
&ServerSession->SsSessionKey);
|
|
|
|
|
|
#ifdef BAD_ALIGNMENT
|
|
NlPrint((NL_CHALLENGE_RES,
|
|
"NlCheckAuthenticator: Server Authenticator SEND = %lx %lx\n",
|
|
((DWORD *) (&ReturnAuthenticator->Credential))[0],
|
|
((DWORD *) (&ReturnAuthenticator->Credential))[1]));
|
|
|
|
|
|
NlPrint((NL_CHALLENGE_RES,
|
|
"NlCheckAuthenticator: Seed + time + 1= %lx %lx\n",
|
|
((DWORD *) (&ServerSession->SsAuthenticationSeed))[0],
|
|
((DWORD *) (&ServerSession->SsAuthenticationSeed))[1]));
|
|
#endif // BAD_ALIGNMENT
|
|
|
|
|
|
//
|
|
// Indicate successful communication with the client
|
|
//
|
|
|
|
ServerSession->SsCheck = 0;
|
|
ServerSession->SsPulseTimeoutCount = 0;
|
|
ServerSession->SsFlags &= ~SS_PULSE_SENT;
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
NlComputeCredentials(
|
|
IN PNETLOGON_CREDENTIAL Challenge,
|
|
OUT PNETLOGON_CREDENTIAL Credential,
|
|
IN PNETLOGON_SESSION_KEY SessionKey
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Calculate the credentials by encrypting the 8 byte
|
|
challenge with first 7 bytes of sessionkey and then
|
|
further encrypting it by next 7 bytes of sessionkey.
|
|
|
|
Arguments:
|
|
|
|
Challenge - Supplies the 8 byte (64 bit) challenge
|
|
|
|
Credential - Returns the 8 byte (64 bit) number generated
|
|
|
|
SessionKey 14 byte (112 bit) encryption key
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
BLOCK_KEY BlockKey;
|
|
CYPHER_BLOCK IntermediateBlock;
|
|
|
|
RtlZeroMemory(Credential, sizeof(*Credential));
|
|
|
|
//
|
|
// use first 7 bytes of SessionKey for first encryption
|
|
//
|
|
|
|
RtlCopyMemory( &BlockKey, SessionKey, BLOCK_KEY_LENGTH );
|
|
|
|
Status = RtlEncryptBlock( (PCLEAR_BLOCK) Challenge, // Cleartext
|
|
&BlockKey, // Key
|
|
&IntermediateBlock ); // Cypher Block
|
|
|
|
NlAssert( NT_SUCCESS(Status) );
|
|
|
|
//
|
|
// further encrypt the encrypted Credential using next 7 bytes
|
|
//
|
|
|
|
RtlCopyMemory( &BlockKey,
|
|
((PUCHAR)SessionKey) + BLOCK_KEY_LENGTH,
|
|
BLOCK_KEY_LENGTH );
|
|
|
|
Status = RtlEncryptBlock( (PCLEAR_BLOCK) &IntermediateBlock, // Cleartext
|
|
&BlockKey, // Key
|
|
Credential ); // Cypher Block
|
|
|
|
NlAssert( NT_SUCCESS(Status) );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
NlComputeChallenge(
|
|
OUT PNETLOGON_CREDENTIAL Challenge
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Generates a 64 bit challenge
|
|
|
|
Make an 8 byte seed by filling in BigTime i.e. seconds
|
|
since Jan 1 1970 in lower four bytes and a counter in
|
|
upper four bytes. Counter is incremented after each use.
|
|
This seed is used as encryption key to encrypt standard
|
|
text which will be used as challenge.
|
|
|
|
Arguments:
|
|
|
|
Challenge - Returns the computed challenge
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
char Seed[PWLEN];
|
|
LM_OWF_PASSWORD BigChallenge;
|
|
LARGE_INTEGER TimeNow;
|
|
|
|
|
|
RtlZeroMemory(Seed, sizeof(Seed) );
|
|
|
|
//
|
|
// we need to remember ClientChallenge and RequestorName for future use
|
|
// put these into shared seg SSISEG
|
|
// NlGlobalSessionCounter is a global initialized to 0 at UAS init time
|
|
//
|
|
|
|
|
|
Status = NtQuerySystemTime( &TimeNow );
|
|
NlAssert( NT_SUCCESS(Status) );
|
|
|
|
Status = RtlTimeToSecondsSince1970( &TimeNow, ((unsigned long * ) Seed) );
|
|
NlAssert( NT_SUCCESS(Status) );
|
|
|
|
*((unsigned long * ) & Seed[4]) = NlGlobalSessionCounter++;
|
|
|
|
//
|
|
// Create ClientChallenge
|
|
//
|
|
// NOTE: RtlCalculateLmOwfPassword() will generate 16 byte txt
|
|
//
|
|
|
|
Status = RtlCalculateLmOwfPassword(Seed, &BigChallenge);
|
|
NlAssert( NT_SUCCESS(Status) );
|
|
|
|
//
|
|
// we need (or will use) only 8 bytes of this info
|
|
//
|
|
|
|
RtlCopyMemory(Challenge, &BigChallenge, sizeof(Challenge) );
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
NlBuildAuthenticator(
|
|
IN OUT PNETLOGON_CREDENTIAL AuthenticationSeed,
|
|
IN PNETLOGON_SESSION_KEY SessionKey,
|
|
OUT PNETLOGON_AUTHENTICATOR Authenticator
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Build the authenticator to be sent to primary.
|
|
This routine will modify the seed by adding the
|
|
time-of-day before computing the credentials.
|
|
|
|
Arguments:
|
|
|
|
AuthenticationSeed -- The current authentication seed. This seed will
|
|
have the current time of day added to it prior to building the
|
|
Authenticator.
|
|
|
|
SessionKey - The Session Key used for encrypting the Authenticator.
|
|
|
|
Authenticator - The Authenticator to pass to the PDC for the current
|
|
call.
|
|
|
|
Return Value:
|
|
|
|
NT Status code
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
LARGE_INTEGER TimeNow;
|
|
|
|
//
|
|
// Use the current time of day to modify the authentication seed
|
|
//
|
|
|
|
RtlZeroMemory(Authenticator, sizeof(*Authenticator));
|
|
|
|
Status = NtQuerySystemTime( &TimeNow );
|
|
NlAssert( NT_SUCCESS(Status) );
|
|
|
|
Status = RtlTimeToSecondsSince1970( &TimeNow, &Authenticator->timestamp );
|
|
NlAssert( NT_SUCCESS(Status) );
|
|
|
|
//
|
|
// Modify the AuthenticationSeed before computing auth_credential for
|
|
// verification .
|
|
//
|
|
// Two long words are added and overflow carry (if any) ignored
|
|
// This will leave upper 4 bytes unchanged
|
|
//
|
|
|
|
|
|
#ifdef BAD_ALIGNMENT
|
|
NlPrint((NL_CHALLENGE_RES,"NlBuildAuthenticator: Old Seed = %lx %lx\n",
|
|
((DWORD *) (AuthenticationSeed))[0],
|
|
((DWORD *) (AuthenticationSeed))[1]));
|
|
|
|
NlPrint((NL_CHALLENGE_RES,"NlBuildAuthenticator: Time = %lx\n",
|
|
((DWORD *) (&Authenticator->timestamp))[0] ));
|
|
#endif // BAD_ALIGNMENT
|
|
|
|
|
|
|
|
*((unsigned long * ) AuthenticationSeed) += Authenticator->timestamp;
|
|
|
|
|
|
#ifdef BAD_ALIGNMENT
|
|
NlPrint((NL_CHALLENGE_RES,"NlBuildAuthenticator: New Seed = %lx %lx\n",
|
|
((DWORD *) (AuthenticationSeed))[0],
|
|
((DWORD *) (AuthenticationSeed))[1]));
|
|
|
|
|
|
NlPrint((NL_CHALLENGE_RES,
|
|
"NlBuildAuthenticator: SessionKey = %lx %lx %lx %lx\n",
|
|
((DWORD *) (SessionKey))[0],
|
|
((DWORD *) (SessionKey))[1],
|
|
((DWORD *) (SessionKey))[2],
|
|
((DWORD *) (SessionKey))[3]));
|
|
#endif // BAD_ALIGNMENT
|
|
|
|
|
|
//
|
|
// compute AuthenticationSeed to verify the one supplied by Requestor
|
|
//
|
|
|
|
NlComputeCredentials( AuthenticationSeed,
|
|
&Authenticator->Credential,
|
|
SessionKey);
|
|
|
|
|
|
#ifdef BAD_ALIGNMENT
|
|
NlPrint((NL_CHALLENGE_RES,"NlBuildAuthenticator: Client Authenticator = %lx %lx\n",
|
|
((DWORD *) (&Authenticator->Credential))[0],
|
|
((DWORD *) (&Authenticator->Credential))[1]));
|
|
#endif // BAD_ALIGNMENT
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
NlUpdateSeed(
|
|
IN OUT PNETLOGON_CREDENTIAL AuthenticationSeed,
|
|
IN PNETLOGON_CREDENTIAL TargetCredential,
|
|
IN PNETLOGON_SESSION_KEY SessionKey
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called by the initiator of a communication over the secure channel
|
|
following a successful transaction.
|
|
|
|
The PDC would have incremented the seed so we must do so also.
|
|
|
|
We also verify that the incremented seed builds a credential identical
|
|
to the one passed back by the PDC.
|
|
|
|
Arguments:
|
|
|
|
AuthenticationSeed - Pointer to the AuthenticationSeed to be incremented.
|
|
|
|
TargetCredential - Supplies the Credential that the incremented
|
|
AuthenticationSeed should encrypt to.
|
|
|
|
SessionKey - Supplies the encryption key to use for the encryption.
|
|
|
|
Return Value:
|
|
|
|
TRUE: Success
|
|
FALSE: Failure
|
|
|
|
--*/
|
|
{
|
|
NETLOGON_CREDENTIAL NewCredential;
|
|
|
|
//
|
|
// modify our AuthenticationSeed before computing NewCredential to check
|
|
// those returned from primary (NewSeed = AuthenticationSeed+1)
|
|
//
|
|
|
|
(*((unsigned long * ) AuthenticationSeed))++;
|
|
|
|
|
|
#ifdef BAD_ALIGNMENT
|
|
NlPrint((NL_CHALLENGE_RES,"NlUpdateSeed: Seed + time + 1= %lx %lx\n",
|
|
((DWORD *) (AuthenticationSeed))[0],
|
|
((DWORD *) (AuthenticationSeed))[1]));
|
|
#endif // BAD_ALIGNMENT
|
|
|
|
|
|
//
|
|
// Compute ClientCredential to check which came from primary
|
|
//
|
|
|
|
NlComputeCredentials(AuthenticationSeed, &NewCredential, SessionKey);
|
|
|
|
|
|
#ifdef BAD_ALIGNMENT
|
|
NlPrint((NL_CHALLENGE_RES,"NlUpdateSeed: Server Authenticator GOT = %lx %lx\n",
|
|
((DWORD *) (TargetCredential))[0],
|
|
((DWORD *) (TargetCredential))[1]));
|
|
|
|
|
|
NlPrint((NL_CHALLENGE_RES,"NlUpdateSeed: Server Authenticator MADE = %lx %lx\n",
|
|
((DWORD *) (&NewCredential))[0],
|
|
((DWORD *) (&NewCredential))[1]));
|
|
#endif // BAD_ALIGNMENT
|
|
|
|
|
|
if (RtlCompareMemory( TargetCredential,
|
|
&NewCredential,
|
|
sizeof(NewCredential)) !=
|
|
sizeof(NewCredential)) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Done
|
|
//
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
NlEncryptRC4(
|
|
IN OUT PVOID Buffer,
|
|
IN ULONG BufferSize,
|
|
IN PSESSION_INFO SessionInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Encrypt data using RC4 with the session key as the key.
|
|
|
|
Arguments:
|
|
|
|
Buffer -- Buffer containing the data to encrypt in place.
|
|
|
|
BufferSize -- Size (in bytes) of Buffer.
|
|
|
|
SessionInfo -- Info describing secure channel
|
|
|
|
Return Value:
|
|
|
|
NT status code
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus;
|
|
DATA_KEY KeyData;
|
|
CRYPT_BUFFER Data;
|
|
|
|
//
|
|
// Build a data buffer to describe the encryption key.
|
|
//
|
|
|
|
KeyData.Length = sizeof(NETLOGON_SESSION_KEY);
|
|
KeyData.MaximumLength = sizeof(NETLOGON_SESSION_KEY);
|
|
KeyData.Buffer = (PVOID)&SessionInfo->SessionKey;
|
|
|
|
NlAssert( SessionInfo->NegotiatedFlags & NETLOGON_SUPPORTS_RC4_ENCRYPTION );
|
|
|
|
//
|
|
// Build a data buffer to decribe the encrypted data.
|
|
//
|
|
|
|
Data.Length = Data.MaximumLength = BufferSize;
|
|
Data.Buffer = Buffer;
|
|
|
|
//
|
|
// Encrypt the data.
|
|
//
|
|
|
|
IF_DEBUG( ENCRYPT ) {
|
|
NlPrint((NL_ENCRYPT, "NlEncryptRC4: Clear data\n" ));
|
|
NlpDumpHexData( NL_ENCRYPT,
|
|
(LPDWORD)Data.Buffer,
|
|
Data.Length / sizeof(DWORD) );
|
|
}
|
|
|
|
NtStatus = RtlEncryptData2( &Data, &KeyData );
|
|
NlAssert( NT_SUCCESS(NtStatus) );
|
|
|
|
IF_DEBUG( ENCRYPT ) {
|
|
NlPrint((NL_ENCRYPT, "NlEncryptRC4: Encrypted data\n" ));
|
|
NlpDumpHexData( NL_ENCRYPT,
|
|
(LPDWORD)Data.Buffer,
|
|
Data.Length / sizeof(DWORD) );
|
|
}
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
NlDecryptRC4(
|
|
IN OUT PVOID Buffer,
|
|
IN ULONG BufferSize,
|
|
IN PSESSION_INFO SessionInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Decrypt data using RC4 with the session key as the key.
|
|
|
|
Arguments:
|
|
|
|
Buffer -- Buffer containing the data to decrypt in place.
|
|
|
|
BufferSize -- Size (in bytes) of Buffer.
|
|
|
|
SessionInfo -- Info describing secure channel
|
|
|
|
Return Value:
|
|
|
|
NT status code
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus;
|
|
DATA_KEY KeyData;
|
|
CRYPT_BUFFER Data;
|
|
|
|
//
|
|
// Build a data buffer to describe the encryption key.
|
|
//
|
|
|
|
KeyData.Length = sizeof(NETLOGON_SESSION_KEY);
|
|
KeyData.MaximumLength = sizeof(NETLOGON_SESSION_KEY);
|
|
KeyData.Buffer = (PVOID)&SessionInfo->SessionKey;
|
|
|
|
NlAssert( SessionInfo->NegotiatedFlags & NETLOGON_SUPPORTS_RC4_ENCRYPTION );
|
|
|
|
//
|
|
// Build a data buffer to decribe the encrypted data.
|
|
//
|
|
|
|
Data.Length = Data.MaximumLength = BufferSize;
|
|
Data.Buffer = Buffer;
|
|
|
|
//
|
|
// Encrypt the data.
|
|
//
|
|
|
|
|
|
IF_DEBUG( ENCRYPT ) {
|
|
NlPrint((NL_ENCRYPT, "NlDecryptRC4: Encrypted data\n" ));
|
|
NlpDumpHexData( NL_ENCRYPT,
|
|
(LPDWORD)Data.Buffer,
|
|
Data.Length / sizeof(DWORD) );
|
|
}
|
|
|
|
NtStatus = RtlDecryptData2( &Data, &KeyData );
|
|
NlAssert( NT_SUCCESS(NtStatus) );
|
|
|
|
IF_DEBUG( ENCRYPT ) {
|
|
NlPrint((NL_ENCRYPT, "NlDecryptRC4: Clear data\n" ));
|
|
NlpDumpHexData( NL_ENCRYPT,
|
|
(LPDWORD)Data.Buffer,
|
|
Data.Length / sizeof(DWORD) );
|
|
}
|
|
|
|
}
|