|
|
/*++
Copyright (c) 1991-92 Microsoft Corporation
Module Name:
sccrypt.c
Abstract:
This module provides support routines to encrypt and decrypt a password.
Author:
Rita Wong (ritaw) 27-Apr-1992
Environment:
Contains NT specific code.
Revision History:
--*/
#include <scpragma.h>
extern "C" { #include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
}
#include <crypt.h>
#include <windef.h> // DWORD (needed by scdebug.h).
#include <winerror.h> // NO_ERROR
#include <winbase.h> // LocalAlloc
#include <stdlib.h>
#include <scdebug.h> // STATIC.
#include <svcctl.h> // SC_RPC_HANDLE
#include <sccrypt.h> // Exported function prototypes
DWORD ScEncryptPassword( IN SC_RPC_HANDLE ContextHandle, IN LPWSTR Password, OUT LPBYTE *EncryptedPassword, OUT LPDWORD EncryptedPasswordSize ) /*++
Routine Description:
This function encrypts a user specified clear text password with the user session key gotten from the RPC context handle.
This is called by the RPC client.
Arguments:
ContextHandle - Supplies the RPC context handle.
Password - Supplies the user specified password.
EncryptedPassword - Receives a pointer to memory which contains the encrypted password. This memory must be freed with LocalFree when done.
EncryptedPasswordSize - Receives the number of bytes of encrypted password returned.
Return Value:
NO_ERROR - Successful encryption.
ERROR_NOT_ENOUGH_MEMORY - Failed to allocate the EncryptedPassword buffer.
ERROR_GEN_FAILURE - Any other failures encountered by this function.
--*/ { NTSTATUS ntstatus; USER_SESSION_KEY SessionKey;
CLEAR_DATA ClearTextPW; DATA_KEY DataKey; CYPHER_DATA EncryptPW;
ntstatus = RtlGetUserSessionKeyClient((PVOID) ContextHandle, &SessionKey);
if (!NT_SUCCESS(ntstatus)) { SCC_LOG1(ERROR, "ScEncryptPassword: RtlGetUserSessionKeyClient returned " FORMAT_NTSTATUS "\n", ntstatus);
return RtlNtStatusToDosErrorNoTeb(ntstatus); }
//
// Encryption includes the NULL terminator.
//
ClearTextPW.Length = ((DWORD) wcslen(Password) + 1) * sizeof(WCHAR); ClearTextPW.MaximumLength = ClearTextPW.Length; ClearTextPW.Buffer = (PVOID) Password;
DataKey.Length = USER_SESSION_KEY_LENGTH; DataKey.MaximumLength = USER_SESSION_KEY_LENGTH; DataKey.Buffer = (PVOID) &SessionKey;
EncryptPW.Length = 0; EncryptPW.MaximumLength = 0; EncryptPW.Buffer = NULL;
//
// Call RtlEncryptData with 0 length so that it will return the
// required length.
//
ntstatus = RtlEncryptData( &ClearTextPW, &DataKey, &EncryptPW );
if (ntstatus != STATUS_BUFFER_TOO_SMALL) { SCC_LOG1(ERROR, "ScEncryptPassword: RtlEncryptData returned " FORMAT_NTSTATUS "\n", ntstatus);
return RtlNtStatusToDosErrorNoTeb(ntstatus); }
if ((EncryptPW.Buffer = (PVOID) LocalAlloc(0, EncryptPW.Length)) == NULL) { SCC_LOG1(ERROR, "ScEncryptPassword: LocalAlloc failed " FORMAT_DWORD "\n", GetLastError());
return ERROR_NOT_ENOUGH_MEMORY; }
EncryptPW.MaximumLength = EncryptPW.Length;
ntstatus = RtlEncryptData( &ClearTextPW, &DataKey, &EncryptPW );
if (!NT_SUCCESS(ntstatus)) { SCC_LOG1(ERROR, "ScEncryptPassword: RtlEncryptData returned " FORMAT_NTSTATUS "\n", ntstatus);
LocalFree(EncryptPW.Buffer); return RtlNtStatusToDosErrorNoTeb(ntstatus); }
*EncryptedPassword = (LPBYTE) EncryptPW.Buffer; *EncryptedPasswordSize = EncryptPW.Length;
return NO_ERROR; }
DWORD ScDecryptPassword( IN SC_RPC_HANDLE ContextHandle, IN LPBYTE EncryptedPassword, IN DWORD EncryptedPasswordSize, OUT LPWSTR *Password ) /*++
Routine Description:
This function decrypts a given encrypted password back to clear text with the user session key gotten from the RPC context handle.
This is called by the RPC server.
Arguments:
ContextHandle - Supplies the RPC context handle.
EncryptedPassword - Supplies a buffer which contains the encrypted password.
EncryptedPasswordSize - Supplies the number of bytes in EncryptedPassword.
Password - Receives a pointer to the memory which contains the clear text password. This memory must be freed with LocalFree when done.
Return Value:
NO_ERROR - Successful encryption.
ERROR_NOT_ENOUGH_MEMORY - Failed to allocate the Password buffer.
ERROR_GEN_FAILURE - Any other failures encountered by this function.
--*/ { NTSTATUS ntstatus; USER_SESSION_KEY SessionKey;
CYPHER_DATA EncryptPW; DATA_KEY DataKey; CLEAR_DATA ClearTextPW;
ntstatus = RtlGetUserSessionKeyServer((PVOID) ContextHandle, &SessionKey);
if (!NT_SUCCESS(ntstatus)) { SC_LOG1(ERROR, "ScDecryptPassword: RtlGetUserSessionKeyClient returned " FORMAT_NTSTATUS "\n", ntstatus);
return RtlNtStatusToDosErrorNoTeb(ntstatus); }
EncryptPW.Length = EncryptedPasswordSize; EncryptPW.MaximumLength = EncryptedPasswordSize; EncryptPW.Buffer = (PVOID) EncryptedPassword;
DataKey.Length = USER_SESSION_KEY_LENGTH; DataKey.MaximumLength = USER_SESSION_KEY_LENGTH; DataKey.Buffer = (PVOID) &SessionKey;
ClearTextPW.Length = 0; ClearTextPW.MaximumLength = 0; ClearTextPW.Buffer = NULL;
//
// Call RtlDecryptData with 0 length so that it will return the
// required length.
//
ntstatus = RtlDecryptData( &EncryptPW, &DataKey, &ClearTextPW );
if (ntstatus != STATUS_BUFFER_TOO_SMALL) { if (ntstatus == STATUS_SUCCESS && ClearTextPW.Length == 0) { //
// Assume empty password
//
*Password = NULL; return NO_ERROR; }
SC_LOG1(ERROR, "ScDecryptPassword: RtlDecryptData returned " FORMAT_NTSTATUS "\n", ntstatus);
return RtlNtStatusToDosErrorNoTeb(ntstatus); }
//
// Allocate exact size needed because NULL terminator is included in
// the encrypted string.
//
if ((ClearTextPW.Buffer = (PVOID) LocalAlloc(LMEM_ZEROINIT, ClearTextPW.Length)) == NULL) { SC_LOG1(ERROR, "ScDecryptPassword: LocalAlloc failed " FORMAT_DWORD "\n", GetLastError());
return ERROR_NOT_ENOUGH_MEMORY; }
ClearTextPW.MaximumLength = ClearTextPW.Length;
ntstatus = RtlDecryptData( &EncryptPW, &DataKey, &ClearTextPW );
if (!NT_SUCCESS(ntstatus)) { SC_LOG1(ERROR, "ScDecryptPassword: RtlDecryptData returned " FORMAT_NTSTATUS "\n", ntstatus);
return RtlNtStatusToDosErrorNoTeb(ntstatus); }
*Password = (LPWSTR) ClearTextPW.Buffer;
return NO_ERROR; }
|