306 lines
7.4 KiB
C++
306 lines
7.4 KiB
C++
|
/*++
|
|||
|
|
|||
|
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 ERROR_GEN_FAILURE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// 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 ERROR_GEN_FAILURE;
|
|||
|
}
|
|||
|
|
|||
|
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 ERROR_GEN_FAILURE;
|
|||
|
}
|
|||
|
|
|||
|
*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 ERROR_GEN_FAILURE;
|
|||
|
}
|
|||
|
|
|||
|
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 ERROR_GEN_FAILURE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// 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 ERROR_GEN_FAILURE;
|
|||
|
}
|
|||
|
|
|||
|
*Password = (LPWSTR) ClearTextPW.Buffer;
|
|||
|
|
|||
|
return NO_ERROR;
|
|||
|
}
|