windows-nt/Source/XPSP1/NT/ds/security/base/lsa/common/cr.c
2020-09-26 16:20:57 +08:00

413 lines
9.3 KiB
C

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
cr.c
Abstract:
Local Security Authority - Cipher Routines common to Client and Server
These routines interface the LSA client or server sides with the Cipher
Routines. They perform RPC-style memory allocation.
Author:
Scott Birrell (ScottBi) December 13, 1991
Environment:
Revision History:
--*/
#include <lsacomp.h>
VOID
LsapCrFreeMemoryValue(
IN PVOID MemoryValue
)
/*++
Routine Description:
This function frees the memory allocated for an Cipher Value.
Arguments:
None.
Return Value:
--*/
{
//
// The memory is currently a counted string contained in a UNICODE
// STRING structure in which the buffer follows the structure. A
// single MIDL_user_free will therefore do the trick.
//
MIDL_user_free(MemoryValue);
}
NTSTATUS
LsapCrEncryptValue(
IN OPTIONAL PLSAP_CR_CLEAR_VALUE ClearValue,
IN PLSAP_CR_CIPHER_KEY CipherKey,
OUT PLSAP_CR_CIPHER_VALUE *CipherValue
)
/*++
Routine Description:
This function two-way encrypts a Value with the given Cipher Key
and allocates memory for the output. The memory must be freed after
use by calling LsapCrFreeMemoryValue().
Arguments:
ClearValue - Pointer to structure referencing value to be encrypted.
A NULL pointer may be specified.
CipherKey - Pointer to structure referencing the Cipher Key
CipherValue - Receives a pointer to a structure referencing the
encrypted value or NULL.
Return Value:
--*/
{
NTSTATUS Status;
LSAP_CR_CIPHER_VALUE TempCipherValue;
PLSAP_CR_CIPHER_VALUE OutputCipherValue = NULL;
ULONG CipherValueBufferLength;
LSAP_CR_CLEAR_VALUE LocalFake = { 0 };
//
// If NULL is specified for input, return NULL for output.
//
if (!ARGUMENT_PRESENT(ClearValue)) {
*CipherValue = NULL;
ClearValue = &LocalFake ;
}
//
// Obtain the length of the encrypted value buffer that will be
// required by calling the encryption routine in 'query' mode
// by passing a pointer to a return Cipher Value structure containing
// a MaximumLength of 0.
//
TempCipherValue.MaximumLength = 0;
TempCipherValue.Length = 0;
TempCipherValue.Buffer = NULL;
Status = LsapCrRtlEncryptData(
ClearValue,
CipherKey,
&TempCipherValue
);
if (Status != STATUS_BUFFER_TOO_SMALL) {
goto EncryptValueError;
}
//
// Allocate memory for the output structure followed by buffer.
//
CipherValueBufferLength = TempCipherValue.Length;
Status = STATUS_INSUFFICIENT_RESOURCES;
OutputCipherValue = MIDL_user_allocate(
sizeof (LSAP_CR_CIPHER_VALUE) +
CipherValueBufferLength
);
if (OutputCipherValue == NULL) {
goto EncryptValueError;
}
//
// Initialize Cipher Value structure. The Buffer pointer is set to
// to point to the byte following the structure header.
//
OutputCipherValue->Buffer = (PCHAR)(OutputCipherValue + 1);
OutputCipherValue->MaximumLength = CipherValueBufferLength;
OutputCipherValue->Length = CipherValueBufferLength;
//
// Now call the two-way encryption routine.
//
Status = LsapCrRtlEncryptData(
ClearValue,
CipherKey,
OutputCipherValue
);
if (NT_SUCCESS(Status)) {
*CipherValue = OutputCipherValue;
return(Status);
}
EncryptValueError:
//
// If necessary, free the memory allocated for the output encrypted value.
//
if (OutputCipherValue != NULL) {
MIDL_user_free(OutputCipherValue);
}
*CipherValue = NULL;
return(Status);
}
NTSTATUS
LsapCrDecryptValue(
IN OPTIONAL PLSAP_CR_CIPHER_VALUE CipherValue,
IN PLSAP_CR_CIPHER_KEY CipherKey,
OUT PLSAP_CR_CLEAR_VALUE *ClearValue
)
/*++
Routine Description:
This function decrypts a Value that has been two-way Cipher with the
given Cipher Key and allocates memory for the output. The memory
must be freed after use by calling LsapCrFreeMemoryValue();
Arguments:
CipherValue - Pointer to structure referencing encrypted Value.
CipherKey - Pointer to structure referencing the Cipher Key
ClearValue - Receives a pointer to a structure referencing the
Decrypted Value.
Return Value:
--*/
{
NTSTATUS Status;
LSAP_CR_CLEAR_VALUE TempClearValue;
PLSAP_CR_CLEAR_VALUE OutputClearValue = NULL;
ULONG ClearValueBufferLength;
//
// If NULL is specified for input, return NULL for output.
//
if (!ARGUMENT_PRESENT(CipherValue)) {
*ClearValue = NULL;
} else {
if ( CipherValue->MaximumLength < CipherValue->Length ||
( CipherValue->Length != 0 && CipherValue->Buffer == NULL ) ) {
return STATUS_INVALID_PARAMETER;
}
}
//
// Obtain the length of the decrypted (clear) value buffer that will be
// required by calling the decryption routine in 'query' mode
// by passing a pointer to a return Clear Value structure containing
// a MaximumLength of 0.
//
TempClearValue.MaximumLength = 0;
TempClearValue.Length = 0;
TempClearValue.Buffer = NULL;
Status = LsapCrRtlDecryptData(
CipherValue,
CipherKey,
&TempClearValue
);
//
// Since we supplied a buffer length of 0, we would normally expect
// to receive STATUS_BUFFER_TOO_SMALL back plus the buffer size required.
// There is one exceptional case and that is where the original
// unencrypted data had length 0. In this case, we expect
// STATUS_SUCCESS and a length required equal to 0 returned.
//
if (Status != STATUS_BUFFER_TOO_SMALL) {
if (!(Status == STATUS_SUCCESS && TempClearValue.Length == 0)) {
goto DecryptValueError;
}
}
//
// Allocate memory for the output structure followed by buffer.
//
ClearValueBufferLength = TempClearValue.Length;
Status = STATUS_INSUFFICIENT_RESOURCES;
OutputClearValue = MIDL_user_allocate(
sizeof (LSAP_CR_CLEAR_VALUE) +
ClearValueBufferLength
);
if (OutputClearValue == NULL) {
goto DecryptValueError;
}
//
// Initialize Clear Value structure. The Buffer pointer is set to
// to point to the byte following the structure header.
//
OutputClearValue->Buffer = (PCHAR)(OutputClearValue + 1);
OutputClearValue->MaximumLength = ClearValueBufferLength;
OutputClearValue->Length = ClearValueBufferLength;
//
// Now call the two-way decryption routine.
//
Status = LsapCrRtlDecryptData(
CipherValue,
CipherKey,
OutputClearValue
);
if (NT_SUCCESS(Status)) {
*ClearValue = OutputClearValue;
return(Status);
}
DecryptValueError:
//
// If necessary, free the memory allocated for the output decrypted value.
//
if (OutputClearValue != NULL) {
MIDL_user_free(OutputClearValue);
}
*ClearValue = NULL;
return(Status);
}
VOID
LsapCrUnicodeToClearValue(
IN OPTIONAL PUNICODE_STRING UnicodeString,
OUT PLSAP_CR_CLEAR_VALUE ClearValue
)
/*++
Routine Description:
This function converts a Unicode structure to a Clear Value structure.
Arguments:
UnicodeString - Optional pointer to Unicode string. If NULL, the
output Clear Value structure is initialized to have zero
length and Maximum length, and with a NULL buffer pointer.
ClearValue - Pointer to Clear Value structure.
Return Value:
None.
--*/
{
UNICODE_STRING IntermediateUnicodeString;
if (ARGUMENT_PRESENT(UnicodeString)) {
IntermediateUnicodeString = *UnicodeString;
ClearValue->Length = (ULONG) IntermediateUnicodeString.Length;
ClearValue->MaximumLength = (ULONG) IntermediateUnicodeString.MaximumLength;
ClearValue->Buffer = (PUCHAR) IntermediateUnicodeString.Buffer;
return;
}
ClearValue->Length = ClearValue->MaximumLength = 0;
ClearValue->Buffer = NULL;
}
VOID
LsapCrClearValueToUnicode(
IN OPTIONAL PLSAP_CR_CLEAR_VALUE ClearValue,
OUT PUNICODE_STRING UnicodeString
)
/*++
Routine Description:
This function converts a Clear Value to a Unicode String. The Clear
Value structure must have valid syntax - no checking will be done.
Arguments:
ClearValue - Optional pointer to Clear Value to be converted. If
NULL is specified, the output Unicode String structure will
be initialized to point to the NULL string.
UnicodeString - Pointer to target Unicode String structure.
Return Value:
None.
--*/
{
LSAP_CR_CLEAR_VALUE IntermediateClearValue;
if (ARGUMENT_PRESENT(ClearValue)) {
IntermediateClearValue = *ClearValue;
UnicodeString->Length = (USHORT) IntermediateClearValue.Length;
UnicodeString->MaximumLength = (USHORT) IntermediateClearValue.MaximumLength;
UnicodeString->Buffer = (PWSTR) IntermediateClearValue.Buffer;
return;
}
UnicodeString->Length = UnicodeString->MaximumLength = 0;
UnicodeString->Buffer = NULL;
}